This commit is contained in:
zhinianboke 2025-08-28 20:30:25 +08:00
parent 1b4254d36f
commit 960ac76962
2 changed files with 143 additions and 0 deletions

View File

@ -123,6 +123,10 @@ class XianyuLive:
_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):
"""安全地将异常转换为字符串"""
try:
@ -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失效的情况

View File

@ -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)