|
@@ -1,8 +1,10 @@ |
|
|
# encoding:utf-8 |
|
|
# encoding:utf-8 |
|
|
|
|
|
|
|
|
import importlib |
|
|
import importlib |
|
|
|
|
|
import importlib.util |
|
|
import json |
|
|
import json |
|
|
import os |
|
|
import os |
|
|
|
|
|
import sys |
|
|
from common.singleton import singleton |
|
|
from common.singleton import singleton |
|
|
from common.sorted_dict import SortedDict |
|
|
from common.sorted_dict import SortedDict |
|
|
from .event import * |
|
|
from .event import * |
|
@@ -18,6 +20,7 @@ class PluginManager: |
|
|
self.instances = {} |
|
|
self.instances = {} |
|
|
self.pconf = {} |
|
|
self.pconf = {} |
|
|
self.current_plugin_path = None |
|
|
self.current_plugin_path = None |
|
|
|
|
|
self.loaded = {} |
|
|
|
|
|
|
|
|
def register(self, name: str, desire_priority: int = 0, **kwargs): |
|
|
def register(self, name: str, desire_priority: int = 0, **kwargs): |
|
|
def wrapper(plugincls): |
|
|
def wrapper(plugincls): |
|
@@ -30,9 +33,10 @@ class PluginManager: |
|
|
plugincls.namecn = kwargs.get('namecn') if kwargs.get('namecn') != None else name |
|
|
plugincls.namecn = kwargs.get('namecn') if kwargs.get('namecn') != None else name |
|
|
plugincls.hidden = kwargs.get('hidden') if kwargs.get('hidden') != None else False |
|
|
plugincls.hidden = kwargs.get('hidden') if kwargs.get('hidden') != None else False |
|
|
plugincls.enabled = True |
|
|
plugincls.enabled = True |
|
|
|
|
|
if self.current_plugin_path == None: |
|
|
|
|
|
raise Exception("Plugin path not set") |
|
|
self.plugins[name.upper()] = plugincls |
|
|
self.plugins[name.upper()] = plugincls |
|
|
logger.info("Plugin %s_v%s registered, path=%s" % (name, plugincls.version, plugincls.path)) |
|
|
logger.info("Plugin %s_v%s registered, path=%s" % (name, plugincls.version, plugincls.path)) |
|
|
return plugincls |
|
|
|
|
|
return wrapper |
|
|
return wrapper |
|
|
|
|
|
|
|
|
def save_config(self): |
|
|
def save_config(self): |
|
@@ -58,6 +62,7 @@ class PluginManager: |
|
|
def scan_plugins(self): |
|
|
def scan_plugins(self): |
|
|
logger.info("Scaning plugins ...") |
|
|
logger.info("Scaning plugins ...") |
|
|
plugins_dir = "./plugins" |
|
|
plugins_dir = "./plugins" |
|
|
|
|
|
raws = [self.plugins[name] for name in self.plugins] |
|
|
for plugin_name in os.listdir(plugins_dir): |
|
|
for plugin_name in os.listdir(plugins_dir): |
|
|
plugin_path = os.path.join(plugins_dir, plugin_name) |
|
|
plugin_path = os.path.join(plugins_dir, plugin_name) |
|
|
if os.path.isdir(plugin_path): |
|
|
if os.path.isdir(plugin_path): |
|
@@ -68,17 +73,27 @@ class PluginManager: |
|
|
import_path = "plugins.{}".format(plugin_name) |
|
|
import_path = "plugins.{}".format(plugin_name) |
|
|
try: |
|
|
try: |
|
|
self.current_plugin_path = plugin_path |
|
|
self.current_plugin_path = plugin_path |
|
|
main_module = importlib.import_module(import_path) |
|
|
|
|
|
|
|
|
if plugin_path in self.loaded: |
|
|
|
|
|
if self.loaded[plugin_path] == None: |
|
|
|
|
|
logger.info("reload module %s" % plugin_name) |
|
|
|
|
|
self.loaded[plugin_path] = importlib.reload(sys.modules[import_path]) |
|
|
|
|
|
dependent_module_names = [name for name in sys.modules.keys() if name.startswith( import_path+ '.')] |
|
|
|
|
|
for name in dependent_module_names: |
|
|
|
|
|
logger.info("reload module %s" % name) |
|
|
|
|
|
importlib.reload(sys.modules[name]) |
|
|
|
|
|
else: |
|
|
|
|
|
self.loaded[plugin_path] = importlib.import_module(import_path) |
|
|
|
|
|
self.current_plugin_path = None |
|
|
except Exception as e: |
|
|
except Exception as e: |
|
|
logger.warn("Failed to import plugin %s: %s" % (plugin_name, e)) |
|
|
|
|
|
|
|
|
logger.exception("Failed to import plugin %s: %s" % (plugin_name, e)) |
|
|
continue |
|
|
continue |
|
|
pconf = self.pconf |
|
|
pconf = self.pconf |
|
|
new_plugins = [] |
|
|
|
|
|
|
|
|
news = [self.plugins[name] for name in self.plugins] |
|
|
|
|
|
new_plugins = list(set(news) - set(raws)) |
|
|
modified = False |
|
|
modified = False |
|
|
for name, plugincls in self.plugins.items(): |
|
|
for name, plugincls in self.plugins.items(): |
|
|
rawname = plugincls.name |
|
|
rawname = plugincls.name |
|
|
if rawname not in pconf["plugins"]: |
|
|
if rawname not in pconf["plugins"]: |
|
|
new_plugins.append(plugincls) |
|
|
|
|
|
modified = True |
|
|
modified = True |
|
|
logger.info("Plugin %s not found in pconfig, adding to pconfig..." % name) |
|
|
logger.info("Plugin %s not found in pconfig, adding to pconfig..." % name) |
|
|
pconf["plugins"][rawname] = {"enabled": plugincls.enabled, "priority": plugincls.priority} |
|
|
pconf["plugins"][rawname] = {"enabled": plugincls.enabled, "priority": plugincls.priority} |
|
@@ -95,14 +110,16 @@ class PluginManager: |
|
|
self.listening_plugins[event].sort(key=lambda name: self.plugins[name].priority, reverse=True) |
|
|
self.listening_plugins[event].sort(key=lambda name: self.plugins[name].priority, reverse=True) |
|
|
|
|
|
|
|
|
def activate_plugins(self): # 生成新开启的插件实例 |
|
|
def activate_plugins(self): # 生成新开启的插件实例 |
|
|
|
|
|
failed_plugins = [] |
|
|
for name, plugincls in self.plugins.items(): |
|
|
for name, plugincls in self.plugins.items(): |
|
|
if plugincls.enabled: |
|
|
if plugincls.enabled: |
|
|
if name not in self.instances: |
|
|
if name not in self.instances: |
|
|
try: |
|
|
try: |
|
|
instance = plugincls() |
|
|
instance = plugincls() |
|
|
except Exception as e: |
|
|
except Exception as e: |
|
|
logger.warn("Failed to create init %s, diabled. %s" % (name, e)) |
|
|
|
|
|
|
|
|
logger.warn("Failed to init %s, diabled. %s" % (name, e)) |
|
|
self.disable_plugin(name) |
|
|
self.disable_plugin(name) |
|
|
|
|
|
failed_plugins.append(name) |
|
|
continue |
|
|
continue |
|
|
self.instances[name] = instance |
|
|
self.instances[name] = instance |
|
|
for event in instance.handlers: |
|
|
for event in instance.handlers: |
|
@@ -110,6 +127,7 @@ class PluginManager: |
|
|
self.listening_plugins[event] = [] |
|
|
self.listening_plugins[event] = [] |
|
|
self.listening_plugins[event].append(name) |
|
|
self.listening_plugins[event].append(name) |
|
|
self.refresh_order() |
|
|
self.refresh_order() |
|
|
|
|
|
return failed_plugins |
|
|
|
|
|
|
|
|
def reload_plugin(self, name:str): |
|
|
def reload_plugin(self, name:str): |
|
|
name = name.upper() |
|
|
name = name.upper() |
|
@@ -159,15 +177,17 @@ class PluginManager: |
|
|
def enable_plugin(self, name:str): |
|
|
def enable_plugin(self, name:str): |
|
|
name = name.upper() |
|
|
name = name.upper() |
|
|
if name not in self.plugins: |
|
|
if name not in self.plugins: |
|
|
return False |
|
|
|
|
|
|
|
|
return False, "插件不存在" |
|
|
if not self.plugins[name].enabled : |
|
|
if not self.plugins[name].enabled : |
|
|
self.plugins[name].enabled = True |
|
|
self.plugins[name].enabled = True |
|
|
rawname = self.plugins[name].name |
|
|
rawname = self.plugins[name].name |
|
|
self.pconf["plugins"][rawname]["enabled"] = True |
|
|
self.pconf["plugins"][rawname]["enabled"] = True |
|
|
self.save_config() |
|
|
self.save_config() |
|
|
self.activate_plugins() |
|
|
|
|
|
return True |
|
|
|
|
|
return True |
|
|
|
|
|
|
|
|
failed_plugins = self.activate_plugins() |
|
|
|
|
|
if name in failed_plugins: |
|
|
|
|
|
return False, "插件开启失败" |
|
|
|
|
|
return True, "插件已开启" |
|
|
|
|
|
return True, "插件已开启" |
|
|
|
|
|
|
|
|
def disable_plugin(self, name:str): |
|
|
def disable_plugin(self, name:str): |
|
|
name = name.upper() |
|
|
name = name.upper() |
|
@@ -206,12 +226,12 @@ class PluginManager: |
|
|
repo = source["repo"][repo]["url"] |
|
|
repo = source["repo"][repo]["url"] |
|
|
match = re.match(r"^(https?:\/\/|git@)([^\/:]+)[\/:]([^\/:]+)\/(.+).git$", repo) |
|
|
match = re.match(r"^(https?:\/\/|git@)([^\/:]+)[\/:]([^\/:]+)\/(.+).git$", repo) |
|
|
if not match: |
|
|
if not match: |
|
|
return False, "source中的仓库地址不合法" |
|
|
|
|
|
|
|
|
return False, "安装插件失败,source中的仓库地址不合法" |
|
|
else: |
|
|
else: |
|
|
return False, "仓库地址不合法" |
|
|
|
|
|
|
|
|
return False, "安装插件失败,仓库地址不合法" |
|
|
except Exception as e: |
|
|
except Exception as e: |
|
|
logger.error("Failed to install plugin, {}".format(e)) |
|
|
logger.error("Failed to install plugin, {}".format(e)) |
|
|
return False, "安装插件失败" |
|
|
|
|
|
|
|
|
return False, "安装插件失败,请检查仓库地址是否正确" |
|
|
dirname = os.path.join("./plugins",match.group(4)) |
|
|
dirname = os.path.join("./plugins",match.group(4)) |
|
|
try: |
|
|
try: |
|
|
repo = porcelain.clone(repo, dirname, checkout=True) |
|
|
repo = porcelain.clone(repo, dirname, checkout=True) |
|
@@ -221,7 +241,7 @@ class PluginManager: |
|
|
return True, "安装插件成功,请扫描插件或重启程序" |
|
|
return True, "安装插件成功,请扫描插件或重启程序" |
|
|
except Exception as e: |
|
|
except Exception as e: |
|
|
logger.error("Failed to install plugin, {}".format(e)) |
|
|
logger.error("Failed to install plugin, {}".format(e)) |
|
|
return False, "安装插件失败" |
|
|
|
|
|
|
|
|
return False, "安装插件失败,"+str(e) |
|
|
|
|
|
|
|
|
def uninstall_plugin(self, name:str): |
|
|
def uninstall_plugin(self, name:str): |
|
|
name = name.upper() |
|
|
name = name.upper() |
|
@@ -233,8 +253,12 @@ class PluginManager: |
|
|
try: |
|
|
try: |
|
|
import shutil |
|
|
import shutil |
|
|
shutil.rmtree(dirname) |
|
|
shutil.rmtree(dirname) |
|
|
|
|
|
rawname = self.plugins[name].name |
|
|
del self.plugins[name] |
|
|
del self.plugins[name] |
|
|
|
|
|
del self.pconf["plugins"][rawname] |
|
|
|
|
|
self.loaded[dirname] = None |
|
|
|
|
|
self.save_config() |
|
|
return True, "卸载插件成功" |
|
|
return True, "卸载插件成功" |
|
|
except Exception as e: |
|
|
except Exception as e: |
|
|
logger.error("Failed to uninstall plugin, {}".format(e)) |
|
|
logger.error("Failed to uninstall plugin, {}".format(e)) |
|
|
return False, "卸载插件失败" |
|
|
|
|
|
|
|
|
return False, "卸载插件失败,请手动删除文件夹完成卸载,"+str(e) |