From 960ac769620da5cfada697da757d4c28ec06dfec Mon Sep 17 00:00:00 2001 From: zhinianboke <115088296+zhinianboke@users.noreply.github.com> Date: Thu, 28 Aug 2025 20:30:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- XianyuAutoAsync.py | 42 +++++++++++++++++++ reply_server.py | 101 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+) diff --git a/XianyuAutoAsync.py b/XianyuAutoAsync.py index 7c93570..3de38cb 100644 --- a/XianyuAutoAsync.py +++ b/XianyuAutoAsync.py @@ -122,6 +122,10 @@ class XianyuLive: # 商品详情缓存(24小时有效) _item_detail_cache = {} # {item_id: {'detail': str, 'timestamp': float}} _item_detail_cache_lock = asyncio.Lock() + + # 类级别的实例管理字典,用于API调用 + _instances = {} # {cookie_id: XianyuLive实例} + _instances_lock = asyncio.Lock() def _safe_str(self, e): """安全地将异常转换为字符串""" @@ -213,7 +217,41 @@ class XianyuLive: self.max_connection_failures = 5 # 最大连续失败次数 self.last_successful_connection = 0 # 上次成功连接时间 + # 注册实例到类级别字典(用于API调用) + self._register_instance() + def _register_instance(self): + """注册当前实例到类级别字典""" + try: + # 使用同步方式注册,避免在__init__中使用async + XianyuLive._instances[self.cookie_id] = self + logger.debug(f"【{self.cookie_id}】实例已注册到全局字典") + except Exception as e: + logger.error(f"【{self.cookie_id}】注册实例失败: {self._safe_str(e)}") + + def _unregister_instance(self): + """从类级别字典中注销当前实例""" + try: + if self.cookie_id in XianyuLive._instances: + del XianyuLive._instances[self.cookie_id] + logger.debug(f"【{self.cookie_id}】实例已从全局字典中注销") + except Exception as e: + logger.error(f"【{self.cookie_id}】注销实例失败: {self._safe_str(e)}") + + @classmethod + def get_instance(cls, cookie_id: str): + """获取指定cookie_id的XianyuLive实例""" + return cls._instances.get(cookie_id) + + @classmethod + def get_all_instances(cls): + """获取所有活跃的XianyuLive实例""" + return dict(cls._instances) + + @classmethod + def get_instance_count(cls): + """获取当前活跃实例数量""" + return len(cls._instances) def is_auto_confirm_enabled(self) -> bool: """检查当前账号是否启用自动确认发货""" @@ -4991,6 +5029,10 @@ class XianyuLive: self.cookie_refresh_task.cancel() await self.close_session() # 确保关闭session + # 从全局实例字典中注销当前实例 + self._unregister_instance() + logger.info(f"【{self.cookie_id}】XianyuLive主程序已完全退出") + async def get_item_list_info(self, page_number=1, page_size=20, retry_count=0): """获取商品信息,自动处理token失效的情况 diff --git a/reply_server.py b/reply_server.py index 238a230..0ebf46d 100644 --- a/reply_server.py +++ b/reply_server.py @@ -848,6 +848,107 @@ async def register(request: RegisterRequest): ) +# ------------------------- 发送消息接口 ------------------------- + +# 固定的API秘钥(生产环境中应该从配置文件或环境变量读取) +API_SECRET_KEY = "xianyu_api_secret_2024" + +class SendMessageRequest(BaseModel): + api_key: str + cookie_id: str + chat_id: str + to_user_id: str + message: str + + +class SendMessageResponse(BaseModel): + success: bool + message: str + + +def verify_api_key(api_key: str) -> bool: + """验证API秘钥""" + return api_key == API_SECRET_KEY + + +@app.post('/send-message', response_model=SendMessageResponse) +async def send_message_api(request: SendMessageRequest): + """发送消息API接口(使用秘钥验证)""" + try: + # 验证API秘钥 + if not verify_api_key(request.api_key): + logger.warning(f"API秘钥验证失败: {request.api_key}") + return SendMessageResponse( + success=False, + message="API秘钥验证失败" + ) + + # 检查cookie_manager是否可用 + if not cookie_manager.manager: + logger.error("CookieManager未初始化") + return SendMessageResponse( + success=False, + message="系统未就绪,请稍后重试" + ) + + # 检查Cookie是否存在 + if request.cookie_id not in cookie_manager.manager.cookies: + logger.warning(f"Cookie不存在: {request.cookie_id}") + return SendMessageResponse( + success=False, + message="指定的Cookie账号不存在" + ) + + # 检查账号是否启用 + if not cookie_manager.manager.get_cookie_status(request.cookie_id): + logger.warning(f"尝试使用已禁用的账号发送消息: {request.cookie_id}") + return SendMessageResponse( + success=False, + message="该账号已被禁用,无法发送消息" + ) + + # 获取XianyuLive实例 + from XianyuAutoAsync import XianyuLive + live_instance = XianyuLive.get_instance(request.cookie_id) + + if not live_instance: + logger.warning(f"账号实例不存在或未连接: {request.cookie_id}") + return SendMessageResponse( + success=False, + message="账号实例不存在或未连接,请检查账号状态" + ) + + # 检查WebSocket连接状态 + if not live_instance.ws or live_instance.ws.closed: + logger.warning(f"账号WebSocket连接已断开: {request.cookie_id}") + return SendMessageResponse( + success=False, + message="账号WebSocket连接已断开,请等待重连" + ) + + # 发送消息 + await live_instance.send_msg( + live_instance.ws, + request.chat_id, + request.to_user_id, + request.message + ) + + logger.info(f"API成功发送消息: {request.cookie_id} -> {request.to_user_id}, 内容: {request.message[:50]}{'...' if len(request.message) > 50 else ''}") + + return SendMessageResponse( + success=True, + message="消息发送成功" + ) + + except Exception as e: + logger.error(f"API发送消息异常: {request.cookie_id} -> {request.to_user_id}, 错误: {str(e)}") + return SendMessageResponse( + success=False, + message=f"发送消息失败: {str(e)}" + ) + + @app.post("/xianyu/reply", response_model=ResponseModel) async def xianyu_reply(req: RequestModel): msg_template = match_reply(req.cookie_id, req.send_message)