mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 17:38:10 +00:00
fix(plugin): DisablePlugin 禁止禁用未安装插件,防止脏写 disabled_plugins
问题:POST /api/v1/plugins/<name>/disable 对不存在的插件也会把它写进 disabled_plugins 表(registry.go DisablePlugin 无条件 AddDisabledPlugin), 产生脏数据堆积,且同名插件日后真实安装会被误判为已禁用。 修复: - registry.go 新增 pluginInstalled(name):已加载 / 已注册工厂(内置) / 插件目录存在, 任一命中视为已安装 - DisablePlugin 开头校验:未安装返回 'plugin X not installed',不写 disabled_plugins - webui handler:未安装→404,已禁用→409(原都返回500);enable 失败含'failed'→404 - 新增 registry_disable_test.go:覆盖未安装拒绝/内置判定/目录存在判定/普通文件不算 本机端到端验证:disable 不存在插件返回404且表无脏数据;真实插件 disable/enable 正常
This commit is contained in:
@ -672,6 +672,33 @@ func (r *Registry) IsBuiltinPlugin(name string) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// pluginInstalled 判断插件是否已安装(可用于禁用/启用等操作前的存在性校验)。
|
||||
// 命中任一即视为已安装:
|
||||
// 1. 已加载(plugins map 中)
|
||||
// 2. 已注册工厂(内置插件,通过 init() 自注册,无需物理目录)
|
||||
// 3. 插件目录 plgDir/<name> 存在(外部插件的安装目录)
|
||||
func (r *Registry) pluginInstalled(name string) bool {
|
||||
if r == nil || name == "" {
|
||||
return false
|
||||
}
|
||||
r.mu.RLock()
|
||||
_, loaded := r.plugins[name]
|
||||
_, isFactory := r.factories[name]
|
||||
r.mu.RUnlock()
|
||||
if loaded || isFactory {
|
||||
return true
|
||||
}
|
||||
if _, ok := globalFactories.Load(name); ok {
|
||||
return true
|
||||
}
|
||||
if r.plgDir != "" {
|
||||
if fi, err := os.Stat(filepath.Join(r.plgDir, name)); err == nil && fi.IsDir() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *Registry) ListLoadedPlugins() []string { return r.List() }
|
||||
|
||||
func (r *Registry) ListDisabledPlugins() []sdk.DisabledPluginInfo {
|
||||
@ -692,6 +719,11 @@ func (r *Registry) ListDisabledPlugins() []sdk.DisabledPluginInfo {
|
||||
func (r *Registry) IsPluginDisabled(name string) bool { return r.isDisabled(name) }
|
||||
|
||||
func (r *Registry) DisablePlugin(name, by string) error {
|
||||
// 插件不存在(未安装):拒绝并返回错误,避免把不存在的插件写进 disabled_plugins。
|
||||
// 判断标准:已加载 / 已注册工厂(内置)/ 插件目录存在,任一命中视为已安装。
|
||||
if !r.pluginInstalled(name) {
|
||||
return fmt.Errorf("plugin %s not installed", name)
|
||||
}
|
||||
// Check not disabling self if running
|
||||
if r.cfgReg != nil {
|
||||
// If already disabled, no-op
|
||||
@ -731,7 +763,6 @@ func (r *Registry) DisablePlugin(name, by string) error {
|
||||
}
|
||||
|
||||
func (r *Registry) EnablePlugin(name string) error { return r.Enable(name) }
|
||||
|
||||
// StopAndUnload 停止并从注册表移除插件,但保留其配置表(config_<name>)。
|
||||
// 供插件更新/升级流程使用:换 so/文件不动配置,重装后配置原样生效。
|
||||
// 不执行 onRemove 回调(那是删除专用语义)。目录由调用方管理。
|
||||
|
||||
Reference in New Issue
Block a user