package httpapi import ( "encoding/json" "net/http" "strconv" "strings" "github.com/dtoro/oikos/internal/execlog" "github.com/go-chi/chi/v5" "github.com/google/uuid" ) // serveExecutionLogs returns an execution's streamed command output. // // Registered as a carve-out rather than through the OpenAPI codegen for the // same reason as /activity/recent: it is a recency-ordered projection with no // schema type yet. Without this the execution_logs rows would be write-only — // which is the exact shape of the bugs this whole change set has been about. func (s *Server) serveExecutionLogs(w http.ResponseWriter, req *http.Request) { ctx := req.Context() rawID := chi.URLParam(req, "id") execID, err := uuid.Parse(rawID) if err != nil { writeProblem(w, req, http.StatusBadRequest, "invalid execution id", rawID) return } limit := 1000 if l := req.URL.Query().Get("limit"); l != "" { if n, perr := strconv.Atoi(l); perr == nil && n > 0 && n <= 5000 { limit = n } } chunks, err := execlog.Read(ctx, s.pool, execID, limit) if err != nil { writeProblem(w, req, http.StatusInternalServerError, "query failed", err.Error()) return } // Also hand back the concatenation, since that is what a caller tailing // output actually wants to render. var combined strings.Builder for _, c := range chunks { combined.WriteString(c.Chunk) } w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(map[string]any{ "items": chunks, "combined": combined.String(), }) }