mirror of
https://gitcode.com/JianFeeeee/homeagent-sdk.git
synced 2026-09-20 17:08:01 +00:00
docs: README 顶部补版本兼容性表与并发约定,下载链接升到 v1.1.0
两件事此前没写进 README,会让读者拿到错的现状: ## 版本兼容性表 README 开头没有版本号、没有兼容性说明,读者无从判断「我这个版本能不能用新接口」。 补一张「内核版本 ↔ SDK 版本」表,说清 patch 位恒为 .0 的语义,以及 1.0.x 升 1.1.x 不需要改代码也不需要重编(新增是「插件调用、内核实现」方向, 不调就不受影响;实测用 SDK 0.9.2 编的旧 plugin.bin 在新内核上直接建链通过)。 ## 并发约定 PluginSDK 是被多个 goroutine 同时使用的共享对象,这一点此前没有写在明处。 列出 SDK 已保证的(访问器/注入/注册/handler 幂等)与开发者必须自己保证的 (StageContext 字段全导出,并发读写要自己持锁;Extra 的 map 并发写是直接 fatal)。 并顺手把下载链接从 v1.0.0 升到 v1.1.0——照旧链接去 release 页面会找不到 v1.1.0 的产物,因为那条 curl 用的是 v1.0.0。
This commit is contained in:
49
README.md
49
README.md
@ -2,6 +2,26 @@
|
||||
|
||||
HomeAgent 插件开发 SDK,用于构建与 HomeAgent 平台交互的智能插件。
|
||||
|
||||
## 版本与兼容性
|
||||
|
||||
当前:**SDK 1.1.0**(需要内核 **1.1.1+** 才能用媒体接口;媒体之外的能力内核 1.0.0 即可)。
|
||||
|
||||
**版本号跟随内核的中版本,patch 位恒为 `.0`**:
|
||||
|
||||
| 内核版本 | 对应 SDK |
|
||||
|---|---|
|
||||
| 1.0.0 / 1.0.1 / … / 1.0.4 | 1.0.0 |
|
||||
| 1.1.0 / 1.1.1 / … / 1.1.N | **1.1.0** |
|
||||
| 1.2.0 起 | 1.2.0 |
|
||||
|
||||
内核的 patch 位专用于 bugfix 与漏洞修复,不碰公开接口,所以 SDK 版本号不跟着动——
|
||||
否则你要么被迫跟版、要么怀疑自己版本过时,而接口其实一个字都没变。
|
||||
|
||||
**1.0.x 插件升到 1.1.x:不需要改代码,也不需要重编。** 1.1.0 的新增全部是
|
||||
「插件调用、内核实现」方向,不调就不受影响(已用 SDK 0.9.2 编的旧 `plugin.bin`
|
||||
实测验证:在新内核上直接建链通过,因为握手校验的是 `ProtocolVersion`、不是 SDK 版本)。
|
||||
想用新字段时重编即可。
|
||||
|
||||
## SDK API 接口
|
||||
|
||||
### Plugin 接口
|
||||
@ -226,8 +246,8 @@ func New(name string, sett SettingsAPI, regTool ToolRegistrar, regStage StageReg
|
||||
[Releases](https://gitcode.com/JianFeeeee/homeagent-sdk/releases) 下载后加入 PATH 即可:
|
||||
|
||||
```bash
|
||||
# 从 release 附件下载(以 v1.0.0 / linux amd64 为例)
|
||||
curl -Lo plugindev https://gitcode.com/JianFeeeee/homeagent-sdk/releases/download/v1.0.0/plugindev_linux_amd64
|
||||
# 从 release 附件下载(以 v1.1.0 / linux amd64 为例)
|
||||
curl -Lo plugindev https://gitcode.com/JianFeeeee/homeagent-sdk/releases/download/v1.1.0/plugindev_linux_amd64
|
||||
chmod +x plugindev
|
||||
|
||||
# 或从源码自己编
|
||||
@ -368,6 +388,31 @@ enabled := sdk.AutoRestart()
|
||||
|
||||
插件崩溃时平台自动拉起,保障服务可用性。
|
||||
|
||||
> ⚠️ `SetAutoRestart` 的典型用法是「外部连接建好后再判定能否自动重启」,而连接建立
|
||||
> 通常在后台 goroutine 里,内核又在另一个 goroutine 读它——这对读写天然并发。
|
||||
> **SDK 1.1.0 已给这个标志与全部 API 字段加锁**(`-race` 实测 11 处竞态,
|
||||
> 生产表现是插件重载瞬间偶发 nil 解引用崩溃)。早于 1.1.0 的版本建议升级。
|
||||
|
||||
## 插件开发者的并发约定
|
||||
|
||||
`PluginSDK` 是**被多个 goroutine 同时使用的共享对象**:你在 `Start()` 里起的轮询、
|
||||
监听、定时器都拿着同一份 `*PluginSDK` 往里注消息,而内核会在加载/重载时写它的
|
||||
API 字段。因此:
|
||||
|
||||
- **SDK 侧已保证的**:全部 API 访问器(`Memory()`/`DocMemory()`/…)、全部注入方法、
|
||||
`SetAutoRestart`/`AutoRestart`、`RegisterTool`/`RegisterStage`、
|
||||
`RunStopHandlers`/`RunOnRemoveHandlers`(幂等,并发调也只执行一次)。
|
||||
- **你需要自己保证的**:`StageContext` 的字段全部导出,并发读写必须自己持
|
||||
`ctx.Lock()`/`ctx.RLock()`。尤其是 `ctx.Extra`——**map 的并发写在 Go 里是直接 fatal,
|
||||
`recover` 接不住**。
|
||||
|
||||
```go
|
||||
ctx.Lock()
|
||||
ctx.Extra["mykey"] = value
|
||||
ctx.FinalText += "补充说明"
|
||||
ctx.Unlock()
|
||||
```
|
||||
|
||||
## 受限 SDK vs 完整 SDK
|
||||
|
||||
外部插件(第三方分发)使用**受限 SDK**,仅暴露安全子集:
|
||||
|
||||
54
README_EN.md
54
README_EN.md
@ -2,6 +2,29 @@
|
||||
|
||||
Plugin development SDK for building intelligent plugins that interact with the HomeAgent platform.
|
||||
|
||||
## Version and Compatibility
|
||||
|
||||
Current: **SDK 1.1.0** (the media APIs need kernel **1.1.1+**; everything else works on kernel 1.0.0).
|
||||
|
||||
**The version tracks the kernel's minor version, with the patch position pinned at `.0`**:
|
||||
|
||||
| Kernel version | Matching SDK |
|
||||
|---|---|
|
||||
| 1.0.0 / 1.0.1 / … / 1.0.4 | 1.0.0 |
|
||||
| 1.1.0 / 1.1.1 / … / 1.1.N | **1.1.0** |
|
||||
| 1.2.0 onward | 1.2.0 |
|
||||
|
||||
The kernel's patch position is reserved for bugfixes and vulnerability fixes, which never touch the
|
||||
public interface, so the SDK version has no reason to move with it — otherwise you would either be
|
||||
forced to chase releases or suspect your version is stale, when not one character of the interface
|
||||
has changed.
|
||||
|
||||
**Upgrading a 1.0.x plugin to 1.1.x: no code changes, no rebuild.** Everything added in 1.1.0 is
|
||||
in the "plugin calls, kernel implements" direction, so not calling it means not being affected
|
||||
(verified with an old `plugin.bin` built against SDK 0.9.2: it handshakes fine on the new kernel,
|
||||
because the handshake validates `ProtocolVersion`, not the SDK version). Rebuild only when you want
|
||||
the new fields.
|
||||
|
||||
## SDK API Surface
|
||||
|
||||
### Plugin Interface
|
||||
@ -233,8 +256,8 @@ Plugin developers only need to implement the `Plugin` interface and export a `Ne
|
||||
[Releases](https://gitcode.com/JianFeeeee/homeagent-sdk/releases) and put it on your PATH:
|
||||
|
||||
```bash
|
||||
# From release assets (v1.0.0 / linux amd64 shown)
|
||||
curl -Lo plugindev https://gitcode.com/JianFeeeee/homeagent-sdk/releases/download/v1.0.0/plugindev_linux_amd64
|
||||
# From release assets (v1.1.0 / linux amd64 shown)
|
||||
curl -Lo plugindev https://gitcode.com/JianFeeeee/homeagent-sdk/releases/download/v1.1.0/plugindev_linux_amd64
|
||||
chmod +x plugindev
|
||||
|
||||
# Or build from source
|
||||
@ -341,6 +364,33 @@ enabled := sdk.AutoRestart()
|
||||
|
||||
The platform automatically restarts the plugin on crash, ensuring service availability.
|
||||
|
||||
> ⚠️ `SetAutoRestart` is typically used to decide whether auto-restart is safe *after* an
|
||||
> external connection has been established, and that connection setup usually happens in a
|
||||
> background goroutine while the kernel reads the flag from another one — which is inherently
|
||||
> concurrent. **SDK 1.1.0 locks this flag and all API fields** (`-race` reported 11 data races;
|
||||
> in production this showed up as sporadic nil-dereference crashes during plugin reload). Upgrade
|
||||
> if you are on anything earlier.
|
||||
|
||||
## Concurrency Contract for Plugin Developers
|
||||
|
||||
`PluginSDK` is a **shared object used by multiple goroutines**: the polling, listening and timer
|
||||
callbacks you start in `Start()` all hold the same `*PluginSDK` and push messages into it, while
|
||||
the kernel writes its API fields during load/reload. So:
|
||||
|
||||
- **Guaranteed by the SDK**: all API accessors (`Memory()`/`DocMemory()`/…), all injection methods,
|
||||
`SetAutoRestart`/`AutoRestart`, `RegisterTool`/`RegisterStage`, and
|
||||
`RunStopHandlers`/`RunOnRemoveHandlers` (idempotent; concurrent calls still run it once).
|
||||
- **Your responsibility**: every field of `StageContext` is exported, and concurrent read/write
|
||||
must hold `ctx.Lock()`/`ctx.RLock()`. Especially `ctx.Extra` — **concurrent map writes are a
|
||||
fatal in Go, and `recover` cannot catch it**.
|
||||
|
||||
```go
|
||||
ctx.Lock()
|
||||
ctx.Extra["mykey"] = value
|
||||
ctx.FinalText += "supplementary note"
|
||||
ctx.Unlock()
|
||||
```
|
||||
|
||||
## Restricted SDK vs Full SDK
|
||||
|
||||
External plugins (third-party distribution) use a **restricted SDK** that only exposes a safe subset:
|
||||
|
||||
Reference in New Issue
Block a user