Files
DanDingNoneBot/danding_bot/plugins/group_horse_racing/points_service.py
Mr.Xia c01338f496 refactor(plugins): comprehensive code review - ~35 fixes across 14 plugins
Phase 1 - Plugin code review (14/14 plugins):
- Security: 3x token leak in print→logger.debug, Bearer prefix handling
- Bug: bare except→specific exceptions, HorseState type safety, sync→async
- Critical: response_model undefined, route dead code, sync blocking event loop
- Quality: 11x print()→logger, variable name shadowing, consistent logging

Phase 2 - Deep analysis:
- Fix: payout int truncation→max(1, round(amount*odds))
- Fix: room_store get_lock race condition→dict.setdefault()
- Verify: data_manager f-string SQL is safe (uses ? placeholders)

Infrastructure: review reports generated for all plugins.
2026-05-09 23:22:28 +08:00

87 lines
3.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 = max(1, round(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)