// Package server provides the HTTP server for kindexr, including the /health endpoint. package server import ( "encoding/json" "net/http" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "git.utn.lol/enki/kindexr/internal/config" "git.utn.lol/enki/kindexr/internal/db" ) // Server holds the HTTP server state. type Server struct { cfg *config.Config db *db.DB router chi.Router version string } // New creates a new Server with the given config, database, and version string. func New(cfg *config.Config, database *db.DB, version string) *Server { s := &Server{ cfg: cfg, db: database, version: version, } s.router = s.buildRouter() return s } // Handler returns the root http.Handler for the server. func (s *Server) Handler() http.Handler { return s.router } // buildRouter wires up all routes and middleware. func (s *Server) buildRouter() chi.Router { r := chi.NewRouter() r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Get("/health", s.healthHandler) return r } // healthResponse is the JSON body returned by GET /health. type healthResponse struct { Status string `json:"status"` Version string `json:"version"` RelaysConnected int `json:"relays_connected"` EventsTotal int64 `json:"events_total"` LastEventAt *int64 `json:"last_event_at"` } // healthHandler handles GET /health. func (s *Server) healthHandler(w http.ResponseWriter, r *http.Request) { stats, err := s.db.GetStats(r.Context()) if err != nil { http.Error(w, `{"error":"internal server error"}`, http.StatusInternalServerError) return } resp := healthResponse{ Status: "ok", Version: s.version, RelaysConnected: 0, // populated in Phase 1 when relay connections are active EventsTotal: stats.EventsTotal, LastEventAt: stats.LastEventAt, } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) _ = json.NewEncoder(w).Encode(resp) }