fix(race): 代码质量审查修复 + commands包拆分 + 赛马取消命令
- P1: bet.py赔率计算移入锁内防竞态 - P1: config.py TESTERS解析失败添加warning日志 - P2: 新增赛马取消命令(积分退还/任务取消/状态重置) - P3: bet.py清理未使用的_send_to_scope导入 - 将commands.py拆分为commands/包(access/bet/help/race/register) - OpenSpec变更提案: fix-race-conditions-and-logs
This commit is contained in:
@@ -1,74 +1,76 @@
|
||||
from pydantic import Field, field_validator
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
import json
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
model_config = SettingsConfigDict(
|
||||
extra="ignore",
|
||||
env_prefix="GROUP_HORSE_RACING_",
|
||||
)
|
||||
|
||||
# 测试模式配置
|
||||
TEST_MODE: bool = False
|
||||
TESTERS: set[int] = Field(default_factory=set)
|
||||
TEST_GROUPS: set[int] = Field(default_factory=set)
|
||||
ALLOWED_GROUPS: set[int] = Field(default_factory=set)
|
||||
|
||||
# 奖励配置
|
||||
PARTICIPANT_REWARD: int = 20
|
||||
CHAMPION_REWARD: int = 150
|
||||
MIN_BET: int = 10
|
||||
MIN_ODDS: float = 1.2
|
||||
RACE_DISTANCE: int = 100
|
||||
RACE_TICK_INTERVAL: int = 5
|
||||
RACE_RENDER_AS_IMAGE: bool = True
|
||||
RACE_IMAGE_WIDTH: int = 900
|
||||
RACE_IMAGE_FONT_SIZE: int = 26
|
||||
RACE_IMAGE_PADDING: int = 28
|
||||
RACE_IMAGE_LINE_SPACING: float = 1.35
|
||||
|
||||
# 消息撤回配置
|
||||
MESSAGE_RECALL: dict[str, int] = Field(
|
||||
default_factory=lambda: {
|
||||
"race_update": 30,
|
||||
"registration": 180,
|
||||
"bet_confirm": 180,
|
||||
"cancel_confirm": 60,
|
||||
"error": 60,
|
||||
"race_result": 0,
|
||||
"leaderboard": 0,
|
||||
"help": 0,
|
||||
"odds_display": 0,
|
||||
}
|
||||
)
|
||||
|
||||
# 数据库配置
|
||||
RACE_DB_FILE: str = "data/group_horse_racing/race.db"
|
||||
|
||||
@field_validator("TESTERS", "TEST_GROUPS", "ALLOWED_GROUPS", mode="before")
|
||||
@classmethod
|
||||
def parse_id_sets(cls, v):
|
||||
"""Parse ID sets from various formats."""
|
||||
if isinstance(v, set):
|
||||
return v
|
||||
if isinstance(v, str):
|
||||
return cls._parse_id_set(v)
|
||||
if isinstance(v, (list, tuple)):
|
||||
return set(int(x) for x in v)
|
||||
return v if isinstance(v, set) else set()
|
||||
|
||||
@staticmethod
|
||||
def _parse_id_set(v: str) -> set[int]:
|
||||
"""Parse ID sets from various formats."""
|
||||
try:
|
||||
parsed = json.loads(v)
|
||||
if isinstance(parsed, list):
|
||||
return set(int(x) for x in parsed)
|
||||
except (json.JSONDecodeError, ValueError, TypeError):
|
||||
pass
|
||||
try:
|
||||
return set(int(x.strip()) for x in v.split(",") if x.strip())
|
||||
except ValueError:
|
||||
pass
|
||||
return set()
|
||||
from pydantic import Field, field_validator
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
import json
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
model_config = SettingsConfigDict(
|
||||
extra="ignore",
|
||||
env_prefix="GROUP_HORSE_RACING_",
|
||||
)
|
||||
|
||||
# 测试模式配置
|
||||
TEST_MODE: bool = False
|
||||
TESTERS: set[int] = Field(default_factory=set)
|
||||
TEST_GROUPS: set[int] = Field(default_factory=set)
|
||||
ALLOWED_GROUPS: set[int] = Field(default_factory=set)
|
||||
|
||||
# 奖励配置
|
||||
PARTICIPANT_REWARD: int = 20
|
||||
CHAMPION_REWARD: int = 150
|
||||
MIN_BET: int = 10
|
||||
MIN_ODDS: float = 1.2
|
||||
RACE_DISTANCE: int = 100
|
||||
RACE_TICK_INTERVAL: int = 5
|
||||
RACE_RENDER_AS_IMAGE: bool = True
|
||||
RACE_IMAGE_WIDTH: int = 900
|
||||
RACE_IMAGE_FONT_SIZE: int = 26
|
||||
RACE_IMAGE_PADDING: int = 28
|
||||
RACE_IMAGE_LINE_SPACING: float = 1.35
|
||||
|
||||
# 消息撤回配置
|
||||
MESSAGE_RECALL: dict[str, int] = Field(
|
||||
default_factory=lambda: {
|
||||
"race_update": 30,
|
||||
"registration": 180,
|
||||
"bet_confirm": 180,
|
||||
"cancel_confirm": 60,
|
||||
"error": 60,
|
||||
"race_result": 0,
|
||||
"leaderboard": 0,
|
||||
"help": 0,
|
||||
"odds_display": 0,
|
||||
}
|
||||
)
|
||||
|
||||
# 数据库配置
|
||||
RACE_DB_FILE: str = "data/group_horse_racing/race.db"
|
||||
|
||||
@field_validator("TESTERS", "TEST_GROUPS", "ALLOWED_GROUPS", mode="before")
|
||||
@classmethod
|
||||
def parse_id_sets(cls, v):
|
||||
"""Parse ID sets from various formats."""
|
||||
if isinstance(v, set):
|
||||
return v
|
||||
if isinstance(v, str):
|
||||
return cls._parse_id_set(v)
|
||||
if isinstance(v, (list, tuple)):
|
||||
return set(int(x) for x in v)
|
||||
return v if isinstance(v, set) else set()
|
||||
|
||||
@staticmethod
|
||||
def _parse_id_set(v: str) -> set[int]:
|
||||
"""Parse ID sets from various formats."""
|
||||
try:
|
||||
parsed = json.loads(v)
|
||||
if isinstance(parsed, list):
|
||||
return set(int(x) for x in parsed)
|
||||
except (json.JSONDecodeError, ValueError, TypeError) as e:
|
||||
import logging
|
||||
logging.getLogger(__name__).warning(f"TESTERS 解析失败: {v}, error: {e}")
|
||||
pass
|
||||
try:
|
||||
return set(int(x.strip()) for x in v.split(",") if x.strip())
|
||||
except ValueError:
|
||||
pass
|
||||
return set()
|
||||
|
||||
Reference in New Issue
Block a user