// Package api — HTTP-сервер монолита: маршруты, CORS, health. package api import ( "log/slog" "net/http" "github.com/gorilla/mux" "gitea.services.ngcloud.ru/Nail/IoT/internal/service/api/handler" "gitea.services.ngcloud.ru/Nail/IoT/internal/service/api/middleware" ) // corsMiddleware добавляет CORS-заголовки (консоль и API на одном домене платформы). func corsMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type") if r.Method == http.MethodOptions { w.WriteHeader(http.StatusNoContent) return } next.ServeHTTP(w, r) }) } // NewRouter собирает все маршруты сервиса. func NewRouter(h *handler.Handler, log *slog.Logger, authTestMode bool, version string) http.Handler { r := mux.NewRouter() // Health — для платформенных проверок контейнера. r.HandleFunc("/health", healthHandler(version)).Methods(http.MethodGet) r.HandleFunc("/healthz", healthHandler(version)).Methods(http.MethodGet) // UI — публичные страницы (без данных). r.HandleFunc("/console", ServeIoTConsole).Methods(http.MethodGet) r.HandleFunc("/iot-admin", ServeIoTAdmin).Methods(http.MethodGet) // Админ-статистика — свой Bearer-токен. r.HandleFunc("/iot-admin/stats", h.AdminStats).Methods(http.MethodGet) // MQTT auth/acl — для EMQX, без JWT. r.HandleFunc("/internal/mqtt/auth", h.MQTTAuth).Methods(http.MethodPost) r.HandleFunc("/internal/mqtt/acl", h.MQTTAcl).Methods(http.MethodPost) // /v1 — под JWT. v1 := r.PathPrefix("/v1").Subrouter() v1.HandleFunc("/namespaces/{namespace}/iot/devices", h.ListIoTDevices).Methods(http.MethodGet) v1.HandleFunc("/namespaces/{namespace}/iot/devices", h.CreateIoTDevice).Methods(http.MethodPost) v1.HandleFunc("/namespaces/{namespace}/iot/devices/{name}", h.GetIoTDevice).Methods(http.MethodGet) v1.HandleFunc("/namespaces/{namespace}/iot/devices/{name}", h.DeleteIoTDevice).Methods(http.MethodDelete) v1.HandleFunc("/namespaces/{namespace}/iot/devices/{name}", h.UpdateIoTDevice).Methods(http.MethodPatch) v1.HandleFunc("/namespaces/{namespace}/iot/telemetry", h.ListIoTTelemetry).Methods(http.MethodGet) v1.Use(func(next http.Handler) http.Handler { return middleware.Auth(authTestMode, log, next) }) return corsMiddleware(middleware.Logging(log, r)) } // healthHandler отдаёт статус сервиса и версию (для платформы). func healthHandler(version string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte(`{"status":"ok","version":"` + version + `"}`)) } }