2727from app .log import logger
2828from app .schemas .types import EventType , SystemConfigKey
2929from app .utils .crypto import RSAUtils
30- from app .utils .limit import rate_limit_window
30+ from app .utils .debounce import debounce
3131from app .utils .object import ObjectUtils
3232from app .utils .singleton import Singleton
3333from app .utils .string import StringUtils
@@ -47,33 +47,62 @@ def on_modified(self, event):
4747 if not event_path .name .endswith (".py" ) or "pycache" in event_path .parts :
4848 return
4949
50- # 读取插件根目录下的__init__.py文件,读取class XXXX(_PluginBase)的类名
50+ # 防抖模式下处理文件修改事件
51+ self ._handle_modification (event_path )
52+
53+ @debounce (interval = 1.0 , leading = False , source = "PluginMonitorHandler" , enable_logging = False )
54+ def _handle_modification (self , event_path : Path ):
55+ """
56+ 处理文件修改事件
57+ :param event_path:
58+ :return:
59+ """
60+ logger .debug (f"防抖计时结束,开始处理文件修改事件: { event_path } " )
61+ # 解析插件ID
62+ pid = self ._get_plugin_id_from_path (event_path )
63+ if not pid :
64+ logger .debug (f"文件不属于任何有效插件,已忽略: { event_path } " )
65+ return
66+
67+ # 触发重载
68+ self .__reload_plugin (pid )
69+
70+ @staticmethod
71+ def _get_plugin_id_from_path (event_path : Path ) -> Optional [str ]:
72+ """
73+ 根据文件路径解析出插件的ID。
74+ :param event_path: 被修改文件的 Path 对象。
75+ :return: 插件ID字符串,如果不是有效插件文件则返回 None。
76+ """
5177 try :
5278 plugins_root = settings .ROOT_PATH / "app" / "plugins"
5379 # 确保修改的文件在 plugins 目录下
5480 if plugins_root not in event_path .parents :
55- return
56- # 获取插件目录路径,没有找到__init__.py时,说明不是有效包,跳过插件重载
57- # 插件重载目前没有支持app/plugins/plugin/package/__init__.py的场景,这里也不做支持
81+ return None
82+
83+ # 找到插件的根目录
5884 plugin_dir = event_path .parent
85+ while plugin_dir .parent != plugins_root :
86+ plugin_dir = plugin_dir .parent
87+ if plugin_dir == plugins_root : # 防止无限循环
88+ break
89+
5990 init_file = plugin_dir / "__init__.py"
6091 if not init_file .exists ():
61- logger .debug (f"{ plugin_dir } 下没有找到 __init__.py,跳过插件重载" )
62- return
92+ return None
6393
94+ # 读取 __init__.py 文件,查找插件主类名
6495 with open (init_file , "r" , encoding = "utf-8" ) as f :
65- lines = f .readlines ()
66- pid = None
67- for line in lines :
68- if line .startswith ("class" ) and "(_PluginBase)" in line :
69- pid = line .split ("class " )[1 ].split ("(_PluginBase)" )[0 ].strip ()
70- if pid :
71- self .__reload_plugin (pid )
96+ for line in f :
97+ if line .startswith ("class" ) and "(_PluginBase)" in line :
98+ # 解析出类名作为插件ID
99+ return line .split ("class " )[1 ].split ("(_PluginBase)" )[0 ].strip ()
100+ return None
72101 except Exception as e :
73- logger .error (f"插件文件修改后重载出错:{ str (e )} " )
102+ logger .error (f"从路径解析插件ID时出错: { e } " )
103+ return None
74104
75105 @staticmethod
76- @rate_limit_window (max_calls = 1 , window_seconds = 2 , source = "PluginMonitor" , enable_logging = False )
77106 def __reload_plugin (pid ):
78107 """
79108 重新加载插件
@@ -265,7 +294,6 @@ def _load_selective_plugins(pid: Optional[str], installed_plugins: List[str],
265294
266295 # 导入模块
267296 module = importlib .import_module (module_name )
268- importlib .reload (module )
269297
270298 # 检查模块中的类
271299 for name , obj in module .__dict__ .items ():
@@ -411,6 +439,10 @@ def _clear_plugin_modules(plugin_id: Optional[str] = None):
411439 except KeyError :
412440 # 模块可能已经被删除
413441 pass
442+
443+ importlib .invalidate_caches ()
444+ logger .debug ("已清除查找器的缓存" )
445+
414446 if plugin_id :
415447 if modules_to_remove :
416448 logger .info (f"插件 { plugin_id } 共清除 { len (modules_to_remove )} 个模块缓存:{ modules_to_remove } " )
0 commit comments