feat: add execution history queries and preserve bounded JSON payloads

This commit is contained in:
2026-09-17 14:55:23 +08:00
parent da123bba69
commit 4d4b2e9f7d
32 changed files with 1461 additions and 28 deletions

View File

@@ -0,0 +1,65 @@
package httpserver
import (
"net/http"
"net/url"
"strconv"
"git.yuntuo.hk/k2safe/orbit/internal/fault"
core "git.yuntuo.hk/k2safe/orbit/model"
"git.yuntuo.hk/k2safe/orbit/platform/auth"
"git.yuntuo.hk/k2safe/orbit/pulse/service"
)
func historyQuery(r *http.Request, paged bool) (service.HistoryPageInput, error) {
var in service.HistoryPageInput
q, err := url.ParseQuery(r.URL.RawQuery)
if err != nil {
return in, fault.Invalid("invalid query encoding")
}
for key, values := range q {
if !paged || len(values) != 1 || (key != "limit" && key != "cursor") {
return in, fault.Invalid("invalid history query parameter")
}
}
if q.Has("limit") {
in.Limit, err = strconv.Atoi(q.Get("limit"))
if err != nil || in.Limit < 1 {
return in, fault.Invalid("invalid history limit")
}
}
in.Cursor = q.Get("cursor")
return in, nil
}
func registerHistory(mux *http.ServeMux, s *service.Service) {
mux.HandleFunc("GET /v1/tasks/{task}/attempts", wrap(func(r *http.Request, t auth.Token) (any, int, error) {
in, err := historyQuery(r, true)
if err != nil {
return nil, 0, err
}
out, err := s.ListTaskAttempts(r.Context(), t, core.ID(r.PathValue("task")), in)
return out, 200, err
}))
mux.HandleFunc("GET /v1/tasks/{task}/attempts/{attempt}", wrap(func(r *http.Request, t auth.Token) (any, int, error) {
if _, err := historyQuery(r, false); err != nil {
return nil, 0, err
}
out, err := s.GetTaskAttempt(r.Context(), t, core.ID(r.PathValue("task")), core.ID(r.PathValue("attempt")))
return out, 200, err
}))
mux.HandleFunc("GET /v1/tasks/{task}/attempts/{attempt}/evidence", wrap(func(r *http.Request, t auth.Token) (any, int, error) {
in, err := historyQuery(r, true)
if err != nil {
return nil, 0, err
}
out, err := s.ListAttemptEvidence(r.Context(), t, core.ID(r.PathValue("task")), core.ID(r.PathValue("attempt")), in)
return out, 200, err
}))
mux.HandleFunc("GET /v1/tasks/{task}/attempts/{attempt}/evidence/{evidence}", wrap(func(r *http.Request, t auth.Token) (any, int, error) {
if _, err := historyQuery(r, false); err != nil {
return nil, 0, err
}
out, err := s.GetAttemptEvidence(r.Context(), t, core.ID(r.PathValue("task")), core.ID(r.PathValue("attempt")), core.ID(r.PathValue("evidence")))
return out, 200, err
}))
}

View File

@@ -32,6 +32,7 @@ func New(addr string, ready Checker, tasks ...*service.Service) *http.Server {
})
if len(tasks) > 0 && tasks[0] != nil {
registerTasks(mux, tasks[0])
registerHistory(mux, tasks[0])
}
return &http.Server{Addr: addr, Handler: mux, ReadHeaderTimeout: 5 * time.Second, ReadTimeout: 10 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, MaxHeaderBytes: 16 << 10}
}

View File

@@ -17,6 +17,7 @@ import (
"git.yuntuo.hk/k2safe/orbit/internal/fault"
"git.yuntuo.hk/k2safe/orbit/internal/jsonvalue"
"git.yuntuo.hk/k2safe/orbit/internal/jsonwire"
core "git.yuntuo.hk/k2safe/orbit/model"
"git.yuntuo.hk/k2safe/orbit/platform/auth"
pulse "git.yuntuo.hk/k2safe/orbit/pulse/model"
@@ -149,7 +150,7 @@ func wrap(next endpoint) http.HandlerFunc {
}
}
func writeJSON(w http.ResponseWriter, status int, body any) {
raw, err := json.Marshal(body)
raw, err := jsonwire.Marshal(body)
if err != nil {
status = 503
raw = []byte(`{"error":{"code":"UNAVAILABLE","message":"operation unavailable"}}`)

View File

@@ -13,6 +13,7 @@ import (
"git.yuntuo.hk/k2safe/orbit/internal/fault"
"git.yuntuo.hk/k2safe/orbit/internal/jsonvalue"
"git.yuntuo.hk/k2safe/orbit/internal/jsonwire"
core "git.yuntuo.hk/k2safe/orbit/model"
"git.yuntuo.hk/k2safe/orbit/platform/auth"
"git.yuntuo.hk/k2safe/orbit/pulse/worker"
@@ -154,7 +155,7 @@ func (h *WorkerHub) ServeHTTP(w http.ResponseWriter, r *http.Request) {
_ = writeWorkerFrame(ctx, conn, workerFrame{Version: "1", Type: "error", MessageID: requestID, ReplyTo: hello.MessageID, Error: publicWorkerError(err)})
return
}
welcomeRaw, err := json.Marshal(welcome)
welcomeRaw, err := jsonwire.Marshal(welcome)
if err != nil {
return
}
@@ -219,7 +220,7 @@ func (h *WorkerHub) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return false
}
}
raw, err := json.Marshal(frame)
raw, err := jsonwire.Marshal(frame)
if err != nil {
return false
}
@@ -320,7 +321,7 @@ func (h *WorkerHub) ServeHTTP(w http.ResponseWriter, r *http.Request) {
reply.Type = "error"
reply.Error = publicWorkerError(commandErr)
} else {
reply.Body, commandErr = json.Marshal(body)
reply.Body, commandErr = jsonwire.Marshal(body)
if commandErr != nil {
return
}
@@ -354,7 +355,7 @@ func (h *WorkerHub) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if assignment == nil {
break
}
raw, err := json.Marshal(assignment)
raw, err := jsonwire.Marshal(assignment)
if err != nil {
return
}
@@ -374,7 +375,7 @@ func publicWorkerError(err error) *fault.Error {
return fault.Unavailable
}
func writeWorkerFrame(ctx context.Context, conn *websocket.Conn, frame workerFrame) error {
raw, err := json.Marshal(frame)
raw, err := jsonwire.Marshal(frame)
if err != nil {
return err
}