// Создано: 2026-04-05 // iot_telemetry_handler.go — REST handler для чтения IoT телеметрии. // // Endpoint: // GET /v1/namespaces/{namespace}/iot/telemetry?device={id}&limit={n} // // Авторизация: Bearer JWT → namespace validation (как все /v1/ маршруты). // Данные берутся из per-tenant Postgres DB через IoTPostgresStore. // Если IoTPG не инициализирован (IOT_PG_DSN не задан) — возвращает 503. package handler import ( "net/http" "strconv" "github.com/gorilla/mux" "gitea.services.ngcloud.ru/Nail/IoT/internal/storage/iotpg" ) // ListIoTTelemetry обрабатывает GET /v1/namespaces/{namespace}/iot/telemetry. // Параметры: device (опционально), limit (default 50, max 1000). func (h *Handler) ListIoTTelemetry(w http.ResponseWriter, r *http.Request) { if h.IoTPG == nil { writeJSON(w, http.StatusServiceUnavailable, errResp("IoT telemetry storage not configured")) return } ns := mux.Vars(r)["namespace"] deviceID := r.URL.Query().Get("device_id") limit := 50 if ls := r.URL.Query().Get("limit"); ls != "" { if n, err := strconv.Atoi(ls); err == nil && n > 0 { limit = n } } rows, err := h.IoTPG.QueryTelemetry(r.Context(), ns, deviceID, limit, 0) if err != nil { h.Log.Error("query IoT telemetry", "namespace", ns, "device", deviceID, "err", err) writeJSON(w, http.StatusInternalServerError, errResp("failed to query telemetry")) return } // Возвращаем пустой массив вместо null — удобнее для JS if rows == nil { rows = []iotpg.TelemetryRow{} } writeJSON(w, http.StatusOK, map[string]any{ "items": rows, "count": len(rows), }) }