package nodedispatch import ( "context" "encoding/json" "fmt" "io" "net/http" "strings" "evobgp/internal/birdfmt" "evobgp/internal/store" ) // BirdProtocolsResult is agent birdc scrape outcome. type BirdProtocolsResult struct { SpeakerID string `json:"speaker_id,omitempty"` Sessions []birdfmt.BGPSession `json:"sessions"` Error string `json:"error,omitempty"` } // FetchBirdProtocols GETs /v1/agent/bird/protocols on a replica agent. func FetchBirdProtocols(ctx context.Context, sp *store.Speaker, opts Options) BirdProtocolsResult { res := BirdProtocolsResult{} if sp != nil { res.SpeakerID = sp.ID } if sp == nil { res.Error = "nil speaker" return res } meta := store.ParseSpeakerMeta(sp.MetaJSON) url := store.AgentBirdProtocolsURL(meta) if url == "" { res.Error = "agent_domain not configured" return res } secret := strings.TrimSpace(meta.AgentSecret) if secret == "" { res.Error = "agent_secret missing" return res } req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { res.Error = err.Error() return res } req.Header.Set("Authorization", "Bearer "+secret) resp, err := opts.client().Do(req) if err != nil { res.Error = err.Error() return res } defer func() { _ = resp.Body.Close() }() b, _ := io.ReadAll(resp.Body) if resp.StatusCode < 200 || resp.StatusCode >= 300 { res.Error = fmt.Sprintf("HTTP %d: %s", resp.StatusCode, strings.TrimSpace(string(b))) return res } var out struct { Sessions []birdfmt.BGPSession `json:"sessions"` } if err := json.Unmarshal(b, &out); err != nil { res.Error = err.Error() return res } res.Sessions = out.Sessions return res }