From f9a3e99795a9eff3eedf1867e71f01abe8da1954 Mon Sep 17 00:00:00 2001 From: RockChinQ <1010553892@qq.com> Date: Thu, 8 Feb 2024 13:12:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=81=A2=E5=A4=8Dnakuru=E4=BD=BF?= =?UTF-8?q?=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/platform/adapter.py | 28 ++++++++++- pkg/platform/manager.py | 52 ++++++++++++++------ pkg/platform/sources/aiocqhttp.py | 2 +- pkg/platform/sources/nakuru.py | 79 ++++++++++++++++--------------- pkg/platform/sources/qqbotpy.py | 3 +- pkg/platform/sources/yirimirai.py | 7 ++- templates/platform.json | 6 +++ templates/system.json | 5 +- 8 files changed, 123 insertions(+), 59 deletions(-) diff --git a/pkg/platform/adapter.py b/pkg/platform/adapter.py index ffb8b77a..5ebec9eb 100644 --- a/pkg/platform/adapter.py +++ b/pkg/platform/adapter.py @@ -1,14 +1,38 @@ +from __future__ import annotations + # MessageSource的适配器 import typing import abc import mirai +from ..core import app + + +preregistered_adapters: list[typing.Type[MessageSourceAdapter]] = [] + +def adapter_class( + name: str +): + def decorator(cls: typing.Type[MessageSourceAdapter]) -> typing.Type[MessageSourceAdapter]: + cls.name = name + preregistered_adapters.append(cls) + return cls + return decorator + class MessageSourceAdapter(metaclass=abc.ABCMeta): + name: str + bot_account_id: int - def __init__(self, config: dict): - pass + + config: dict + + ap: app.Application + + def __init__(self, config: dict, ap: app.Application): + self.config = config + self.ap = ap async def send_message( self, diff --git a/pkg/platform/manager.py b/pkg/platform/manager.py index 469cd330..9e7a213b 100644 --- a/pkg/platform/manager.py +++ b/pkg/platform/manager.py @@ -14,13 +14,14 @@ from ..platform import adapter as msadapter from ..core import app, entities as core_entities from ..plugin import events - # 控制QQ消息输入输出的类 class PlatformManager: adapter: msadapter.MessageSourceAdapter = None - bot_account_id: int = 0 + @property + def bot_account_id(self): + return self.adapter.bot_account_id # modern ap: app.Application = None @@ -31,22 +32,43 @@ class PlatformManager: async def initialize(self): - if self.ap.platform_cfg.data['platform-adapter'] == 'yiri-mirai': - from pkg.platform.sources.yirimirai import YiriMiraiAdapter + # if self.ap.platform_cfg.data['platform-adapter'] == 'yiri-mirai': + # from pkg.platform.sources.yirimirai import YiriMiraiAdapter - mirai_http_api_config = self.ap.platform_cfg.data['yiri-mirai-config'] - self.bot_account_id = mirai_http_api_config['qq'] - self.adapter = YiriMiraiAdapter(mirai_http_api_config) - elif self.ap.platform_cfg.data['platform-adapter'] == 'aiocqhttp': - from pkg.platform.sources.aiocqhttp import AiocqhttpAdapter + # mirai_http_api_config = self.ap.platform_cfg.data['yiri-mirai-config'] + # self.adapter = YiriMiraiAdapter(mirai_http_api_config, self.ap) + # elif self.ap.platform_cfg.data['platform-adapter'] == 'nakuru': + # from pkg.platform.sources.nakuru import NakuruProjectAdapter - aiocqhttp_config = self.ap.platform_cfg.data['aiocqhttp-config'] - self.adapter = AiocqhttpAdapter(aiocqhttp_config, self.ap) - elif self.ap.platform_cfg.data['platform-adapter'] == 'qq-botpy': - from pkg.platform.sources.qqbotpy import OfficialAdapter + # nakuru_config = self.ap.platform_cfg.data['nakuru-config'] + # self.adapter = NakuruProjectAdapter(nakuru_config, self.ap) + # elif self.ap.platform_cfg.data['platform-adapter'] == 'aiocqhttp': + # from pkg.platform.sources.aiocqhttp import AiocqhttpAdapter - qqbotpy_config = self.ap.platform_cfg.data['qq-botpy-config'] - self.adapter = OfficialAdapter(qqbotpy_config, self.ap) + # aiocqhttp_config = self.ap.platform_cfg.data['aiocqhttp-config'] + # self.adapter = AiocqhttpAdapter(aiocqhttp_config, self.ap) + # elif self.ap.platform_cfg.data['platform-adapter'] == 'qq-botpy': + # from pkg.platform.sources.qqbotpy import OfficialAdapter + + # qqbotpy_config = self.ap.platform_cfg.data['qq-botpy-config'] + # self.adapter = OfficialAdapter(qqbotpy_config, self.ap) + + from .sources import yirimirai, nakuru, aiocqhttp, qqbotpy + + adapter_cls = None + + for adapter in msadapter.preregistered_adapters: + if adapter.name == self.ap.platform_cfg.data['platform-adapter']: + adapter_cls = adapter + break + if adapter_cls is None: + raise Exception('未知的平台适配器: ' + self.ap.platform_cfg.data['platform-adapter']) + + cfg_key = self.ap.platform_cfg.data['platform-adapter'] + '-config' + self.adapter = adapter_cls( + self.ap.platform_cfg.data[cfg_key], + self.ap + ) async def on_friend_message(event: FriendMessage): diff --git a/pkg/platform/sources/aiocqhttp.py b/pkg/platform/sources/aiocqhttp.py index 169aca8b..0b5b2aff 100644 --- a/pkg/platform/sources/aiocqhttp.py +++ b/pkg/platform/sources/aiocqhttp.py @@ -191,6 +191,7 @@ class AiocqhttpEventConverter(adapter.EventConverter): ) +@adapter.adapter_class("aiocqhttp") class AiocqhttpAdapter(adapter.MessageSourceAdapter): bot: aiocqhttp.CQHttp @@ -243,7 +244,6 @@ class AiocqhttpAdapter(adapter.MessageSourceAdapter): ): async def on_message(event: aiocqhttp.Event): self.bot_account_id = event.self_id - self.ap.im_mgr.bot_account_id = event.self_id try: return await callback(self.event_converter.target2yiri(event)) except: diff --git a/pkg/platform/sources/nakuru.py b/pkg/platform/sources/nakuru.py index ccdfe6ae..202f3f6c 100644 --- a/pkg/platform/sources/nakuru.py +++ b/pkg/platform/sources/nakuru.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import asyncio import typing import traceback @@ -10,6 +12,7 @@ import nakuru.entities.components as nkc from .. import adapter as adapter_model from ...pipeline.longtext.strategies import forward +from ...core import app class NakuruProjectMessageConverter(adapter_model.MessageConverter): @@ -96,7 +99,7 @@ class NakuruProjectMessageConverter(adapter_model.MessageConverter): yiri_msg_list.append(mirai.AtAll()) else: pass - logging.debug("转换后的消息链: " + str(yiri_msg_list)) + # logging.debug("转换后的消息链: " + str(yiri_msg_list)) chain = mirai.MessageChain(yiri_msg_list) return chain @@ -156,6 +159,7 @@ class NakuruProjectEventConverter(adapter_model.EventConverter): raise Exception("未支持转换的事件类型: " + str(event)) +@adapter_model.adapter_class("nakuru") class NakuruProjectAdapter(adapter_model.MessageSourceAdapter): """nakuru-project适配器""" bot: nakuru.CQHTTP @@ -166,34 +170,20 @@ class NakuruProjectAdapter(adapter_model.MessageSourceAdapter): listener_list: list[dict] - def __init__(self, cfg: dict): + ap: app.Application + + cfg: dict + + def __init__(self, cfg: dict, ap: app.Application): """初始化nakuru-project的对象""" - self.bot = nakuru.CQHTTP(**cfg) + cfg['port'] = cfg['ws_port'] + del cfg['ws_port'] + self.cfg = cfg + self.ap = ap self.listener_list = [] - # nakuru库有bug,这个接口没法带access_token,会失败 - # 所以目前自行发请求 + self.bot = nakuru.CQHTTP(**self.cfg) - config = context.get_config_manager().data - - import requests - resp = requests.get( - url="http://{}:{}/get_login_info".format(config['nakuru_config']['host'], config['nakuru_config']['http_port']), - headers={ - 'Authorization': "Bearer " + config['nakuru_config']['token'] if 'token' in config['nakuru_config']else "" - }, - timeout=5, - proxies=None - ) - if resp.status_code == 403: - logging.error("go-cqhttp拒绝访问,请检查config.py中nakuru_config的token是否与go-cqhttp设置的access-token匹配") - raise Exception("go-cqhttp拒绝访问,请检查config.py中nakuru_config的token是否与go-cqhttp设置的access-token匹配") - try: - self.bot_account_id = int(resp.json()['data']['user_id']) - except Exception as e: - logging.error("获取go-cqhttp账号信息失败: {}, 请检查是否已启动go-cqhttp并配置正确".format(e)) - raise Exception("获取go-cqhttp账号信息失败: {}, 请检查是否已启动go-cqhttp并配置正确".format(e)) - - def send_message( + async def send_message( self, target_type: str, target_id: str, @@ -226,9 +216,9 @@ class NakuruProjectAdapter(adapter_model.MessageSourceAdapter): else: raise Exception("Unknown target type: " + target_type) - asyncio.run(task) + await task - def reply_message( + async def reply_message( self, message_source: mirai.MessageEvent, message: mirai.MessageChain, @@ -242,14 +232,14 @@ class NakuruProjectAdapter(adapter_model.MessageSourceAdapter): ) ) if type(message_source) is mirai.GroupMessage: - self.send_message( + await self.send_message( "group", message_source.sender.group.id, message, converted=True ) elif type(message_source) is mirai.FriendMessage: - self.send_message( + await self.send_message( "person", message_source.sender.id, message, @@ -270,11 +260,11 @@ class NakuruProjectAdapter(adapter_model.MessageSourceAdapter): callback: typing.Callable[[mirai.Event], None] ): try: - logging.debug("注册监听器: " + str(event_type) + " -> " + str(callback)) # 包装函数 async def listener_wrapper(app: nakuru.CQHTTP, source: NakuruProjectAdapter.event_converter.yiri2target(event_type)): - callback(self.event_converter.target2yiri(source)) + print(1111) + await callback(self.event_converter.target2yiri(source)) # 将包装函数和原函数的对应关系存入列表 self.listener_list.append( @@ -287,7 +277,6 @@ class NakuruProjectAdapter(adapter_model.MessageSourceAdapter): # 注册监听器 self.bot.receiver(self.event_converter.yiri2target(event_type).__name__)(listener_wrapper) - logging.debug("注册完成") except Exception as e: traceback.print_exc() raise e @@ -318,10 +307,26 @@ class NakuruProjectAdapter(adapter_model.MessageSourceAdapter): self.bot.event[nakuru_event_name] = new_event_list - def run_sync(self): - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - self.bot.run() + async def run_async(self): + try: + import requests + resp = requests.get( + url="http://{}:{}/get_login_info".format(self.cfg['host'], self.cfg['http_port']), + headers={ + 'Authorization': "Bearer " + self.cfg['token'] if 'token' in self.cfg else "" + }, + timeout=5, + proxies=None + ) + if resp.status_code == 403: + raise Exception("go-cqhttp拒绝访问,请检查config.py中nakuru_config的token是否与go-cqhttp设置的access-token匹配") + self.bot_account_id = int(resp.json()['data']['user_id']) + except Exception as e: + raise Exception("获取go-cqhttp账号信息失败, 请检查是否已启动go-cqhttp并配置正确") + await self.bot._run() + self.ap.logger.info("运行 Nakuru 适配器") + while True: + await asyncio.sleep(100) def kill(self) -> bool: return False \ No newline at end of file diff --git a/pkg/platform/sources/qqbotpy.py b/pkg/platform/sources/qqbotpy.py index 7f725615..8264a193 100644 --- a/pkg/platform/sources/qqbotpy.py +++ b/pkg/platform/sources/qqbotpy.py @@ -263,6 +263,7 @@ class OfficialEventConverter(adapter_model.EventConverter): ) +@adapter_model.adapter_class("qq-botpy") class OfficialAdapter(adapter_model.MessageSourceAdapter): """QQ 官方消息适配器""" bot: botpy.Client = None @@ -298,8 +299,6 @@ class OfficialAdapter(adapter_model.MessageSourceAdapter): self.bot = botpy.Client(intents=intents) - # TODO 获取机器人id和昵称 - async def send_message( self, target_type: str, diff --git a/pkg/platform/sources/yirimirai.py b/pkg/platform/sources/yirimirai.py index 04149623..c43e13fb 100644 --- a/pkg/platform/sources/yirimirai.py +++ b/pkg/platform/sources/yirimirai.py @@ -6,14 +6,18 @@ import mirai.models.bus from mirai.bot import MiraiRunner from .. import adapter as adapter_model +from ...core import app +@adapter_model.adapter_class("yiri-mirai") class YiriMiraiAdapter(adapter_model.MessageSourceAdapter): """YiriMirai适配器""" bot: mirai.Mirai - def __init__(self, config: dict): + def __init__(self, config: dict, ap: app.Application): """初始化YiriMirai的对象""" + self.ap = ap + self.config = config if 'adapter' not in config or \ config['adapter'] == 'WebSocketAdapter': self.bot = mirai.Mirai( @@ -111,6 +115,7 @@ class YiriMiraiAdapter(adapter_model.MessageSourceAdapter): bus.unsubscribe(event_type, callback) async def run_async(self): + self.bot_account_id = self.bot.qq return await MiraiRunner(self.bot)._run() async def kill(self) -> bool: diff --git a/templates/platform.json b/templates/platform.json index 94162c24..bef28523 100644 --- a/templates/platform.json +++ b/templates/platform.json @@ -7,6 +7,12 @@ "verifyKey": "yirimirai", "qq": 123456789 }, + "nakuru-config": { + "host": "127.0.0.1", + "ws_port": 8080, + "http_port": 5700, + "token": "" + }, "aiocqhttp-config": { "host": "127.0.0.1", "port": 8080 diff --git a/templates/system.json b/templates/system.json index c7b0118e..72d29b98 100644 --- a/templates/system.json +++ b/templates/system.json @@ -1,6 +1,9 @@ { "admin-sessions": [], - "network-proxies": {}, + "network-proxies": { + "http": null, + "https": null + }, "report-usage": true, "logging-level": "info", "session-concurrency": {