Files
kindexr/archive/go/internal/server/server.go
T
enki 57cda1281b rewrite phases 0+1 in Rust; archive Go implementation
Move entire Go tree to archive/go/ preserving history. Add Rust
implementation: axum HTTP server, nostr-sdk relay reader, sqlx/SQLite
storage, Torznab caps+search endpoints, figment config, clap CLI.
Update spec.md tech stack and repo layout to reflect Rust. Add
docs/FIPS.md with Mode A/B/C deployment walkthrough. Add Phase 6
(FIPS deployment) to phase plan.
2026-05-17 02:23:26 -07:00

94 lines
2.4 KiB
Go

// 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"
"git.utn.lol/enki/kindexr/internal/torznab"
)
// Server holds the HTTP server state.
type Server struct {
cfg *config.Config
db *db.DB
router chi.Router
version string
connectedRelays func() int // returns live relay count; nil = always 0
}
// 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
}
// SetConnectedRelays wires in a function that returns the current connected
// relay count. Call this after the reader is started.
func (s *Server) SetConnectedRelays(fn func() int) {
s.connectedRelays = fn
}
// 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)
tz := torznab.New(s.cfg, s.db, s.version)
tz.Mount(r)
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
}
relaysConnected := 0
if s.connectedRelays != nil {
relaysConnected = s.connectedRelays()
}
resp := healthResponse{
Status: "ok",
Version: s.version,
RelaysConnected: relaysConnected,
EventsTotal: stats.EventsTotal,
LastEventAt: stats.LastEventAt,
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_ = json.NewEncoder(w).Encode(resp)
}