Files
creator-hub/cmd/control-plane/phasea.go
T

158 lines
4.6 KiB
Go

package main
import (
"bytes"
"encoding/json"
"errors"
"io"
"git.ipao.vip/rogee/creator-hub/internal/phasea"
"github.com/gofiber/fiber/v3"
)
type accountRequest struct {
ID string `json:"id"`
ProfileID string `json:"profile_id"`
CredentialReference struct {
ID string `json:"id"`
Provider string `json:"provider"`
Key string `json:"key"`
} `json:"credential_reference"`
}
func registerPhaseA(app *fiber.App, store *phasea.Store) {
app.Post("/api/phase-a/accounts", func(c fiber.Ctx) error {
var input accountRequest
if err := decodePhaseA(c, &input); err != nil {
return phaseAError(c, err)
}
err := store.CreateAccount(c.Context(), phasea.Account{
ID: input.ID, ProfileID: input.ProfileID, CredentialReferenceID: input.CredentialReference.ID,
CredentialProvider: input.CredentialReference.Provider, CredentialKey: input.CredentialReference.Key,
})
if err != nil {
return phaseAError(c, err)
}
return c.Status(fiber.StatusCreated).JSON(map[string]string{"id": input.ID, "profile_id": input.ProfileID})
})
app.Post("/api/phase-a/accounts/:id/pause", func(c fiber.Ctx) error {
if err := store.PauseAccount(c.Context(), c.Params("id")); err != nil {
return phaseAError(c, err)
}
return c.SendStatus(fiber.StatusNoContent)
})
app.Post("/api/phase-a/runtimes", func(c fiber.Ctx) error {
var input phasea.RuntimeBinding
if err := decodePhaseA(c, &input); err != nil {
return phaseAError(c, err)
}
if err := store.BindRuntime(c.Context(), input); err != nil {
return phaseAError(c, err)
}
return c.Status(fiber.StatusCreated).JSON(map[string]string{"id": input.ID})
})
app.Delete("/api/phase-a/runtimes/:id", func(c fiber.Ctx) error {
if err := store.ReleaseRuntime(c.Context(), c.Params("id")); err != nil {
return phaseAError(c, err)
}
return c.SendStatus(fiber.StatusNoContent)
})
app.Post("/api/phase-a/drafts", func(c fiber.Ctx) error {
var input phasea.Draft
if err := decodePhaseA(c, &input); err != nil {
return phaseAError(c, err)
}
if err := store.CreateDraft(c.Context(), input); err != nil {
return phaseAError(c, err)
}
return c.Status(fiber.StatusCreated).JSON(map[string]string{"id": input.ID})
})
app.Post("/api/phase-a/confirmations", func(c fiber.Ctx) error {
var input phasea.Confirmation
if err := decodePhaseA(c, &input); err != nil {
return phaseAError(c, err)
}
if err := store.Confirm(c.Context(), input); err != nil {
return phaseAError(c, err)
}
return c.Status(fiber.StatusCreated).JSON(map[string]string{"id": input.ID})
})
app.Post("/api/phase-a/tasks", func(c fiber.Ctx) error {
var input phasea.Task
if err := decodePhaseA(c, &input); err != nil {
return phaseAError(c, err)
}
task, inserted, err := store.Enqueue(c.Context(), input)
if err != nil {
return phaseAError(c, err)
}
status := fiber.StatusOK
if inserted {
status = fiber.StatusCreated
}
return c.Status(status).JSON(task)
})
app.Post("/api/phase-a/tasks/:id/cancel", func(c fiber.Ctx) error {
if err := store.CancelTask(c.Context(), c.Params("id")); err != nil {
return phaseAError(c, err)
}
return c.SendStatus(fiber.StatusNoContent)
})
app.Post("/api/phase-a/mock/execute", func(c fiber.Ctx) error {
var input struct {
WorkerID string `json:"worker_id"`
Outcome string `json:"outcome"`
}
if err := decodePhaseA(c, &input); err != nil {
return phaseAError(c, err)
}
execution, err := store.ExecuteMock(c.Context(), input.WorkerID, input.Outcome)
if err != nil {
return phaseAError(c, err)
}
return c.JSON(execution)
})
app.Get("/api/phase-a/audit", func(c fiber.Ctx) error {
events, err := store.Audit(c.Context())
if err != nil {
return phaseAError(c, err)
}
return c.JSON(events)
})
}
func decodePhaseA(c fiber.Ctx, destination any) error {
decoder := json.NewDecoder(bytes.NewReader(c.Body()))
decoder.DisallowUnknownFields()
if err := decoder.Decode(destination); err != nil {
return phasea.ErrInvalid
}
if err := decoder.Decode(&struct{}{}); !errors.Is(err, io.EOF) {
return phasea.ErrInvalid
}
return nil
}
func phaseAError(c fiber.Ctx, err error) error {
status := fiber.StatusInternalServerError
message := "phase A operation failed"
switch {
case errors.Is(err, phasea.ErrInvalid):
status, message = fiber.StatusBadRequest, phasea.ErrInvalid.Error()
case errors.Is(err, phasea.ErrConflict):
status, message = fiber.StatusConflict, phasea.ErrConflict.Error()
case errors.Is(err, phasea.ErrNotFound):
status, message = fiber.StatusNotFound, phasea.ErrNotFound.Error()
}
return c.Status(status).JSON(map[string]string{"error": message})
}