chore(dev): update dev environment

This commit is contained in:
MingxuanGame
2025-08-24 13:49:09 +00:00
parent 7eea68aa9a
commit 86c6c291e4
11 changed files with 538 additions and 115 deletions

View File

@@ -6,11 +6,17 @@
"workspaceFolder": "/workspaces/osu_lazer_api",
"containerEnv": {
"MYSQL_DATABASE": "osu_api",
"MYSQL_USER": "osu_user",
"MYSQL_PASSWORD": "osu_password",
"MYSQL_USER": "osu_api",
"MYSQL_PASSWORD": "password",
"MYSQL_HOST": "mysql",
"MYSQL_PORT": "3306"
},
"runArgs": [
"--name",
"g0v0-devcontainer",
"--label",
"jetbrains-attach=true"
],
"customizations": {
"vscode": {
"extensions": [
@@ -21,7 +27,12 @@
"ms-vscode.vscode-json",
"redhat.vscode-yaml",
"ms-vscode.docker",
"rust-lang.rust-analyzer"
"rust-lang.rust-analyzer",
"ms-dotnettools.csdevkit",
"ms-dotnettools.csharp",
"ms-dotnettools.vscode-dotnet-runtime",
"ms-dotnettools.blazorwasm-companion",
"editorconfig.editorconfig"
],
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python",
@@ -57,7 +68,24 @@
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer",
"editor.formatOnSave": true
},
"dotnet.defaultSolution": "/workspaces/osu_lazer_api/spectator-server/osu.Server.Spectator.sln",
"[csharp]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
},
"dotnet.completion.showCompletionItemsFromUnimportedNamespaces": true,
"dotnet.inlayHints.enableInlayHintsForParameters": true,
"dotnet.inlayHints.enableInlayHintsForLiteralParameters": true,
"dotnet.inlayHints.enableInlayHintsForIndexerParameters": true,
"dotnet.inlayHints.enableInlayHintsForObjectCreationParameters": true,
"dotnet.inlayHints.enableInlayHintsForOtherParameters": true,
"dotnet.inlayHints.enableInlayHintsForTypes": true,
"dotnet.inlayHints.enableInlayHintsForImplicitVariableTypes": true,
"dotnet.inlayHints.enableInlayHintsForLambdaParameterTypes": true,
"dotnet.inlayHints.enableInlayHintsForImplicitObjectCreation": true
}
}
},
@@ -66,13 +94,19 @@
"ghcr.io/devcontainers/features/rust:1": {
"version": "latest",
"profile": "default"
},
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "8.0"
}
},
"forwardPorts": [
8000,
3306,
6379
6379,
8086,
80,
8080
],
"postCreateCommand": "uv sync --dev && uv pip install rosu-pp-py && uv run alembic upgrade head && uv run pre-commit install && cd packages/msgpack_lazer_api && cargo check",
"postCreateCommand": "uv sync --dev && uv pip install rosu-pp-py && uv run alembic upgrade head && uv run pre-commit install && cd packages/msgpack_lazer_api && cargo check && cd ../../spectator-server && dotnet restore",
"remoteUser": "vscode"
}

View File

@@ -12,21 +12,41 @@ services:
depends_on:
- mysql
- redis
- nginx
environment:
DATABASE_URL: mysql+aiomysql://osu_user:osu_password@mysql:3306/osu_api
# Python/FastAPI 环境变量
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: osu_api
MYSQL_USER: osu_api
MYSQL_PASSWORD: password
REDIS_URL: redis://redis:6379/0
SECRET_KEY: dev-secret-key-change-in-production
OSU_CLIENT_ID: "5"
OSU_CLIENT_SECRET: "FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"
# Spectator Server 环境变量
SAVE_REPLAYS: "0"
REPLAY_UPLOAD_THREADS: "1"
TRACK_BUILD_USER_COUNTS: "1"
SERVER_PORT: "8086"
REDIS_HOST: "redis"
DD_AGENT_HOST: "localhost"
SHARED_INTEROP_DOMAIN: "http://localhost:8000"
SHARED_INTEROP_SECRET: "dev-interop-secret"
SENTRY_DSN: "https://5840d8cb8d2b4d238369443bedef1d74@glitchtip.g0v0.top/4"
USE_LEGACY_RSA_AUTH: "0"
# .NET 环境变量
DOTNET_CLI_TELEMETRY_OPTOUT: "1"
DOTNET_NOLOGO: "1"
mysql:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: osu_api
MYSQL_USER: osu_user
MYSQL_PASSWORD: osu_password
MYSQL_USER: osu_api
MYSQL_PASSWORD: password
ports:
- "3306:3306"
volumes:
@@ -47,6 +67,20 @@ services:
- devcontainer-network
command: redis-server --appendonly yes
nginx:
image: nginx:alpine
restart: unless-stopped
ports:
- "80:80"
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
networks:
- devcontainer-network
depends_on:
- mysql
- redis
networks:
devcontainer-network:
driver: bridge

