import os import sys import time import logging import importlib import threading from pathlib import Path from enum import Enum, auto from PySide6.QtCore import QObject,Signal from dataclasses import dataclass, field, fields LOCAL_PLUGINS_PATH = Path("./plugins") REMOTE_PLUGINS_PATH = Path('Y:/SE/xufeifei/plugins') logger = logging.getLogger(__name__) class Event(Enum): Update = auto() Install = auto() Uninstall = auto() class PluginRegistry(QObject): """插件注册中心。""" plugins_loader_signal = Signal(dict) update_plugins_card_signal = Signal(dict) def __init__(self, parent = None) -> None: super().__init__(parent) self.plugins = dict() self.start_discover_local(LOCAL_PLUGINS_PATH, self.plugins) self.start_discover_remote(REMOTE_PLUGINS_PATH, self.plugins) def start_discover_local(self,plugins_dir: Path, plugins:dict): self.thread_local = threading.Thread(target= self.discover_local_event,args=(plugins_dir, plugins,)) self.thread_local.start() def discover_local_event(self, plugins_dir: Path, plugins:dict): if not os.path.exists(plugins_dir): os.mkdir(plugins_dir) return sys.path.append(str(plugins_dir)) for tool in Path(plugins_dir).glob("*.pyd"): tool_name = tool.stem try: module = importlib.import_module(tool_name) obj = module.create_plugin() name = module.read_plugin_name() version = module.read_plugin_version() if name in plugins.keys(): pass else: plugins[name] = {} plugins[name]['obj'] = obj plugins[name]['local version'] = version except Exception as e: logger.error(f"插件{tool_name}注册失败,{str(e)}") sys.path.remove(str(LOCAL_PLUGINS_PATH)) self.plugins_loader_signal.emit(plugins) def start_discover_remote(self,plugins_dir: Path, plugins:dict): self.thread_remote = threading.Thread(target= self.discover_remote_event,args=(plugins_dir, plugins,)) self.thread_remote.start() def discover_remote_event(self, plugins_dir: Path, plugins:dict): if not os.path.exists(plugins_dir): logger.error("服务器链接错误!") return #读取服务器工具信息 time.sleep(0.01) sys.path.append(str(plugins_dir)) for tool in Path(plugins_dir).glob("*.pyd"): tool_name = tool.stem try: module = importlib.import_module(tool_name) name = module.read_plugin_name() version = module.read_plugin_version() description = module.read_plugin_description() if name in plugins.keys(): pass else: print("discover_remote_event") plugins[name] = {} plugins[name]["tool_name"] = tool_name plugins[name]["local version"] = None plugins[name]["local description"] = None plugins[name]["remote version"] = version plugins[name]["remote description"] = description plugins[name]['remote path'] = plugins_dir except Exception as e: logger.error(f"服务器{tool_name}无法加载:{str(e)}") sys.path.remove(str(plugins_dir)) self.update_plugins_card_signal.emit(plugins) def start_plugins_event(self, event:Event, name:str): if event == Event.Install: local_path = str(LOCAL_PLUGINS_PATH) + '\\' + f"{self.plugins[name]['tool_name']}.pyd" remote_path = str(REMOTE_PLUGINS_PATH) + '\\' + f"{self.plugins[name]['tool_name']}.pyd" self.sub_thread = threading.Thread(target= self.install_plugins_event,args=(local_path,remote_path,)) self.sub_thread.start() pass def install_plugins_event(self, local_path, remote_path): try: total_size = os.path.getsize(remote_path) copied_size = 0 with open(remote_path, 'rb') as fsrc, open(local_path, 'wb') as fdst: while True: buf = fsrc.read(1024*1024) if not buf: break fdst.write(buf) copied_size += len(buf) logger.info(f"安装进度: {copied_size/1024/1024:.2f} MB / {total_size/1024/1024:.2f} MB") time.sleep(0.1) logger.info(f"{local_path}安装成功!!!") except Exception as e: logger.error(f"{remote_path}安装失败{e.args}") return