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