fix: 赛马插件P0-P2问题修复
- P0: room_store sqlite3→aiosqlite异步化 - P0: points_service统一异常处理+轻量重试 - P0: _send_to_scope加warning日志 - P1: 积分历史记录补充source/reason字段 - P1: 赛马结算写入赔率快照(odds_snapshot) - P1: test_commands改为commands_mod间接引用(测试隔离) - P2: 马名去重统一casefold()比较
This commit is contained in:
@@ -1,63 +1,86 @@
|
||||
from typing import Tuple
|
||||
from danding_bot.plugins.danding_points import points_api
|
||||
from .config import Config
|
||||
|
||||
|
||||
class PointsService:
|
||||
def __init__(self, config: Config):
|
||||
self.config = config
|
||||
|
||||
async def spend_bet_points(
|
||||
self, user_id: str, amount: int, reason: str = "赛马下注"
|
||||
) -> Tuple[bool, int]:
|
||||
"""Deduct points for betting with retry."""
|
||||
success, balance = await points_api.spend_points(
|
||||
user_id, amount, "horse_race", reason
|
||||
)
|
||||
if not success:
|
||||
success, balance = await points_api.spend_points(
|
||||
user_id, amount, "horse_race", reason
|
||||
)
|
||||
return success, balance
|
||||
|
||||
async def refund_bet_points(
|
||||
self, user_id: str, amount: int, reason: str = "取消报名退还"
|
||||
) -> Tuple[bool, int]:
|
||||
"""Refund bet points."""
|
||||
return await points_api.add_points(user_id, amount, "horse_race", reason)
|
||||
|
||||
async def payout_winnings(
|
||||
self, user_id: str, amount: int, odds: float
|
||||
) -> Tuple[bool, int]:
|
||||
"""Payout bet winnings."""
|
||||
payout = int(amount * odds)
|
||||
reason = f"下注获胜 ×{odds:.2f}"
|
||||
return await points_api.add_points(user_id, payout, "horse_race", reason)
|
||||
|
||||
async def reward_participant(self, user_id: str) -> Tuple[bool, int]:
|
||||
"""Reward race participant."""
|
||||
return await points_api.add_points(
|
||||
user_id,
|
||||
self.config.PARTICIPANT_REWARD,
|
||||
"horse_race",
|
||||
"参赛奖励",
|
||||
)
|
||||
|
||||
async def reward_champion(self, user_id: str) -> Tuple[bool, int]:
|
||||
"""Reward race champion."""
|
||||
return await points_api.add_points(
|
||||
user_id,
|
||||
self.config.CHAMPION_REWARD,
|
||||
"horse_race",
|
||||
"冠军奖励",
|
||||
)
|
||||
|
||||
async def set_points(
|
||||
self, user_id: str, amount: int, reason: str = "测试设置积分"
|
||||
) -> Tuple[bool, int]:
|
||||
"""Set user points (for testing)."""
|
||||
return await points_api.set_points(user_id, amount, "horse_race", reason)
|
||||
|
||||
async def get_balance(self, user_id: str) -> int:
|
||||
"""Get user balance."""
|
||||
return await points_api.get_balance(user_id)
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import Tuple
|
||||
from danding_bot.plugins.danding_points import points_api
|
||||
from .config import Config
|
||||
|
||||
logger = logging.getLogger("horse_racing.points")
|
||||
|
||||
MAX_RETRIES = 3
|
||||
RETRY_DELAY = 0.5
|
||||
|
||||
|
||||
class PointsService:
|
||||
def __init__(self, config: Config):
|
||||
self.config = config
|
||||
|
||||
async def _call_with_retry(self, func, *args, retries=MAX_RETRIES):
|
||||
"""Call API function with retry logic."""
|
||||
last_exc = None
|
||||
for attempt in range(retries):
|
||||
try:
|
||||
return await func(*args)
|
||||
except Exception as e:
|
||||
last_exc = e
|
||||
logger.warning(
|
||||
f"Points API call failed (attempt {attempt + 1}/{retries}): {e}"
|
||||
)
|
||||
if attempt < retries - 1:
|
||||
await asyncio.sleep(RETRY_DELAY)
|
||||
logger.error(f"Points API call failed after {retries} attempts: {last_exc}")
|
||||
raise last_exc
|
||||
|
||||
async def spend_bet_points(
|
||||
self, user_id: str, amount: int, reason: str = "赛马下注"
|
||||
) -> Tuple[bool, int]:
|
||||
"""Deduct points for betting with retry."""
|
||||
try:
|
||||
return await self._call_with_retry(
|
||||
points_api.spend_points,
|
||||
user_id, amount, "horse_race", reason
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"spend_bet_points failed for user {user_id}: {e}")
|
||||
return False, 0
|
||||
|
||||
async def refund_bet_points(
|
||||
self, user_id: str, amount: int, reason: str = "取消报名退还"
|
||||
) -> Tuple[bool, int]:
|
||||
"""Refund bet points."""
|
||||
return await points_api.add_points(user_id, amount, "horse_race", reason)
|
||||
|
||||
async def payout_winnings(
|
||||
self, user_id: str, amount: int, odds: float
|
||||
) -> Tuple[bool, int]:
|
||||
"""Payout bet winnings."""
|
||||
payout = int(amount * odds)
|
||||
reason = f"下注获胜 ×{odds:.2f}"
|
||||
return await points_api.add_points(user_id, payout, "horse_race", reason)
|
||||
|
||||
async def reward_participant(self, user_id: str) -> Tuple[bool, int]:
|
||||
"""Reward race participant."""
|
||||
return await points_api.add_points(
|
||||
user_id,
|
||||
self.config.PARTICIPANT_REWARD,
|
||||
"horse_race",
|
||||
"参赛奖励",
|
||||
)
|
||||
|
||||
async def reward_champion(self, user_id: str) -> Tuple[bool, int]:
|
||||
"""Reward race champion."""
|
||||
return await points_api.add_points(
|
||||
user_id,
|
||||
self.config.CHAMPION_REWARD,
|
||||
"horse_race",
|
||||
"冠军奖励",
|
||||
)
|
||||
|
||||
async def set_points(
|
||||
self, user_id: str, amount: int, reason: str = "测试设置积分"
|
||||
) -> Tuple[bool, int]:
|
||||
"""Set user points (for testing)."""
|
||||
return await points_api.set_points(user_id, amount, "horse_race", reason)
|
||||
|
||||
async def get_balance(self, user_id: str) -> int:
|
||||
"""Get user balance."""
|
||||
return await points_api.get_balance(user_id)
|
||||
|
||||
Reference in New Issue
Block a user