mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 12:05:54 +00:00
273 lines
8.7 KiB
Python
273 lines
8.7 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
import logging
|
|
import asyncio
|
|
import traceback
|
|
import sqlalchemy
|
|
|
|
from .sources import qqofficial
|
|
|
|
# FriendMessage, Image, MessageChain, Plain
|
|
from ..platform import adapter as msadapter
|
|
|
|
from ..core import app, entities as core_entities, taskmgr
|
|
from ..plugin import events
|
|
from .types import message as platform_message
|
|
from .types import events as platform_events
|
|
from .types import entities as platform_entities
|
|
|
|
from ..discover import engine
|
|
|
|
from ..entity.persistence import bot as persistence_bot
|
|
|
|
# 处理 3.4 移除了 YiriMirai 之后,插件的兼容性问题
|
|
from . import types as mirai
|
|
sys.modules['mirai'] = mirai
|
|
|
|
|
|
class RuntimeBot:
|
|
"""运行时机器人"""
|
|
|
|
ap: app.Application
|
|
|
|
bot_entity: persistence_bot.Bot
|
|
|
|
enable: bool
|
|
|
|
adapter: msadapter.MessagePlatformAdapter
|
|
|
|
task_wrapper: taskmgr.TaskWrapper
|
|
|
|
task_context: taskmgr.TaskContext
|
|
|
|
def __init__(self, ap: app.Application, bot_entity: persistence_bot.Bot, adapter: msadapter.MessagePlatformAdapter):
|
|
self.ap = ap
|
|
self.bot_entity = bot_entity
|
|
self.enable = bot_entity.enable
|
|
self.adapter = adapter
|
|
self.task_context = taskmgr.TaskContext()
|
|
|
|
async def initialize(self):
|
|
|
|
async def on_friend_message(event: platform_events.FriendMessage, adapter: msadapter.MessagePlatformAdapter):
|
|
|
|
await self.ap.query_pool.add_query(
|
|
launcher_type=core_entities.LauncherTypes.PERSON,
|
|
launcher_id=event.sender.id,
|
|
sender_id=event.sender.id,
|
|
message_event=event,
|
|
message_chain=event.message_chain,
|
|
adapter=adapter,
|
|
pipeline_uuid=self.bot_entity.use_pipeline_uuid
|
|
)
|
|
|
|
async def on_group_message(event: platform_events.GroupMessage, adapter: msadapter.MessagePlatformAdapter):
|
|
|
|
await self.ap.query_pool.add_query(
|
|
launcher_type=core_entities.LauncherTypes.GROUP,
|
|
launcher_id=event.group.id,
|
|
sender_id=event.sender.id,
|
|
message_event=event,
|
|
message_chain=event.message_chain,
|
|
adapter=adapter,
|
|
pipeline_uuid=self.bot_entity.use_pipeline_uuid
|
|
)
|
|
|
|
self.adapter.register_listener(
|
|
platform_events.FriendMessage,
|
|
on_friend_message
|
|
)
|
|
self.adapter.register_listener(
|
|
platform_events.GroupMessage,
|
|
on_group_message
|
|
)
|
|
|
|
async def run(self):
|
|
|
|
async def exception_wrapper():
|
|
try:
|
|
self.task_context.set_current_action('Running...')
|
|
await self.adapter.run_async()
|
|
self.task_context.set_current_action('Exited.')
|
|
except Exception as e:
|
|
if isinstance(e, asyncio.CancelledError):
|
|
self.task_context.set_current_action('Exited.')
|
|
return
|
|
self.task_context.set_current_action('Exited with error.')
|
|
self.task_context.log(f'平台适配器运行出错: {e}')
|
|
self.task_context.log(f"Traceback: {traceback.format_exc()}")
|
|
self.ap.logger.error(f'平台适配器运行出错: {e}')
|
|
self.ap.logger.debug(f"Traceback: {traceback.format_exc()}")
|
|
|
|
self.task_wrapper = self.ap.task_mgr.create_task(
|
|
exception_wrapper(),
|
|
kind="platform-adapter",
|
|
name=f"platform-adapter-{self.adapter.__class__.__name__}",
|
|
context=self.task_context,
|
|
scopes=[core_entities.LifecycleControlScope.APPLICATION, core_entities.LifecycleControlScope.PLATFORM]
|
|
)
|
|
|
|
async def shutdown(self):
|
|
await self.adapter.kill()
|
|
|
|
|
|
# 控制QQ消息输入输出的类
|
|
class PlatformManager:
|
|
|
|
# adapter: msadapter.MessageSourceAdapter = None
|
|
adapters: list[msadapter.MessagePlatformAdapter] = []
|
|
|
|
message_platform_adapter_components: list[engine.Component] = []
|
|
|
|
# ====== 4.0 ======
|
|
ap: app.Application = None
|
|
|
|
bots: list[RuntimeBot]
|
|
|
|
adapter_components: list[engine.Component]
|
|
|
|
adapter_dict: dict[str, type[msadapter.MessagePlatformAdapter]]
|
|
|
|
def __init__(self, ap: app.Application = None):
|
|
|
|
self.ap = ap
|
|
self.adapters = []
|
|
self.bots = []
|
|
self.adapter_components = []
|
|
self.adapter_dict = {}
|
|
|
|
async def initialize(self):
|
|
|
|
self.adapter_components = self.ap.discover.get_components_by_kind('MessagePlatformAdapter')
|
|
adapter_dict: dict[str, type[msadapter.MessagePlatformAdapter]] = {}
|
|
for component in self.adapter_components:
|
|
adapter_dict[component.metadata.name] = component.get_python_component_class()
|
|
self.adapter_dict = adapter_dict
|
|
|
|
await self.load_bots_from_db()
|
|
|
|
async def load_bots_from_db(self):
|
|
self.ap.logger.info('Loading bots from db...')
|
|
|
|
self.bots = []
|
|
|
|
result = await self.ap.persistence_mgr.execute_async(
|
|
sqlalchemy.select(persistence_bot.Bot)
|
|
)
|
|
|
|
bots = result.all()
|
|
|
|
for bot in bots:
|
|
# load all bots here, enable or disable will be handled in runtime
|
|
await self.load_bot(bot)
|
|
|
|
async def load_bot(self, bot_entity: persistence_bot.Bot | sqlalchemy.Row[persistence_bot.Bot] | dict) -> RuntimeBot:
|
|
"""加载机器人"""
|
|
if isinstance(bot_entity, sqlalchemy.Row):
|
|
bot_entity = persistence_bot.Bot(**bot_entity._mapping)
|
|
elif isinstance(bot_entity, dict):
|
|
bot_entity = persistence_bot.Bot(**bot_entity)
|
|
|
|
adapter_inst = self.adapter_dict[bot_entity.adapter](
|
|
bot_entity.adapter_config,
|
|
self.ap
|
|
)
|
|
|
|
runtime_bot = RuntimeBot(
|
|
ap=self.ap,
|
|
bot_entity=bot_entity,
|
|
adapter=adapter_inst
|
|
)
|
|
|
|
await runtime_bot.initialize()
|
|
|
|
self.bots.append(runtime_bot)
|
|
|
|
return runtime_bot
|
|
|
|
async def get_bot_by_uuid(self, bot_uuid: str) -> RuntimeBot | None:
|
|
for bot in self.bots:
|
|
if bot.bot_entity.uuid == bot_uuid:
|
|
return bot
|
|
return None
|
|
|
|
async def remove_bot(self, bot_uuid: str):
|
|
for bot in self.bots:
|
|
if bot.bot_entity.uuid == bot_uuid:
|
|
if bot.enable:
|
|
await bot.shutdown()
|
|
self.bots.remove(bot)
|
|
return
|
|
|
|
def get_available_adapters_info(self) -> list[dict]:
|
|
return [
|
|
component.to_plain_dict()
|
|
for component in self.message_platform_adapter_components
|
|
]
|
|
|
|
def get_available_adapter_info_by_name(self, name: str) -> dict | None:
|
|
for component in self.message_platform_adapter_components:
|
|
if component.metadata.name == name:
|
|
return component.to_plain_dict()
|
|
return None
|
|
|
|
async def write_back_config(self, adapter_name: str, adapter_inst: msadapter.MessagePlatformAdapter, config: dict):
|
|
index = -2
|
|
|
|
for i, adapter in enumerate(self.adapters):
|
|
if adapter == adapter_inst:
|
|
index = i
|
|
break
|
|
|
|
if index == -2:
|
|
raise Exception('平台适配器未找到')
|
|
|
|
# 只修改启用的适配器
|
|
real_index = -1
|
|
|
|
for i, adapter in enumerate(self.ap.platform_cfg.data['platform-adapters']):
|
|
if adapter['enable']:
|
|
index -= 1
|
|
if index == -1:
|
|
real_index = i
|
|
break
|
|
|
|
new_cfg = {
|
|
'adapter': adapter_name,
|
|
'enable': True,
|
|
**config
|
|
}
|
|
self.ap.platform_cfg.data['platform-adapters'][real_index] = new_cfg
|
|
await self.ap.platform_cfg.dump_config()
|
|
|
|
async def send(self, event: platform_events.MessageEvent, msg: platform_message.MessageChain, adapter: msadapter.MessagePlatformAdapter):
|
|
|
|
if self.ap.platform_cfg.data['at-sender'] and isinstance(event, platform_events.GroupMessage):
|
|
|
|
msg.insert(
|
|
0,
|
|
platform_message.At(
|
|
event.sender.id
|
|
)
|
|
)
|
|
|
|
await adapter.reply_message(
|
|
event,
|
|
msg,
|
|
quote_origin=True if self.ap.platform_cfg.data['quote-origin'] else False
|
|
)
|
|
|
|
async def run(self):
|
|
# This method will only be called when the application launching
|
|
for bot in self.bots:
|
|
if bot.enable:
|
|
await bot.run()
|
|
|
|
async def shutdown(self):
|
|
for bot in self.bots:
|
|
if bot.enable:
|
|
await bot.shutdown()
|
|
self.ap.task_mgr.cancel_by_scope(core_entities.LifecycleControlScope.PLATFORM) |