mirror of
https://github.com/langbot-app/LangBot.git
synced 2025-11-25 19:37:36 +08:00
feat: 基本插件加载功能
This commit is contained in:
10
main.py
10
main.py
@@ -117,9 +117,16 @@ def main(first_time_init=False):
|
|||||||
timeout=config.process_message_timeout, retry=config.retry_times,
|
timeout=config.process_message_timeout, retry=config.retry_times,
|
||||||
first_time_init=first_time_init)
|
first_time_init=first_time_init)
|
||||||
|
|
||||||
|
# 加载插件
|
||||||
|
import pkg.plugin.host
|
||||||
|
pkg.plugin.host.load_plugins()
|
||||||
|
|
||||||
|
pkg.plugin.host.initialize_plugins()
|
||||||
|
|
||||||
if first_time_init: # 不是热重载之后的启动,则不启动新的bot线程
|
if first_time_init: # 不是热重载之后的启动,则不启动新的bot线程
|
||||||
|
|
||||||
import mirai.exceptions
|
import mirai.exceptions
|
||||||
|
|
||||||
def run_bot_wrapper():
|
def run_bot_wrapper():
|
||||||
global known_exception_caught
|
global known_exception_caught
|
||||||
try:
|
try:
|
||||||
@@ -201,6 +208,9 @@ def stop():
|
|||||||
import pkg.qqbot.manager
|
import pkg.qqbot.manager
|
||||||
import pkg.openai.session
|
import pkg.openai.session
|
||||||
try:
|
try:
|
||||||
|
import pkg.plugin.host
|
||||||
|
pkg.plugin.host.unload_plugins()
|
||||||
|
|
||||||
qqbot_inst = pkg.utils.context.get_qqbot_manager()
|
qqbot_inst = pkg.utils.context.get_qqbot_manager()
|
||||||
assert isinstance(qqbot_inst, pkg.qqbot.manager.QQBotManager)
|
assert isinstance(qqbot_inst, pkg.qqbot.manager.QQBotManager)
|
||||||
|
|
||||||
|
|||||||
0
pkg/plugin/__init__.py
Normal file
0
pkg/plugin/__init__.py
Normal file
93
pkg/plugin/host.py
Normal file
93
pkg/plugin/host.py
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# 插件管理模块
|
||||||
|
import logging
|
||||||
|
import importlib
|
||||||
|
import pkgutil
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import pkg.utils.context as context
|
||||||
|
|
||||||
|
__plugins__ = {}
|
||||||
|
"""{
|
||||||
|
"example": {
|
||||||
|
"name": "example",
|
||||||
|
"description": "example",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"author": "RockChinQ",
|
||||||
|
"class": <class 'plugins.example.ExamplePlugin'>,
|
||||||
|
"hooks": {
|
||||||
|
"person_message": [
|
||||||
|
<function ExamplePlugin.person_message at 0x0000020E1D1B8D38>
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"instance": None
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
|
||||||
|
|
||||||
|
def walk_plugin_path(module, prefix=''):
|
||||||
|
"""遍历插件路径"""
|
||||||
|
for item in pkgutil.iter_modules(module.__path__):
|
||||||
|
if item.ispkg:
|
||||||
|
walk_plugin_path(__import__(module.__name__ + '.' + item.name, fromlist=['']), prefix + item.name + '.')
|
||||||
|
else:
|
||||||
|
logging.info('加载模块: {}'.format(prefix + item.name))
|
||||||
|
|
||||||
|
importlib.import_module(module.__name__ + '.' + item.name)
|
||||||
|
|
||||||
|
|
||||||
|
def load_plugins():
|
||||||
|
""" 加载插件 """
|
||||||
|
logging.info("加载插件")
|
||||||
|
PluginHost()
|
||||||
|
walk_plugin_path(__import__('plugins'))
|
||||||
|
|
||||||
|
logging.debug(__plugins__)
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_plugins():
|
||||||
|
""" 初始化插件 """
|
||||||
|
logging.info("初始化插件")
|
||||||
|
for plugin in __plugins__.values():
|
||||||
|
try:
|
||||||
|
plugin['instance'] = plugin["class"]()
|
||||||
|
except:
|
||||||
|
logging.error("插件{}初始化时发生错误: {}".format(plugin['name'], sys.exc_info()))
|
||||||
|
|
||||||
|
|
||||||
|
def unload_plugins():
|
||||||
|
""" 卸载插件 """
|
||||||
|
for plugin in __plugins__.values():
|
||||||
|
if plugin['instance'] is not None:
|
||||||
|
if not hasattr(plugin['instance'], '__del__'):
|
||||||
|
logging.warning("插件{}没有定义析构函数".format(plugin['name']))
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
plugin['instance'].__del__()
|
||||||
|
logging.info("卸载插件: {}".format(plugin['name']))
|
||||||
|
except:
|
||||||
|
logging.error("插件{}卸载时发生错误: {}".format(plugin['name'], sys.exc_info()))
|
||||||
|
|
||||||
|
|
||||||
|
def emit(event: str, **kwargs):
|
||||||
|
""" 触发事件 """
|
||||||
|
for plugin in __plugins__.values():
|
||||||
|
for hook in plugin['hooks'].get(event, []):
|
||||||
|
try:
|
||||||
|
kwargs['plugin_host'] = context.get_plugin_host()
|
||||||
|
hook(plugin['instance'], **kwargs)
|
||||||
|
except:
|
||||||
|
logging.error("插件{}触发事件{}时发生错误: {}".format(plugin['name'], event, sys.exc_info()))
|
||||||
|
|
||||||
|
|
||||||
|
class PluginHost:
|
||||||
|
"""插件宿主"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
context.set_plugin_host(self)
|
||||||
|
|
||||||
|
def prevent_default(self):
|
||||||
|
"""阻止默认行为"""
|
||||||
|
|
||||||
|
def get_runtime_context(self) -> context:
|
||||||
|
"""获取运行时上下文"""
|
||||||
|
return context
|
||||||
89
pkg/plugin/models.py
Normal file
89
pkg/plugin/models.py
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
import pkg.plugin.host as host
|
||||||
|
|
||||||
|
__current_registering_plugin__ = ""
|
||||||
|
|
||||||
|
import pkg.utils.context
|
||||||
|
|
||||||
|
PersonMessage = "person_message"
|
||||||
|
GroupMessage = "group_message"
|
||||||
|
PersonNormalMessage = "person_normal_message"
|
||||||
|
PersonCommand = "person_command"
|
||||||
|
GroupNormalMessage = "group_normal_message"
|
||||||
|
GroupCommand = "group_command"
|
||||||
|
SessionFirstMessage = "session_first_message"
|
||||||
|
SessionReset = "session_reset"
|
||||||
|
SessionExpired = "session_expired"
|
||||||
|
KeyExceeded = "key_exceeded"
|
||||||
|
KeySwitched = "key_switched"
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin:
|
||||||
|
|
||||||
|
host: host.PluginHost
|
||||||
|
"""插件宿主,提供插件的一些基础功能"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def on(cls, event):
|
||||||
|
"""事件处理器装饰器
|
||||||
|
|
||||||
|
:param
|
||||||
|
event: 事件类型
|
||||||
|
:return:
|
||||||
|
None
|
||||||
|
"""
|
||||||
|
|
||||||
|
def wrapper(func):
|
||||||
|
plugin_hooks = host.__plugins__[__current_registering_plugin__]["hooks"]
|
||||||
|
|
||||||
|
if event not in plugin_hooks:
|
||||||
|
plugin_hooks[event] = []
|
||||||
|
plugin_hooks[event].append(func)
|
||||||
|
|
||||||
|
host.__plugins__[__current_registering_plugin__]["hooks"] = plugin_hooks
|
||||||
|
|
||||||
|
return func
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def register(name: str, description: str, version: str, author: str):
|
||||||
|
"""注册插件, 此函数作为装饰器使用
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): 插件名称
|
||||||
|
description (str): 插件描述
|
||||||
|
version (str): 插件版本
|
||||||
|
author (str): 插件作者
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
None
|
||||||
|
"""
|
||||||
|
global __current_registering_plugin__
|
||||||
|
|
||||||
|
__current_registering_plugin__ = name
|
||||||
|
|
||||||
|
host.__plugins__[name] = {
|
||||||
|
"name": name,
|
||||||
|
"description": description,
|
||||||
|
"version": version,
|
||||||
|
"author": author,
|
||||||
|
"hooks": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
def wrapper(cls: Plugin):
|
||||||
|
cls.name = name
|
||||||
|
cls.description = description
|
||||||
|
cls.version = version
|
||||||
|
cls.author = author
|
||||||
|
cls.host = pkg.utils.context.get_plugin_host()
|
||||||
|
|
||||||
|
# 存到插件列表
|
||||||
|
host.__plugins__[name]["class"] = cls
|
||||||
|
|
||||||
|
logging.info("插件注册完成: n='{}', d='{}', v={}, a='{}' ({})".format(name, description, version, author, cls))
|
||||||
|
|
||||||
|
return cls
|
||||||
|
|
||||||
|
return wrapper
|
||||||
@@ -16,6 +16,9 @@ import pkg.qqbot.filter
|
|||||||
import pkg.qqbot.process as processor
|
import pkg.qqbot.process as processor
|
||||||
import pkg.utils.context
|
import pkg.utils.context
|
||||||
|
|
||||||
|
import pkg.plugin.host as plugin_host
|
||||||
|
import pkg.plugin.models as plugin_models
|
||||||
|
|
||||||
|
|
||||||
# 并行运行
|
# 并行运行
|
||||||
def go(func, args=()):
|
def go(func, args=()):
|
||||||
@@ -155,6 +158,8 @@ class QQBotManager:
|
|||||||
|
|
||||||
# 私聊消息处理
|
# 私聊消息处理
|
||||||
def on_person_message(self, event: MessageEvent):
|
def on_person_message(self, event: MessageEvent):
|
||||||
|
plugin_host.emit(plugin_models.PersonMessage)
|
||||||
|
|
||||||
reply = ''
|
reply = ''
|
||||||
|
|
||||||
if event.sender.id == self.bot.qq:
|
if event.sender.id == self.bot.qq:
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ context = {
|
|||||||
},
|
},
|
||||||
'logger_handler': None,
|
'logger_handler': None,
|
||||||
'config': None,
|
'config': None,
|
||||||
|
'plugin_host': None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -39,3 +40,11 @@ def set_qqbot_manager(inst):
|
|||||||
|
|
||||||
def get_qqbot_manager():
|
def get_qqbot_manager():
|
||||||
return context['inst']['qqbot.manager.QQBotManager']
|
return context['inst']['qqbot.manager.QQBotManager']
|
||||||
|
|
||||||
|
|
||||||
|
def set_plugin_host(inst):
|
||||||
|
context['plugin_host'] = inst
|
||||||
|
|
||||||
|
|
||||||
|
def get_plugin_host():
|
||||||
|
return context['plugin_host']
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ def reload_all(notify=True):
|
|||||||
importlib.reload(__import__('config'))
|
importlib.reload(__import__('config'))
|
||||||
importlib.reload(__import__('main'))
|
importlib.reload(__import__('main'))
|
||||||
importlib.reload(__import__('banlist'))
|
importlib.reload(__import__('banlist'))
|
||||||
|
importlib.reload(__import__('plugins'))
|
||||||
pkg.utils.context.context = context
|
pkg.utils.context.context = context
|
||||||
|
|
||||||
# 执行启动流程
|
# 执行启动流程
|
||||||
|
|||||||
Reference in New Issue
Block a user