Files
raisfast/docs/plugin-system-assessment.md
T

9.5 KiB
Raw Blame History

插件系统评估

基于 WASM/JS/Lua 三引擎插件系统完成后的全面评估,分析当前水平与差距,确定改进方向。


1. 当前水平

中等偏上 — 对博客系统而言优秀,对平台框架而言不够。


2. 已有的亮点

能力 说明
三引擎沙箱 WASM (wasmtime) / JavaScript (rquickjs) / Lua (mlua),比大多数开源博客项目丰富
Hook 四类分派 Filter(链式)/ Action(顺序)/ RenderOverride(首覆写)/ Route(自定义路由)
热重载 notify 文件监听 + mpsc channel + 1 秒防抖,支持 .wasm / .js / .lua
优先级调度 manifest 声明 priority,按数值排序执行
安全沙箱 WASM fuel/memory 限制;JS interrupt handler 超时;Lua 禁用 io/os/debug 库 + 指令计数超时
Host API 跨引擎统一 Host.log() + Host.getConfig() 在三引擎中行为一致
测试覆盖 117 单元测试 + 60 集成测试,含三引擎交叉测试
Feature flag 隔离 plugin-wasm / plugin-js / plugin-lua / plugin-all,按需编译

3. 缺什么才算「先进」

3.1 P0 — 不补就做不了有用的插件

Host API 严重不足

当前仅 log + getConfig 两个 Host 函数。插件无法与外部世界交互,实际能做的事极其有限。

需要补齐:

Host 函数 说明 引擎
host_http_get(url) HTTP GET 请求(受域名白名单限制) 三引擎
host_http_post(url, body) HTTP POST 请求(受域名白名单限制) 三引擎
host_get_post(slug) 获取文章内容(只读) 三引擎
host_db_query(sql, params) 数据库只读查询(受表权限控制) 三引擎
host_kv_get(key) 插件 KV 存储 — 读取 三引擎
host_kv_set(key, value, ttl?) 插件 KV 存储 — 写入 三引擎

实现要点:

  • HTTP 请求需校验 manifest 中 permissions.http 白名单
  • DB 查询需校验 permissions.db-read 表白名单,且强制只读(SELECT only)
  • KV store 可用 SQLite plugin_storage 表(plugin_id TEXT, key TEXT, value TEXT, expires_at TEXT

权限声明未强制执行

manifest 中声明了 permissionshttp、config、db-read、db-write),但运行时没有任何检查逻辑。

修复方案:

// src/plugins/permissions.rs
impl Permissions {
    pub fn is_url_allowed(&self, url: &str) -> bool {
        // 解析 URL domain,检查是否匹配 permissions.http 白名单
    }

    pub fn is_config_key_allowed(&self, key: &str) -> bool {
        // 检查 key 是否匹配 permissions.config 前缀
    }

    pub fn is_table_readable(&self, table: &str) -> bool {
        self.db_read.iter().any(|t| t == table)
    }
}

每个 Host 函数实现中必须在执行前检查权限,拒绝则返回错误。


3.2 P1 — 不补就做不好

插件管理 API

运行时无法通过 API 查看插件状态、启用/禁用插件。

需要:

GET    /api/v1/admin/plugins          — 列出所有插件及状态
GET    /api/v1/admin/plugins/:id      — 插件详情
POST   /api/v1/admin/plugins/:id/enable   — 启用
POST   /api/v1/admin/plugins/:id/disable  — 禁用
POST   /api/v1/admin/plugins/:id/reload   — 重载
DELETE /api/v1/admin/plugins/:id      — 卸载(从内存+磁盘移除)

生命周期 Hook

插件无法在加载/卸载时执行初始化/清理逻辑。

需要:

Hook 触发时机 用途
on_load 插件加载完成 初始化连接、注册定时任务、预加载数据
on_unload 插件卸载前 清理资源、关闭连接、保存状态
on_config_change 宿主配置变更时 热更新插件行为

插件持久状态

插件没有地方存储自己的数据。例如 SEO 插件想缓存分析结果、通知插件想记录已发送的邮件。

方案 A — SQLite plugin_storage 表:

CREATE TABLE IF NOT EXISTS plugin_storage (
    plugin_id TEXT NOT NULL,
    key TEXT NOT NULL,
    value TEXT NOT NULL,
    expires_at TEXT,
    updated_at TEXT NOT NULL DEFAULT (datetime('now')),
    PRIMARY KEY (plugin_id, key)
);

方案 B — KV Host API

-- Lua 插件中
Host.setData("last_notified", "2026-04-14T00:00:00Z")
local last = Host.getData("last_notified")

3.3 P2 — 做大时才需要

错误恢复

当前插件抛异常后静默跳过,无法感知插件健康状态。

需要:

  • 每个插件维护 error_countlast_error
  • 连续 N 次错误(如 5 次)后自动禁用该插件
  • 记录错误日志 + 可选告警通知
  • 管理 API 中展示插件健康状态
