package api import ( "net/http" "strconv" "time" "browser.local/platform/domain" "browser.local/platform/dto" ) // runMetricBatchIngest godoc // @Summary Ingest bounded Run metric samples // @Description Persists a signed bounded metric batch for server instances owned by the Run endpoint. // @Tags run-metrics // @Accept json // @Produce json // @Param body body dto.MetricBatchIngestRequest true "Metric batch" // @Success 200 {object} dto.MetricBatchIngestResponse // @Failure 400 {object} dto.ErrorResponse // @Failure 401 {object} dto.ErrorResponse // @Router /api/v1/run/metrics/batches [post] func (h *coreHandlers) runMetricBatchIngest(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeMethodNotAllowed(w, http.MethodPost) return } request, err := decodeJSON[dto.MetricBatchIngestRequest](r) if err != nil { writeDecodeError(w, err) return } result, err := h.core.IngestMetricBatch(request.ToDomain()) if err != nil { writeServiceError(w, err) return } writeJSON(w, http.StatusOK, dto.MetricBatchIngestFromDomain(result)) } // metricHistory godoc // @Summary Query persisted server metric samples // @Description Returns an owner-authorized bounded metric history without machine credentials or fencing state. // @Tags metrics // @Produce json // @Success 200 {object} dto.MetricSampleListResponse // @Failure 401 {object} dto.ErrorResponse // @Failure 403 {object} dto.ErrorResponse // @Router /api/v1/metrics/server-instances/history [get] func (h *coreHandlers) metricHistory(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeMethodNotAllowed(w, http.MethodGet) return } limit, _ := strconv.Atoi(r.URL.Query().Get("limit")) items, err := h.core.ListMetricSamplesForSession(bearerToken(r), domain.MetricSampleFilter{ServerInstanceID: r.URL.Query().Get("serverInstanceId"), After: parseQueryTime(r.URL.Query().Get("after")), Before: parseQueryTime(r.URL.Query().Get("before")), Limit: limit}) if err != nil { writeServiceError(w, err) return } writeJSON(w, http.StatusOK, dto.MetricSampleListFromDomain(items)) } // backups godoc // @Summary Create or list durable backup records // @Description Creates or returns owner-authorized backup metadata and recovery state. // @Tags backups // @Accept json // @Produce json // @Success 200 {object} dto.BackupListResponse // @Success 201 {object} dto.BackupResponse // @Failure 401 {object} dto.ErrorResponse // @Failure 403 {object} dto.ErrorResponse // @Router /api/v1/backups [get] // @Router /api/v1/backups [post] func (h *coreHandlers) backups(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: items, err := h.core.ListBackupsForSession(bearerToken(r), domain.BackupFilter{ServerInstanceID: r.URL.Query().Get("serverInstanceId"), State: domain.BackupState(r.URL.Query().Get("state"))}) if err != nil { writeServiceError(w, err) return } writeJSON(w, http.StatusOK, dto.BackupListFromDomain(items)) case http.MethodPost: request, err := decodeJSON[dto.BackupCreateRequest](r) if err != nil { writeDecodeError(w, err) return } record, err := h.core.CreateBackupForSession(bearerToken(r), request.ToDomain()) if err != nil { writeServiceError(w, err) return } writeJSON(w, http.StatusCreated, dto.BackupFromDomain(record)) default: writeMethodNotAllowed(w, "GET, POST") } } // backupDetail godoc // @Summary Get one durable backup record // @Tags backups // @Produce json // @Success 200 {object} dto.BackupResponse // @Failure 401 {object} dto.ErrorResponse // @Failure 403 {object} dto.ErrorResponse // @Failure 404 {object} dto.ErrorResponse // @Router /api/v1/backups/{id} [get] func (h *coreHandlers) backupDetail(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeMethodNotAllowed(w, http.MethodGet) return } record, err := h.core.GetBackupForSession(bearerToken(r), r.PathValue("id")) if err != nil { writeServiceError(w, err) return } writeJSON(w, http.StatusOK, dto.BackupFromDomain(record)) } func parseQueryTime(value string) time.Time { parsed, _ := time.Parse(time.RFC3339Nano, value) return parsed }