CUB-127: implement Control Center CRUD API in Go
This commit is contained in:
158
go-backend/internal/handler/agent.go
Normal file
158
go-backend/internal/handler/agent.go
Normal file
@@ -0,0 +1,158 @@
|
||||
// Package handler contains HTTP handlers for the Control Center API.
|
||||
// Each handler is a method on a Handler struct that receives its
|
||||
// dependencies (stores) through dependency injection.
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"code.cubecraftcreations.com/CubeCraft-Creations/Control-Center/go-backend/internal/models"
|
||||
"code.cubecraftcreations.com/CubeCraft-Creations/Control-Center/go-backend/internal/store"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
// Handler groups all route handlers and their dependencies.
|
||||
type Handler struct {
|
||||
AgentStore *store.AgentStore
|
||||
SessionStore *store.SessionStore
|
||||
TaskStore *store.TaskStore
|
||||
ProjectStore *store.ProjectStore
|
||||
validate *validator.Validate
|
||||
}
|
||||
|
||||
// NewHandler returns a fully wired Handler.
|
||||
func NewHandler(
|
||||
as *store.AgentStore,
|
||||
ss *store.SessionStore,
|
||||
ts *store.TaskStore,
|
||||
ps *store.ProjectStore,
|
||||
) *Handler {
|
||||
v := validator.New()
|
||||
v.RegisterValidation("agentStatus", validateAgentStatus)
|
||||
return &Handler{
|
||||
AgentStore: as,
|
||||
SessionStore: ss,
|
||||
TaskStore: ts,
|
||||
ProjectStore: ps,
|
||||
validate: v,
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Agent Handlers ────────────────────────────────────────────────────────────
|
||||
|
||||
// ListAgents handles GET /api/agents.
|
||||
func (h *Handler) ListAgents(w http.ResponseWriter, r *http.Request) {
|
||||
statusFilter := models.AgentStatus(r.URL.Query().Get("status"))
|
||||
allAgents := h.AgentStore.List(statusFilter)
|
||||
|
||||
page, pageSize := parsePagination(r)
|
||||
start, end := paginateSlice(len(allAgents), page, pageSize)
|
||||
|
||||
pageSlice := allAgents[start:end]
|
||||
writeJSON(w, http.StatusOK, models.PaginatedResponse{
|
||||
Data: pageSlice,
|
||||
TotalCount: h.AgentStore.Count(),
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
HasMore: end < len(allAgents),
|
||||
})
|
||||
}
|
||||
|
||||
// GetAgent handles GET /api/agents/{id}.
|
||||
func (h *Handler) GetAgent(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
agent, ok := h.AgentStore.Get(id)
|
||||
if !ok {
|
||||
writeJSON(w, http.StatusNotFound, models.ErrorResponse{Error: "agent not found"})
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, agent)
|
||||
}
|
||||
|
||||
// CreateAgent handles POST /api/agents.
|
||||
func (h *Handler) CreateAgent(w http.ResponseWriter, r *http.Request) {
|
||||
var req models.CreateAgentRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, models.ErrorResponse{Error: "invalid request body"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.validate.Struct(req); err != nil {
|
||||
writeJSON(w, http.StatusUnprocessableEntity, models.ErrorResponse{
|
||||
Error: "validation failed",
|
||||
Details: validationErrors(err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
agent := models.AgentCardData{
|
||||
ID: req.ID,
|
||||
DisplayName: req.DisplayName,
|
||||
Role: req.Role,
|
||||
Status: req.Status,
|
||||
CurrentTask: req.CurrentTask,
|
||||
SessionKey: req.SessionKey,
|
||||
Channel: req.Channel,
|
||||
LastActivity: time.Now().UTC().Format(time.RFC3339),
|
||||
}
|
||||
|
||||
if ok := h.AgentStore.Create(agent); !ok {
|
||||
writeJSON(w, http.StatusConflict, models.ErrorResponse{Error: "agent with this ID already exists"})
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusCreated, agent)
|
||||
}
|
||||
|
||||
// UpdateAgent handles PUT /api/agents/{id}.
|
||||
func (h *Handler) UpdateAgent(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
|
||||
var req models.UpdateAgentRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, models.ErrorResponse{Error: "invalid request body"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.validate.Struct(req); err != nil {
|
||||
writeJSON(w, http.StatusUnprocessableEntity, models.ErrorResponse{
|
||||
Error: "validation failed",
|
||||
Details: validationErrors(err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
agent, ok := h.AgentStore.Update(id, req)
|
||||
if !ok {
|
||||
writeJSON(w, http.StatusNotFound, models.ErrorResponse{Error: "agent not found"})
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, agent)
|
||||
}
|
||||
|
||||
// DeleteAgent handles DELETE /api/agents/{id}.
|
||||
func (h *Handler) DeleteAgent(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
if ok := h.AgentStore.Delete(id); !ok {
|
||||
writeJSON(w, http.StatusNotFound, models.ErrorResponse{Error: "agent not found"})
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// AgentHistory handles GET /api/agents/{id}/history.
|
||||
func (h *Handler) AgentHistory(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
if _, ok := h.AgentStore.Get(id); !ok {
|
||||
writeJSON(w, http.StatusNotFound, models.ErrorResponse{Error: "agent not found"})
|
||||
return
|
||||
}
|
||||
|
||||
history := h.AgentStore.History(id)
|
||||
if history == nil {
|
||||
history = []models.AgentStatusHistoryEntry{}
|
||||
}
|
||||
writeJSON(w, http.StatusOK, history)
|
||||
}
|
||||
Reference in New Issue
Block a user