78
.devcontainer/nginx.conf Normal file
View File

@@ -0,0 +1,78 @@
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream app {
server devcontainer:8000;
}
upstream spectator {
server devcontainer:8086;
}
server {
listen 80;
server_name _;
client_max_body_size 50m;
# 屏蔽 /_lio/ 及其所有子路径的外部访问
location ~ ^/_lio/ {
return 403;
}
# Spectator Server SignalR Hub
location /signalr/ {
proxy_pass http://spectator/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Authorization $http_authorization;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_connect_timeout 60s;
proxy_cache_bypass $http_upgrade;
proxy_buffering off;
}
# Health check for spectator server
location /health {
proxy_pass http://spectator/health;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# FastAPI application
location / {
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_connect_timeout 60s;
proxy_cache_bypass $http_upgrade;
proxy_buffering off;
}
}

View File

@@ -0,0 +1,42 @@
#!/bin/bash
# 开发环境启动脚本
# 同时启动 FastAPI 和 Spectator Server
set -e
if [ -f .env ]; then
echo "加载 .env 文件中的环境变量..."
set -a
source .env
set +a
else
echo ".env 文件未找到,跳过加载环境变量。"
fi
echo "🚀 启动开发环境..."
# 启动 FastAPI 服务器
echo "启动 FastAPI 服务器..."
cd /workspaces/osu_lazer_api
uv run uvicorn main:app --host 0.0.0.0 --port 8000 --reload &
FASTAPI_PID=$!
# 启动 Spectator Server
echo "启动 Spectator Server..."
cd /workspaces/osu_lazer_api/spectator-server
dotnet run --project osu.Server.Spectator --urls "http://0.0.0.0:8086" &
SPECTATOR_PID=$!
echo "✅ 服务已启动:"
echo " - FastAPI: http://localhost:8000"
echo " - Spectator Server: http://localhost:8086"
echo " - Nginx (统一入口): http://localhost:8080"
echo ""
echo "按 Ctrl+C 停止所有服务"
# 等待用户中断
trap 'echo "🛑 正在停止服务..."; kill $FASTAPI_PID $SPECTATOR_PID; exit 0' INT
# 保持脚本运行
wait

View File

@@ -26,3 +26,232 @@ indent_size = 2
[{*.py,*.pyi}]
indent_size = 4
# C# files
[*.cs]
#### Core EditorConfig Options ####
# Indentation and spacing
indent_size = 4
indent_style = space
tab_width = 4
# New line preferences
end_of_line = crlf
insert_final_newline = false
#### .NET Coding Conventions ####
# Organize usings
dotnet_separate_import_directive_groups = false
dotnet_sort_system_directives_first = false
file_header_template = unset
# this. and Me. preferences
dotnet_style_qualification_for_event = false
dotnet_style_qualification_for_field = false
dotnet_style_qualification_for_method = false
dotnet_style_qualification_for_property = false
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true
dotnet_style_predefined_type_for_member_access = true
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
dotnet_style_parentheses_in_other_operators = never_if_unnecessary
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members
# Expression-level preferences
dotnet_style_coalesce_expression = true
dotnet_style_collection_initializer = true
dotnet_style_explicit_tuple_names = true
dotnet_style_namespace_match_folder = true
dotnet_style_null_propagation = true
dotnet_style_object_initializer = true
dotnet_style_operator_placement_when_wrapping = beginning_of_line
dotnet_style_prefer_auto_properties = true
dotnet_style_prefer_collection_expression = when_types_loosely_match
dotnet_style_prefer_compound_assignment = true
dotnet_style_prefer_conditional_expression_over_assignment = true
dotnet_style_prefer_conditional_expression_over_return = true
dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
dotnet_style_prefer_inferred_anonymous_type_member_names = true
dotnet_style_prefer_inferred_tuple_names = true
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
dotnet_style_prefer_simplified_boolean_expressions = true
dotnet_style_prefer_simplified_interpolation = true
# Field preferences
dotnet_style_readonly_field = true
# Parameter preferences
dotnet_code_quality_unused_parameters = all:silent
# Suppression preferences
dotnet_remove_unnecessary_suppression_exclusions = none
# New line preferences
dotnet_style_allow_multiple_blank_lines_experimental = true
dotnet_style_allow_statement_immediately_after_block_experimental = true
#### C# Coding Conventions ####
# var preferences
csharp_style_var_elsewhere = false
csharp_style_var_for_built_in_types = false
csharp_style_var_when_type_is_apparent = false
# Expression-bodied members
csharp_style_expression_bodied_accessors = true
csharp_style_expression_bodied_constructors = false
csharp_style_expression_bodied_indexers = true
csharp_style_expression_bodied_lambdas = true
csharp_style_expression_bodied_local_functions = false
csharp_style_expression_bodied_methods = false
csharp_style_expression_bodied_operators = false
csharp_style_expression_bodied_properties = true
# Pattern matching preferences
csharp_style_pattern_matching_over_as_with_null_check = true
csharp_style_pattern_matching_over_is_with_cast_check = true
csharp_style_prefer_extended_property_pattern = true
csharp_style_prefer_not_pattern = true
csharp_style_prefer_pattern_matching = true
csharp_style_prefer_switch_expression = true
# Null-checking preferences
csharp_style_conditional_delegate_call = true
# Modifier preferences
csharp_prefer_static_local_function = true
csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async
csharp_style_prefer_readonly_struct = true
csharp_style_prefer_readonly_struct_member = true
# Code-block preferences
csharp_prefer_braces = true
csharp_prefer_simple_using_statement = true
csharp_style_namespace_declarations = block_scoped
csharp_style_prefer_method_group_conversion = true
csharp_style_prefer_primary_constructors = true
csharp_style_prefer_top_level_statements = true
# Expression-level preferences
csharp_prefer_simple_default_expression = true
csharp_style_deconstructed_variable_declaration = true
csharp_style_implicit_object_creation_when_type_is_apparent = true
csharp_style_inlined_variable_declaration = true
csharp_style_prefer_index_operator = true
csharp_style_prefer_local_over_anonymous_function = true
csharp_style_prefer_null_check_over_type_check = true
csharp_style_prefer_range_operator = true
csharp_style_prefer_tuple_swap = true
csharp_style_prefer_utf8_string_literals = true
csharp_style_throw_expression = true
csharp_style_unused_value_assignment_preference = discard_variable
csharp_style_unused_value_expression_statement_preference = discard_variable
# 'using' directive preferences
csharp_using_directive_placement = outside_namespace
# New line preferences
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true
csharp_style_allow_embedded_statements_on_same_line_experimental = true
#### C# Formatting Rules ####
# New line preferences
csharp_new_line_before_catch = true
csharp_new_line_before_else = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_open_brace = all
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_labels = one_less_than_current
csharp_indent_switch_labels = true
# Space preferences
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
# Wrapping preferences
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true
#### Naming styles ####
# Naming rules
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
# Symbol specifications
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
# Naming styles
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case

3
.gitignore vendored
View File

@@ -176,7 +176,8 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.idea/
./spectator-server/.idea/
# Abstra
# Abstra is an AI-powered process automation framework.

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "spectator-server"]
path = spectator-server
url = https://github.com/GooGuTeam/osu-server-spectator.git

