package containerapi import ( "context" "encoding/json" "errors" "net/http" "strconv" "strings" "time" "github.com/itworx/pulse/internal/auth" "github.com/itworx/pulse/internal/container" "github.com/itworx/pulse/internal/problem" ) type Handler struct { Provider interface { Snapshot(context.Context) (container.Snapshot, error) } Limits container.Limits } func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet || (r.URL.Path != "/api/v1/containers" && !strings.HasPrefix(r.URL.Path, "/api/v1/containers/")) { http.NotFound(w, r) return } if _, ok := auth.PrincipalFromContext(r.Context()); !ok { problem.Write(w, r, http.StatusUnauthorized, "UNAUTHORIZED", "Authentication required", "Authentication is required to read containers.", nil) return } snapshot, err := h.snapshot(r) if err != nil { if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { return } problem.Write(w, r, http.StatusServiceUnavailable, "CONTAINERS_UNAVAILABLE", "Containers not available", "Containergegevens konden niet worden gelezen.", nil) return } if r.URL.Path != "/api/v1/containers" { id := strings.TrimPrefix(r.URL.Path, "/api/v1/containers/") for _, item := range snapshot.Containers { if item.ID == id { writeJSON(w, struct { Source container.Source `json:"source"` Container container.Container `json:"container"` }{Source: snapshot.Source, Container: item}) return } } http.NotFound(w, r) return } limit := 50 if value := r.URL.Query().Get("limit"); value != "" { parsed, parseErr := strconv.Atoi(value) if parseErr != nil { problem.Write(w, r, http.StatusBadRequest, "CONTAINER_QUERY_INVALID", "Invalid container query", "De containerlimiet is ongeldig.", nil) return } limit = parsed } order := r.URL.Query().Get("sort") if order == "" { order = "name" } page, err := container.FilteredPage(snapshot, limit, r.URL.Query().Get("after"), h.Limits, r.URL.Query().Get("q"), r.URL.Query().Get("state"), r.URL.Query().Get("health"), order) if err != nil { problem.Write(w, r, http.StatusBadRequest, "CONTAINER_QUERY_INVALID", "Invalid container query", "De containerlimiet of cursor is ongeldig.", nil) return } writeJSON(w, page) } func (h Handler) snapshot(r *http.Request) (container.Snapshot, error) { if h.Provider == nil { return container.UnknownSnapshot(time.Now().UTC(), "container", "agent", "source_unavailable"), nil } return h.Provider.Snapshot(r.Context()) } func writeJSON(w http.ResponseWriter, value any) { w.Header().Set("Content-Type", "application/json") w.Header().Set("Cache-Control", "private, max-age=5") _ = json.NewEncoder(w).Encode(value) }