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)