feat: document and surface node p2p telemetry

This commit is contained in:
lpf
2026-03-09 00:56:32 +08:00
parent f441972c56
commit c0fe977bce
9 changed files with 571 additions and 50 deletions

View File

@@ -1075,12 +1075,45 @@ func (s *Server) webUINodesPayload(ctx context.Context) map[string]interface{} {
p2p = s.nodeP2PStatus()
}
return map[string]interface{}{
"nodes": list,
"trees": s.buildNodeAgentTrees(ctx, list),
"p2p": p2p,
"nodes": list,
"trees": s.buildNodeAgentTrees(ctx, list),
"p2p": p2p,
"dispatches": s.webUINodesDispatchPayload(12),
}
}
func (s *Server) webUINodesDispatchPayload(limit int) []map[string]interface{} {
workspace := strings.TrimSpace(s.workspacePath)
if workspace == "" {
return []map[string]interface{}{}
}
path := filepath.Join(workspace, "memory", "nodes-dispatch-audit.jsonl")
data, err := os.ReadFile(path)
if err != nil {
return []map[string]interface{}{}
}
lines := strings.Split(strings.TrimSpace(string(data)), "\n")
if len(lines) == 1 && strings.TrimSpace(lines[0]) == "" {
return []map[string]interface{}{}
}
out := make([]map[string]interface{}, 0, limit)
for i := len(lines) - 1; i >= 0; i-- {
line := strings.TrimSpace(lines[i])
if line == "" {
continue
}
row := map[string]interface{}{}
if err := json.Unmarshal([]byte(line), &row); err != nil {
continue
}
out = append(out, row)
if limit > 0 && len(out) >= limit {
break
}
}
return out
}
func (s *Server) webUISessionsPayload() map[string]interface{} {
sessionsDir := filepath.Join(filepath.Dir(s.workspacePath), "agents", "main", "sessions")
_ = os.MkdirAll(sessionsDir, 0755)
@@ -1520,48 +1553,9 @@ func (s *Server) handleWebUINodes(w http.ResponseWriter, r *http.Request) {
}
switch r.Method {
case http.MethodGet:
list := []nodes.NodeInfo{}
if s.mgr != nil {
list = s.mgr.List()
}
host, _ := os.Hostname()
local := nodes.NodeInfo{ID: "local", Name: "local", Endpoint: "gateway", Version: gatewayBuildVersion(), LastSeenAt: time.Now(), Online: true}
if strings.TrimSpace(host) != "" {
local.Name = host
}
if ip := detectLocalIP(); ip != "" {
local.Endpoint = ip
}
hostLower := strings.ToLower(strings.TrimSpace(host))
matched := false
for i := range list {
id := strings.ToLower(strings.TrimSpace(list[i].ID))
name := strings.ToLower(strings.TrimSpace(list[i].Name))
if id == "local" || name == "local" || (hostLower != "" && name == hostLower) {
// Always keep local node green/alive with latest ip+version
list[i].ID = "local"
list[i].Online = true
list[i].Version = local.Version
if strings.TrimSpace(local.Endpoint) != "" {
list[i].Endpoint = local.Endpoint
}
if strings.TrimSpace(local.Name) != "" {
list[i].Name = local.Name
}
list[i].LastSeenAt = time.Now()
matched = true
break
}
}
if !matched {
list = append([]nodes.NodeInfo{local}, list...)
}
trees := s.buildNodeAgentTrees(r.Context(), list)
p2p := map[string]interface{}{}
if s.nodeP2PStatus != nil {
p2p = s.nodeP2PStatus()
}
_ = json.NewEncoder(w).Encode(map[string]interface{}{"ok": true, "nodes": list, "trees": trees, "p2p": p2p})
payload := s.webUINodesPayload(r.Context())
payload["ok"] = true
_ = json.NewEncoder(w).Encode(payload)
case http.MethodPost:
var body struct {
Action string `json:"action"`

View File

@@ -433,6 +433,14 @@ func TestHandleWebUINodesIncludesP2PSummary(t *testing.T) {
t.Parallel()
srv := NewServer("127.0.0.1", 0, "", nodes.NewManager())
workspace := t.TempDir()
srv.SetWorkspacePath(workspace)
if err := os.MkdirAll(filepath.Join(workspace, "memory"), 0755); err != nil {
t.Fatalf("mkdir memory: %v", err)
}
if err := os.WriteFile(filepath.Join(workspace, "memory", "nodes-dispatch-audit.jsonl"), []byte("{\"node\":\"edge-b\",\"used_transport\":\"webrtc\",\"fallback_from\":\"\",\"duration_ms\":12}\n"), 0644); err != nil {
t.Fatalf("write audit: %v", err)
}
srv.SetNodeP2PStatusHandler(func() map[string]interface{} {
return map[string]interface{}{
"enabled": true,
@@ -455,4 +463,8 @@ func TestHandleWebUINodesIncludesP2PSummary(t *testing.T) {
if p2p == nil || p2p["transport"] != "webrtc" {
t.Fatalf("expected p2p summary, got %+v", body)
}
dispatches, _ := body["dispatches"].([]interface{})
if len(dispatches) != 1 {
t.Fatalf("expected dispatch audit rows, got %+v", body["dispatches"])
}
}