first commit
This commit is contained in:
125
core/plugin_manager.py
Normal file
125
core/plugin_manager.py
Normal file
@@ -0,0 +1,125 @@
|
||||
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
|
||||
Reference in New Issue
Block a user