mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-22 09:58:06 +00:00
plugin: 删除 C ABI 通道(Part 6.2 完成,-3198 行)
外部插件统一走子进程 + stdio RPC,三套独立 ABI 实现收敛为单一 RPC 实现。 用户决策:彻底舍弃 .so 能力,不保留双通道回退。 ## 删除清单 internal/plugin/cabi/ 1156 行(loader.go/loader.c/types.go/output_test.go) internal/plugin/dynamic_dll_windows.go 272 行(§9.2 记录的能力退化实现) internal/plugin/dynamic_loader_unix.go 79 行(唯一 cabi 引用点) internal/plugin/dynamic_dll_test.go 32 行 internal/plugin/dynamic_dll_stub.go 11 行 internal/plugin/dynamic_loader_windows.go 11 行 internal/plugin/bridge_e2e_test.go (测的是 cabi 路径) third_party/.../plugindev/templates.go 1296 行(取消跟踪,SDK 仓才是权威副本) dynamic.go:entryCABI 通道删除,soEntry/dllEntry 常量删除。 registry.go:tryDynamic 探测顺序从 .so → .dll → .lua 变成 proc → lua。 ## 旧 .so 给明确错误,不静默跳过 静默跳过会让「插件目录在但没加载」看起来像配置问题,而实际原因是需要 用新版 plugindev 重编。故保留 legacyCABIEntries 表专门用于识别残留: plugin legacy: 检测到旧 C ABI 产物(plugin.so/.dll/.dylib)。 外部插件已改为子进程模式,请用新版 plugindev 重编产出 plugin.bin (业务代码无需修改) 错误消息里「业务代码无需修改」这句是有测试守着的——迁移的核心承诺就是它。 ## pluginmgr 安装逻辑跟进 bundle 命名 子进程模式下各平台产物统一叫 plugin.bin(进程边界即 ABI 边界),故 zip 内 按平台加后缀 plugin.bin.<goos>.<goarch>,解包时挑当前平台那一份重命名。 platformBinary 改为按 runtime.GOOS+GOARCH 生成条目名;platformBinaries 固定表 换成 isPlatformBinary 前缀判断(平台组合会增长:linux/arm64、darwin/arm64…, 按前缀判断无需维护清单)。 新增 chmod 0755:zip 保留了原权限位,但经某些工具链/传输后可能丢失, 内核加载时会因缺执行位报错。提前补上比事后让用户 chmod 更好。 ## 测试 entry_dispatch_test.go 重写(12 项): - classifyEntry 对 .so/.dll/.dylib 现在返回 unknown - LegacyManifestFallsBackToProbe:存量插件 manifest 仍写 "plugin.so" (17 个插件没人去改),须靠目录探测找到 plugin.bin —— 这是 「外部插件零改动」的直接后果 - LegacyCABIGivesActionableError:错误消息须含 plugindev / plugin.bin / 业务代码 - PluginEntryHash_IgnoresLegacyCABI:.so 不参与 hash(内核已不认它) upgrade_test.go 的 .hmap 构造改用 plugin.bin。 验证:go build ./... 通过;go test ./... 全仓无失败; go test -race ./internal/plugin/... 全绿;三平台构建通过。 Ref: docs/zh/架构迁移评估.md §3.1/§9.2、docs/zh/plugin-migration-plan.md Part 6
This commit is contained in:
@ -7,31 +7,34 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
soEntry = "plugin.so"
|
||||
dllEntry = "plugin.dll"
|
||||
binEntry = "plugin.bin" // 子进程插件(纯 Go 二进制,stdio JSON-RPC)
|
||||
binEntry = "plugin.bin" // 子进程插件(纯 Go 二进制,stdio JSON-RPC + 共享内存)
|
||||
luaEntry = "main.lua"
|
||||
skillEntry = "SKILL.md"
|
||||
metaEntry = "plugin.json"
|
||||
)
|
||||
|
||||
// legacyCABIEntries 是已退场的 C ABI 产物名。
|
||||
//
|
||||
// 保留这张表只为**给出明确错误**:插件目录里躺着 plugin.so 而内核不再认它时,
|
||||
// 静默跳过会让「目录在但插件没加载」看起来像配置问题,而实际原因是需要用
|
||||
// 新版 plugindev 重编。
|
||||
var legacyCABIEntries = []string{"plugin.so", "plugin.dll", "plugin.dylib"}
|
||||
|
||||
// entryKind 描述插件入口归属的加载通道。
|
||||
// 外部插件多进程化期间 .so/.dll(cabi)与 .bin(proc)**双通道共存**,
|
||||
// 按 plugin.json 的 entry 字段分派,使迁移可逐插件推进、随时回退。
|
||||
//
|
||||
// C ABI 通道(.so/.dll/.dylib)已整体退场:外部插件统一走子进程 + stdio RPC,
|
||||
// 三套独立 ABI 实现收敛为单一 RPC 实现(§9.2)。
|
||||
type entryKind int
|
||||
|
||||
const (
|
||||
entryUnknown entryKind = iota
|
||||
entryCABI // plugin.so / plugin.dll / plugin.dylib —— C ABI 动态库
|
||||
entryProc // plugin.bin —— 子进程 + stdio JSON-RPC
|
||||
entryProc // plugin.bin —— 子进程 + stdio JSON-RPC + 共享内存
|
||||
entryLua // main.lua
|
||||
entrySkill // SKILL.md
|
||||
)
|
||||
|
||||
func (k entryKind) String() string {
|
||||
switch k {
|
||||
case entryCABI:
|
||||
return "cabi"
|
||||
case entryProc:
|
||||
return "proc"
|
||||
case entryLua:
|
||||
@ -43,11 +46,12 @@ func (k entryKind) String() string {
|
||||
}
|
||||
|
||||
// classifyEntry 把 manifest 的 entry 字段映射到加载通道。
|
||||
// entry 为空时返回 entryUnknown,由调用方回退到目录探测(兼容无 manifest 的旧插件)。
|
||||
//
|
||||
// entry 为空或声明已退场的 C ABI 产物时返回 entryUnknown,
|
||||
// 由调用方回退到目录探测(兼容无 manifest 的旧插件),
|
||||
// 并在探测到 C ABI 残留时给出明确的重编提示。
|
||||
func classifyEntry(entry string) entryKind {
|
||||
switch entry {
|
||||
case soEntry, dllEntry, "plugin.dylib":
|
||||
return entryCABI
|
||||
case binEntry:
|
||||
return entryProc
|
||||
case luaEntry:
|
||||
@ -59,8 +63,9 @@ func classifyEntry(entry string) entryKind {
|
||||
}
|
||||
|
||||
// detectEntryKind 先读 manifest 的 entry,读不到则按目录内存在的入口文件推断。
|
||||
// 推断顺序:.bin 优先于 .so——迁移期间同一插件目录可能两个产物共存(升级未清理),
|
||||
// 此时应走新通道;manifest 显式声明优先级最高。
|
||||
//
|
||||
// 注意:存量插件的 plugin.json 可能仍写着 "plugin.so"(工具链已不再据此分派,
|
||||
// 但历史产物里有),此时 classifyEntry 返回 unknown,靠目录探测找到 plugin.bin。
|
||||
func detectEntryKind(plgDir string) entryKind {
|
||||
if mft := readManifest(plgDir); mft != nil {
|
||||
if k := classifyEntry(mft.Entry); k != entryUnknown {
|
||||
@ -72,9 +77,6 @@ func detectEntryKind(plgDir string) entryKind {
|
||||
kind entryKind
|
||||
}{
|
||||
{binEntry, entryProc},
|
||||
{soEntry, entryCABI},
|
||||
{"plugin.dylib", entryCABI},
|
||||
{dllEntry, entryCABI},
|
||||
{luaEntry, entryLua},
|
||||
{skillEntry, entrySkill},
|
||||
} {
|
||||
@ -85,6 +87,18 @@ func detectEntryKind(plgDir string) entryKind {
|
||||
return entryUnknown
|
||||
}
|
||||
|
||||
// hasLegacyCABIEntry 判断插件目录里是否只剩已退场的 C ABI 产物。
|
||||
//
|
||||
// 用于给出「需要重编」而非「插件不存在」的错误。
|
||||
func hasLegacyCABIEntry(plgDir string) bool {
|
||||
for _, name := range legacyCABIEntries {
|
||||
if st, err := os.Stat(filepath.Join(plgDir, name)); err == nil && !st.IsDir() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func readManifest(dir string) *PluginManifest {
|
||||
data, err := os.ReadFile(filepath.Join(dir, metaEntry))
|
||||
if err != nil {
|
||||
@ -96,5 +110,3 @@ func readManifest(dir string) *PluginManifest {
|
||||
}
|
||||
return &m
|
||||
}
|
||||
|
||||
var _ = json.Marshal
|
||||
|
||||
Reference in New Issue
Block a user