This commit is contained in:
tt-P607
2025-10-01 00:44:52 +08:00
4 changed files with 54 additions and 83 deletions

View File

@@ -88,27 +88,25 @@ class MaiZoneRefactoredPlugin(BasePlugin):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
async def on_plugin_loaded(self): async def on_plugin_loaded(self):
"""插件加载完成后的回调,初始化服务并启动后台任务"""
# --- 注册权限节点 ---
await permission_api.register_permission_node( await permission_api.register_permission_node(
"plugin.maizone.send_feed", "是否可以使用机器人发送QQ空间说说", "maiZone", False "plugin.maizone.send_feed", "是否可以使用机器人发送QQ空间说说", "maiZone", False
) )
await permission_api.register_permission_node( await permission_api.register_permission_node(
"plugin.maizone.read_feed", "是否可以使用机器人读取QQ空间说说", "maiZone", True "plugin.maizone.read_feed", "是否可以使用机器人读取QQ空间说说", "maiZone", True
) )
# 创建所有服务实例
# --- 创建并注册所有服务实例 ---
content_service = ContentService(self.get_config) content_service = ContentService(self.get_config)
image_service = ImageService(self.get_config) image_service = ImageService(self.get_config)
cookie_service = CookieService(self.get_config) cookie_service = CookieService(self.get_config)
reply_tracker_service = ReplyTrackerService() reply_tracker_service = ReplyTrackerService()
# 使用已创建的 reply_tracker_service 实例
qzone_service = QZoneService( qzone_service = QZoneService(
self.get_config, self.get_config,
content_service, content_service,
image_service, image_service,
cookie_service, cookie_service,
reply_tracker_service, reply_tracker_service, # 传入已创建的实例
) )
scheduler_service = SchedulerService(self.get_config, qzone_service) scheduler_service = SchedulerService(self.get_config, qzone_service)
monitor_service = MonitorService(self.get_config, qzone_service) monitor_service = MonitorService(self.get_config, qzone_service)
@@ -117,12 +115,18 @@ class MaiZoneRefactoredPlugin(BasePlugin):
register_service("reply_tracker", reply_tracker_service) register_service("reply_tracker", reply_tracker_service)
register_service("get_config", self.get_config) register_service("get_config", self.get_config)
logger.info("MaiZone重构版插件服务已注册。") # 保存服务引用以便后续启动
self.scheduler_service = scheduler_service
self.monitor_service = monitor_service
# --- 启动后台任务 --- logger.info("MaiZone重构版插件已加载服务已注册。")
asyncio.create_task(scheduler_service.start())
asyncio.create_task(monitor_service.start()) async def on_plugin_loaded(self):
logger.info("MaiZone后台监控和定时任务已启动。") """插件加载完成后的回调,启动异步服务"""
if hasattr(self, "scheduler_service") and hasattr(self, "monitor_service"):
asyncio.create_task(self.scheduler_service.start())
asyncio.create_task(self.monitor_service.start())
logger.info("MaiZone后台任务已启动。")
def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
return [ return [

View File

@@ -113,32 +113,31 @@ class CookieService:
async def get_cookies(self, qq_account: str, stream_id: Optional[str]) -> Optional[Dict[str, str]]: async def get_cookies(self, qq_account: str, stream_id: Optional[str]) -> Optional[Dict[str, str]]:
""" """
获取Cookie按以下顺序尝试 获取Cookie按以下顺序尝试
1. HTTP备用端点 (更稳定) 1. Adapter API
2. 本地文件缓存 2. HTTP备用端点
3. Adapter API (作为最后手段) 3. 本地文件缓存
""" """
# 1. 尝试从HTTP备用端点获取 # 1. 尝试从Adapter获取
logger.info(f"开始尝试从HTTP备用地址获取 {qq_account} 的Cookie...")
cookies = await self._get_cookies_from_http()
if cookies:
logger.info(f"成功从HTTP备用地址为 {qq_account} 获取Cookie。")
self._save_cookies_to_file(qq_account, cookies)
return cookies
# 2. 尝试从本地文件加载
logger.warning(f"从HTTP备用地址获取 {qq_account} 的Cookie失败尝试加载本地缓存。")
cookies = self._load_cookies_from_file(qq_account)
if cookies:
logger.info(f"成功从本地文件为 {qq_account} 加载缓存的Cookie。")
return cookies
# 3. 尝试从Adapter获取 (作为最后的备用方案)
logger.warning(f"从本地缓存加载 {qq_account} 的Cookie失败最后尝试使用Adapter API。")
cookies = await self._get_cookies_from_adapter(stream_id) cookies = await self._get_cookies_from_adapter(stream_id)
if cookies: if cookies:
logger.info(f"成功从Adapter API为 {qq_account} 获取Cookie。") logger.info("成功从Adapter获取Cookie。")
self._save_cookies_to_file(qq_account, cookies) self._save_cookies_to_file(qq_account, cookies)
return cookies return cookies
logger.error(f"{qq_account} 获取Cookie的所有方法均失败。请确保Napcat HTTP服务或Adapter连接至少有一个正常工作或存在有效的本地Cookie文件。") # 2. 尝试从HTTP备用端点获取
logger.warning("从Adapter获取Cookie失败尝试使用HTTP备用地址。")
cookies = await self._get_cookies_from_http()
if cookies:
logger.info("成功从HTTP备用地址获取Cookie。")
self._save_cookies_to_file(qq_account, cookies)
return cookies
# 3. 尝试从本地文件加载
logger.warning("从HTTP备用地址获取Cookie失败尝试加载本地缓存。")
cookies = self._load_cookies_from_file(qq_account)
if cookies:
logger.info("成功从本地文件加载缓存的Cookie。")
return cookies
logger.error("所有Cookie获取方法均失败。")
return None return None

View File

@@ -409,9 +409,8 @@ class QZoneService:
cookie_dir.mkdir(exist_ok=True) cookie_dir.mkdir(exist_ok=True)
cookie_file_path = cookie_dir / f"cookies-{qq_account}.json" cookie_file_path = cookie_dir / f"cookies-{qq_account}.json"
# 优先尝试通过Napcat HTTP服务获取最新的Cookie
try: try:
logger.info("尝试通过Napcat HTTP服务获取Cookie...") # 使用HTTP服务器方式获取Cookie
host = self.get_config("cookie.http_fallback_host", "172.20.130.55") host = self.get_config("cookie.http_fallback_host", "172.20.130.55")
port = self.get_config("cookie.http_fallback_port", "9999") port = self.get_config("cookie.http_fallback_port", "9999")
napcat_token = self.get_config("cookie.napcat_token", "") napcat_token = self.get_config("cookie.napcat_token", "")
@@ -422,43 +421,23 @@ class QZoneService:
parsed_cookies = { parsed_cookies = {
k.strip(): v.strip() for k, v in (p.split("=", 1) for p in cookie_str.split("; ") if "=" in p) k.strip(): v.strip() for k, v in (p.split("=", 1) for p in cookie_str.split("; ") if "=" in p)
} }
# 成功获取后,异步写入本地文件作为备份 with open(cookie_file_path, "wb") as f:
try: f.write(orjson.dumps(parsed_cookies))
with open(cookie_file_path, "wb") as f: logger.info(f"Cookie已更新并保存至: {cookie_file_path}")
f.write(orjson.dumps(parsed_cookies))
logger.info(f"通过Napcat服务成功更新Cookie并已保存至: {cookie_file_path}")
except Exception as e:
logger.warning(f"保存Cookie到文件时出错: {e}")
return parsed_cookies return parsed_cookies
else:
logger.warning("通过Napcat服务未能获取有效Cookie。")
except Exception as e: # 如果HTTP获取失败尝试读取本地文件
logger.warning(f"通过Napcat HTTP服务获取Cookie时发生异常: {e}。将尝试从本地文件加载。") if cookie_file_path.exists():
# 如果通过服务获取失败,则尝试从本地文件加载
logger.info("尝试从本地Cookie文件加载...")
if cookie_file_path.exists():
try:
with open(cookie_file_path, "rb") as f: with open(cookie_file_path, "rb") as f:
cookies = orjson.loads(f.read()) return orjson.loads(f.read())
logger.info(f"成功从本地文件加载Cookie: {cookie_file_path}") return None
return cookies except Exception as e:
except Exception as e: logger.error(f"更新或加载Cookie时发生异常: {e}")
logger.error(f"从本地文件 {cookie_file_path} 读取或解析Cookie失败: {e}") return None
else:
logger.warning(f"本地Cookie文件不存在: {cookie_file_path}")
logger.error("所有获取Cookie的方式均失败。") async def _fetch_cookies_http(self, host: str, port: str, napcat_token: str) -> Optional[Dict]:
return None
async def _fetch_cookies_http(self, host: str, port: int, napcat_token: str) -> Optional[Dict]:
"""通过HTTP服务器获取Cookie""" """通过HTTP服务器获取Cookie"""
# 从配置中读取主机和端口,如果未提供则使用传入的参数 url = f"http://{host}:{port}/get_cookies"
final_host = self.get_config("cookie.http_fallback_host", host)
final_port = self.get_config("cookie.http_fallback_port", port)
url = f"http://{final_host}:{final_port}/get_cookies"
max_retries = 5 max_retries = 5
retry_delay = 1 retry_delay = 1
@@ -502,19 +481,14 @@ class QZoneService:
async def _get_api_client(self, qq_account: str, stream_id: Optional[str]) -> Optional[Dict]: async def _get_api_client(self, qq_account: str, stream_id: Optional[str]) -> Optional[Dict]:
cookies = await self.cookie_service.get_cookies(qq_account, stream_id) cookies = await self.cookie_service.get_cookies(qq_account, stream_id)
if not cookies: if not cookies:
logger.error("获取API客户端失败未能获取到Cookie。请检查Napcat连接是否正常或是否存在有效的本地Cookie文件。")
return None return None
p_skey = cookies.get("p_skey") or cookies.get("p_skey".upper()) p_skey = cookies.get("p_skey") or cookies.get("p_skey".upper())
if not p_skey: if not p_skey:
logger.error(f"获取API客户端失败Cookie中缺少关键的 'p_skey'。Cookie内容: {cookies}")
return None return None
gtk = self._generate_gtk(p_skey) gtk = self._generate_gtk(p_skey)
uin = cookies.get("uin", "").lstrip("o") uin = cookies.get("uin", "").lstrip("o")
if not uin:
logger.error(f"获取API客户端失败Cookie中缺少关键的 'uin'。Cookie内容: {cookies}")
return None
async def _request(method, url, params=None, data=None, headers=None): async def _request(method, url, params=None, data=None, headers=None):
final_headers = {"referer": f"https://user.qzone.qq.com/{uin}", "origin": "https://user.qzone.qq.com"} final_headers = {"referer": f"https://user.qzone.qq.com/{uin}", "origin": "https://user.qzone.qq.com"}

View File

@@ -185,13 +185,9 @@ class SendHandler:
logger.info(f"执行适配器命令: {action}") logger.info(f"执行适配器命令: {action}")
# 根据action决定处理方式 # 直接向Napcat发送命令并获取响应
if action == "get_cookies": response_task = asyncio.create_task(self.send_message_to_napcat(action, params))
# 对于get_cookies我们需要一个更长的超时时间 response = await response_task
response = await self.send_message_to_napcat(action, params, timeout=40.0)
else:
# 对于其他命令,使用默认超时
response = await self.send_message_to_napcat(action, params)
# 发送响应回MaiBot # 发送响应回MaiBot
await self.send_adapter_command_response(raw_message_base, response, request_id) await self.send_adapter_command_response(raw_message_base, response, request_id)
@@ -200,8 +196,6 @@ class SendHandler:
logger.info(f"适配器命令 {action} 执行成功") logger.info(f"适配器命令 {action} 执行成功")
else: else:
logger.warning(f"适配器命令 {action} 执行失败napcat返回{str(response)}") logger.warning(f"适配器命令 {action} 执行失败napcat返回{str(response)}")
# 无论成功失败,都记录下完整的响应内容以供调试
logger.debug(f"适配器命令 {action} 的完整响应: {response}")
except Exception as e: except Exception as e:
logger.error(f"处理适配器命令时发生错误: {e}") logger.error(f"处理适配器命令时发生错误: {e}")
@@ -589,7 +583,7 @@ class SendHandler:
}, },
) )
async def send_message_to_napcat(self, action: str, params: dict, timeout: float = 20.0) -> dict: async def send_message_to_napcat(self, action: str, params: dict) -> dict:
request_uuid = str(uuid.uuid4()) request_uuid = str(uuid.uuid4())
payload = json.dumps({"action": action, "params": params, "echo": request_uuid}) payload = json.dumps({"action": action, "params": params, "echo": request_uuid})
@@ -601,9 +595,9 @@ class SendHandler:
try: try:
await connection.send(payload) await connection.send(payload)
response = await get_response(request_uuid, timeout=timeout) # 使用传入的超时时间 response = await get_response(request_uuid)
except TimeoutError: except TimeoutError:
logger.error(f"发送消息超时{timeout}秒),未收到响应: action={action}, params={params}") logger.error("发送消息超时,未收到响应")
return {"status": "error", "message": "timeout"} return {"status": "error", "message": "timeout"}
except Exception as e: except Exception as e:
logger.error(f"发送消息失败: {e}") logger.error(f"发送消息失败: {e}")