diff --git a/app/application/messaging/router.py b/app/application/messaging/router.py index e82b963aa..d03dcfa09 100644 --- a/app/application/messaging/router.py +++ b/app/application/messaging/router.py @@ -43,6 +43,53 @@ class CallbackRoute: dispatch: Callable[[str, InteractionContext], InteractionDispatch] +def adapt_session_text_handler( + handle: Callable[..., Any], +) -> Callable[[InteractionContext, str], bool]: + """把传统关键字参数入口适配为文本会话路由处理器。""" + + def _handle(context: InteractionContext, text: str) -> bool: + """使用统一交互上下文调用传统文本入口。""" + return bool( + handle( + channel=context.channel, + source=context.source, + userid=context.user_id, + username=context.username, + text=text, + ) + ) + + return _handle + + +def adapt_callback_handler( + handle: Callable[..., Any], +) -> Callable[[str, InteractionContext], InteractionDispatch]: + """把传统关键字参数入口适配为按钮回调路由处理器。""" + + def _dispatch( + callback_data: str, + context: InteractionContext, + ) -> InteractionDispatch: + """使用统一交互上下文调用传统回调入口。""" + return InteractionDispatch( + handled=bool( + handle( + callback_data=callback_data, + channel=context.channel, + source=context.source, + userid=context.user_id, + username=context.username, + original_message_id=context.original_message_id, + original_chat_id=context.original_chat_id, + ) + ) + ) + + return _dispatch + + class InteractionRouter: """统一选择活动文本会话并按顺序派发按钮回调。""" diff --git a/app/application/messaging/update.py b/app/application/messaging/update.py index c48accfde..0c7670029 100644 --- a/app/application/messaging/update.py +++ b/app/application/messaging/update.py @@ -39,17 +39,11 @@ class SystemUpdateInteractionActions(Protocol): """立即检查主程序正式版本更新。""" ... - def download_update( - self, - target: SystemUpdateType = "application", - ) -> SystemOperationResult: + def download_update(self, target: SystemUpdateType = "application") -> SystemOperationResult: """启动主程序更新包下载。""" ... - def install_update( - self, - target: SystemUpdateType = "application", - ) -> SystemOperationResult: + def install_update(self, target: SystemUpdateType = "application") -> SystemOperationResult: """确认主程序更新包并请求重启安装。""" ... @@ -72,7 +66,6 @@ class SystemUpdateInteractionHandler: """编排 `/update` 的检查、下载进度编辑和重启确认流程。""" _poll_interval_seconds = 3.0 - _terminal_download_states = {"idle", "available", "ready", "failed", "installing"} def __init__( self, @@ -87,10 +80,13 @@ class SystemUpdateInteractionHandler: """注入消息网关、系统更新用例和受管后台任务提交器。""" self._messenger = messenger self._actions = actions - self._submit_monitor = submit_monitor self._mark_restart = mark_restart self._clear_restart_marker = clear_restart_marker - self._poll_interval_seconds = max(0.0, poll_interval_seconds) + self._renderer = _SystemUpdateRenderer(messenger=messenger, actions=actions) + self._progress_monitor = _SystemUpdateProgressMonitor( + actions=actions, renderer=self._renderer, submit_monitor=submit_monitor, + poll_interval_seconds=poll_interval_seconds, + ) def remote_update( self, @@ -113,7 +109,7 @@ class SystemUpdateInteractionHandler: status = self._actions.check_update() except Exception as error: # noqa: BLE001 交互入口必须回显稳定错误 logger.warning(f"检查 MoviePilot 更新失败:{error}") - self._render_check_failure( + self._renderer.render_check_failure( request=request, channel=channel, source=source, @@ -132,7 +128,7 @@ class SystemUpdateInteractionHandler: text=normalized_arg, ): return - self._render_status( + self._renderer.render_status( request=request, status=status, channel=channel, @@ -296,7 +292,7 @@ class SystemUpdateInteractionHandler: try: status = self._actions.update_status() except Exception as error: # noqa: BLE001 文本交互错误必须回显 - self._render_check_failure( + self._renderer.render_check_failure( request=request, channel=channel, source=source, @@ -305,7 +301,7 @@ class SystemUpdateInteractionHandler: error=str(error), ) return True - self._render_status( + self._renderer.render_status( request=request, status=status, channel=channel, @@ -331,7 +327,7 @@ class SystemUpdateInteractionHandler: status = self._actions.check_update() except Exception as error: # noqa: BLE001 交互入口必须回显稳定错误 logger.warning(f"检查 MoviePilot 更新失败:{error}") - self._render_check_failure( + self._renderer.render_check_failure( request=request, channel=channel, source=source, @@ -342,7 +338,7 @@ class SystemUpdateInteractionHandler: original_chat_id=original_chat_id, ) return - self._render_status( + self._renderer.render_status( request=request, status=status, channel=channel, @@ -370,7 +366,7 @@ class SystemUpdateInteractionHandler: status = result.data if isinstance(result.data, SystemUpdateStatus) else self._actions.update_status() except Exception as error: # noqa: BLE001 交互入口必须回显稳定错误 logger.warning(f"启动 MoviePilot 更新下载失败:{error}") - self._render_operation_failure( + self._renderer.render_operation_failure( request=request, channel=channel, source=source, @@ -383,7 +379,7 @@ class SystemUpdateInteractionHandler: return operation_error = None if result.success else result.message or "无法启动更新包下载" - self._render_status( + self._renderer.render_status( request=request, status=status, channel=channel, @@ -394,9 +390,9 @@ class SystemUpdateInteractionHandler: original_message_id=original_message_id, original_chat_id=original_chat_id, ) - item = self._application_item(status) + item = self._renderer.application_item(status) if result.success and item.state == "downloading": - self._schedule_monitor( + self._progress_monitor.schedule( request=request, channel=channel, source=source, @@ -422,7 +418,7 @@ class SystemUpdateInteractionHandler: try: status = self._actions.update_status() except Exception as error: # noqa: BLE001 交互入口必须回显稳定错误 - self._render_operation_failure( + self._renderer.render_operation_failure( request=request, channel=channel, source=source, @@ -433,9 +429,9 @@ class SystemUpdateInteractionHandler: original_chat_id=original_chat_id, ) return - item = self._application_item(status) + item = self._renderer.application_item(status) if item.state != "ready": - self._render_status( + self._renderer.render_status( request=request, status=status, channel=channel, @@ -449,7 +445,7 @@ class SystemUpdateInteractionHandler: return installing = item.model_copy(update={"state": "installing", "can_install": False}) - self._render_item( + self._renderer.render_item( request=request, item=installing, channel=channel, @@ -465,7 +461,7 @@ class SystemUpdateInteractionHandler: except Exception as error: # noqa: BLE001 重启失败必须恢复交互 self._clear_restart_marker() logger.warning(f"安装 MoviePilot 更新失败:{error}") - self._render_operation_failure( + self._renderer.render_operation_failure( request=request, channel=channel, source=source, @@ -489,7 +485,7 @@ class SystemUpdateInteractionHandler: current_version=item.current_version or "unknown", updates=[item], ) - self._render_status( + self._renderer.render_status( request=request, status=status, channel=channel, @@ -501,17 +497,27 @@ class SystemUpdateInteractionHandler: original_chat_id=original_chat_id, ) - def _schedule_monitor( - self, - *, - request: PendingSlashInteraction, - channel: NotificationChannel, - source: Optional[str], - userid: Union[str, int], - username: Optional[str], +class _SystemUpdateProgressMonitor: + """管理主程序更新下载的后台轮询与消息刷新。""" + + _terminal_download_states = {"idle", "available", "ready", "failed", "installing"} + + def __init__( + self, *, actions: SystemUpdateInteractionActions, + renderer: _SystemUpdateRenderer, submit_monitor: UpdateMonitorSubmitter, + poll_interval_seconds: float, + ) -> None: + """注入状态读取、消息渲染和后台任务提交能力。""" + self._actions = actions + self._renderer = renderer + self._submit_monitor = submit_monitor + self._poll_interval_seconds = max(0.0, poll_interval_seconds) + + def schedule( + self, *, request: PendingSlashInteraction, channel: NotificationChannel, + source: Optional[str], userid: Union[str, int], username: Optional[str], initial_item: SystemUpdateItemStatus, - original_message_id: Optional[Union[str, int]], - original_chat_id: Optional[str], + original_message_id: Optional[Union[str, int]], original_chat_id: Optional[str], ) -> None: """确保同一交互只登记一个非阻塞下载进度监视任务。""" with _monitor_lock: @@ -535,34 +541,24 @@ class SystemUpdateInteractionHandler: with _monitor_lock: _monitored_requests.discard(request.request_id) logger.warning(f"登记 MoviePilot 更新进度监视失败:{error}") - self._messenger.post_message( - Message( - channel=channel, - source=source, - userid=userid, - username=username, + self._renderer.post_view( + view=SystemUpdateInteractionView( title="更新包已开始下载", text="自动进度更新暂不可用,可重新发送 /update 查看状态。", - original_message_id=original_message_id, - original_chat_id=original_chat_id, - save_history=False, - ) + ), + channel=channel, source=source, userid=userid, username=username, + original_message_id=original_message_id, + original_chat_id=original_chat_id, ) async def _monitor_download( - self, - *, - request_id: str, - channel: NotificationChannel, - source: Optional[str], - userid: Union[str, int], - username: Optional[str], + self, *, request_id: str, channel: NotificationChannel, + source: Optional[str], userid: Union[str, int], username: Optional[str], initial_item: SystemUpdateItemStatus, - original_message_id: Optional[Union[str, int]], - original_chat_id: Optional[str], + original_message_id: Optional[Union[str, int]], original_chat_id: Optional[str], ) -> None: """按 Web 端三秒节奏轮询状态,并持续编辑原消息直到下载终态。""" - last_fingerprint = self._item_fingerprint(initial_item) + last_fingerprint = self._renderer.item_fingerprint(initial_item) last_progress_bucket = initial_item.progress // 10 edit_fallback_sent = False try: @@ -572,14 +568,18 @@ class SystemUpdateInteractionHandler: if request is None: return status = await asyncio.to_thread(self._actions.update_status) - item = self._application_item(status) - fingerprint = self._item_fingerprint(item) + item = self._renderer.application_item(status) + fingerprint = self._renderer.item_fingerprint(item) if fingerprint != last_fingerprint: - request.awaiting_input = self._awaiting_input(item) - view = self._build_view(request=request, item=item, channel=channel) + request.awaiting_input = self._renderer.awaiting_input(item) + view = self._renderer.build_view( + request=request, + item=item, + channel=channel, + ) if original_message_id and original_chat_id and ChannelCapabilityManager.supports_editing(channel): edited = await asyncio.to_thread( - self._edit_view, + self._renderer.edit_view, view=view, channel=channel, source=source, @@ -589,7 +589,7 @@ class SystemUpdateInteractionHandler: ) if not edited and (not edit_fallback_sent or item.state in self._terminal_download_states): await asyncio.to_thread( - self._post_view, + self._renderer.post_view, view=view, channel=channel, source=source, @@ -603,7 +603,7 @@ class SystemUpdateInteractionHandler: progress_bucket = item.progress // 10 if progress_bucket != last_progress_bucket or item.state in self._terminal_download_states: await asyncio.to_thread( - self._post_view, + self._renderer.post_view, view=view, channel=channel, source=source, @@ -622,7 +622,7 @@ class SystemUpdateInteractionHandler: request = update_interaction_manager.get_by_id(request_id, userid) if request is not None: await asyncio.to_thread( - self._render_operation_failure, + self._renderer.render_operation_failure, request=request, channel=channel, source=source, @@ -636,22 +636,26 @@ class SystemUpdateInteractionHandler: with _monitor_lock: _monitored_requests.discard(request_id) - def _render_status( - self, - *, - request: PendingSlashInteraction, - status: SystemUpdateStatus, - channel: NotificationChannel, - source: Optional[str], - userid: Union[str, int], - username: Optional[str], +class _SystemUpdateRenderer: + """把主程序更新状态转换为渠道消息并负责发送或编辑。""" + + def __init__( + self, *, messenger: MessageGateway, actions: SystemUpdateInteractionActions, + ) -> None: + """注入消息网关与更新状态读取用例。""" + self._messenger = messenger + self._actions = actions + + def render_status( + self, *, request: PendingSlashInteraction, status: SystemUpdateStatus, + channel: NotificationChannel, source: Optional[str], + userid: Union[str, int], username: Optional[str], operation_error: Optional[str] = None, - original_message_id: Optional[Union[str, int]] = None, - original_chat_id: Optional[str] = None, + original_message_id: Optional[Union[str, int]] = None, original_chat_id: Optional[str] = None, ) -> None: """从聚合更新快照提取主程序状态并更新交互消息。""" - item = self._application_item(status) - self._render_item( + item = self.application_item(status) + self.render_item( request=request, item=item, channel=channel, @@ -665,22 +669,16 @@ class SystemUpdateInteractionHandler: if item.state == "idle" and not item.error and not operation_error: update_interaction_manager.remove(request.request_id) - def _render_item( - self, - *, - request: PendingSlashInteraction, - item: SystemUpdateItemStatus, - channel: NotificationChannel, - source: Optional[str], - userid: Union[str, int], - username: Optional[str], + def render_item( + self, *, request: PendingSlashInteraction, item: SystemUpdateItemStatus, + channel: NotificationChannel, source: Optional[str], + userid: Union[str, int], username: Optional[str], operation_error: Optional[str] = None, - original_message_id: Optional[Union[str, int]] = None, - original_chat_id: Optional[str] = None, + original_message_id: Optional[Union[str, int]] = None, original_chat_id: Optional[str] = None, ) -> None: """更新会话阶段并优先编辑原消息展示指定主程序状态。""" - request.awaiting_input = self._awaiting_input(item) - view = self._build_view( + request.awaiting_input = self.awaiting_input(item) + view = self.build_view( request=request, item=item, channel=channel, @@ -699,17 +697,10 @@ class SystemUpdateInteractionHandler: original_chat_id=original_chat_id, ) - def _render_check_failure( - self, - *, - request: PendingSlashInteraction, - channel: NotificationChannel, - source: Optional[str], - userid: Union[str, int], - username: Optional[str], - error: str, - original_message_id: Optional[Union[str, int]] = None, - original_chat_id: Optional[str] = None, + def render_check_failure( + self, *, request: PendingSlashInteraction, channel: NotificationChannel, + source: Optional[str], userid: Union[str, int], username: Optional[str], error: str, + original_message_id: Optional[Union[str, int]] = None, original_chat_id: Optional[str] = None, ) -> None: """展示版本检查失败并保留刷新入口。""" request.awaiting_input = "refresh" @@ -734,23 +725,16 @@ class SystemUpdateInteractionHandler: original_chat_id=original_chat_id, ) - def _render_operation_failure( - self, - *, - request: PendingSlashInteraction, - channel: NotificationChannel, - source: Optional[str], - userid: Union[str, int], - username: Optional[str], - error: str, - original_message_id: Optional[Union[str, int]] = None, - original_chat_id: Optional[str] = None, + def render_operation_failure( + self, *, request: PendingSlashInteraction, channel: NotificationChannel, + source: Optional[str], userid: Union[str, int], username: Optional[str], error: str, + original_message_id: Optional[Union[str, int]] = None, original_chat_id: Optional[str] = None, ) -> None: """读取最新状态后展示下载或安装动作失败。""" try: status = self._actions.update_status() except Exception: # noqa: BLE001 保留原始动作错误 - self._render_check_failure( + self.render_check_failure( request=request, channel=channel, source=source, @@ -761,7 +745,7 @@ class SystemUpdateInteractionHandler: original_chat_id=original_chat_id, ) return - self._render_status( + self.render_status( request=request, status=status, channel=channel, @@ -773,11 +757,8 @@ class SystemUpdateInteractionHandler: original_chat_id=original_chat_id, ) - def _build_view( - self, - *, - request: PendingSlashInteraction, - item: SystemUpdateItemStatus, + def build_view( + self, *, request: PendingSlashInteraction, item: SystemUpdateItemStatus, channel: NotificationChannel, operation_error: Optional[str] = None, ) -> SystemUpdateInteractionView: @@ -850,7 +831,7 @@ class SystemUpdateInteractionHandler: ) @staticmethod - def _application_item(status: SystemUpdateStatus) -> SystemUpdateItemStatus: + def application_item(status: SystemUpdateStatus) -> SystemUpdateItemStatus: """读取主程序明细,并兼容旧版只有聚合字段的状态。""" item = next((value for value in status.updates if value.type == "application"), None) if item is not None: @@ -874,7 +855,7 @@ class SystemUpdateInteractionHandler: ) @staticmethod - def _awaiting_input(item: SystemUpdateItemStatus) -> Optional[str]: + def awaiting_input(item: SystemUpdateItemStatus) -> Optional[str]: """把更新状态映射为文本渠道下一步输入阶段。""" if item.state in {"available", "failed"}: return "download" @@ -885,7 +866,7 @@ class SystemUpdateInteractionHandler: return None @staticmethod - def _item_fingerprint(item: SystemUpdateItemStatus) -> tuple[Any, ...]: + def item_fingerprint(item: SystemUpdateItemStatus) -> tuple[Any, ...]: """生成需要刷新消息的状态指纹。""" return ( item.state, @@ -944,13 +925,9 @@ class SystemUpdateInteractionHandler: ] ] - def _edit_view( - self, - *, - view: SystemUpdateInteractionView, - channel: NotificationChannel, - source: Optional[str], - userid: Union[str, int], + def edit_view( + self, *, view: SystemUpdateInteractionView, channel: NotificationChannel, + source: Optional[str], userid: Union[str, int], original_message_id: Union[str, int], original_chat_id: str, ) -> bool: @@ -971,16 +948,10 @@ class SystemUpdateInteractionHandler: ) ) - def _post_view( - self, - *, - view: SystemUpdateInteractionView, - channel: NotificationChannel, - source: Optional[str], - userid: Union[str, int], - username: Optional[str], - original_message_id: Optional[Union[str, int]] = None, - original_chat_id: Optional[str] = None, + def post_view( + self, *, view: SystemUpdateInteractionView, channel: NotificationChannel, + source: Optional[str], userid: Union[str, int], username: Optional[str], + original_message_id: Optional[Union[str, int]] = None, original_chat_id: Optional[str] = None, ) -> None: """在无法编辑时发送一次进度或终态消息。""" self._messenger.post_message( diff --git a/app/chain/message.py b/app/chain/message.py index 7d7489d03..eac479eba 100644 --- a/app/chain/message.py +++ b/app/chain/message.py @@ -9,7 +9,7 @@ from concurrent.futures import CancelledError as FutureCancelledError from dataclasses import dataclass from datetime import datetime from pathlib import Path -from typing import Any, Callable, Dict, List, Optional, Protocol, Tuple, Union +from typing import Any, Dict, List, Optional, Protocol, Tuple, Union from urllib.parse import unquote, urlparse from app.application.agent import ( @@ -18,11 +18,11 @@ from app.application.agent import ( supports_image_input, transcribe_audio, ) +from app.application.messaging import router as interaction_router from app.application.messaging.agent import agent_interaction_manager, parse_agent_choice_callback from app.application.messaging.interaction import InteractionContext, InteractionDispatch from app.application.messaging.media import media_interaction_manager from app.application.messaging.plugin import PluginInputInteractionHandler -from app.application.messaging.router import CallbackRoute, InteractionRouter, SessionRoute from app.application.messaging.session import MessageSessionService from app.application.messaging.site import site_interaction_manager from app.application.messaging.skill import SkillInteractionHandler, skill_interaction_manager @@ -704,66 +704,41 @@ class MessageChain(ChainBase): chat_id=status.chat_id or original_chat_id, ) - def _interaction_router(self) -> InteractionRouter: + def _interaction_router(self) -> interaction_router.InteractionRouter: """构造交互路由器,文本会话按创建时间选择,回调路由注册顺序即优先级。""" - - def session_text( - handle: Callable[..., Any], - ) -> Callable[[InteractionContext, str], bool]: - """包装传统交互入口为会话路由的文本处理函数,保持懒构造。""" - def _handle(context: InteractionContext, text: str) -> bool: - return bool(handle( - channel=context.channel, - source=context.source, - userid=context.user_id, - username=context.username, - text=text, - )) - return _handle - - def callback_dispatch( - handle: Callable[..., Any], - ) -> Callable[[str, InteractionContext], InteractionDispatch]: - """包装传统回调入口为回调路由的派发函数,保持懒构造。""" - def _dispatch(callback_data: str, context: InteractionContext) -> InteractionDispatch: - return InteractionDispatch(handled=bool(handle( - callback_data=callback_data, - channel=context.channel, - source=context.source, - userid=context.user_id, - username=context.username, - original_message_id=context.original_message_id, - original_chat_id=context.original_chat_id, - ))) - return _dispatch - session_routes = [ - SessionRoute( + interaction_router.SessionRoute( name="sites", get_pending=site_interaction_manager.get_by_user, - handle_text=session_text(lambda **kw: SiteChain().handle_text_interaction(**kw)), + handle_text=interaction_router.adapt_session_text_handler( + lambda **kw: SiteChain().handle_text_interaction(**kw) + ), ), - SessionRoute( + interaction_router.SessionRoute( name="subscribes", get_pending=subscribe_interaction_manager.get_by_user, - handle_text=session_text(lambda **kw: SubscribeChain().handle_text_interaction(**kw)), + handle_text=interaction_router.adapt_session_text_handler( + lambda **kw: SubscribeChain().handle_text_interaction(**kw) + ), ), - SessionRoute( + interaction_router.SessionRoute( name="skills", get_pending=skill_interaction_manager.get_by_user, - handle_text=session_text( + handle_text=interaction_router.adapt_session_text_handler( lambda **kw: SkillInteractionHandler(messenger=self).handle_text_interaction(**kw) ), ), - SessionRoute( + interaction_router.SessionRoute( name="media", get_pending=media_interaction_manager.get_by_user, - handle_text=session_text(lambda **kw: _MediaInteractionChain().handle_text_interaction(**kw)), + handle_text=interaction_router.adapt_session_text_handler( + lambda **kw: _MediaInteractionChain().handle_text_interaction(**kw) + ), ), - SessionRoute( + interaction_router.SessionRoute( name="update", get_pending=update_interaction_manager.get_by_user, - handle_text=session_text(lambda **kw: SystemChain().handle_update_text_interaction(**kw)), + handle_text=interaction_router.adapt_session_text_handler(lambda **kw: SystemChain().handle_update_text_interaction(**kw)), ), ] @@ -796,7 +771,7 @@ class MessageChain(ChainBase): return InteractionDispatch(handled=True) callback_routes = [ - CallbackRoute( + interaction_router.CallbackRoute( name="transfer", matches=lambda data: TransferChain.parse_failed_transfer_callback(data) is not None, dispatch=lambda data, context: InteractionDispatch( @@ -809,45 +784,54 @@ class MessageChain(ChainBase): ) ), ), - CallbackRoute( + interaction_router.CallbackRoute( name="skill", matches=lambda data: data.startswith("skills:"), - dispatch=callback_dispatch( + dispatch=interaction_router.adapt_callback_handler( lambda **kw: SkillInteractionHandler(messenger=self).handle_callback_interaction(**kw) ), ), - CallbackRoute( + interaction_router.CallbackRoute( name="site", matches=lambda data: data.startswith("sites:"), - dispatch=callback_dispatch(lambda **kw: SiteChain().handle_callback_interaction(**kw)), + dispatch=interaction_router.adapt_callback_handler( + lambda **kw: SiteChain().handle_callback_interaction(**kw) + ), ), - CallbackRoute( + interaction_router.CallbackRoute( name="subscribe", matches=lambda data: data.startswith("subscribes:"), - dispatch=callback_dispatch(lambda **kw: SubscribeChain().handle_callback_interaction(**kw)), + dispatch=interaction_router.adapt_callback_handler( + lambda **kw: SubscribeChain().handle_callback_interaction(**kw) + ), ), - CallbackRoute( + interaction_router.CallbackRoute( name="media", matches=lambda data: _MediaInteractionChain.parse_callback(data) is not None, - dispatch=callback_dispatch(lambda **kw: _MediaInteractionChain().handle_callback_interaction(**kw)), + dispatch=interaction_router.adapt_callback_handler( + lambda **kw: _MediaInteractionChain().handle_callback_interaction(**kw) + ), ), - CallbackRoute( + interaction_router.CallbackRoute( name="update", matches=lambda data: data.startswith("update:"), - dispatch=callback_dispatch(lambda **kw: SystemChain().handle_update_callback_interaction(**kw)), + dispatch=interaction_router.adapt_callback_handler(lambda **kw: SystemChain().handle_update_callback_interaction(**kw)), ), - CallbackRoute( + interaction_router.CallbackRoute( name="agent_choice", matches=lambda data: parse_agent_choice_callback(data) is not None, dispatch=_dispatch_agent_choice, ), - CallbackRoute( + interaction_router.CallbackRoute( name="plugin", matches=lambda data: data.startswith("[PLUGIN]"), dispatch=_dispatch_plugin_callback, ), ] - return InteractionRouter(session_routes=session_routes, callback_routes=callback_routes) + return interaction_router.InteractionRouter( + session_routes=session_routes, + callback_routes=callback_routes, + ) def _handle_callback( self, diff --git a/app/chain/system.py b/app/chain/system.py index 022638345..0eba6acff 100644 --- a/app/chain/system.py +++ b/app/chain/system.py @@ -102,14 +102,10 @@ def _close_system_response(response: SystemResponsePort) -> None: logger.debug(f"释放版本响应失败:{str(err)}") -class SystemChain(ChainBase): - """ - 系统级处理链 - """ +class _SystemUpdateChain(ChainBase): + """提供通知渠道主程序升级交互的 Chain 入口。""" - _restart_file = "__system_restart__" _update_restart_file = "__system_update_restart__" - _plugin_restore_pending_file = "__plugin_restore_pending__" def _update_interaction_handler(self) -> SystemUpdateInteractionHandler: """构造复用当前消息网关和系统应用服务的更新交互控制器。""" @@ -201,6 +197,13 @@ class SystemChain(ChainBase): text=text, ) + +class SystemChain(_SystemUpdateChain): + """系统级处理链。""" + + _restart_file = "__system_restart__" + _plugin_restore_pending_file = "__plugin_restore_pending__" + def remote_clear_cache(self, channel: NotificationChannel, userid: Union[int, str], source: Optional[str] = None): """ 清理系统缓存