package server import ( "net/http" "sync" "github.com/google/uuid" ) // GCLastRun records the result of the last GC run. type GCLastRun struct { StartedAt string `json:"started_at"` CompletedAt string `json:"completed_at,omitempty"` BlobsRemoved int `json:"blobs_removed"` BytesFreed int64 `json:"bytes_freed"` } // GCState tracks the current state of garbage collection. type GCState struct { mu sync.Mutex Running bool `json:"running"` LastRun *GCLastRun `json:"last_run,omitempty"` } type gcStatusResponse struct { Running bool `json:"running"` LastRun *GCLastRun `json:"last_run,omitempty"` } type gcTriggerResponse struct { ID string `json:"id"` } // AdminTriggerGCHandler handles POST /v1/gc. func AdminTriggerGCHandler(state *GCState) http.HandlerFunc { return func(w http.ResponseWriter, _ *http.Request) { state.mu.Lock() if state.Running { state.mu.Unlock() writeAdminError(w, http.StatusConflict, "garbage collection already running") return } state.Running = true state.mu.Unlock() // GC engine is Phase 9 -- for now, just mark as running and return. // The actual GC goroutine will be wired up in Phase 9. gcID := uuid.New().String() writeJSON(w, http.StatusAccepted, gcTriggerResponse{ID: gcID}) } } // AdminGCStatusHandler handles GET /v1/gc/status. func AdminGCStatusHandler(state *GCState) http.HandlerFunc { return func(w http.ResponseWriter, _ *http.Request) { state.mu.Lock() resp := gcStatusResponse{ Running: state.Running, LastRun: state.LastRun, } state.mu.Unlock() writeJSON(w, http.StatusOK, resp) } }