406 lines
13 KiB
Python
406 lines
13 KiB
Python
"""
|
||
CoreSink 统一管理器
|
||
|
||
负责管理 InProcessCoreSink 和 ProcessCoreSink 双实例,
|
||
提供统一的消息收发接口,自动维护与适配器子进程的通信管道。
|
||
|
||
核心职责:
|
||
1. 创建和管理 InProcessCoreSink(进程内消息)和 ProcessCoreSink(跨进程消息)
|
||
2. 自动维护 ProcessCoreSink 与子进程的通信管道
|
||
3. 使用 MessageRuntime 进行消息路由和处理
|
||
4. 提供统一的消息发送接口
|
||
|
||
架构说明(2025-11 重构):
|
||
- 集成 mofox_wire.MessageRuntime 作为消息路由中心
|
||
- 使用 @runtime.on_message() 装饰器注册消息处理器
|
||
- 利用 before_hook/after_hook/error_hook 处理前置/后置/错误逻辑
|
||
- 简化消息处理链条,提高可扩展性
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import asyncio
|
||
import multiprocessing as mp
|
||
from collections.abc import Awaitable, Callable
|
||
from typing import Any
|
||
|
||
from mofox_wire import (
|
||
InProcessCoreSink,
|
||
MessageEnvelope,
|
||
MessageRuntime,
|
||
ProcessCoreSinkServer,
|
||
)
|
||
|
||
from src.common.logger import get_logger
|
||
|
||
logger = get_logger("core_sink_manager")
|
||
|
||
|
||
# 消息处理器类型
|
||
MessageHandlerCallback = Callable[[MessageEnvelope], Awaitable[None]]
|
||
|
||
|
||
class CoreSinkManager:
|
||
"""
|
||
CoreSink 统一管理器
|
||
|
||
管理 InProcessCoreSink 和 ProcessCoreSinkServer 双实例,
|
||
集成 MessageRuntime 提供统一的消息路由和收发接口。
|
||
|
||
架构说明:
|
||
- InProcessCoreSink: 用于同进程内的适配器(run_in_subprocess=False)
|
||
- ProcessCoreSinkServer: 用于管理与子进程适配器的通信
|
||
- MessageRuntime: 统一消息路由,支持 @on_message 装饰器和钩子机制
|
||
|
||
消息流向:
|
||
1. 适配器(同进程)→ InProcessCoreSink → MessageRuntime.handle_message() → 注册的处理器
|
||
2. 适配器(子进程)→ ProcessCoreSinkServer → MessageRuntime.handle_message() → 注册的处理器
|
||
3. 核心回复 → CoreSinkManager.send_outgoing → 适配器
|
||
|
||
使用 MessageRuntime 的优势:
|
||
- 支持 @runtime.on_message(message_type="xxx") 按消息类型路由
|
||
- 支持 before_hook/after_hook/error_hook 统一处理流程
|
||
- 支持中间件机制(洋葱模型)
|
||
- 自动处理同步/异步处理器
|
||
"""
|
||
|
||
def __init__(self):
|
||
# MessageRuntime 实例
|
||
self._runtime: MessageRuntime = MessageRuntime()
|
||
|
||
# InProcessCoreSink 实例(用于同进程适配器)
|
||
self._in_process_sink: InProcessCoreSink | None = None
|
||
|
||
# 子进程通信管理
|
||
# key: adapter_name, value: (ProcessCoreSinkServer, incoming_queue, outgoing_queue)
|
||
self._process_sinks: dict[str, tuple[ProcessCoreSinkServer, mp.Queue, mp.Queue]] = {}
|
||
|
||
# multiprocessing context
|
||
self._mp_ctx = mp.get_context("spawn")
|
||
|
||
# 运行状态
|
||
self._running = False
|
||
self._initialized = False
|
||
|
||
# 后台任务集合(防止任务被垃圾回收)
|
||
self._background_tasks: set[asyncio.Task] = set()
|
||
|
||
@property
|
||
def runtime(self) -> MessageRuntime:
|
||
"""
|
||
获取 MessageRuntime 实例
|
||
|
||
外部模块可以通过此属性注册消息处理器、钩子等:
|
||
|
||
```python
|
||
manager = get_core_sink_manager()
|
||
|
||
# 注册消息处理器
|
||
@manager.runtime.on_message(message_type="text")
|
||
async def handle_text(envelope: MessageEnvelope):
|
||
...
|
||
|
||
# 注册前置钩子
|
||
manager.runtime.register_before_hook(my_before_hook)
|
||
```
|
||
|
||
Returns:
|
||
MessageRuntime 实例
|
||
"""
|
||
return self._runtime
|
||
|
||
async def initialize(self) -> None:
|
||
"""
|
||
初始化 CoreSink 管理器
|
||
|
||
创建 InProcessCoreSink,将收到的消息交给 MessageRuntime 处理。
|
||
"""
|
||
if self._initialized:
|
||
logger.warning("CoreSinkManager 已经初始化,跳过重复初始化")
|
||
return
|
||
|
||
logger.info("正在初始化 CoreSink 管理器...")
|
||
|
||
# 创建 InProcessCoreSink,使用 MessageRuntime 作为消息处理入口
|
||
self._in_process_sink = InProcessCoreSink(self._dispatch_to_runtime)
|
||
|
||
self._running = True
|
||
self._initialized = True
|
||
|
||
logger.info("CoreSink 管理器初始化完成(已集成 MessageRuntime)")
|
||
|
||
async def shutdown(self) -> None:
|
||
"""关闭 CoreSink 管理器"""
|
||
if not self._running:
|
||
return
|
||
|
||
logger.info("正在关闭 CoreSink 管理器...")
|
||
self._running = False
|
||
|
||
# 关闭所有 ProcessCoreSinkServer
|
||
for adapter_name, (server, _, _) in list(self._process_sinks.items()):
|
||
try:
|
||
await server.close()
|
||
logger.info(f"已关闭适配器 {adapter_name} 的 ProcessCoreSinkServer")
|
||
except Exception as e:
|
||
logger.error(f"关闭适配器 {adapter_name} 的 ProcessCoreSinkServer 时出错: {e}")
|
||
|
||
self._process_sinks.clear()
|
||
|
||
# 关闭 InProcessCoreSink
|
||
if self._in_process_sink:
|
||
await self._in_process_sink.close()
|
||
self._in_process_sink = None
|
||
|
||
self._initialized = False
|
||
logger.info("CoreSink 管理器已关闭")
|
||
|
||
def get_in_process_sink(self) -> InProcessCoreSink:
|
||
"""
|
||
获取 InProcessCoreSink 实例
|
||
|
||
用于同进程运行的适配器
|
||
|
||
Returns:
|
||
InProcessCoreSink 实例
|
||
|
||
Raises:
|
||
RuntimeError: 如果管理器未初始化
|
||
"""
|
||
if self._in_process_sink is None:
|
||
raise RuntimeError("CoreSinkManager 未初始化,请先调用 initialize()")
|
||
return self._in_process_sink
|
||
|
||
def create_process_sink_queues(self, adapter_name: str) -> tuple[mp.Queue, mp.Queue]:
|
||
"""
|
||
为子进程适配器创建通信队列
|
||
|
||
创建 incoming 和 outgoing 队列对,用于与子进程适配器通信。
|
||
同时创建 ProcessCoreSinkServer 来处理消息转发。
|
||
|
||
Args:
|
||
adapter_name: 适配器名称
|
||
|
||
Returns:
|
||
(to_core_queue, from_core_queue) 元组
|
||
- to_core_queue: 子进程发送到核心的队列
|
||
- from_core_queue: 核心发送到子进程的队列
|
||
|
||
Raises:
|
||
RuntimeError: 如果管理器未初始化
|
||
"""
|
||
if not self._initialized:
|
||
raise RuntimeError("CoreSinkManager 未初始化,请先调用 initialize()")
|
||
|
||
if adapter_name in self._process_sinks:
|
||
logger.warning(f"适配器 {adapter_name} 的队列已存在,将被覆盖")
|
||
# 先关闭旧的
|
||
old_server, _, _ = self._process_sinks[adapter_name]
|
||
task = asyncio.create_task(old_server.close())
|
||
self._background_tasks.add(task)
|
||
task.add_done_callback(self._background_tasks.discard)
|
||
|
||
# 创建通信队列
|
||
incoming_queue = self._mp_ctx.Queue() # 子进程 → 核心
|
||
outgoing_queue = self._mp_ctx.Queue() # 核心 → 子进程
|
||
|
||
# 创建 ProcessCoreSinkServer,使用 MessageRuntime 处理消息
|
||
server = ProcessCoreSinkServer(
|
||
incoming_queue=incoming_queue,
|
||
outgoing_queue=outgoing_queue,
|
||
core_handler=self._dispatch_to_runtime,
|
||
name=adapter_name,
|
||
)
|
||
|
||
# 启动服务器
|
||
server.start()
|
||
|
||
# 存储引用
|
||
self._process_sinks[adapter_name] = (server, incoming_queue, outgoing_queue)
|
||
|
||
logger.info(f"为适配器 {adapter_name} 创建了 ProcessCoreSink 通信队列")
|
||
|
||
return incoming_queue, outgoing_queue
|
||
|
||
def remove_process_sink(self, adapter_name: str) -> None:
|
||
"""
|
||
移除子进程适配器的通信队列
|
||
|
||
Args:
|
||
adapter_name: 适配器名称
|
||
"""
|
||
if adapter_name not in self._process_sinks:
|
||
logger.warning(f"适配器 {adapter_name} 的队列不存在")
|
||
return
|
||
|
||
server, _, _ = self._process_sinks.pop(adapter_name)
|
||
task = asyncio.create_task(server.close())
|
||
self._background_tasks.add(task)
|
||
task.add_done_callback(self._background_tasks.discard)
|
||
logger.info(f"已移除适配器 {adapter_name} 的 ProcessCoreSink 通信队列")
|
||
|
||
async def send_outgoing(
|
||
self,
|
||
envelope: MessageEnvelope,
|
||
platform: str | None = None,
|
||
adapter_name: str | None = None
|
||
) -> None:
|
||
"""
|
||
发送消息到适配器
|
||
|
||
根据 platform 或 adapter_name 路由到正确的适配器。
|
||
|
||
Args:
|
||
envelope: 消息信封
|
||
platform: 目标平台(可选)
|
||
adapter_name: 目标适配器名称(可选)
|
||
|
||
路由规则:
|
||
1. 如果指定了 adapter_name,直接发送到该适配器
|
||
2. 如果指定了 platform,发送到所有匹配平台的适配器
|
||
3. 如果都没指定,从 envelope 中提取 platform 并广播
|
||
"""
|
||
# 从 envelope 中获取 platform
|
||
if platform is None:
|
||
platform = envelope.get("platform") or envelope.get("message_info", {}).get("platform")
|
||
|
||
# 发送到 InProcessCoreSink(会自动广播到所有注册的 outgoing handler)
|
||
if self._in_process_sink:
|
||
await self._in_process_sink.push_outgoing(envelope)
|
||
|
||
# 发送到所有 ProcessCoreSinkServer
|
||
for name, (server, _, _) in self._process_sinks.items():
|
||
if adapter_name and name != adapter_name:
|
||
continue
|
||
try:
|
||
await server.push_outgoing(envelope)
|
||
except Exception as e:
|
||
logger.error(f"发送消息到适配器 {name} 失败: {e}")
|
||
|
||
async def _dispatch_to_runtime(self, envelope: MessageEnvelope) -> None:
|
||
"""
|
||
将消息分发给 MessageRuntime 处理
|
||
|
||
这是内部方法,由 InProcessCoreSink 和 ProcessCoreSinkServer 调用。
|
||
所有从适配器接收到的消息都会经过这里,然后交给 MessageRuntime 路由。
|
||
|
||
Args:
|
||
envelope: 消息信封
|
||
"""
|
||
if not self._running:
|
||
logger.warning("CoreSinkManager 未运行,忽略接收到的消息")
|
||
return
|
||
|
||
try:
|
||
# 使用 MessageRuntime 处理消息
|
||
await self._runtime.handle_message(envelope)
|
||
except Exception as e:
|
||
logger.error(f"MessageRuntime 处理消息时出错: {e}")
|
||
|
||
|
||
# 全局单例
|
||
_core_sink_manager: CoreSinkManager | None = None
|
||
|
||
|
||
def get_core_sink_manager() -> CoreSinkManager:
|
||
"""获取 CoreSinkManager 单例"""
|
||
global _core_sink_manager
|
||
if _core_sink_manager is None:
|
||
_core_sink_manager = CoreSinkManager()
|
||
return _core_sink_manager
|
||
|
||
|
||
def get_message_runtime() -> MessageRuntime:
|
||
"""
|
||
获取全局 MessageRuntime 实例
|
||
|
||
这是获取 MessageRuntime 的推荐方式,用于注册消息处理器、钩子等:
|
||
|
||
```python
|
||
from src.common.core_sink_manager import get_message_runtime
|
||
|
||
runtime = get_message_runtime()
|
||
|
||
@runtime.on_message(message_type="text")
|
||
async def handle_text(envelope: MessageEnvelope):
|
||
...
|
||
```
|
||
|
||
Returns:
|
||
MessageRuntime 实例
|
||
"""
|
||
return get_core_sink_manager().runtime
|
||
|
||
|
||
async def initialize_core_sink_manager() -> CoreSinkManager:
|
||
"""
|
||
初始化 CoreSinkManager 单例
|
||
|
||
Returns:
|
||
初始化后的 CoreSinkManager 实例
|
||
"""
|
||
manager = get_core_sink_manager()
|
||
await manager.initialize()
|
||
return manager
|
||
|
||
|
||
async def shutdown_core_sink_manager() -> None:
|
||
"""关闭 CoreSinkManager 单例"""
|
||
global _core_sink_manager
|
||
if _core_sink_manager:
|
||
await _core_sink_manager.shutdown()
|
||
_core_sink_manager = None
|
||
|
||
|
||
# ============================================================================
|
||
# 向后兼容的 API
|
||
# ============================================================================
|
||
|
||
def get_core_sink() -> InProcessCoreSink:
|
||
"""
|
||
获取 InProcessCoreSink 实例(向后兼容)
|
||
|
||
这是旧版 API,推荐使用 get_core_sink_manager().get_in_process_sink()
|
||
|
||
Returns:
|
||
InProcessCoreSink 实例
|
||
"""
|
||
return get_core_sink_manager().get_in_process_sink()
|
||
|
||
|
||
def set_core_sink(sink: Any) -> None:
|
||
"""
|
||
设置 CoreSink(向后兼容,现已弃用)
|
||
|
||
新架构中 CoreSink 由 CoreSinkManager 统一管理,不再支持外部设置。
|
||
此函数保留仅为兼容旧代码,调用会记录警告日志。
|
||
"""
|
||
logger.warning(
|
||
"set_core_sink() 已弃用,CoreSink 现由 CoreSinkManager 统一管理。"
|
||
"请使用 initialize_core_sink_manager() 初始化。"
|
||
)
|
||
|
||
|
||
async def push_outgoing(envelope: MessageEnvelope) -> None:
|
||
"""
|
||
将消息推送到所有适配器(向后兼容)
|
||
|
||
Args:
|
||
envelope: 消息信封
|
||
"""
|
||
manager = get_core_sink_manager()
|
||
await manager.send_outgoing(envelope)
|
||
|
||
|
||
__all__ = [
|
||
"CoreSinkManager",
|
||
# 向后兼容
|
||
"get_core_sink",
|
||
"get_core_sink_manager",
|
||
"get_message_runtime",
|
||
"initialize_core_sink_manager",
|
||
"push_outgoing",
|
||
"set_core_sink",
|
||
"shutdown_core_sink_manager",
|
||
]
|