import os import importlib import inspect import asyncio from typing import List, Dict, Optional from core.crawler import BasePlugin from core.log import logger class PluginManager: def __init__(self, plugin_dir='plugins'): self.plugin_dir = plugin_dir self.plugins = [] self.plugin_stats = {} self._load_plugins() self._init_stats() def _init_stats(self): for plugin in self.plugins: self.plugin_stats[plugin.name] = { 'success_count': 0, 'failure_count': 0, 'last_run': None } def _load_plugins(self): base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) full_plugin_path = os.path.join(base_dir, self.plugin_dir) if not os.path.exists(full_plugin_path): logger.error(f"插件目录不存在: {full_plugin_path}") return for filename in os.listdir(full_plugin_path): if filename.endswith('.py') and not filename.startswith('__'): module_name = f"{self.plugin_dir}.{filename[:-3]}" try: module = importlib.import_module(module_name) for name, obj in inspect.getmembers(module): if inspect.isclass(obj) and issubclass(obj, BasePlugin) and obj is not BasePlugin: plugin_instance = obj() if plugin_instance.enabled: logger.info(f"成功加载插件: {name} 来自 {module_name}") self.plugins.append(plugin_instance) else: logger.info(f"插件已禁用,跳过加载: {name} 来自 {module_name}") except Exception as e: logger.error(f"加载插件失败 {module_name}: {e}") def get_plugin_by_name(self, plugin_name: str) -> Optional[BasePlugin]: for plugin in self.plugins: if plugin.name == plugin_name: return plugin return None def get_all_plugin_info(self) -> List[Dict]: plugins_info = [] for plugin in self.plugins: stats = self.plugin_stats.get(plugin.name, { 'success_count': 0, 'failure_count': 0, 'last_run': None }) plugins_info.append({ 'id': plugin.name, 'name': plugin.name, 'enabled': plugin.enabled, 'description': getattr(plugin, 'description', f'从{plugin.name}网站爬取代理'), 'last_run': stats['last_run'], 'success_count': stats['success_count'], 'failure_count': stats['failure_count'] }) return plugins_info def toggle_plugin(self, plugin_name: str, enabled: bool) -> bool: plugin = self.get_plugin_by_name(plugin_name) if plugin: plugin.enabled = enabled logger.info(f"插件 {plugin_name} 已{'启用' if enabled else '禁用'}") return True return False async def run_plugin(self, plugin_name: str): plugin = self.get_plugin_by_name(plugin_name) if not plugin: logger.error(f"插件不存在: {plugin_name}") return [] if not plugin.enabled: logger.warning(f"插件已禁用: {plugin_name}") return [] try: results = await plugin.run() success_count = len(results) failure_count = 0 from datetime import datetime self.plugin_stats[plugin.name] = { 'success_count': self.plugin_stats[plugin.name]['success_count'] + success_count, 'failure_count': self.plugin_stats[plugin.name]['failure_count'] + failure_count, 'last_run': datetime.now().isoformat() } logger.info(f"插件 {plugin_name} 执行完成,成功: {success_count}") return results except Exception as e: logger.error(f"插件 {plugin_name} 执行失败: {e}") from datetime import datetime self.plugin_stats[plugin.name] = { 'success_count': self.plugin_stats[plugin.name]['success_count'], 'failure_count': self.plugin_stats[plugin.name]['failure_count'] + 1, 'last_run': datetime.now().isoformat() } return [] async def run_all(self): """并发运行所有插件""" tasks = [plugin.run() for plugin in self.plugins] # 并发执行并收集结果 results_list = await asyncio.gather(*tasks) # 将嵌套列表扁平化并产出结果 for results in results_list: for proxy in results: yield proxy