// admin.go — статистика для страницы администратора. // // Endpoint: GET /iot-admin/stats (Bearer ADMIN_STATS_TOKEN). // Источники: PostgreSQL (iotpg), shared-SQS (атрибуты очереди), рантайм процесса. // k8s-статусы подов убраны — компоненты теперь в одном процессе. package handler import ( "context" "net/http" "strings" "time" ) // AdminStats — GET /iot-admin/stats. func (h *Handler) AdminStats(w http.ResponseWriter, r *http.Request) { if h.Cfg.AdminStatsToken == "" { writeJSON(w, http.StatusServiceUnavailable, errResp("admin stats not configured: ADMIN_STATS_TOKEN not set")) return } authHeader := r.Header.Get("Authorization") if !strings.HasPrefix(authHeader, "Bearer ") || strings.TrimPrefix(authHeader, "Bearer ") != h.Cfg.AdminStatsToken { writeJSON(w, http.StatusUnauthorized, errResp("unauthorized")) return } ctx, cancel := context.WithTimeout(r.Context(), 15*time.Second) defer cancel() result := map[string]any{ "collected_at": time.Now().UTC(), } // PostgreSQL: статистика по всем tenant (как в старом коде). if h.IoTPG != nil { pgStats, err := h.IoTPG.GetAdminStats(ctx) if err != nil { result["postgres"] = map[string]any{"reachable": false, "error": err.Error()} } else { result["postgres"] = pgStats } } else { result["postgres"] = map[string]any{"reachable": false, "error": "IoTPG not configured"} } // SQS: approximate counts очереди телеметрии. result["sqs"] = h.collectSQSStats(ctx) // Рантайм процесса (вместо статусов k8s-подов). result["runtime"] = map[string]any{ "version": h.Version, "uptime_sec": int64(time.Since(h.StartedAt).Seconds()), "started_at": h.StartedAt.UTC().Format(time.RFC3339), } writeJSON(w, http.StatusOK, result) }