View File

@@ -1,6 +1,6 @@
default_install_hook_types: [pre-commit, prepare-commit-msg]
ci:
autofix_commit_msg: "chore(deps): auto fix by pre-commit hooks"
autofix_commit_msg: "chore(linter): auto fix by pre-commit hooks"
autofix_prs: true
autoupdate_branch: master
autoupdate_schedule: monthly

View File

@@ -156,11 +156,10 @@ def create_access_token(data: dict, expires_delta: timedelta | None = None) -> s
expire = utcnow() + timedelta(minutes=settings.access_token_expire_minutes)
# 添加标准JWT声明
to_encode.update({"exp": expire, "random": secrets.token_hex(16)})
if hasattr(settings, "jwt_audience") and settings.jwt_audience:
to_encode.update({"exp": expire, "jti": secrets.token_hex(16)})
if settings.jwt_audience:
to_encode["aud"] = settings.jwt_audience
if hasattr(settings, "jwt_issuer") and settings.jwt_issuer:
to_encode["iss"] = settings.jwt_issuer
to_encode["iss"] = str(settings.server_url)
# 编码JWT
encoded_jwt = jwt.encode(to_encode, settings.secret_key, algorithm=settings.algorithm)

View File

@@ -5,6 +5,9 @@
},
{
"path": "packages/msgpack_lazer_api"
},
{
"path": "spectator-server"
}
]
}