package httpapi import ( "context" "encoding/json" "fmt" "io" "net/http" "strings" "time" ) type infraStatusResponse struct { At time.Time `json:"at"` Sidecar map[string]any `json:"sidecar,omitempty"` SidecarError string `json:"sidecar_error,omitempty"` } func (s *Server) handleInfraStatus(w http.ResponseWriter, r *http.Request) { resp := infraStatusResponse{At: time.Now().UTC()} baseURL := strings.TrimRight(strings.TrimSpace(s.cfg.AIStatsSidecarURL), "/") if baseURL == "" { resp.SidecarError = "AI stats sidecar is not configured" writeJSON(w, http.StatusOK, resp) return } timeout := s.cfg.AIStatsTimeout if timeout <= 0 { timeout = 8 * time.Second } ctx, cancel := contextWithTimeout(r, timeout) defer cancel() sidecar, err := fetchAIStatsSidecar(ctx, baseURL, timeout) if err != nil { resp.SidecarError = err.Error() } else { resp.Sidecar = sidecar } writeJSON(w, http.StatusOK, resp) } func fetchAIStatsSidecar(ctx context.Context, baseURL string, timeout time.Duration) (map[string]any, error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, baseURL+"/stats", nil) if err != nil { return nil, err } client := &http.Client{Timeout: timeout} res, err := client.Do(req) if err != nil { return nil, err } defer res.Body.Close() if res.StatusCode >= 300 { body, _ := io.ReadAll(io.LimitReader(res.Body, 2048)) return nil, fmt.Errorf("sidecar HTTP %d: %s", res.StatusCode, strings.TrimSpace(string(body))) } var out map[string]any if err := json.NewDecoder(res.Body).Decode(&out); err != nil { return nil, err } return out, nil }