2024-01-29 21:22:27 +08:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
import typing
|
2024-01-30 21:45:17 +08:00
|
|
|
import traceback
|
2024-01-29 21:22:27 +08:00
|
|
|
|
|
|
|
from ..core import app
|
|
|
|
from . import context, loader, events, installer, setting, models
|
|
|
|
from .loaders import legacy
|
|
|
|
from .installers import github
|
|
|
|
|
|
|
|
|
|
|
|
class PluginManager:
|
2024-03-03 16:34:59 +08:00
|
|
|
"""插件管理器"""
|
2024-01-29 21:22:27 +08:00
|
|
|
|
|
|
|
ap: app.Application
|
|
|
|
|
|
|
|
loader: loader.PluginLoader
|
|
|
|
|
|
|
|
installer: installer.PluginInstaller
|
|
|
|
|
|
|
|
setting: setting.SettingManager
|
|
|
|
|
|
|
|
api_host: context.APIHost
|
|
|
|
|
|
|
|
plugins: list[context.RuntimeContainer]
|
|
|
|
|
|
|
|
def __init__(self, ap: app.Application):
|
|
|
|
self.ap = ap
|
|
|
|
self.loader = legacy.PluginLoader(ap)
|
|
|
|
self.installer = github.GitHubRepoInstaller(ap)
|
|
|
|
self.setting = setting.SettingManager(ap)
|
|
|
|
self.api_host = context.APIHost(ap)
|
|
|
|
self.plugins = []
|
|
|
|
|
|
|
|
async def initialize(self):
|
|
|
|
await self.loader.initialize()
|
|
|
|
await self.installer.initialize()
|
|
|
|
await self.setting.initialize()
|
|
|
|
await self.api_host.initialize()
|
|
|
|
|
|
|
|
setattr(models, 'require_ver', self.api_host.require_ver)
|
|
|
|
|
|
|
|
async def load_plugins(self):
|
|
|
|
self.plugins = await self.loader.load_plugins()
|
|
|
|
|
|
|
|
await self.setting.sync_setting(self.plugins)
|
|
|
|
|
|
|
|
# 按优先级倒序
|
|
|
|
self.plugins.sort(key=lambda x: x.priority, reverse=True)
|
|
|
|
|
|
|
|
async def initialize_plugins(self):
|
2024-01-29 21:41:20 +08:00
|
|
|
for plugin in self.plugins:
|
|
|
|
try:
|
|
|
|
plugin.plugin_inst = plugin.plugin_class(self.api_host)
|
|
|
|
except Exception as e:
|
|
|
|
self.ap.logger.error(f'插件 {plugin.plugin_name} 初始化失败: {e}')
|
|
|
|
self.ap.logger.exception(e)
|
|
|
|
continue
|
2024-01-29 21:22:27 +08:00
|
|
|
|
|
|
|
async def install_plugin(
|
|
|
|
self,
|
|
|
|
plugin_source: str,
|
|
|
|
):
|
|
|
|
"""安装插件
|
|
|
|
"""
|
|
|
|
await self.installer.install_plugin(plugin_source)
|
|
|
|
|
2024-01-31 00:02:19 +08:00
|
|
|
await self.ap.ctr_mgr.plugin.post_install_record(
|
|
|
|
{
|
|
|
|
"name": "unknown",
|
|
|
|
"remote": plugin_source,
|
|
|
|
"author": "unknown",
|
|
|
|
"version": "HEAD"
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2024-01-29 21:22:27 +08:00
|
|
|
async def uninstall_plugin(
|
|
|
|
self,
|
|
|
|
plugin_name: str,
|
|
|
|
):
|
|
|
|
"""卸载插件
|
|
|
|
"""
|
|
|
|
await self.installer.uninstall_plugin(plugin_name)
|
|
|
|
|
2024-01-31 00:02:19 +08:00
|
|
|
plugin_container = self.get_plugin_by_name(plugin_name)
|
|
|
|
|
|
|
|
await self.ap.ctr_mgr.plugin.post_remove_record(
|
|
|
|
{
|
|
|
|
"name": plugin_name,
|
|
|
|
"remote": plugin_container.plugin_source,
|
|
|
|
"author": plugin_container.plugin_author,
|
|
|
|
"version": plugin_container.plugin_version
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2024-01-29 21:22:27 +08:00
|
|
|
async def update_plugin(
|
|
|
|
self,
|
|
|
|
plugin_name: str,
|
|
|
|
plugin_source: str=None,
|
|
|
|
):
|
|
|
|
"""更新插件
|
|
|
|
"""
|
|
|
|
await self.installer.update_plugin(plugin_name, plugin_source)
|
2024-01-31 00:02:19 +08:00
|
|
|
|
|
|
|
plugin_container = self.get_plugin_by_name(plugin_name)
|
|
|
|
|
|
|
|
await self.ap.ctr_mgr.plugin.post_update_record(
|
|
|
|
plugin={
|
|
|
|
"name": plugin_name,
|
|
|
|
"remote": plugin_container.plugin_source,
|
|
|
|
"author": plugin_container.plugin_author,
|
|
|
|
"version": plugin_container.plugin_version
|
|
|
|
},
|
|
|
|
old_version=plugin_container.plugin_version,
|
|
|
|
new_version="HEAD"
|
|
|
|
)
|
2024-01-29 21:22:27 +08:00
|
|
|
|
|
|
|
def get_plugin_by_name(self, plugin_name: str) -> context.RuntimeContainer:
|
|
|
|
"""通过插件名获取插件
|
|
|
|
"""
|
|
|
|
for plugin in self.plugins:
|
|
|
|
if plugin.plugin_name == plugin_name:
|
|
|
|
return plugin
|
|
|
|
return None
|
|
|
|
|
|
|
|
async def emit_event(self, event: events.BaseEventModel) -> context.EventContext:
|
|
|
|
"""触发事件
|
|
|
|
"""
|
|
|
|
|
|
|
|
ctx = context.EventContext(
|
|
|
|
host=self.api_host,
|
|
|
|
event=event
|
|
|
|
)
|
|
|
|
|
2024-01-31 00:02:19 +08:00
|
|
|
emitted_plugins: list[context.RuntimeContainer] = []
|
|
|
|
|
2024-01-29 21:22:27 +08:00
|
|
|
for plugin in self.plugins:
|
|
|
|
if plugin.enabled:
|
|
|
|
if event.__class__ in plugin.event_handlers:
|
2024-03-08 21:10:43 +08:00
|
|
|
self.ap.logger.debug(f'插件 {plugin.plugin_name} 触发事件 {event.__class__.__name__}')
|
2024-01-30 21:45:17 +08:00
|
|
|
|
|
|
|
is_prevented_default_before_call = ctx.is_prevented_default()
|
|
|
|
|
2024-01-29 21:22:27 +08:00
|
|
|
try:
|
|
|
|
await plugin.event_handlers[event.__class__](
|
|
|
|
plugin.plugin_inst,
|
|
|
|
ctx
|
|
|
|
)
|
|
|
|
except Exception as e:
|
|
|
|
self.ap.logger.error(f'插件 {plugin.plugin_name} 触发事件 {event.__class__.__name__} 时发生错误: {e}')
|
2024-01-30 21:45:17 +08:00
|
|
|
self.ap.logger.debug(f"Traceback: {traceback.format_exc()}")
|
2024-01-29 21:22:27 +08:00
|
|
|
|
2024-03-08 21:10:43 +08:00
|
|
|
emitted_plugins.append(plugin)
|
|
|
|
|
2024-01-30 21:45:17 +08:00
|
|
|
if not is_prevented_default_before_call and ctx.is_prevented_default():
|
|
|
|
self.ap.logger.debug(f'插件 {plugin.plugin_name} 阻止了默认行为执行')
|
|
|
|
|
2024-01-29 21:22:27 +08:00
|
|
|
if ctx.is_prevented_postorder():
|
|
|
|
self.ap.logger.debug(f'插件 {plugin.plugin_name} 阻止了后序插件的执行')
|
|
|
|
break
|
2024-01-30 21:45:17 +08:00
|
|
|
|
|
|
|
for key in ctx.__return_value__.keys():
|
|
|
|
if hasattr(ctx.event, key):
|
|
|
|
setattr(ctx.event, key, ctx.__return_value__[key][0])
|
2024-01-29 21:22:27 +08:00
|
|
|
|
|
|
|
self.ap.logger.debug(f'事件 {event.__class__.__name__}({ctx.eid}) 处理完成,返回值 {ctx.__return_value__}')
|
|
|
|
|
2024-01-31 00:02:19 +08:00
|
|
|
if emitted_plugins:
|
|
|
|
plugins_info: list[dict] = [
|
|
|
|
{
|
|
|
|
'name': plugin.plugin_name,
|
|
|
|
'remote': plugin.plugin_source,
|
|
|
|
'version': plugin.plugin_version,
|
|
|
|
'author': plugin.plugin_author
|
|
|
|
} for plugin in emitted_plugins
|
|
|
|
]
|
|
|
|
|
|
|
|
await self.ap.ctr_mgr.usage.post_event_record(
|
|
|
|
plugins=plugins_info,
|
|
|
|
event_name=event.__class__.__name__
|
|
|
|
)
|
|
|
|
|
2024-01-30 21:45:17 +08:00
|
|
|
return ctx
|