mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-05-05 15:17:28 +08:00
persist node state to shared file for gateway/cli visibility
This commit is contained in:
@@ -88,6 +88,7 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers
|
|||||||
toolsRegistry.Register(tools.NewProcessTool(processManager))
|
toolsRegistry.Register(tools.NewProcessTool(processManager))
|
||||||
nodesManager := nodes.DefaultManager()
|
nodesManager := nodes.DefaultManager()
|
||||||
nodesManager.SetAuditPath(filepath.Join(workspace, "memory", "nodes-audit.jsonl"))
|
nodesManager.SetAuditPath(filepath.Join(workspace, "memory", "nodes-audit.jsonl"))
|
||||||
|
nodesManager.SetStatePath(filepath.Join(workspace, "memory", "nodes-state.json"))
|
||||||
nodesManager.Upsert(nodes.NodeInfo{ID: "local", Name: "local", Capabilities: nodes.Capabilities{Run: true, Invoke: true, Model: true, Camera: true, Screen: true, Location: true, Canvas: true}, Models: []string{"local-sim"}, Online: true})
|
nodesManager.Upsert(nodes.NodeInfo{ID: "local", Name: "local", Capabilities: nodes.Capabilities{Run: true, Invoke: true, Model: true, Camera: true, Screen: true, Location: true, Canvas: true}, Models: []string{"local-sim"}, Online: true})
|
||||||
nodesManager.RegisterHandler("local", func(req nodes.Request) nodes.Response {
|
nodesManager.RegisterHandler("local", func(req nodes.Request) nodes.Response {
|
||||||
switch req.Action {
|
switch req.Action {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ type Manager struct {
|
|||||||
handlers map[string]Handler
|
handlers map[string]Handler
|
||||||
ttl time.Duration
|
ttl time.Duration
|
||||||
auditPath string
|
auditPath string
|
||||||
|
statePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultManager = NewManager()
|
var defaultManager = NewManager()
|
||||||
@@ -39,6 +40,13 @@ func (m *Manager) SetAuditPath(path string) {
|
|||||||
m.auditPath = strings.TrimSpace(path)
|
m.auditPath = strings.TrimSpace(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) SetStatePath(path string) {
|
||||||
|
m.mu.Lock()
|
||||||
|
m.statePath = strings.TrimSpace(path)
|
||||||
|
m.mu.Unlock()
|
||||||
|
m.loadState()
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Manager) Upsert(info NodeInfo) {
|
func (m *Manager) Upsert(info NodeInfo) {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
@@ -60,15 +68,21 @@ func (m *Manager) Upsert(info NodeInfo) {
|
|||||||
}
|
}
|
||||||
m.nodes[info.ID] = info
|
m.nodes[info.ID] = info
|
||||||
m.mu.Unlock()
|
m.mu.Unlock()
|
||||||
|
m.saveState()
|
||||||
m.appendAudit("upsert", info.ID, map[string]interface{}{"existed": existed, "endpoint": info.Endpoint, "version": info.Version})
|
m.appendAudit("upsert", info.ID, map[string]interface{}{"existed": existed, "endpoint": info.Endpoint, "version": info.Version})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) MarkOffline(id string) {
|
func (m *Manager) MarkOffline(id string) {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
changed := false
|
||||||
if n, ok := m.nodes[id]; ok {
|
if n, ok := m.nodes[id]; ok {
|
||||||
n.Online = false
|
n.Online = false
|
||||||
m.nodes[id] = n
|
m.nodes[id] = n
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
m.mu.Unlock()
|
||||||
|
if changed {
|
||||||
|
m.saveState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +222,9 @@ func (m *Manager) reaperLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.mu.Unlock()
|
m.mu.Unlock()
|
||||||
|
if len(offlined) > 0 {
|
||||||
|
m.saveState()
|
||||||
|
}
|
||||||
for _, id := range offlined {
|
for _, id := range offlined {
|
||||||
m.appendAudit("offline_ttl", id, nil)
|
m.appendAudit("offline_ttl", id, nil)
|
||||||
}
|
}
|
||||||
@@ -234,3 +251,47 @@ func (m *Manager) appendAudit(event, nodeID string, data map[string]interface{})
|
|||||||
defer f.Close()
|
defer f.Close()
|
||||||
_, _ = f.Write(append(b, '\n'))
|
_, _ = f.Write(append(b, '\n'))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) saveState() {
|
||||||
|
m.mu.RLock()
|
||||||
|
path := m.statePath
|
||||||
|
items := make([]NodeInfo, 0, len(m.nodes))
|
||||||
|
for _, n := range m.nodes {
|
||||||
|
items = append(items, n)
|
||||||
|
}
|
||||||
|
m.mu.RUnlock()
|
||||||
|
if strings.TrimSpace(path) == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = os.MkdirAll(filepath.Dir(path), 0755)
|
||||||
|
b, err := json.MarshalIndent(items, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = os.WriteFile(path, b, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) loadState() {
|
||||||
|
m.mu.RLock()
|
||||||
|
path := m.statePath
|
||||||
|
m.mu.RUnlock()
|
||||||
|
if strings.TrimSpace(path) == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var items []NodeInfo
|
||||||
|
if err := json.Unmarshal(b, &items); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.mu.Lock()
|
||||||
|
for _, n := range items {
|
||||||
|
if strings.TrimSpace(n.ID) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m.nodes[n.ID] = n
|
||||||
|
}
|
||||||
|
m.mu.Unlock()
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user