176 lines
6.6 KiB
Python
Executable File
176 lines
6.6 KiB
Python
Executable File
from typing import Any, Dict, Optional
|
|
|
|
from fastapi import APIRouter, Depends
|
|
from fastapi.responses import FileResponse
|
|
from pydantic import BaseModel, Field
|
|
|
|
from api.deps import require_admin_auth
|
|
from core.error_handler import raise_api_error
|
|
from core.plugin_system import plugin_manager
|
|
|
|
|
|
router = APIRouter(prefix="/api/plugins", tags=["插件"])
|
|
|
|
|
|
class PluginTogglePayload(BaseModel):
|
|
enabled: bool
|
|
|
|
|
|
class PluginConfigPayload(BaseModel):
|
|
config: Dict[str, Any]
|
|
|
|
|
|
class PluginActionPayload(BaseModel):
|
|
payload: Dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class PluginSearchPayload(BaseModel):
|
|
keyword: str
|
|
page: int = 1
|
|
plugin_id: Optional[str] = None
|
|
|
|
|
|
class PluginSyncPayload(BaseModel):
|
|
force: bool = True
|
|
|
|
|
|
class PluginSearchJobPayload(BaseModel):
|
|
plugin_id: Optional[str] = None
|
|
keyword: str
|
|
page: int = 1
|
|
|
|
|
|
@router.get("")
|
|
async def list_plugins(_session_data: dict = Depends(require_admin_auth)):
|
|
return {"success": True, "data": plugin_manager.list_plugins()}
|
|
|
|
|
|
@router.post("/rescan")
|
|
async def rescan_plugins(_session_data: dict = Depends(require_admin_auth)):
|
|
try:
|
|
plugins = await plugin_manager.scan_plugins()
|
|
return {"success": True, "data": plugins, "message": "插件扫描完成"}
|
|
except Exception as e:
|
|
raise_api_error(f"扫描插件失败: {e}", "rescan_plugins")
|
|
|
|
|
|
@router.get("/{plugin_id}/ui/{asset_path:path}")
|
|
async def get_plugin_ui_asset(plugin_id: str, asset_path: str, _session_data: dict = Depends(require_admin_auth)):
|
|
try:
|
|
file_path = plugin_manager.get_plugin_ui_file(plugin_id, asset_path)
|
|
return FileResponse(
|
|
str(file_path),
|
|
headers={
|
|
"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
|
|
"Pragma": "no-cache",
|
|
"Expires": "0",
|
|
}
|
|
)
|
|
except KeyError as e:
|
|
raise_api_error(str(e), "get_plugin_ui_asset", 404)
|
|
except FileNotFoundError as e:
|
|
raise_api_error(str(e), "get_plugin_ui_asset", 404)
|
|
except Exception as e:
|
|
raise_api_error(f"获取插件前台资源失败: {e}", "get_plugin_ui_asset")
|
|
|
|
|
|
@router.post("/{plugin_id}/toggle")
|
|
async def toggle_plugin(plugin_id: str, payload: PluginTogglePayload, _session_data: dict = Depends(require_admin_auth)):
|
|
try:
|
|
plugin = await plugin_manager.set_plugin_enabled(plugin_id, payload.enabled)
|
|
return {"success": True, "data": plugin, "message": "插件状态已更新"}
|
|
except KeyError as e:
|
|
raise_api_error(str(e), "toggle_plugin", 404)
|
|
except Exception as e:
|
|
raise_api_error(f"更新插件状态失败: {e}", "toggle_plugin")
|
|
|
|
|
|
@router.put("/{plugin_id}/config")
|
|
async def update_plugin_config(plugin_id: str, payload: PluginConfigPayload, _session_data: dict = Depends(require_admin_auth)):
|
|
try:
|
|
plugin = await plugin_manager.update_plugin_config(plugin_id, payload.config)
|
|
return {"success": True, "data": plugin, "message": "插件配置已更新"}
|
|
except KeyError as e:
|
|
raise_api_error(str(e), "update_plugin_config", 404)
|
|
except Exception as e:
|
|
raise_api_error(f"更新插件配置失败: {e}", "update_plugin_config")
|
|
|
|
|
|
@router.post("/{plugin_id}/actions/{action}")
|
|
async def execute_plugin_action(plugin_id: str, action: str, payload: PluginActionPayload, _session_data: dict = Depends(require_admin_auth)):
|
|
try:
|
|
result = await plugin_manager.execute_plugin_action(plugin_id, action, payload.payload)
|
|
return {"success": True, "data": result}
|
|
except KeyError as e:
|
|
raise_api_error(str(e), "execute_plugin_action", 404)
|
|
except Exception as e:
|
|
raise_api_error(f"执行插件动作失败: {e}", "execute_plugin_action")
|
|
|
|
|
|
@router.post("/search")
|
|
async def search_resources(payload: PluginSearchPayload, _session_data: dict = Depends(require_admin_auth)):
|
|
plugin_id = payload.plugin_id or "resource_search"
|
|
try:
|
|
result = await plugin_manager.execute_search(plugin_id, payload.keyword, payload.page)
|
|
return {"success": True, "data": result}
|
|
except KeyError as e:
|
|
raise_api_error(str(e), "search_resources", 404)
|
|
except Exception as e:
|
|
raise_api_error(f"资源搜索失败: {e}", "search_resources")
|
|
|
|
|
|
@router.post("/search-jobs")
|
|
async def start_search_job(payload: PluginSearchJobPayload, _session_data: dict = Depends(require_admin_auth)):
|
|
plugin_id = payload.plugin_id or "resource_search"
|
|
try:
|
|
result = await plugin_manager.start_search_job(plugin_id, payload.keyword, payload.page)
|
|
return {"success": True, "data": result}
|
|
except KeyError as e:
|
|
raise_api_error(str(e), "start_search_job", 404)
|
|
except Exception as e:
|
|
raise_api_error(f"启动搜索失败: {e}", "start_search_job")
|
|
|
|
|
|
@router.get("/search-jobs/{job_id}")
|
|
async def get_search_job(job_id: str, _session_data: dict = Depends(require_admin_auth)):
|
|
try:
|
|
result = plugin_manager.get_search_job(job_id)
|
|
return {"success": True, "data": result}
|
|
except KeyError as e:
|
|
raise_api_error(str(e), "get_search_job", 404)
|
|
except Exception as e:
|
|
raise_api_error(f"获取搜索任务失败: {e}", "get_search_job")
|
|
|
|
|
|
@router.post("/search-jobs/{job_id}/cancel")
|
|
async def cancel_search_job(job_id: str, _session_data: dict = Depends(require_admin_auth)):
|
|
try:
|
|
result = await plugin_manager.cancel_search_job(job_id)
|
|
return {"success": True, "data": result, "message": "搜索任务已停止"}
|
|
except KeyError as e:
|
|
raise_api_error(str(e), "cancel_search_job", 404)
|
|
except Exception as e:
|
|
raise_api_error(f"停止搜索任务失败: {e}", "cancel_search_job")
|
|
|
|
|
|
@router.post("/{plugin_id}/test-connection")
|
|
async def test_plugin_connection(plugin_id: str, _session_data: dict = Depends(require_admin_auth)):
|
|
try:
|
|
result = await plugin_manager.test_plugin_connection(plugin_id)
|
|
return {"success": True, "data": result, "message": "连通性测试完成"}
|
|
except KeyError as e:
|
|
raise_api_error(str(e), "test_plugin_connection", 404)
|
|
except Exception as e:
|
|
raise_api_error(f"连通性测试失败: {e}", "test_plugin_connection")
|
|
|
|
|
|
@router.post("/{plugin_id}/sync")
|
|
async def sync_plugin_index(plugin_id: str, payload: PluginSyncPayload, _session_data: dict = Depends(require_admin_auth)):
|
|
try:
|
|
result = await plugin_manager.sync_plugin_index(plugin_id, force=payload.force)
|
|
return {"success": True, "data": result, "message": "同步完成"}
|
|
except KeyError as e:
|
|
raise_api_error(str(e), "sync_plugin_index", 404)
|
|
except Exception as e:
|
|
raise_api_error(f"同步资源失败: {e}", "sync_plugin_index")
|