mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-03 07:43:58 +00:00
fix(webui): 设置接口不再吐内部数据;--webui 覆盖生效;端口占用不再静默成功
三处实测确认的缺陷:
① 设置接口整块吐出聊天记录
plugin.webui.chathistory 是 webui 自己持久化的整段聊天记录(生产实例
实测 5,176,016 字节),躺在插件配置表里被设置接口当普通配置项整块返回,
前端还会把它渲染成一个巨大的文本框。
修复:GET 跳过该键(按插件+键精确判定),PUT 直接 400,避免误改。
② CLI --webui 与 webui.listen_addr 一直是死配置
内核原本在插件加载前写 settings["addr"],但那时 config_<name> 表还没建
(表只在插件注册 def 时创建),PluginSettings.Set 的 INSERT 失败,而错误被
"_ =" 忽略了;随后插件 Start 里 RegisterDef 才建表并写入默认 :8080。
实测:传 "-webui 127.0.0.1:18099" 仍然监听 :8080。
修复:覆盖值改由插件自己接收(webui.SetListenOverride,loadPlugins 前调用),
优先级 CLI > webui.listen_addr(非默认值才算显式配置)> settings["addr"]。
实测修复后:"-webui 127.0.0.1:18099" 正确监听 18099,与生产的 :8080 并存。
③ 端口被占时 webui 静默死亡
Start 在后台 goroutine 里 ListenAndServe,先打印 "listening on" 再尝试绑定,
失败只留一行日志,Start 永远返回 nil → 插件仍被当成加载成功。
修复:net.Listen 同步做,失败即返回 error(交给加载器/守护),
成功后才起 Serve,并打印真实绑定地址。
A/B 实测(两个实例都撞生产的 :8080):
修复前:"listening on :8080" + "server error: address already in use" + LOADED: webui
修复后:"[plugin] start webui: webui: 监听 :8080 失败: ...",不再有 LOADED: webui
效果实测(同一实例,先注入 5,271,690 字节 chathistory):
GET /api/v1/settings 8,244,108 → 28,652 字节(约 1/288)
meta 条数 5,208 → 105,幻影键 0 条
设置页仍正常:?prefix=plugin.webui 返回 8 条 def;普通键 PUT 落库;
校验:GET/PUT 内部键被拒;-webui 覆盖真实生效。
新增测试:TestSettingsNoCrossPluginLeak(跨插件泄漏/幻影键/chathistory 读写)、
TestListenOverrideAndBindFailure(覆盖生效 + 端口占用必须报错)、
TestResolveListenAddrPrecedence(优先级)。
This commit is contained in:
@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -52,6 +53,35 @@ var webFilesDir string
|
||||
// handleChatFile 落盘、handleUploads 下载共用;参考 qq 插件 files_dir 收文件设计。
|
||||
var uploadsDir string
|
||||
|
||||
// listenOverride 是内核在插件加载前给出的监听地址覆盖(CLI --webui,
|
||||
// 或核心配置 webui.listen_addr 被显式改成非默认值)。
|
||||
//
|
||||
// 为什么需要这个旁路:内核曾在插件加载前写 settings["addr"],但那时
|
||||
// config_<name> 表还没建,PluginSettings.Set 的 INSERT 会失败且错误被忽略;
|
||||
// 随后 plugin Start 里 RegisterDef 才建表并写入默认值 :8080。结果是
|
||||
// CLI --webui 与 webui.listen_addr **一直是死配置**。这里改为插件自己
|
||||
// 接受一个显式覆盖值,优先级高于 settings["addr"](后者是 Web 设置页的持久值)。
|
||||
var listenOverride string
|
||||
|
||||
// SetListenOverride 设置监听地址覆盖(空值表示不覆盖)。
|
||||
// 由 cmd/homed 在插件加载前调用,见 resolveWebUIOverride。
|
||||
func SetListenOverride(addr string) {
|
||||
listenOverride = strings.TrimSpace(addr)
|
||||
}
|
||||
|
||||
// resolveListenAddr 决定最终监听地址:覆盖值 > 插件设置 > 内置默认。
|
||||
// 抽成纯函数是为了能被单测直接钉住优先级。
|
||||
func resolveListenAddr(setting string) string {
|
||||
addr := ":8080"
|
||||
if setting != "" {
|
||||
addr = setting
|
||||
}
|
||||
if listenOverride != "" {
|
||||
addr = listenOverride
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
// stageWebFile 把 agent 要发送的本地文件拷贝到 webui_files 中转目录,
|
||||
// 返回可下载 URL 路径与字节数。image/file 的 payload 支持本地路径或 http(s) URL
|
||||
// (URL 直接透传给前端,不落盘)。文件名用随机 UUID 防路径猜测,扩展名保留自源文件。
|
||||
@ -146,6 +176,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
||||
addr = s2
|
||||
}
|
||||
}
|
||||
addr = resolveListenAddr(addr)
|
||||
|
||||
// 能力位 7 = CapText|CapFile|CapImage;旧值 1 仅文本,agent 无法向 webui 发文件/图片
|
||||
// 入站通道:webui(控制台对话)与 http(外部 HTTP 注入),都由本插件注入输入。
|
||||
@ -238,13 +269,22 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
||||
|
||||
// 最外层套 logged 中间件:记录每个请求的来源 IP / 方法 / 路径 / 认证方式 / 状态码。
|
||||
// 用于排查“谁调用了什么接口”(如插件禁用等变更操作)。
|
||||
p.server = &http.Server{Addr: addr, Handler: p.handler.logged(p.mux)}
|
||||
//
|
||||
// 同步 Listen:端口被占时必须**在这里**失败并把错误交回加载器,
|
||||
// 而不是“后台 goroutine 里报一行日志、插件仍被当成加载成功”。
|
||||
// 修复前 Start 总是返回 nil,于是 :8080 被占时 WebUI 静默死亡,
|
||||
// 调用方看不到任何失败信号。
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("webui: 监听 %s 失败: %w", addr, err)
|
||||
}
|
||||
p.server = &http.Server{Handler: p.handler.logged(p.mux)}
|
||||
go func() {
|
||||
log.Printf("[webui] HTTP server listening on %s", addr)
|
||||
if err := p.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
if err := p.server.Serve(ln); err != nil && err != http.ErrServerClosed {
|
||||
log.Printf("[webui] server error: %v", err)
|
||||
}
|
||||
}()
|
||||
log.Printf("[webui] HTTP server listening on %s", ln.Addr())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user