Files
WPSBot/routers/callback.py

247 lines
8.2 KiB
Python
Raw Normal View History

2025-10-28 13:00:35 +08:00
"""Callback路由处理"""
import logging
from fastapi import APIRouter, Request
from fastapi.responses import JSONResponse
from core.models import CallbackRequest
from core.database import get_db
from utils.message import get_message_sender
from utils.parser import CommandParser
from utils.rate_limit import get_rate_limiter
logger = logging.getLogger(__name__)
router = APIRouter()
@router.get("/callback")
async def callback_verify():
"""Callback可用性校验 - WPS会发送GET请求验证"""
logger.info("收到Callback验证请求")
return JSONResponse({"result": "ok"})
@router.post("/callback")
async def callback_receive(request: Request):
"""接收WPS Callback消息"""
try:
# 解析请求数据
data = await request.json()
logger.info(f"收到消息: chatid={data.get('chatid')}, creator={data.get('creator')}")
2025-10-28 17:43:21 +08:00
logger.info(f"消息内容: {data.get('content')}")
logger.info(f"完整callback数据: {data}")
2025-10-28 13:00:35 +08:00
# 验证请求
try:
callback_data = CallbackRequest(**data)
except Exception as e:
logger.error(f"请求数据验证失败: {e}")
return JSONResponse({"result": "ok"}) # 仍返回ok以避免重试
# 解析指令
parse_result = CommandParser.parse(callback_data.content)
if not parse_result:
# 不是有效指令,忽略
logger.debug("非有效指令,忽略")
return JSONResponse({"result": "ok"})
game_type, command = parse_result
logger.info(f"识别指令: game_type={game_type}, command={command}")
# 检查限流
rate_limiter = get_rate_limiter()
if not rate_limiter.is_allowed():
remaining = rate_limiter.get_remaining()
reset_time = int(rate_limiter.get_reset_time())
sender = get_message_sender()
await sender.send_text(
f"⚠️ 消息发送过于频繁,请等待 {reset_time} 秒后再试\n"
f"剩余配额: {remaining}"
)
return JSONResponse({"result": "ok"})
# 更新用户信息
db = get_db()
db.get_or_create_user(callback_data.creator)
# 处理指令
response_text = await handle_command(
game_type=game_type,
command=command,
chat_id=callback_data.chatid,
user_id=callback_data.creator
)
# 发送回复
if response_text:
sender = get_message_sender()
# AI 对话:统一按 Markdown 发送(按任务决策)
if game_type == 'ai_chat':
try:
await sender.send_markdown(response_text)
except Exception as send_md_err:
logger.error(f"发送Markdown消息失败改用文本发送: {send_md_err}")
await sender.send_text(response_text)
2025-10-28 13:00:35 +08:00
else:
# 其他模块保持原有启发式:以 # 开头视为 Markdown否则文本
if response_text.startswith('#'):
await sender.send_markdown(response_text)
else:
await sender.send_text(response_text)
2025-10-28 13:00:35 +08:00
return JSONResponse({"result": "ok"})
except Exception as e:
logger.error(f"处理Callback异常: {e}", exc_info=True)
# 仍然返回ok避免WPS重试
return JSONResponse({"result": "ok"})
async def handle_command(game_type: str, command: str,
chat_id: int, user_id: int) -> str:
"""处理游戏指令
Args:
game_type: 游戏类型
command: 完整指令
chat_id: 会话ID
user_id: 用户ID
Returns:
回复文本
"""
try:
# 帮助指令
if game_type == 'help':
from games.base import get_help_message
return get_help_message()
# 统计指令
if game_type == 'stats':
from games.base import get_stats_message
return get_stats_message(user_id)
2025-10-29 15:49:39 +08:00
# 注册系统
if game_type == 'register':
return await handle_register_command(command, chat_id, user_id)
2025-10-28 13:00:35 +08:00
# 骰娘游戏
if game_type == 'dice':
from games.dice import DiceGame
game = DiceGame()
return await game.handle(command, chat_id, user_id)
# 石头剪刀布
if game_type == 'rps':
from games.rps import RPSGame
game = RPSGame()
return await game.handle(command, chat_id, user_id)
# 运势占卜
if game_type == 'fortune':
from games.fortune import FortuneGame
game = FortuneGame()
return await game.handle(command, chat_id, user_id)
# 猜数字
if game_type == 'guess':
from games.guess import GuessGame
game = GuessGame()
return await game.handle(command, chat_id, user_id)
# 问答游戏
if game_type == 'quiz':
from games.quiz import QuizGame
game = QuizGame()
return await game.handle(command, chat_id, user_id)
2025-10-28 16:12:32 +08:00
# 成语接龙
if game_type == 'idiom':
from games.idiom import IdiomGame
game = IdiomGame()
return await game.handle(command, chat_id, user_id)
2025-10-28 17:22:49 +08:00
# 五子棋
if game_type == 'gomoku':
from games.gomoku import GomokuGame
game = GomokuGame()
return await game.handle(command, chat_id, user_id)
2025-10-29 11:32:43 +08:00
# 积分系统
if game_type == 'points':
from games.points import PointsGame
game = PointsGame()
return await game.handle(command, chat_id, user_id)
# 炼金系统
if game_type == 'alchemy':
from games.alchemy import AlchemyGame
game = AlchemyGame()
return await game.handle(command, chat_id, user_id)
2025-10-29 17:23:24 +08:00
# 冒险系统
if game_type == 'adventure':
from games.adventure import AdventureGame
game = AdventureGame()
return await game.handle(command, chat_id, user_id)
2025-10-29 11:32:43 +08:00
# 积分赠送系统
if game_type == 'gift':
from games.gift import GiftGame
game = GiftGame()
return await game.handle(command, chat_id, user_id)
2025-10-29 23:56:57 +08:00
# AI对话系统
if game_type == 'ai_chat':
from games.ai_chat import AIChatGame
game = AIChatGame()
return await game.handle(command, chat_id, user_id)
2025-10-28 13:00:35 +08:00
# 未知游戏类型
logger.warning(f"未知游戏类型: {game_type}")
return "❌ 未知的游戏类型"
except Exception as e:
logger.error(f"处理游戏指令异常: {e}", exc_info=True)
return f"❌ 处理指令时出错: {str(e)}"
2025-10-29 15:49:39 +08:00
async def handle_register_command(command: str, chat_id: int, user_id: int) -> str:
"""处理注册命令
Args:
command: 完整指令 ".register name"
chat_id: 会话ID
user_id: 用户ID
Returns:
注册结果消息
"""
try:
# 提取参数
_, args = CommandParser.extract_command_args(command)
args = args.strip()
# 验证参数
if not args:
return "❌ 请提供要注册的名称!\n\n正确格式:`.register <名称>`\n\n示例:\n`.register 张三`\n`.register 小明`"
if len(args) > 20:
return "❌ 名称过长最多支持20个字符。"
# 更新用户名称
db = get_db()
success = db.update_user_name(user_id, args)
if success:
return f"✅ 注册成功!\n\n**您的名称**{args}\n\n之后您可以使用这个名称参与各种游戏和功能。"
else:
return "❌ 注册失败!请稍后重试。"
except Exception as e:
logger.error(f"处理注册指令错误: {e}", exc_info=True)
return f"❌ 处理指令出错: {str(e)}"