feat(plugin): 新增插件兼容性自检提示
3 个文件变更
+54
-4
fangqihang1717@163.com
| •docs/PLUGIN.md | +6 -1 |
| •internal/plugin/plugin.go | +47 -2 |
| •web/templates/admin.html | +1 -1 |
变更内容
diff --git a/docs/PLUGIN.md b/docs/PLUGIN.md
index 212158b..df94029 100644
--- a/docs/PLUGIN.md
+++ b/docs/PLUGIN.md
@@ -249,8 +249,13 @@ zip -r official-guard.zip plugin.json
| 场景 | 建议 |
|---|---|
+| **插件装了但完全没反应** | 按顺序检查:① 是否已在「插件管理」点**启用**(安装 ≠ 启用);② 后台插件列表里插件名下方是否出现 ⚠ 提示 —— 有提示说明正在运行的表白墙版本过旧,不认识插件的钩子类型,**升级二进制即可**;③ 浏览器打开 `/compose` 查看网页源码,若没有 `data-admin-nicks` 属性,同样说明服务端是旧版本 |
| 改了 plugin.json 不生效 | 插件清单每次请求都会重新读取磁盘,但 `content_filter` 规则有 30 秒缓存 |
| 配置改了没生效 | 配置存在 `settings` 表并带内存缓存,保存后立即刷新,无需重启 |
| 钩子没触发 | 确认插件已在「插件管理」中**启用**(安装 ≠ 启用) |
| 前台注入的 JS 报错 | 打开浏览器控制台查看;注入内容会在渲染时直接输出,注意转义引号 |
-| 想看当前插件与配置 | 后台「插件管理」页可查看全部插件、状态与配置表单 |
+| 保存 plugin.json 后插件不出现 | 确认文件为 **UTF-8 无 BOM**(带 BOM 会导致 JSON 解析失败而静默跳过),可用 `jq . plugin.json` 验证 |
+| 想看当前插件与配置 | 后台「插件管理」页可查看全部插件、状态、兼容性提示与配置表单 |
+
+> 兼容性原则:插件使用了当前内核不支持的钩子类型时,**该钩子会被跳过而不是报错**,
+> 因此请务必留意后台插件列表中的 ⚠ 兼容性提示。
diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go
index 92c0280..e0c24d7 100644
--- a/internal/plugin/plugin.go
+++ b/internal/plugin/plugin.go
@@ -18,6 +18,7 @@ import (
"os"
"path/filepath"
"regexp"
+ "strconv"
"strings"
"sync"
"time"
@@ -70,6 +71,50 @@ type Plugin struct {
type Meta struct {
Plugin
Enabled bool
+ Warn string // 兼容性提示:使用了当前版本不支持的钩子 / 版本要求不满足
+}
+
+// supportedTypes 当前内核支持的钩子类型
+var supportedTypes = map[string]bool{
+ "html": true, "filter": true, "http": true, "guard": true, "badge": true,
+}
+
+// checkCompat 返回插件的兼容性提示(空串表示没有问题)
+func (p *Plugin) checkCompat() string {
+ var bad []string
+ seen := map[string]bool{}
+ for _, h := range p.Hooks {
+ if h.Type == "" || supportedTypes[h.Type] || seen[h.Type] {
+ continue
+ }
+ seen[h.Type] = true
+ bad = append(bad, h.Type)
+ }
+ if len(bad) > 0 {
+ return "该插件使用了当前版本不支持的钩子类型:" + strings.Join(bad, "、") + ",请升级表白墙后再启用"
+ }
+ if p.Requires != "" && versionLess(config.Version, p.Requires) {
+ return "该插件要求表白墙版本 ≥ " + p.Requires + ",当前版本为 " + config.Version
+ }
+ return ""
+}
+
+// versionLess 按 x.y.z 逐段比较版本号(缺失段按 0 处理)
+func versionLess(a, b string) bool {
+ pa, pb := strings.Split(a, "."), strings.Split(b, ".")
+ for i := 0; i < 3; i++ {
+ x, y := 0, 0
+ if i < len(pa) {
+ x, _ = strconv.Atoi(strings.TrimSpace(pa[i]))
+ }
+ if i < len(pb) {
+ y, _ = strconv.Atoi(strings.TrimSpace(pb[i]))
+ }
+ if x != y {
+ return x < y
+ }
+ }
+ return false
}
// dir 插件目录(跟随数据目录配置,支持 CLEARLOVE_DATA_DIR 自定义)
@@ -120,12 +165,12 @@ func saveEnabled(set map[string]bool) {
_ = models.SetSetting("enabled_plugins", string(b))
}
-// List 管理页用:全部插件及启用状态
+// List 管理页用:全部插件、启用状态与兼容性提示
func List() []Meta {
enabled := enabledSet()
var out []Meta
for _, p := range Load() {
- out = append(out, Meta{Plugin: *p, Enabled: enabled[p.Name]})
+ out = append(out, Meta{Plugin: *p, Enabled: enabled[p.Name], Warn: p.checkCompat()})
}
return out
}
diff --git a/web/templates/admin.html b/web/templates/admin.html
index 384f3a9..ff7c214 100644
--- a/web/templates/admin.html
+++ b/web/templates/admin.html
@@ -503,7 +503,7 @@
<tbody>
{{range .plugins}}
<tr>
- <td><b>{{.Name}}</b></td>
+ <td><b>{{.Name}}</b>{{if .Warn}}<br><small class="warn">⚠ {{.Warn}}</small>{{end}}</td>
<td>{{.Version}}</td>
<td>{{.Author}}</td>
<td class="cell-content">{{.Description}}</td>