package httpserver import ( "net/http" "git.yuntuo.hk/k2safe/orbit/internal/fault" "git.yuntuo.hk/k2safe/orbit/internal/retention" core "git.yuntuo.hk/k2safe/orbit/model" "git.yuntuo.hk/k2safe/orbit/platform/auth" ) // RegisterConsoleArchiveJobs 注册周期归档管理;只接受管理员会话,目标目录由部署配置固定。 func RegisterConsoleArchiveJobs(server *http.Server, consoleAuth RetentionConsoleAuth, store retention.SchedulerStore, storage core.ID) { if server == nil || consoleAuth == nil || store == nil { return } mux, ok := server.Handler.(*http.ServeMux) if !ok { return } parent := mux mux = http.NewServeMux() for _, method := range []string{"GET", "PUT", "POST"} { parent.Handle(method+" /console/archive/", http.NewCrossOriginProtection().Handler(mux)) } check := func(w http.ResponseWriter, r *http.Request) (auth.Token, bool) { t, ok := consoleCookieToken(r) if !ok || consoleAuth.ValidateSession(r.Context(), t) != nil { writeError(w, "", fault.Unauthorized) return auth.Token{}, false } return scopedConsoleToken(r, t), true } key := func(w http.ResponseWriter, r *http.Request) (string, bool) { keys := r.Header.Values("Idempotency-Key") if len(keys) != 1 { writeError(w, "", fault.Invalid("exactly one Idempotency-Key is required")) return "", false } return keys[0], true } mux.HandleFunc("GET /console/archive/plans", func(w http.ResponseWriter, r *http.Request) { t, ok := check(w, r) if !ok { return } items, err := store.ListArchivePlans(r.Context(), t) if err != nil { writeError(w, "", err) return } writeConsoleJSON(w, 200, map[string]any{"data": map[string]any{"items": items, "executor_configured": storage != "", "storage_id": string(storage)}}) }) mux.HandleFunc("PUT /console/archive/plans/{kind}", func(w http.ResponseWriter, r *http.Request) { t, ok := check(w, r) if !ok { return } k, ok := key(w, r) if !ok { return } var in retention.PlanInput if err := decodeBody(r, &in); err != nil { writeError(w, "", err) return } out, err := store.SaveArchivePlan(r.Context(), t, k, r.PathValue("kind"), storage, in) if err != nil { writeError(w, "", err) return } writeConsoleJSON(w, 200, map[string]any{"data": out}) }) mux.HandleFunc("GET /console/archive/jobs", func(w http.ResponseWriter, r *http.Request) { t, ok := check(w, r) if !ok { return } out, err := store.ListArchiveJobs(r.Context(), t, r.URL.Query().Get("before")) if err != nil { writeError(w, "", err) return } writeConsoleJSON(w, 200, map[string]any{"data": out}) }) mux.HandleFunc("POST /console/archive/jobs/{id}/actions", func(w http.ResponseWriter, r *http.Request) { t, ok := check(w, r) if !ok { return } k, ok := key(w, r) if !ok { return } var in retention.JobActionInput if err := decodeBody(r, &in); err != nil { writeError(w, "", err) return } out, err := store.ActArchiveJob(r.Context(), t, core.ID(r.PathValue("id")), k, in) if err != nil { writeError(w, "", err) return } writeConsoleJSON(w, 200, map[string]any{"data": out}) }) }