MaiBot-Napcat-Adapter/src/mmc_com_layer.py

164 lines
6.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

from maim_message import Router, RouteConfig, TargetConfig, MessageBase
from .config import global_config
from .logger import logger, custom_logger
from .send_handler.main_send_handler import send_handler
from .recv_handler.message_sending import message_send_instance
from maim_message.client import create_client_config, WebSocketClient
from maim_message.message import APIMessageBase
from typing import Dict, Any
import importlib.metadata
# 检查 maim_message 版本是否支持 MessageConverter (>= 0.6.2)
try:
maim_message_version = importlib.metadata.version("maim_message")
version_int = [int(x) for x in maim_message_version.split(".")]
HAS_MESSAGE_CONVERTER = version_int >= [0, 6, 2]
except (importlib.metadata.PackageNotFoundError, ValueError):
HAS_MESSAGE_CONVERTER = False
# router = Router(route_config, custom_logger)
# router will be initialized in mmc_start_com
router = None
class APIServerWrapper:
"""
Wrapper to make WebSocketClient compatible with legacy Router interface
"""
def __init__(self, client: WebSocketClient):
self.client = client
self.platform = global_config.maibot_server.platform_name
def register_class_handler(self, handler):
# In API Server mode, we register the on_message callback in config,
# but here we might need to bridge it if the handler structure is different.
# However, WebSocketClient config handles on_message.
# The legacy Router.register_class_handler registers a handler for received messages.
# We need to adapt the callback style.
pass
async def send_message(self, message: MessageBase) -> bool:
# 使用 MessageConverter 转换 Legacy MessageBase 到 APIMessageBase
# 接收场景Adapter 收到来自 Napcat 的消息,发送给 MaiMBot
# group_info/user_info 是消息发送者信息,放入 sender_info
from maim_message import MessageConverter
api_message = MessageConverter.to_api_receive(
message=message,
api_key=global_config.maibot_server.api_key,
platform=message.message_info.platform or self.platform,
)
return await self.client.send_message(api_message)
async def send_custom_message(self, platform: str, message_type_name: str, message: Dict) -> bool:
return await self.client.send_custom_message(message_type_name, message)
async def run(self):
await self.client.start()
await self.client.connect()
async def stop(self):
await self.client.stop()
# Global variable to hold the communication object (Router or Wrapper)
router = None
async def _legacy_message_handler_adapter(message: APIMessageBase, metadata: dict):
# Adapter to call the legacy handler with dict as expected by main_send_handler
# send_handler.handle_message expects a dict.
# We need to convert APIMessageBase back to dict legacy format if possible.
# Or check what handle_message expects.
# main_send_handler.py: handle_message takes raw_message_base_dict: dict
# and does MessageBase.from_dict(raw_message_base_dict).
# So we need to serialize APIMessageBase to a dict that looks like legacy MessageBase dict.
# This might be tricky if structures diverged.
# Let's try `to_dict()` if available, otherwise construct it.
# Inspecting APIMessageBase structure from docs:
# APIMessageBase has message_info, message_segment, message_dim.
# Legacy MessageBase has message_info, message_segment.
# We can try to construct the dict.
data = {
"message_info": {
"id": message.message_info.message_id,
"timestamp": message.message_info.time,
"group_info": {}, # Fill if available
"user_info": {}, # Fill if available
},
"message_segment": {
"type": message.message_segment.type,
"data": message.message_segment.data
}
}
# Note: This is an approximation. Ideally we should check strict compatibility.
# However, for the adapter -> bot direction (sending to napcat),
# the bot sends messages to adapter? No, Adapter sends to Bot?
# mmc_com_layer seems to be for Adapter talking to MaiBot Core.
# recv_handler/message_sending.py uses this router to send TO MaiBot.
# The `register_class_handler` in `mmc_start_com` suggests MaiBot sends messages TO Adapter?
# Wait, `send_handler.handle_message` seems to be handling messages RECEIVED FROM MaiBot.
# So `router` is bidirectional.
# If explicit to_dict is needed:
await send_handler.handle_message(data)
async def mmc_start_com():
global router
config = global_config.maibot_server
if config.enable_api_server and HAS_MESSAGE_CONVERTER:
logger.info("使用 API-Server 模式连接 MaiBot")
# Create legacy adapter handler
# We need to define the on_message callback here to bridge to send_handler
async def on_message_bridge(message: APIMessageBase, metadata: Dict[str, Any]):
# 使用 MessageConverter 转换 APIMessageBase 到 Legacy MessageBase
# 发送场景:收到来自 MaiMBot 的回复消息,需要发送给 Napcat
# receiver_info 包含消息接收者信息,需要提取到 group_info/user_info
try:
from maim_message import MessageConverter
legacy_message = MessageConverter.from_api_send(message)
msg_dict = legacy_message.to_dict()
await send_handler.handle_message(msg_dict)
except Exception as e:
logger.error(f"消息桥接转换失败: {e}")
import traceback
logger.error(traceback.format_exc())
client_config = create_client_config(
url=config.base_url,
api_key=config.api_key,
platform=config.platform_name,
on_message=on_message_bridge
)
client = WebSocketClient(client_config)
router = APIServerWrapper(client)
message_send_instance.maibot_router = router
await router.run()
else:
logger.info("使用 Legacy WebSocket 模式连接 MaiBot")
route_config = RouteConfig(
route_config={
config.platform_name: TargetConfig(
url=f"ws://{config.host}:{config.port}/ws",
token=None,
)
}
)
router = Router(route_config, custom_logger)
router.register_class_handler(send_handler.handle_message)
message_send_instance.maibot_router = router
await router.run()
async def mmc_stop_com():
if router:
await router.stop()