Merge pull request #2047 from InfinityPacer/main

fix 热加载不同平台路径及插件实例化
This commit is contained in:
jxxghp 2024-05-10 19:57:48 +08:00 committed by GitHub
commit 3d5761157a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 47 additions and 7 deletions

View File

@ -1,7 +1,9 @@
import concurrent import concurrent
import concurrent.futures import concurrent.futures
import os
import time import time
import traceback import traceback
from pathlib import Path
from typing import List, Any, Dict, Tuple, Optional from typing import List, Any, Dict, Tuple, Optional
from watchdog.events import FileSystemEventHandler from watchdog.events import FileSystemEventHandler
@ -39,8 +41,9 @@ class PluginMonitorHandler(FileSystemEventHandler):
self.__last_modified = current_time self.__last_modified = current_time
# 读取插件根目录下的__init__.py文件读取class XXXX(_PluginBase)的类名 # 读取插件根目录下的__init__.py文件读取class XXXX(_PluginBase)的类名
try: try:
plugin_dir = event.src_path.split("plugins/")[1].split("/")[0] # 使用os.path和pathlib处理跨平台的路径问题
init_file = settings.ROOT_PATH / "app" / "plugins" / plugin_dir / "__init__.py" plugin_dir = event.src_path.split("plugins" + os.sep)[1].split(os.sep)[0]
init_file = Path(settings.ROOT_PATH) / "app" / "plugins" / plugin_dir / "__init__.py"
with open(init_file, "r", encoding="utf-8") as f: with open(init_file, "r", encoding="utf-8") as f:
lines = f.readlines() lines = f.readlines()
pid = None pid = None
@ -91,11 +94,16 @@ class PluginManager(metaclass=Singleton):
# 扫描插件目录 # 扫描插件目录
plugin_package = "app.plugins" plugin_package = "app.plugins"
if pid: if pid:
plugin_package = f"{plugin_package}.{pid.lower()}" plugins = ModuleHelper.load_with_pre_filter(
plugins = ModuleHelper.load( "app.plugins",
plugin_package, filter_func=lambda name, obj:
filter_func=lambda _, obj: hasattr(obj, 'init_plugin') and hasattr(obj, "plugin_name") hasattr(obj, 'init_plugin') and hasattr(obj, "plugin_name") and name == pid
) )
else:
plugins = ModuleHelper.load(
"app.plugins",
filter_func=lambda _, obj: hasattr(obj, 'init_plugin') and hasattr(obj, "plugin_name")
)
# 已安装插件 # 已安装插件
installed_plugins = self.systemconfig.get(SystemConfigKey.UserInstalledPlugins) or [] installed_plugins = self.systemconfig.get(SystemConfigKey.UserInstalledPlugins) or []
# 排序 # 排序

View File

@ -40,6 +40,38 @@ class ModuleHelper:
return submodules return submodules
@classmethod
def load_with_pre_filter(cls, package_path, filter_func=lambda name, obj: True):
"""
导入子模块
:param package_path: 父包名
:param filter_func: 子模块过滤函数入参为模块名和模块对象返回True则导入否则不导入
:return:
"""
submodules: list = []
packages = importlib.import_module(package_path)
for importer, package_name, _ in pkgutil.iter_modules(packages.__path__):
try:
if package_name.startswith('_'):
continue
full_package_name = f'{package_path}.{package_name}'
module = importlib.import_module(full_package_name)
# 预检查模块中的对象
candidates = [(name, obj) for name, obj in module.__dict__.items() if
not name.startswith('_') and isinstance(obj, type)]
# 确定是否需要重新加载
if any(filter_func(name, obj) for name, obj in candidates):
importlib.reload(module)
# reload后对象已经发生变更重新过滤已经重新加载后的模块中的对象
for name, obj in module.__dict__.items():
if not name.startswith('_') and isinstance(obj, type) and filter_func(name, obj):
submodules.append(obj)
except Exception as err:
logger.debug(f'加载模块 {package_name} 失败:{str(err)} - {traceback.format_exc()}')
return submodules
@staticmethod @staticmethod
def dynamic_import_all_modules(base_path: Path, package_name: str): def dynamic_import_all_modules(base_path: Path, package_name: str):
""" """