struct PluginHealth {
    error_count: u32,
    last_error: Option<String>,
    last_error_at: Option<String>,
    auto_disabled: bool,
}

EventBus(事件总线)

当前 Hook 是同步链式调用,无法解耦。平台级系统需要事件驱动架构。

差距:

  • 插件无法订阅内部事件(如"用户注册"不在 Hook 中则无法感知)
  • 一个 Hook 的处理阻塞后续所有插件
  • 无法异步响应(如"文章创建后异步触发邮件发送")

方案:

// src/eventbus/mod.rs
pub struct EventBus {
    tx: broadcast::Sender<Arc<Event>>,
}

// 订阅者
EventBus.emit(PostCreated)
    ├── PluginManager.dispatch_action(PostCreated)
    ├── NotificationService.notify(author)
    ├── SearchIndexer.index(post)
    └── AuditLogger.log("post.create", ...)

插件间通信

当前插件之间完全隔离,无法互相发现或调用。

可能的方案:

  • 注册表模式:插件 A 在宿主注册一个 named service,插件 B 通过 Host.getService("name") 调用
  • 需要仔细设计以避免循环依赖和安全问题

性能指标

缺少插件执行的可观测性。

需要:

指标 说明
Hook 执行耗时 每个 Hook × 每个插件的 P50/P95/P99
内存占用 每个插件的实际内存使用
调用次数 每个 Hook 的调用频率
错误率 每个插件的错误次数/频率

可集成 Prometheus metrics 或通过管理 API 暴露。

依赖管理

无插件版本冲突检测、无依赖声明。

manifest 扩展:

[plugin]
id = "com.example.seo-optimizer"
version = "1.0.0"

[dependencies]
"com.example.utils" = ">=1.0.0"

加载时检测依赖是否满足,缺失则拒绝加载。


4. 与成熟系统对比

能力 WordPress Ghost raisfast
沙箱隔离 无(PHP 直接执行) 无(Node 直接 require 有(三引擎)
热重载 需插件自身支持 需重启
Hook 数量 ~2000 个 filter/action ~30 个事件 11 个 Hook
Host API 完整(DB/HTTP/FS/Option 完整 2 个函数
权限控制 Role + Capability 细粒度 声明式但未执行
插件状态存储 wp_options 表 DB 表
插件市场
多语言插件 PHP only JS only Rust/JS/Lua/WASM

raisfast 的独特优势是三引擎沙箱隔离,这在博客系统中非常少见。但 Host API 和生态成熟度差距明显。


5. 改进路线图

Phase 1 — 补齐基础能力(1 周)

Week 1:
  ├── 权限执行模块(permissions.rs
  ├── Host API: http_get/http_post(域名白名单)
  ├── Host API: get_post(文章只读访问)
  ├── Host API: KV storeplugin_storage 表 + get_data/set_data
  ├── 插件管理 API(列表/详情/启用/禁用/重载)
  └── 集成测试覆盖新 Host API + 权限检查

Phase 2 — 生命周期与健壮性(1 周)

Week 2:
  ├── 生命周期 Hookon_load/on_unload/on_config_change
  ├── 错误恢复(错误计数 + 自动禁用 + 健康状态)
  ├── 插件管理 API 增强(健康状态、错误日志)
  └── Host API: db_query(只读查询 + 表权限校验)

Phase 3 — 平台化能力(按需)

  ├── EventBus 事件总线
  ├── 插件间通信机制
  ├── 性能指标采集(Prometheus 或内部 metrics)
  ├── 依赖管理与版本冲突检测
  └── 插件脚手架 CLIcargo run -- generate-plugin

6. 依赖新增预估

阶段 依赖 用途 体积影响
Phase 1 reqwest(可能已有) Host HTTP 请求 零增长(已有)
Phase 1 KV store 用 SQLite 零增长
Phase 2 错误恢复纯内存 零增长
Phase 3 prometheus(可选) 指标采集 +~1MB

Phase 1-2 几乎不增加外部依赖。


7. 总结

当前状态:
  ✅ 三引擎沙箱 — 业界领先
  ✅ 热重载 — 生产可用
  ✅ Hook 四类分派 — 架构合理
  ✅ 安全模型 — 沙箱限制到位
  ✅ 测试覆盖 — 质量有保障

  ❌ Host API — 仅 2 个函数,插件做不了实事
  ❌ 权限执行 — 声明式但未运行时检查
  ❌ 管理接口 — 无法运行时管理插件
  ❌ 生命周期 — 无初始化/清理回调
  ❌ 持久状态 — 插件无法存数据

核心判断: 架构骨架扎实,三引擎沙箱是独特优势。但当前能扩展的点太少(11 Hook + 2 Host API),实际可编写的插件非常有限。补齐 Host API、权限执行、管理接口后,才算真正可用的插件平台。