feat(plugins): 插件支持热加载与启用/停用清单

- pugins/__init__.py 重写:load_plugins / discover / set_enabled / reload
- 热加载:把 study_tool.pugins.<名字> 的模块从 sys.modules 摘掉后重新 import;
  重载前先 registry.unregister 旧 id,平台 id 改了也不会留残影
- 启用清单存设置项 plugins({"disabled": [...]}):未列出的默认启用,新插件自动生效;
  停用即从注册表摘掉,/api/platforms 与账号平台下拉同步消失
- platforms/registry.py 新增 unregister(pid)
- 新接口:GET /api/plugins、POST /api/plugins/{name}/enable|disable、
  POST /api/plugins/reload、POST /api/plugins/{name}/reload;失败返回 ok=false
- 同步 docs/pugin.md(新增「加载与启停」)、docs/architecture.md、docs/OPTIMIZATION.md、AGENTS.md
This commit is contained in:
study-tool
2026-10-31 15:50:06 +08:00
parent f1a57853f4
commit f8458cff51
7 changed files with 219 additions and 31 deletions
+40 -2
View File
@@ -1,11 +1,11 @@
"""课程 / 发现 / 学习 / 停止 / 抓包 / 快照 / 历史日志接口。"""
"""课程 / 发现 / 学习 / 停止 / 抓包 / 快照 / 历史日志 / 插件管理接口。"""
import threading
import time
from fastapi.responses import HTMLResponse, JSONResponse
from study_tool.webapp import app
from study_tool import store
from study_tool import pugins, store
from study_tool.capture import *
from study_tool.config import *
from study_tool.engine import study_worker
@@ -25,6 +25,44 @@ def api_platforms():
for p in registry.all()]}
# ------------------------------------------------------------------ 插件管理
# 插件目录 pugins/<名字>/,实现见 study_tool.pugins。
@app.get("/api/plugins")
def api_plugins():
"""磁盘上的插件清单:是否启用、是否已加载、加载后的 label 与 capabilities。"""
return {"ok": True, "plugins": pugins.discover()}
@app.post("/api/plugins/{name}/enable")
def api_plugin_enable(name: str):
return _plugin_call(lambda: pugins.set_enabled(name, True))
@app.post("/api/plugins/{name}/disable")
def api_plugin_disable(name: str):
return _plugin_call(lambda: pugins.set_enabled(name, False))
@app.post("/api/plugins/reload")
def api_plugins_reload():
"""重载全部已启用插件:改完插件代码不用重启服务。"""
return _plugin_call(pugins.reload)
@app.post("/api/plugins/{name}/reload")
def api_plugin_reload(name: str):
return _plugin_call(lambda: pugins.reload(name))
def _plugin_call(fn):
"""插件操作失败不抛 500,返回 ok=false 给前端提示。"""
try:
return {"ok": True, "plugins": fn()}
except Exception as e:
return {"ok": False, "error": str(e), "plugins": pugins.discover()}
# ------------------------------------------------------------------ 运行日志 / 快照
@app.get("/api/log/history")