package handlers import ( "context" "encoding/json" "errors" "net/http" "supervisor/internal/domain" "supervisor/internal/session" ) type SessionService interface { CreateSession(ctx context.Context, params session.CreateSessionParams) (domain.Session, error) StartSession(ctx context.Context, id string) error StopSession(ctx context.Context, id string) error DeleteSession(ctx context.Context, id string) error ListSessions(ctx context.Context) ([]domain.Session, error) GetSession(ctx context.Context, id string) (domain.Session, error) WriteInput(ctx context.Context, id string, input string) error Resize(ctx context.Context, id string, cols, rows int) error Subscribe(id string) (<-chan domain.Event, func(), error) Scrollback(id string) ([]byte, error) } type SessionsHandler struct { manager SessionService } func NewSessionsHandler(manager SessionService) *SessionsHandler { return &SessionsHandler{manager: manager} } func (h *SessionsHandler) List(w http.ResponseWriter, r *http.Request) { sessions, err := h.manager.ListSessions(r.Context()) if err != nil { writeError(w, http.StatusInternalServerError, err) return } writeJSON(w, http.StatusOK, sessions) } func (h *SessionsHandler) Create(w http.ResponseWriter, r *http.Request) { var req session.CreateSessionParams if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, err) return } created, err := h.manager.CreateSession(r.Context(), req) if err != nil { writeError(w, http.StatusBadRequest, err) return } if err := h.manager.StartSession(r.Context(), created.ID); err != nil { writeError(w, http.StatusInternalServerError, err) return } current, err := h.manager.GetSession(r.Context(), created.ID) if err != nil { writeError(w, http.StatusInternalServerError, err) return } writeJSON(w, http.StatusCreated, current) } func (h *SessionsHandler) Get(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") item, err := h.manager.GetSession(r.Context(), id) if err != nil { if errors.Is(err, session.ErrSessionNotFound) { writeError(w, http.StatusNotFound, err) return } writeError(w, http.StatusInternalServerError, err) return } writeJSON(w, http.StatusOK, item) } func (h *SessionsHandler) Input(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req session.InputRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, err) return } if err := h.manager.WriteInput(r.Context(), id, req.Input); err != nil { writeError(w, http.StatusBadRequest, err) return } writeJSON(w, http.StatusOK, map[string]bool{"ok": true}) } func (h *SessionsHandler) Stop(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if err := h.manager.StopSession(r.Context(), id); err != nil { writeError(w, http.StatusBadRequest, err) return } item, err := h.manager.GetSession(r.Context(), id) if err != nil { writeError(w, http.StatusInternalServerError, err) return } writeJSON(w, http.StatusOK, item) } func (h *SessionsHandler) Delete(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if err := h.manager.DeleteSession(r.Context(), id); err != nil { switch { case errors.Is(err, session.ErrSessionNotFound): writeError(w, http.StatusNotFound, err) case errors.Is(err, session.ErrSessionRunning): writeError(w, http.StatusConflict, err) default: writeError(w, http.StatusBadRequest, err) } return } w.WriteHeader(http.StatusNoContent) } func writeJSON(w http.ResponseWriter, code int, payload any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(code) _ = json.NewEncoder(w).Encode(payload) } func writeError(w http.ResponseWriter, code int, err error) { writeJSON(w, code, map[string]string{"error": err.Error()}) }