mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-23 02:18:06 +00:00
feat: 设备桥共享库 + CLI全能力补齐 + GUI omniparse/computeruse 重构
- 抽取设备桥 WS 协议层为共享库 (internal/devicebridge/client/)
- CLI 补齐 11 项 caps 能力(screensee/screensue/speakeruse/camerasue/...)
- GUI 新增 omniparse 能力(Windows UIA 窗口解析)
- GUI computeruse 改用 koffi 直接调用 user32.dll,不再依赖 PowerShell C# 编译
- GUI computeruse JSON 解析兼容非标准格式 {x:500,y:300}
- 新增 mock-server 用于本地测试设备桥协议
- 新增 GUI DLL 桥接模块 (devicebridge_dll.js)
This commit is contained in:
120
internal/devicebridge/client/cmdrouter.go
Normal file
120
internal/devicebridge/client/cmdrouter.go
Normal file
@ -0,0 +1,120 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// CmdRouter 命令路由器,支持按命令前缀分发到不同 handler。
|
||||
// 用于 CLI 和 GUI 根据能力类型注册不同的执行函数。
|
||||
type CmdRouter struct {
|
||||
mu sync.RWMutex
|
||||
prefixes map[string]CmdHandler
|
||||
default_ CmdHandler
|
||||
}
|
||||
|
||||
// NewCmdRouter 创建命令路由器。
|
||||
func NewCmdRouter() *CmdRouter {
|
||||
return &CmdRouter{
|
||||
prefixes: make(map[string]CmdHandler),
|
||||
}
|
||||
}
|
||||
|
||||
// Handle 注册匹配指定前缀的命令处理器。
|
||||
// 例如 Handle("homeagent-", homeagentHandler) 会处理所有 homeagent-* 命令。
|
||||
func (r *CmdRouter) Handle(prefix string, handler CmdHandler) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.prefixes[prefix] = handler
|
||||
}
|
||||
|
||||
// HandleDefault 注册默认命令处理器(无前缀匹配时使用)。
|
||||
func (r *CmdRouter) HandleDefault(handler CmdHandler) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.default_ = handler
|
||||
}
|
||||
|
||||
// Dispatch 分发命令到匹配的处理器。
|
||||
// 返回 true 表示已处理,false 表示无匹配。
|
||||
func (r *CmdRouter) Dispatch(reqID, command string) bool {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
// 先按前缀匹配
|
||||
for prefix, handler := range r.prefixes {
|
||||
if strings.HasPrefix(command, prefix) {
|
||||
handler(reqID, command)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 无前缀匹配,使用默认
|
||||
if r.default_ != nil {
|
||||
r.default_(reqID, command)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ===== 能力解析辅助 =====
|
||||
|
||||
// ParseHomeagentCmd 解析 homeagent-* 命令,返回能力名和参数。
|
||||
// 例如 "homeagent-screensue 5 你好" → ("screensue", "5 你好")
|
||||
// 也支持 "screensue 5 你好"(无前缀)
|
||||
func ParseHomeagentCmd(command string) (capability, args string) {
|
||||
cmd := strings.TrimSpace(command)
|
||||
// 去掉 homeagent- 前缀
|
||||
cmd = strings.TrimPrefix(cmd, "homeagent-")
|
||||
parts := strings.SplitN(cmd, " ", 2)
|
||||
capability = parts[0]
|
||||
if len(parts) > 1 {
|
||||
args = parts[1]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ParseJSONCmd 解析 JSON 格式的命令参数。
|
||||
// 例如 "computeruse {\"x\":100,\"y\":200,\"action\":\"click\"}"
|
||||
// 返回动作名和参数 map。
|
||||
func ParseJSONCmd(command string) (action string, params map[string]interface{}, err error) {
|
||||
cmd := strings.TrimSpace(command)
|
||||
// 去掉 homeagent- 前缀
|
||||
cmd = strings.TrimPrefix(cmd, "homeagent-")
|
||||
|
||||
idx := strings.IndexByte(cmd, '{')
|
||||
if idx < 0 {
|
||||
action = cmd
|
||||
return
|
||||
}
|
||||
action = strings.TrimSpace(cmd[:idx])
|
||||
jsonStr := cmd[idx:]
|
||||
if err = json.Unmarshal([]byte(jsonStr), ¶ms); err != nil {
|
||||
err = fmt.Errorf("parse json params: %w", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// BaseResult 构造基础命令结果。
|
||||
func BaseResult(reqID, status, output, errMsg string) map[string]interface{} {
|
||||
res := map[string]interface{}{
|
||||
"op": "cmd_result",
|
||||
"req_id": reqID,
|
||||
"status": status,
|
||||
}
|
||||
if output != "" {
|
||||
res["output"] = output
|
||||
}
|
||||
if errMsg != "" {
|
||||
res["error"] = errMsg
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// ResultJSON 序列化结果 map 为 JSON。
|
||||
func ResultJSON(res map[string]interface{}) string {
|
||||
b, _ := json.Marshal(res)
|
||||
return string(b)
|
||||
}
|
||||
Reference in New Issue
Block a user