Skip to content

内置插件开发

Weave v0.1 只支持随发布物一起编译、一起测试、一起升级的内置插件。插件不是第三方扩展市场,也没有独立安装、卸载、版本选择、制品上传、WebAssembly(WASM)、原生子进程(native subprocess)、沙箱或微服务运行时。

这个边界是有意的:当前阶段优先保证平台和设备代理能够快速、可靠地发布。需要独立演进的智能体能力,后续可基于 Pi SDK 设计 Weave 项目专用的工作进程协议(worker protocol),不复用通用插件运行时。该协议是 Weave 的待设计方案,不是 Pi SDK 已提供的接口。

运行模型

位置形式注册位置发布单元
后端进程内 Go 模块,实现 pluginsdk.BackendPlugininternal/backend/plugins/catalog/weave
设备端进程内 Go 模块,实现 agentplugin.AgentPlugininternal/agent/plugins/catalog/weave-agent

生命周期固定为:

编译期目录 → Init → Start → Health → Stop(逆序)

注册顺序就是启动顺序。单个插件的 InitStart 失败会被记录并隔离,其他内置插件继续启动。

后端插件

internal/backend/plugins/{plugin-id}/ 实现:

go
type Plugin struct {
    host pluginsdk.HostAPI
}

func New() *Plugin { return &Plugin{} }

func (p *Plugin) Manifest() pluginsdk.PluginManifest {
    return pluginsdk.PluginManifest{
        ID:          "example",
        Version:     "1.0.0",
        Description: "Example builtin module",
        Bus: &pluginsdk.BusCapability{
            Topics: []string{"evt.plugin.example.*"},
        },
        Capabilities: []pluginsdk.Capability{
            "bus.subscribe.evt.plugin.example.*",
        },
    }
}

func (p *Plugin) Init(ctx context.Context, host pluginsdk.HostAPI) error {
    p.host = host
    return nil
}

func (p *Plugin) Start(ctx context.Context) error { return nil }
func (p *Plugin) Stop(ctx context.Context) error  { return nil }
func (p *Plugin) Health() pluginsdk.HealthReport {
    return pluginsdk.HealthReport{Healthy: true}
}

PluginManifest 只描述平台真正消费的内容:

  • 身份:IDVersionDescription
  • HostAPI 声明:HTTPBusMetricsDB
  • 控制面:PermissionsConfigSchemaSurfaces
  • 配置范围:ApplyScopesDefaultApplyTarget
  • 安全能力:Capabilities
  • 可选设备本地端口:UIPort

没有运行时类型、制品地址、依赖图或资源预算字段。

HostAPI 边界

插件只通过 pluginsdk.HostAPI 使用平台能力:

  • HTTP():在 /api/v1/plugins/{plugin-id}/ 下注册路由
  • Bus():发布和订阅声明过的主题
  • Metrics():注册插件命名空间指标
  • DB():执行插件迁移和查询
  • Store():使用按插件 ID 隔离的键值存储(key-value store,KV)
  • PluginConfig()Shadow()Secrets()Auditor()
  • HTTPClient(tenantID):执行按主机能力检查的外部请求

HTTP 路由必须在 Init 注册,因为此时服务器尚未开始监听。总线订阅和后台任务放在 Start

数据库和租户隔离

声明 DB 只代表请求数据库能力。组合根还必须把插件 ID 放进可信内置名单。

访问启用行级安全(Row-Level Security, RLS)的租户表时必须调用:

go
db := host.DB().WithTenant(tenantID)

实现使用事务内的 SET LOCAL app.tenant_id。不得使用 SET SESSION,也不得在插件中导入 bun

HTTP 和基于角色的访问控制(role-based access control,RBAC)

Manifest 中声明路由和权限:

go
HTTP: &pluginsdk.HTTPCapability{Routes: []pluginsdk.RouteDecl{
    {
        Pattern:     "/items/{id}",
        Method:      "GET",
        Subresource: "item",
        Action:      "read",
    },
}},
Permissions: []pluginsdk.PluginPermissionDecl{
    {
        Subresource:  "item",
        Action:       "read",
        Description:  "Read example items",
        DefaultRoles: []string{"viewer", "operator", "tenant_admin"},
    },
},

Init 中注册:

go
host.HTTP().Handle("GET /items/{id}", "item", "read", handler)

权限资源名为 {plugin-id}/{subresource}。管理器在启动时根据 Manifest 幂等写入权限。

注册

后端构造函数只加入 internal/backend/plugins/catalog/catalog.go。设备端构造函数只加入 internal/agent/plugins/catalog/catalog.go。不要从 cmd/weavecmd/weave-agent 直接导入具体插件。

新增内置插件至少要验证:

bash
go test ./internal/backend/plugin/... ./internal/backend/plugins/...
go test ./internal/agent/plugin/... ./internal/agent/plugins/...
go test ./...

如果修改 Protobuf,再运行 make protomake web-proto

Weave — IoT Device Management Platform