添加插件管理后端

This commit is contained in:
John Smith
2024-03-03 11:18:14 +08:00
parent 58afbbf888
commit e1d0473627
6 changed files with 88 additions and 5 deletions

View File

@@ -46,7 +46,8 @@ class ServerInfoHandler(api.base.ApiHandler):
'config': { 'config': {
'enableTranslate': cfg.enable_translate, 'enableTranslate': cfg.enable_translate,
'enableUploadFile': cfg.enable_upload_file, 'enableUploadFile': cfg.enable_upload_file,
'loaderUrl': cfg.loader_url 'loaderUrl': cfg.loader_url,
'enableAdminPlugins': cfg.enable_admin_plugins,
} }
}) })

View File

@@ -10,6 +10,7 @@ import tornado.websocket
import api.base import api.base
import api.chat import api.chat
import blcsdk.models as models import blcsdk.models as models
import config
import services.avatar import services.avatar
import services.chat import services.chat
import services.plugin import services.plugin
@@ -17,7 +18,71 @@ import services.plugin
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class _PluginHandlerBase(api.base.ApiHandler): class _AdminHandlerBase(api.base.ApiHandler):
def prepare(self):
cfg = config.get_config()
if not cfg.enable_admin_plugins:
raise tornado.web.HTTPError(403)
super().prepare()
def _get_plugin(self):
plugin_id = self.json_args.get('pluginId', None)
if not isinstance(plugin_id, str) or plugin_id == '':
raise tornado.web.MissingArgumentError('pluginId')
plugin = services.plugin.get_plugin(plugin_id)
if plugin is None:
raise tornado.web.HTTPError(404, 'no plugin, plugin_id=%s', plugin_id)
return plugin
# 不继承_AdminHandlerBase为了忽略enable_admin_plugins
class PluginsHandler(api.base.ApiHandler):
async def get(self):
plugin_dicts = []
for plugin in services.plugin.iter_plugins():
plugin_cfg = plugin.config
plugin_dicts.append({
'id': plugin.id,
'name': plugin_cfg.name,
'version': plugin_cfg.version,
'author': plugin_cfg.author,
'description': plugin_cfg.description,
'enabled': plugin.enabled,
'isStarted': plugin.is_started,
'isConnected': plugin.is_connected,
})
self.write({'plugins': plugin_dicts})
class EnableHandler(_AdminHandlerBase):
async def post(self):
enabled = bool(self.json_args.get('enabled', False))
plugin = self._get_plugin()
msg = ''
try:
plugin.enabled = enabled
except services.plugin.StartTooFrequently as e:
msg = str(e)
plugin.enabled = False
except services.plugin.StartPluginError as e:
msg = str(e)
self.write({
'enabled': plugin.enabled,
'msg': msg
})
class OpenAdminUiHandler(_AdminHandlerBase):
async def post(self):
plugin = self._get_plugin()
plugin.send_cmd_data(models.Command.OPEN_PLUGIN_ADMIN_UI, {})
self.write({})
class _PluginApiHandlerBase(api.base.ApiHandler):
"""给插件用的接口"""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.plugin: Optional[services.plugin.Plugin] = None self.plugin: Optional[services.plugin.Plugin] = None
@@ -46,7 +111,7 @@ def make_message_body(cmd, data, extra: Optional[dict] = None):
return json.dumps(body).encode('utf-8') return json.dumps(body).encode('utf-8')
class PluginWsHandler(_PluginHandlerBase, tornado.websocket.WebSocketHandler): class PluginWsHandler(_PluginApiHandlerBase, tornado.websocket.WebSocketHandler):
HEARTBEAT_INTERVAL = 10 HEARTBEAT_INTERVAL = 10
RECEIVE_TIMEOUT = HEARTBEAT_INTERVAL + 5 RECEIVE_TIMEOUT = HEARTBEAT_INTERVAL + 5
@@ -161,7 +226,7 @@ class PluginWsHandler(_PluginHandlerBase, tornado.websocket.WebSocketHandler):
self.close() self.close()
class RoomsHandler(api.base.ApiHandler): class RoomsHandler(_PluginApiHandlerBase):
async def get(self): async def get(self):
rooms = [ rooms = [
{ {
@@ -174,6 +239,9 @@ class RoomsHandler(api.base.ApiHandler):
ROUTES = [ ROUTES = [
(r'/api/plugin/plugins', PluginsHandler),
(r'/api/plugin/enable_plugin', EnableHandler),
(r'/api/plugin/open_admin_ui', OpenAdminUiHandler),
(r'/api/plugin/websocket', PluginWsHandler), (r'/api/plugin/websocket', PluginWsHandler),
(r'/api/plugin/rooms', RoomsHandler), (r'/api/plugin/rooms', RoomsHandler),
] ]

View File

@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
__version__ = '0.0.1' __version__ = '0.0.1' # TODO UID改成open ID后再改成正式版
from .handlers import * from .handlers import *
from .client import * from .client import *

View File

@@ -63,6 +63,7 @@ class AppConfig:
self.loader_url = '' self.loader_url = ''
self.open_browser_at_startup = True self.open_browser_at_startup = True
self.enable_upload_file = True self.enable_upload_file = True
self.enable_admin_plugins = True
self.fetch_avatar_max_queue_size = 4 self.fetch_avatar_max_queue_size = 4
self.avatar_cache_size = 10000 self.avatar_cache_size = 10000
@@ -114,6 +115,7 @@ class AppConfig:
self.loader_url = app_section.get('loader_url', self.loader_url) self.loader_url = app_section.get('loader_url', self.loader_url)
self.open_browser_at_startup = app_section.getboolean('open_browser_at_startup', self.open_browser_at_startup) self.open_browser_at_startup = app_section.getboolean('open_browser_at_startup', self.open_browser_at_startup)
self.enable_upload_file = app_section.getboolean('enable_upload_file', self.enable_upload_file) self.enable_upload_file = app_section.getboolean('enable_upload_file', self.enable_upload_file)
self.enable_admin_plugins = app_section.getboolean('enable_admin_plugins', self.enable_admin_plugins)
self.fetch_avatar_max_queue_size = app_section.getint( self.fetch_avatar_max_queue_size = app_section.getint(
'fetch_avatar_max_queue_size', self.fetch_avatar_max_queue_size 'fetch_avatar_max_queue_size', self.fetch_avatar_max_queue_size

View File

@@ -28,6 +28,10 @@ open_browser_at_startup = true
# Enable uploading custom emote file # Enable uploading custom emote file
enable_upload_file = true enable_upload_file = true
# 允许管理插件
# Enable administration for plugins
enable_admin_plugins = true
# 获取头像最大队列长度 # 获取头像最大队列长度
# Maximum queue length for fetching avatar # Maximum queue length for fetching avatar

View File

@@ -72,6 +72,10 @@ def iter_plugins() -> Iterable['Plugin']:
return _plugins.values() return _plugins.values()
def get_plugin(plugin_id):
return _plugins.get(plugin_id, None)
def get_plugin_by_token(token): def get_plugin_by_token(token):
if token == '': if token == '':
return None return None
@@ -156,6 +160,10 @@ class Plugin:
def id(self): def id(self):
return self._id return self._id
@property
def config(self):
return self._config
@property @property
def enabled(self): def enabled(self):
return self._config.enabled return self._config.enabled