重大重构:引擎模块拆分 + P0插件实现 + 55个Bug修复
核心变更: - engine.py(1781行)拆分为8个独立模块: lifecycle/security/deps/ datastore/pl_injector/watcher/signature/manager - 新增plugin-bridge: 事件总线 + 服务注册 + RPC通信 - 新增i18n: 国际化/多语言翻译支持 - 新增plugin-storage: 插件键值/文件存储 - 新增ws-api: WebSocket实时通信(pub/sub + 自定义处理器) - nodejs-adapter统一为Plugin ABC模式 Bug修复: - 修复load_all()中store_dir未定义崩溃 - 修复DependencyResolver入度计算(拓扑排序) - 修复PermissionError隐藏内置异常 - 修复CORS中间件头部未附加到响应 - 修复IntegrityChecker跳过__pycache__目录 - 修复版本号不一致(v2.0.0→v1.2.0) - 修复测试文件的Logger导入/路径/私有方法调用 - 修复context.py缺少typing导入 - 修复config.py STORE_DIR默认路径(./mods→./store) 测试覆盖: 14→91个测试, 全部通过
This commit is contained in:
65
oss/core/watcher.py
Normal file
65
oss/core/watcher.py
Normal file
@@ -0,0 +1,65 @@
|
||||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Callable
|
||||
|
||||
from oss.logger.logger import Log
|
||||
|
||||
|
||||
class HotReloadError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class FileWatcher:
|
||||
def __init__(self, watch_dirs, extensions, callback):
|
||||
self.watch_dirs = watch_dirs
|
||||
self.extensions = extensions
|
||||
self.callback = callback
|
||||
self._running = False
|
||||
self._thread = None
|
||||
self._file_times = {}
|
||||
self._init_file_times()
|
||||
|
||||
def _init_file_times(self):
|
||||
for watch_dir in self.watch_dirs:
|
||||
p = Path(watch_dir)
|
||||
if p.exists():
|
||||
for f in p.rglob("*"):
|
||||
if f.is_file() and f.suffix in self.extensions:
|
||||
self._file_times[str(f)] = f.stat().st_mtime
|
||||
|
||||
def start(self):
|
||||
self._running = True
|
||||
self._thread = threading.Thread(target=self._watch_loop, daemon=True)
|
||||
self._thread.start()
|
||||
Log.info("Core", "文件监控已启动")
|
||||
|
||||
def stop(self):
|
||||
self._running = False
|
||||
if self._thread:
|
||||
self._thread.join(timeout=5)
|
||||
|
||||
def _watch_loop(self):
|
||||
"""监控文件变化,触发热重载回调"""
|
||||
while self._running:
|
||||
try:
|
||||
for watch_dir in self.watch_dirs:
|
||||
p = Path(watch_dir)
|
||||
if not p.exists():
|
||||
continue
|
||||
for f in p.rglob("*"):
|
||||
if not f.is_file() or f.suffix not in self.extensions:
|
||||
continue
|
||||
current_mtime = f.stat().st_mtime
|
||||
last_mtime = self._file_times.get(str(f))
|
||||
if last_mtime is not None and current_mtime > last_mtime:
|
||||
self._file_times[str(f)] = current_mtime
|
||||
try:
|
||||
self.callback(str(f))
|
||||
except Exception as e:
|
||||
Log.error("Core", f"热重载回调执行失败: {e}")
|
||||
elif last_mtime is None:
|
||||
self._file_times[str(f)] = current_mtime
|
||||
except Exception as e:
|
||||
Log.error("Core", f"文件监控异常: {e}")
|
||||
time.sleep(2)
|
||||
Reference in New Issue
Block a user