docs(readme): update readme
This commit is contained in:
128
.env.example
128
.env.example
@@ -1,94 +1,107 @@
|
|||||||
# 数据库设置
|
# see https://github.com/GooGuTeam/g0v0-server/wiki/Configuration
|
||||||
|
# Database Settings
|
||||||
MYSQL_HOST="localhost"
|
MYSQL_HOST="localhost"
|
||||||
MYSQL_PORT=3306
|
MYSQL_PORT=3306
|
||||||
MYSQL_DATABASE="osu_api"
|
MYSQL_DATABASE="osu_api"
|
||||||
MYSQL_USER="osu_api"
|
MYSQL_USER="osu_api"
|
||||||
MYSQL_PASSWORD="password"
|
MYSQL_PASSWORD="password"
|
||||||
MYSQL_ROOT_PASSWORD="password"
|
MYSQL_ROOT_PASSWORD="password"
|
||||||
# Redis URL
|
|
||||||
REDIS_URL="redis://127.0.0.1:6379/0"
|
REDIS_URL="redis://127.0.0.1:6379/0"
|
||||||
|
|
||||||
# JWT 密钥,使用 openssl rand -hex 32 生成
|
# JWT Settings
|
||||||
|
# Use `openssl rand -hex 32` to generate a secure key
|
||||||
JWT_SECRET_KEY="your_jwt_secret_here"
|
JWT_SECRET_KEY="your_jwt_secret_here"
|
||||||
# JWT 算法
|
|
||||||
ALGORITHM="HS256"
|
ALGORITHM="HS256"
|
||||||
# JWT 过期时间
|
|
||||||
ACCESS_TOKEN_EXPIRE_MINUTES=1440
|
ACCESS_TOKEN_EXPIRE_MINUTES=1440
|
||||||
|
|
||||||
# 服务器地址
|
# OAuth Settings
|
||||||
|
OSU_CLIENT_ID=5
|
||||||
|
OSU_CLIENT_SECRET="FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"
|
||||||
|
OSU_WEB_CLIENT_ID=6
|
||||||
|
# Use `openssl rand -hex 40` to generate a secure key
|
||||||
|
OSU_WEB_CLIENT_SECRET="your_osu_web_client_secret_here"
|
||||||
|
|
||||||
|
# Server Settings
|
||||||
HOST="0.0.0.0"
|
HOST="0.0.0.0"
|
||||||
PORT=8000
|
PORT=8000
|
||||||
# 服务器 URL
|
|
||||||
SERVER_URL="http://localhost:8000"
|
|
||||||
# 额外的 CORS 允许的域名列表
|
|
||||||
CORS_URLS='[]'
|
|
||||||
# 前端 URL,当访问从游戏打开的 URL 时会重定向到这个 URL,为空表示不重定向
|
|
||||||
FRONTEND_URL
|
|
||||||
# 调试模式,生产环境请设置为 false
|
|
||||||
DEBUG=false
|
DEBUG=false
|
||||||
|
CORS_URLS='[]'
|
||||||
|
SERVER_URL="http://localhost:8000"
|
||||||
|
FRONTEND_URL=
|
||||||
|
|
||||||
# osu! 登录设置
|
# SignalR Settings
|
||||||
OSU_CLIENT_ID=5 # lazer client ID
|
|
||||||
OSU_CLIENT_SECRET="FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk" # lazer client secret
|
|
||||||
OSU_WEB_CLIENT_ID=6 # 网页端 client ID
|
|
||||||
OSU_WEB_CLIENT_SECRET="your_osu_web_client_secret_here" # 网页端 client secret,使用 openssl rand -hex 40 生成
|
|
||||||
|
|
||||||
# SignalR 服务器设置
|
|
||||||
SIGNALR_NEGOTIATE_TIMEOUT=30
|
SIGNALR_NEGOTIATE_TIMEOUT=30
|
||||||
SIGNALR_PING_INTERVAL=15
|
SIGNALR_PING_INTERVAL=15
|
||||||
|
|
||||||
# Fetcher 设置
|
# Fetcher Settings
|
||||||
FETCHER_CLIENT_ID=""
|
FETCHER_CLIENT_ID=""
|
||||||
FETCHER_CLIENT_SECRET=""
|
FETCHER_CLIENT_SECRET=""
|
||||||
FETCHER_SCOPES=public
|
FETCHER_SCOPES="public"
|
||||||
|
|
||||||
# 日志设置
|
# Logging Settings
|
||||||
LOG_LEVEL="INFO"
|
LOG_LEVEL="INFO"
|
||||||
|
|
||||||
# 邮件服务设置
|
# Email Service Settings
|
||||||
SMTP_SERVER="smtp.gmail.com" # SMTP 服务器地址
|
ENABLE_EMAIL_VERIFICATION=false
|
||||||
SMTP_PORT=587 # SMTP 端口
|
SMTP_SERVER="localhost"
|
||||||
SMTP_USERNAME="your-email@gmail.com" # 邮箱用户名
|
SMTP_PORT=587
|
||||||
SMTP_PASSWORD="your-app-password" # 邮箱密码或应用专用密码
|
SMTP_USERNAME=""
|
||||||
FROM_EMAIL="noreply@your-server.com" # 发送方邮箱
|
SMTP_PASSWORD=""
|
||||||
FROM_NAME="osu! Private Server" # 发送方名称
|
FROM_EMAIL="noreply@example.com"
|
||||||
|
FROM_NAME="osu! server"
|
||||||
|
|
||||||
# 邮件验证功能开关
|
# Sentry Configuration
|
||||||
ENABLE_EMAIL_VERIFICATION=true # 是否启用邮件验证功能(新位置登录时需要邮件验证)
|
SENTRY_DSN=
|
||||||
ENABLE_EMAIL_SENDING=false # 是否真实发送邮件(false时仅模拟发送,输出到日志)
|
|
||||||
|
|
||||||
# Sentry 设置,为空表示不启用
|
# New Relic Configuration
|
||||||
SENTRY_DSN
|
NEW_RELIC_ENVIRONMENT=
|
||||||
|
|
||||||
# GeoIP 配置 - MaxMind License Key(用于 IP 地址地理位置查询)
|
# GeoIP Configuration
|
||||||
MAXMIND_LICENSE_KEY=""
|
MAXMIND_LICENSE_KEY=""
|
||||||
# GeoIP 数据库存储目录
|
|
||||||
GEOIP_DEST_DIR="./geoip"
|
GEOIP_DEST_DIR="./geoip"
|
||||||
# GeoIP 每周更新的星期几(0=周一,6=周日)
|
|
||||||
GEOIP_UPDATE_DAY=1
|
GEOIP_UPDATE_DAY=1
|
||||||
# GeoIP 每周更新时间(小时,0-23)
|
|
||||||
GEOIP_UPDATE_HOUR=2
|
GEOIP_UPDATE_HOUR=2
|
||||||
|
|
||||||
# 游戏设置
|
# Game Settings
|
||||||
ENABLE_RX=false # 启用 RX mod 统计数据
|
ENABLE_RX=false
|
||||||
ENABLE_AP=false # 启用 AP mod Z统计数据
|
ENABLE_AP=false
|
||||||
ENABLE_ALL_MODS_PP=false # 启用所有 Mod 的 PP 计算
|
ENABLE_ALL_MODS_PP=false
|
||||||
ENABLE_SUPPORTER_FOR_ALL_USERS=false # 启用所有新注册用户的支持者状态
|
ENABLE_SUPPORTER_FOR_ALL_USERS=false
|
||||||
ENABLE_ALL_BEATMAP_LEADERBOARD=false # 启用所有谱面的排行榜(没有排行榜的谱面会以 APPROVED 状态返回)
|
ENABLE_ALL_BEATMAP_LEADERBOARD=false
|
||||||
ENABLE_ALL_BEATMAP_PP=false # 允许任何谱面获得 PP
|
ENABLE_ALL_BEATMAP_PP=false
|
||||||
SUSPICIOUS_SCORE_CHECK=true # 是否检查可疑的分数,默认开启
|
SEASONAL_BACKGROUNDS='[]'
|
||||||
SEASONAL_BACKGROUNDS='[]' # 季节背景图 URL 列表
|
|
||||||
BANNED_NAME='["mrekk", "vaxei", "btmc", "cookiezi", "peppy", "saragi", "chocomint"]' # 禁止使用的用户名列表
|
|
||||||
|
|
||||||
# 存储服务设置
|
# Beatmap Cache Settings
|
||||||
# 支持的存储类型:local(本地存储)、r2(Cloudflare R2)、s3(AWS S3)
|
ENABLE_BEATMAP_PRELOAD=true
|
||||||
|
BEATMAP_CACHE_EXPIRE_HOURS=24
|
||||||
|
|
||||||
|
# Ranking Cache Settings
|
||||||
|
ENABLE_RANKING_CACHE=true
|
||||||
|
RANKING_CACHE_EXPIRE_MINUTES=10
|
||||||
|
RANKING_CACHE_REFRESH_INTERVAL_MINUTES=10
|
||||||
|
RANKING_CACHE_MAX_PAGES=20
|
||||||
|
RANKING_CACHE_TOP_COUNTRIES=20
|
||||||
|
|
||||||
|
# User Cache Settings
|
||||||
|
ENABLE_USER_CACHE_PRELOAD=true
|
||||||
|
USER_CACHE_EXPIRE_SECONDS=300
|
||||||
|
USER_SCORES_CACHE_EXPIRE_SECONDS=60
|
||||||
|
USER_BEATMAPSETS_CACHE_EXPIRE_SECONDS=600
|
||||||
|
USER_CACHE_MAX_PRELOAD_USERS=200
|
||||||
|
USER_CACHE_CONCURRENT_LIMIT=10
|
||||||
|
|
||||||
|
# Anti-cheat Settings
|
||||||
|
SUSPICIOUS_SCORE_CHECK=true
|
||||||
|
BANNED_NAME='["mrekk", "vaxei", "btmc", "cookiezi", "peppy", "saragi", "chocomint"]'
|
||||||
|
|
||||||
|
# Storage Settings
|
||||||
|
# Supported storage services: local, r2, s3
|
||||||
STORAGE_SERVICE="local"
|
STORAGE_SERVICE="local"
|
||||||
|
|
||||||
# 存储服务配置 (JSON 格式)
|
# Local Storage Settings (when STORAGE_SERVICE=local)
|
||||||
# 本地存储配置(当 STORAGE_SERVICE=local 时)
|
# STORAGE_SETTINGS='{"local_storage_path": "./storage"}'
|
||||||
STORAGE_SETTINGS='{"local_storage_path": "./storage"}'
|
|
||||||
|
|
||||||
# Cloudflare R2 存储配置(当 STORAGE_SERVICE=r2 时)
|
# Cloudflare R2 Storage Settings (when STORAGE_SERVICE=r2)
|
||||||
# STORAGE_SETTINGS='{
|
# STORAGE_SETTINGS='{
|
||||||
# "r2_account_id": "your_cloudflare_r2_account_id",
|
# "r2_account_id": "your_cloudflare_r2_account_id",
|
||||||
# "r2_access_key_id": "your_r2_access_key_id",
|
# "r2_access_key_id": "your_r2_access_key_id",
|
||||||
@@ -97,11 +110,10 @@ STORAGE_SETTINGS='{"local_storage_path": "./storage"}'
|
|||||||
# "r2_public_url_base": "https://your-custom-domain.com"
|
# "r2_public_url_base": "https://your-custom-domain.com"
|
||||||
# }'
|
# }'
|
||||||
|
|
||||||
# AWS S3 存储配置(当 STORAGE_SERVICE=s3 时)
|
# AWS S3 Storage Settings (when STORAGE_SERVICE=s3)
|
||||||
# STORAGE_SETTINGS='{
|
# STORAGE_SETTINGS='{
|
||||||
# "s3_access_key_id": "your_aws_access_key_id",
|
# "s3_access_key_id": "your_aws_access_key_id",
|
||||||
# "s3_secret_access_key": "your_aws_secret_access_key",
|
# "s3_secret_access_key": "your_aws_secret_access_key",
|
||||||
# "s3_bucket_name": "your_s3_bucket_name",
|
# "s3_bucket_name": "your_s3_bucket_name",
|
||||||
# "s3_region_name": "us-east-1",
|
# "s3_region_name": "us-east-1",
|
||||||
# "s3_public_url_base": "https://your-custom-domain.com"
|
# "s3_public_url_base": "https://your-custom
|
||||||
# }'
|
|
||||||
|
|||||||
129
README.en.md
129
README.en.md
@@ -25,7 +25,7 @@ This is an osu! API server implemented with FastAPI + MySQL + Redis, supporting
|
|||||||
```
|
```
|
||||||
2. Create a `.env` file
|
2. Create a `.env` file
|
||||||
|
|
||||||
Please see the server configuration below to modify the .env file.
|
Please see [wiki](https://github.com/GooGuTeam/g0v0-server/wiki/Configuration) to modify the .env file.
|
||||||
```bash
|
```bash
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
```
|
```
|
||||||
@@ -40,131 +40,6 @@ This is an osu! API server implemented with FastAPI + MySQL + Redis, supporting
|
|||||||
|
|
||||||
Use a [custom osu!lazer client](https://github.com/GooGuTeam/osu), or use [LazerAuthlibInjection](https://github.com/MingxuanGame/LazerAuthlibInjection), and change the server settings to the server's address.
|
Use a [custom osu!lazer client](https://github.com/GooGuTeam/osu), or use [LazerAuthlibInjection](https://github.com/MingxuanGame/LazerAuthlibInjection), and change the server settings to the server's address.
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Database Settings
|
|
||||||
| Variable Name | Description | Default Value |
|
|
||||||
|---|---|---|
|
|
||||||
| `MYSQL_HOST` | MySQL host address | `localhost` |
|
|
||||||
| `MYSQL_PORT` | MySQL port | `3306` |
|
|
||||||
| `MYSQL_DATABASE` | MySQL database name | `osu_api` |
|
|
||||||
| `MYSQL_USER` | MySQL username | `osu_api` |
|
|
||||||
| `MYSQL_PASSWORD` | MySQL password | `password` |
|
|
||||||
| `MYSQL_ROOT_PASSWORD` | MySQL root password | `password` |
|
|
||||||
| `REDIS_URL` | Redis connection string | `redis://127.0.0.1:6379/0` |
|
|
||||||
|
|
||||||
### JWT Settings
|
|
||||||
| Variable Name | Description | Default Value |
|
|
||||||
|---|---|---|
|
|
||||||
| `JWT_SECRET_KEY` | JWT signing key | `your_jwt_secret_here` |
|
|
||||||
| `ALGORITHM` | JWT algorithm | `HS256` |
|
|
||||||
| `ACCESS_TOKEN_EXPIRE_MINUTES` | Access token expiration time (minutes) | `1440` |
|
|
||||||
|
|
||||||
### Server Settings
|
|
||||||
| Variable Name | Description | Default Value |
|
|
||||||
|---|---|---|
|
|
||||||
| `HOST` | Server listening address | `0.0.0.0` |
|
|
||||||
| `PORT` | Server listening port | `8000` |
|
|
||||||
| `DEBUG` | Debug mode | `false` |
|
|
||||||
| `SERVER_URL` | Server URL | `http://localhost:8000` |
|
|
||||||
| `CORS_URLS` | Additional CORS allowed domain list (JSON format) | `[]` |
|
|
||||||
| `FRONTEND_URL` | Frontend URL, redirects to this URL when accessing URLs opened from the game. Empty means no redirection. | `(null)` |
|
|
||||||
|
|
||||||
### OAuth Settings
|
|
||||||
| Variable Name | Description | Default Value |
|
|
||||||
|---|---|---|
|
|
||||||
| `OSU_CLIENT_ID` | OAuth client ID | `5` |
|
|
||||||
| `OSU_CLIENT_SECRET` | OAuth client secret | `FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk` |
|
|
||||||
| `OSU_WEB_CLIENT_ID` | Web OAuth client ID | `6` |
|
|
||||||
| `OSU_WEB_CLIENT_SECRET` | Web OAuth client secret | `your_osu_web_client_secret_here` |
|
|
||||||
|
|
||||||
### SignalR Server Settings
|
|
||||||
| Variable Name | Description | Default Value |
|
|
||||||
|---|---|---|
|
|
||||||
| `SIGNALR_NEGOTIATE_TIMEOUT` | SignalR negotiation timeout (seconds) | `30` |
|
|
||||||
| `SIGNALR_PING_INTERVAL` | SignalR ping interval (seconds) | `15` |
|
|
||||||
|
|
||||||
### Fetcher Settings
|
|
||||||
|
|
||||||
The Fetcher is used to get data from the official osu! API using OAuth 2.0 authentication.
|
|
||||||
|
|
||||||
| Variable Name | Description | Default Value |
|
|
||||||
|---|---|---|
|
|
||||||
| `FETCHER_CLIENT_ID` | Fetcher client ID | `""` |
|
|
||||||
| `FETCHER_CLIENT_SECRET` | Fetcher client secret | `""` |
|
|
||||||
| `FETCHER_SCOPES` | Fetcher scopes | `public` |
|
|
||||||
|
|
||||||
### Log Settings
|
|
||||||
| Variable Name | Description | Default Value |
|
|
||||||
|---|---|---|
|
|
||||||
| `LOG_LEVEL` | Log level | `INFO` |
|
|
||||||
|
|
||||||
### Sentry Settings
|
|
||||||
| Variable Name | Description | Default Value |
|
|
||||||
|---|---|---|
|
|
||||||
| `SENTRY_DSN` | Sentry DSN, empty to disable Sentry | `(null)` |
|
|
||||||
|
|
||||||
### Game Settings
|
|
||||||
| Variable Name | Description | Default Value |
|
|
||||||
|---|---|---|
|
|
||||||
| `ENABLE_RX` | Enable RX mod statistics | `false` |
|
|
||||||
| `ENABLE_AP` | Enable AP mod statistics | `false` |
|
|
||||||
| `ENABLE_ALL_MODS_PP` | Enable PP calculation for all mods | `false` |
|
|
||||||
| `ENABLE_SUPPORTER_FOR_ALL_USERS` | Enable supporter status for all new users | `false` |
|
|
||||||
| `ENABLE_ALL_BEATMAP_LEADERBOARD` | Enable leaderboards for all beatmaps | `false` |
|
|
||||||
| `ENABLE_ALL_BEATMAP_PP` | Allow any beatmap to grant PP | `false` |
|
|
||||||
| `SUSPICIOUS_SCORE_CHECK` | Enable suspicious score check (star>25 & acc<80 or pp>2300) | `true` |
|
|
||||||
| `SEASONAL_BACKGROUNDS` | List of seasonal background URLs | `[]` |
|
|
||||||
| `BANNED_NAME` | List of banned usernames | `["mrekk", "vaxei", "btmc", "cookiezi", "peppy", "saragi", "chocomint"]` |
|
|
||||||
|
|
||||||
### Storage Service Settings
|
|
||||||
|
|
||||||
Used for storing replay files, avatars, and other static assets.
|
|
||||||
|
|
||||||
| Variable Name | Description | Default Value |
|
|
||||||
|---|---|---|
|
|
||||||
| `STORAGE_SERVICE` | Storage service type: `local`, `r2`, `s3` | `local` |
|
|
||||||
| `STORAGE_SETTINGS` | Storage service configuration (JSON format), see below for configuration | `{"local_storage_path": "./storage"}` |
|
|
||||||
|
|
||||||
## Storage Service Configuration
|
|
||||||
|
|
||||||
### Local Storage (Recommended for development)
|
|
||||||
|
|
||||||
Local storage saves files to the server's local filesystem, suitable for development and small-scale deployments.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
STORAGE_SERVICE="local"
|
|
||||||
STORAGE_SETTINGS='{"local_storage_path": "./storage"}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Cloudflare R2 Storage (Recommended for production)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
STORAGE_SERVICE="r2"
|
|
||||||
STORAGE_SETTINGS='{
|
|
||||||
"r2_account_id": "your_cloudflare_account_id",
|
|
||||||
"r2_access_key_id": "your_r2_access_key_id",
|
|
||||||
"r2_secret_access_key": "your_r2_secret_access_key",
|
|
||||||
"r2_bucket_name": "your_bucket_name",
|
|
||||||
"r2_public_url_base": "https://your-custom-domain.com"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### AWS S3 Storage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
STORAGE_SERVICE="s3"
|
|
||||||
STORAGE_SETTINGS='{
|
|
||||||
"s3_access_key_id": "your_aws_access_key_id",
|
|
||||||
"s3_secret_access_key": "your_aws_secret_access_key",
|
|
||||||
"s3_bucket_name": "your_s3_bucket_name",
|
|
||||||
"s3_region_name": "us-east-1",
|
|
||||||
"s3_public_url_base": "https://your-custom-domain.com"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Note**: In a production environment, be sure to change the default keys and passwords!
|
|
||||||
|
|
||||||
### Updating the Database
|
### Updating the Database
|
||||||
|
|
||||||
Refer to the [Database Migration Guide](https://github.com/GooGuTeam/g0v0-server/wiki/Migrate-Database)
|
Refer to the [Database Migration Guide](https://github.com/GooGuTeam/g0v0-server/wiki/Migrate-Database)
|
||||||
@@ -177,6 +52,8 @@ MIT License
|
|||||||
|
|
||||||
The project is currently in a state of rapid iteration. Issues and Pull Requests are welcome!
|
The project is currently in a state of rapid iteration. Issues and Pull Requests are welcome!
|
||||||
|
|
||||||
|
See [Contributing Guide](./CONTRIBUTING.md) for more information.
|
||||||
|
|
||||||
## Discussion
|
## Discussion
|
||||||
|
|
||||||
- Discord: https://discord.gg/AhzJXXWYfF
|
- Discord: https://discord.gg/AhzJXXWYfF
|
||||||
|
|||||||
143
README.md
143
README.md
@@ -26,7 +26,7 @@ cd g0v0-server
|
|||||||
|
|
||||||
2. 创建 `.env` 文件
|
2. 创建 `.env` 文件
|
||||||
|
|
||||||
请参考下方的服务器配置修改 .env 文件
|
请参考 [wiki](https://github.com/GooGuTeam/g0v0-server/wiki/Configuration) 来修改 `.env` 文件
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
@@ -44,145 +44,6 @@ docker-compose -f docker-compose-osurx.yml up -d
|
|||||||
|
|
||||||
使用[自定义的 osu!lazer 客户端](https://github.com/GooGuTeam/osu),或者使用 [LazerAuthlibInjection](https://github.com/MingxuanGame/LazerAuthlibInjection),修改服务器设置为服务器的 IP
|
使用[自定义的 osu!lazer 客户端](https://github.com/GooGuTeam/osu),或者使用 [LazerAuthlibInjection](https://github.com/MingxuanGame/LazerAuthlibInjection),修改服务器设置为服务器的 IP
|
||||||
|
|
||||||
## 环境变量配置
|
|
||||||
|
|
||||||
### 数据库设置
|
|
||||||
| 变量名 | 描述 | 默认值 |
|
|
||||||
|--------|------|--------|
|
|
||||||
| `MYSQL_HOST` | MySQL 主机地址 | `localhost` |
|
|
||||||
| `MYSQL_PORT` | MySQL 端口 | `3306` |
|
|
||||||
| `MYSQL_DATABASE` | MySQL 数据库名 | `osu_api` |
|
|
||||||
| `MYSQL_USER` | MySQL 用户名 | `osu_api` |
|
|
||||||
| `MYSQL_PASSWORD` | MySQL 密码 | `password` |
|
|
||||||
| `MYSQL_ROOT_PASSWORD` | MySQL root 密码 | `password` |
|
|
||||||
| `REDIS_URL` | Redis 连接字符串 | `redis://127.0.0.1:6379/0` |
|
|
||||||
|
|
||||||
### JWT 设置
|
|
||||||
| 变量名 | 描述 | 默认值 |
|
|
||||||
|--------|------|--------|
|
|
||||||
| `JWT_SECRET_KEY` | JWT 签名密钥 | `your_jwt_secret_here` |
|
|
||||||
| `ALGORITHM` | JWT 算法 | `HS256` |
|
|
||||||
| `ACCESS_TOKEN_EXPIRE_MINUTES` | 访问令牌过期时间(分钟) | `1440` |
|
|
||||||
|
|
||||||
### 服务器设置
|
|
||||||
| 变量名 | 描述 | 默认值 |
|
|
||||||
|--------|------|--------|
|
|
||||||
| `HOST` | 服务器监听地址 | `0.0.0.0` |
|
|
||||||
| `PORT` | 服务器监听端口 | `8000` |
|
|
||||||
| `DEBUG` | 调试模式 | `false` |
|
|
||||||
| `SERVER_URL` | 服务器 URL | `http://localhost:8000` |
|
|
||||||
| `CORS_URLS` | 额外的 CORS 允许的域名列表 (JSON 格式) | `[]` |
|
|
||||||
| `FRONTEND_URL` | 前端 URL,当访问从游戏打开的 URL 时会重定向到这个 URL,为空表示不重定向 | `(null)` |
|
|
||||||
|
|
||||||
### OAuth 设置
|
|
||||||
| 变量名 | 描述 | 默认值 |
|
|
||||||
|--------|------|--------|
|
|
||||||
| `OSU_CLIENT_ID` | OAuth 客户端 ID | `5` |
|
|
||||||
| `OSU_CLIENT_SECRET` | OAuth 客户端密钥 | `FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk` |
|
|
||||||
| `OSU_WEB_CLIENT_ID` | Web OAuth 客户端 ID | `6` |
|
|
||||||
| `OSU_WEB_CLIENT_SECRET` | Web OAuth 客户端密钥 | `your_osu_web_client_secret_here`
|
|
||||||
|
|
||||||
### SignalR 服务器设置
|
|
||||||
| 变量名 | 描述 | 默认值 |
|
|
||||||
|--------|------|--------|
|
|
||||||
| `SIGNALR_NEGOTIATE_TIMEOUT` | SignalR 协商超时时间(秒) | `30` |
|
|
||||||
| `SIGNALR_PING_INTERVAL` | SignalR ping 间隔(秒) | `15` |
|
|
||||||
|
|
||||||
### Fetcher 设置
|
|
||||||
|
|
||||||
Fetcher 用于从 osu! 官方 API 获取数据,使用 osu! 官方 API 的 OAuth 2.0 认证
|
|
||||||
|
|
||||||
| 变量名 | 描述 | 默认值 |
|
|
||||||
|--------|------|--------|
|
|
||||||
| `FETCHER_CLIENT_ID` | Fetcher 客户端 ID | `""` |
|
|
||||||
| `FETCHER_CLIENT_SECRET` | Fetcher 客户端密钥 | `""` |
|
|
||||||
| `FETCHER_SCOPES` | Fetcher 权限范围 | `public` |
|
|
||||||
|
|
||||||
### 日志设置
|
|
||||||
| 变量名 | 描述 | 默认值 |
|
|
||||||
|--------|------|--------|
|
|
||||||
| `LOG_LEVEL` | 日志级别 | `INFO` |
|
|
||||||
|
|
||||||
### Sentry 设置
|
|
||||||
| 变量名 | 描述 | 默认值 |
|
|
||||||
|--------|------|--------|
|
|
||||||
| `SENTRY_DSN` | Sentry DSN,为空不启用 Sentry | `(null)` |
|
|
||||||
|
|
||||||
### GeoIP 配置
|
|
||||||
| 变量名 | 描述 | 默认值 |
|
|
||||||
|--------|------|--------|
|
|
||||||
| `MAXMIND_LICENSE_KEY` | MaxMind License Key(用于下载离线IP库) | `""` |
|
|
||||||
| `GEOIP_DEST_DIR` | GeoIP 数据库存储目录 | `"./geoip"` |
|
|
||||||
| `GEOIP_UPDATE_DAY` | GeoIP 每周更新的星期几(0=周一,6=周日) | `1` |
|
|
||||||
| `GEOIP_UPDATE_HOUR` | GeoIP 每周更新时间(小时,0-23) | `2` |
|
|
||||||
|
|
||||||
### New Relic 设置
|
|
||||||
| 变量名 | 描述 | 默认值 |
|
|
||||||
|--------|------|--------|
|
|
||||||
| `NEW_RELIC_ENVIRONMENT` | New Relic 环境标识 | `"production"` 或 `"development"` |
|
|
||||||
|
|
||||||
将 `newrelic.ini` 配置文件放入项目根目录即可自动启用 New Relic 监控。如果配置文件不存在或 newrelic 包未安装,将跳过 New Relic 初始化。可通过环境变量 `NEW_RELIC_ENVIRONMENT` 指定运行环境。
|
|
||||||
|
|
||||||
### 游戏设置
|
|
||||||
| 变量名 | 描述 | 默认值 |
|
|
||||||
|--------|------|--------|
|
|
||||||
| `ENABLE_RX` | 启用 RX mod 统计数据 | `false` |
|
|
||||||
| `ENABLE_AP` | 启用 AP mod 统计数据 | `false` |
|
|
||||||
| `ENABLE_ALL_MODS_PP` | 启用所有 Mod 的 PP 计算 | `false` |
|
|
||||||
| `ENABLE_SUPPORTER_FOR_ALL_USERS` | 启用所有新注册用户的支持者状态 | `false` |
|
|
||||||
| `ENABLE_ALL_BEATMAP_LEADERBOARD` | 启用所有谱面的排行榜 | `false` |
|
|
||||||
| `ENABLE_ALL_BEATMAP_PP` | 允许任何谱面获得 PP | `false` |
|
|
||||||
| `SUSPICIOUS_SCORE_CHECK` | 启用可疑分数检查(star>25&acc<80 或 pp>2300) | `true` |
|
|
||||||
| `SEASONAL_BACKGROUNDS` | 季节背景图 URL 列表 | `[]` |
|
|
||||||
| `BANNED_NAME` | 禁止使用的用户名列表 | `["mrekk", "vaxei", "btmc", "cookiezi", "peppy", "saragi", "chocomint"]` |
|
|
||||||
|
|
||||||
### 存储服务设置
|
|
||||||
|
|
||||||
用于存储回放文件、头像等静态资源。
|
|
||||||
|
|
||||||
| 变量名 | 描述 | 默认值 |
|
|
||||||
|--------|------|--------|
|
|
||||||
| `STORAGE_SERVICE` | 存储服务类型:`local`、`r2`、`s3` | `local` |
|
|
||||||
| `STORAGE_SETTINGS` | 存储服务配置 (JSON 格式),配置见下 | `{"local_storage_path": "./storage"}` |
|
|
||||||
|
|
||||||
## 存储服务配置
|
|
||||||
|
|
||||||
### 本地存储 (推荐用于开发环境)
|
|
||||||
|
|
||||||
本地存储将文件保存在服务器的本地文件系统中,适合开发和小规模部署。
|
|
||||||
|
|
||||||
```bash
|
|
||||||
STORAGE_SERVICE="local"
|
|
||||||
STORAGE_SETTINGS='{"local_storage_path": "./storage"}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Cloudflare R2 存储 (推荐用于生产环境)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
STORAGE_SERVICE="r2"
|
|
||||||
STORAGE_SETTINGS='{
|
|
||||||
"r2_account_id": "your_cloudflare_account_id",
|
|
||||||
"r2_access_key_id": "your_r2_access_key_id",
|
|
||||||
"r2_secret_access_key": "your_r2_secret_access_key",
|
|
||||||
"r2_bucket_name": "your_bucket_name",
|
|
||||||
"r2_public_url_base": "https://your-custom-domain.com"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### AWS S3 存储
|
|
||||||
|
|
||||||
```bash
|
|
||||||
STORAGE_SERVICE="s3"
|
|
||||||
STORAGE_SETTINGS='{
|
|
||||||
"s3_access_key_id": "your_aws_access_key_id",
|
|
||||||
"s3_secret_access_key": "your_aws_secret_access_key",
|
|
||||||
"s3_bucket_name": "your_s3_bucket_name",
|
|
||||||
"s3_region_name": "us-east-1",
|
|
||||||
"s3_public_url_base": "https://your-custom-domain.com"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
> **注意**: 在生产环境中,请务必更改默认的密钥和密码!
|
|
||||||
|
|
||||||
### 更新数据库
|
### 更新数据库
|
||||||
|
|
||||||
@@ -196,6 +57,8 @@ MIT License
|
|||||||
|
|
||||||
项目目前处于快速迭代状态,欢迎提交 Issue 和 Pull Request!
|
项目目前处于快速迭代状态,欢迎提交 Issue 和 Pull Request!
|
||||||
|
|
||||||
|
查看 [贡献指南](./CONTRIBUTING.md) 获取更多信息。
|
||||||
|
|
||||||
## 参与讨论
|
## 参与讨论
|
||||||
|
|
||||||
- QQ 群:`1059561526`
|
- QQ 群:`1059561526`
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ class Settings(BaseSettings):
|
|||||||
log_level: str = "INFO"
|
log_level: str = "INFO"
|
||||||
|
|
||||||
# 邮件服务设置
|
# 邮件服务设置
|
||||||
|
enable_email_verification: bool = Field(default=False, description="是否启用邮件验证功能")
|
||||||
smtp_server: str = "localhost"
|
smtp_server: str = "localhost"
|
||||||
smtp_port: int = 587
|
smtp_port: int = 587
|
||||||
smtp_username: str = ""
|
smtp_username: str = ""
|
||||||
@@ -125,13 +126,12 @@ class Settings(BaseSettings):
|
|||||||
from_email: str = "noreply@example.com"
|
from_email: str = "noreply@example.com"
|
||||||
from_name: str = "osu! server"
|
from_name: str = "osu! server"
|
||||||
|
|
||||||
# 邮件验证功能开关
|
|
||||||
enable_email_verification: bool = Field(default=True, description="是否启用邮件验证功能")
|
|
||||||
enable_email_sending: bool = Field(default=False, description="是否真实发送邮件(False时仅模拟发送)")
|
|
||||||
|
|
||||||
# Sentry 配置
|
# Sentry 配置
|
||||||
sentry_dsn: HttpUrl | None = None
|
sentry_dsn: HttpUrl | None = None
|
||||||
|
|
||||||
|
# New Relic 配置
|
||||||
|
new_relic_environment: None | str = None
|
||||||
|
|
||||||
# GeoIP 配置
|
# GeoIP 配置
|
||||||
maxmind_license_key: str = ""
|
maxmind_license_key: str = ""
|
||||||
geoip_dest_dir: str = "./geoip"
|
geoip_dest_dir: str = "./geoip"
|
||||||
@@ -145,11 +145,11 @@ class Settings(BaseSettings):
|
|||||||
enable_supporter_for_all_users: bool = False
|
enable_supporter_for_all_users: bool = False
|
||||||
enable_all_beatmap_leaderboard: bool = False
|
enable_all_beatmap_leaderboard: bool = False
|
||||||
enable_all_beatmap_pp: bool = False
|
enable_all_beatmap_pp: bool = False
|
||||||
# 性能优化设置
|
seasonal_backgrounds: Annotated[list[str], BeforeValidator(_parse_list)] = []
|
||||||
|
|
||||||
|
# 谱面缓存设置
|
||||||
enable_beatmap_preload: bool = True
|
enable_beatmap_preload: bool = True
|
||||||
beatmap_cache_expire_hours: int = 24
|
beatmap_cache_expire_hours: int = 24
|
||||||
max_concurrent_pp_calculations: int = 10
|
|
||||||
enable_pp_calculation_threading: bool = True
|
|
||||||
|
|
||||||
# 排行榜缓存设置
|
# 排行榜缓存设置
|
||||||
enable_ranking_cache: bool = True
|
enable_ranking_cache: bool = True
|
||||||
@@ -168,7 +168,6 @@ class Settings(BaseSettings):
|
|||||||
|
|
||||||
# 反作弊设置
|
# 反作弊设置
|
||||||
suspicious_score_check: bool = True
|
suspicious_score_check: bool = True
|
||||||
seasonal_backgrounds: Annotated[list[str], BeforeValidator(_parse_list)] = []
|
|
||||||
banned_name: list[str] = [
|
banned_name: list[str] = [
|
||||||
"mrekk",
|
"mrekk",
|
||||||
"vaxei",
|
"vaxei",
|
||||||
|
|||||||
@@ -140,12 +140,6 @@ class EmailService:
|
|||||||
|
|
||||||
msg.attach(MIMEText(html_content, "html", "utf-8"))
|
msg.attach(MIMEText(html_content, "html", "utf-8"))
|
||||||
|
|
||||||
# 发送邮件
|
|
||||||
if not settings.enable_email_sending:
|
|
||||||
# 邮件发送功能禁用时只记录日志,不实际发送
|
|
||||||
logger.info(f"[Email Verification] Mock sending verification code to {email}: {code}")
|
|
||||||
return True
|
|
||||||
|
|
||||||
with smtplib.SMTP(self.smtp_server, self.smtp_port) as server:
|
with smtplib.SMTP(self.smtp_server, self.smtp_port) as server:
|
||||||
if self.smtp_username and self.smtp_password:
|
if self.smtp_username and self.smtp_password:
|
||||||
server.starttls()
|
server.starttls()
|
||||||
|
|||||||
39
main.py
39
main.py
@@ -4,6 +4,7 @@ import asyncio
|
|||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from app.config import settings
|
from app.config import settings
|
||||||
from app.dependencies.database import engine, redis_client
|
from app.dependencies.database import engine, redis_client
|
||||||
@@ -42,27 +43,6 @@ from app.service.redis_message_system import redis_message_system
|
|||||||
from app.service.stats_scheduler import start_stats_scheduler, stop_stats_scheduler
|
from app.service.stats_scheduler import start_stats_scheduler, stop_stats_scheduler
|
||||||
from app.utils import bg_tasks
|
from app.utils import bg_tasks
|
||||||
|
|
||||||
# 检查 New Relic 配置文件是否存在,如果存在则初始化 New Relic
|
|
||||||
newrelic_config_path = os.path.join(os.path.dirname(__file__), "newrelic.ini")
|
|
||||||
if os.path.exists(newrelic_config_path):
|
|
||||||
try:
|
|
||||||
import newrelic.agent
|
|
||||||
|
|
||||||
environment = os.environ.get(
|
|
||||||
"NEW_RELIC_ENVIRONMENT",
|
|
||||||
"production" if not settings.debug else "development",
|
|
||||||
)
|
|
||||||
|
|
||||||
newrelic.agent.initialize(newrelic_config_path, environment)
|
|
||||||
logger.info(f"[NewRelic] Enabled, environment: {environment}")
|
|
||||||
except ImportError:
|
|
||||||
logger.warning("[NewRelic] Config file found but 'newrelic' package is not installed")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"[NewRelic] Initialization failed: {e}")
|
|
||||||
else:
|
|
||||||
logger.info("[NewRelic] No newrelic.ini config file found, skipping initialization")
|
|
||||||
|
|
||||||
|
|
||||||
from fastapi import FastAPI, HTTPException, Request
|
from fastapi import FastAPI, HTTPException, Request
|
||||||
from fastapi.exceptions import RequestValidationError
|
from fastapi.exceptions import RequestValidationError
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
@@ -110,6 +90,23 @@ desc = (
|
|||||||
"V1 API 文档:[osu-api](https://github.com/ppy/osu-api/wiki)"
|
"V1 API 文档:[osu-api](https://github.com/ppy/osu-api/wiki)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 检查 New Relic 配置文件是否存在,如果存在则初始化 New Relic
|
||||||
|
newrelic_config_path = Path("newrelic.ini")
|
||||||
|
if newrelic_config_path.exists():
|
||||||
|
try:
|
||||||
|
import newrelic.agent
|
||||||
|
|
||||||
|
environment = settings.new_relic_environment or ("production" if not settings.debug else "development")
|
||||||
|
|
||||||
|
newrelic.agent.initialize(newrelic_config_path, environment)
|
||||||
|
logger.info(f"[NewRelic] Enabled, environment: {environment}")
|
||||||
|
except ImportError:
|
||||||
|
logger.warning("[NewRelic] Config file found but 'newrelic' package is not installed")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"[NewRelic] Initialization failed: {e}")
|
||||||
|
else:
|
||||||
|
logger.info("[NewRelic] No newrelic.ini config file found, skipping initialization")
|
||||||
|
|
||||||
if settings.sentry_dsn is not None:
|
if settings.sentry_dsn is not None:
|
||||||
sentry_sdk.init(
|
sentry_sdk.init(
|
||||||
dsn=str(settings.sentry_dsn),
|
dsn=str(settings.sentry_dsn),
|
||||||
|
|||||||
Reference in New Issue
Block a user