// Package healthcheck provides health status reporting for the server. package healthcheck import ( "context" "log/slog" "time" "git.eeqj.de/sneak/chat/internal/config" "git.eeqj.de/sneak/chat/internal/db" "git.eeqj.de/sneak/chat/internal/globals" "git.eeqj.de/sneak/chat/internal/logger" "go.uber.org/fx" ) // HealthcheckParams defines the dependencies for creating a Healthcheck. type HealthcheckParams struct { fx.In Globals *globals.Globals Config *config.Config Logger *logger.Logger Database *db.Database } // Healthcheck tracks server uptime and provides health status. type Healthcheck struct { // StartupTime records when the server started. StartupTime time.Time log *slog.Logger params *HealthcheckParams } // New creates a new Healthcheck instance. func New(lc fx.Lifecycle, params HealthcheckParams) (*Healthcheck, error) { s := new(Healthcheck) s.params = ¶ms s.log = params.Logger.Get() lc.Append(fx.Hook{ OnStart: func(_ context.Context) error { s.StartupTime = time.Now() return nil }, OnStop: func(_ context.Context) error { return nil }, }) return s, nil } // HealthcheckResponse is the JSON response returned by the health endpoint. type HealthcheckResponse struct { Status string `json:"status"` Now string `json:"now"` UptimeSeconds int64 `json:"uptimeSeconds"` UptimeHuman string `json:"uptimeHuman"` Version string `json:"version"` Appname string `json:"appname"` Maintenance bool `json:"maintenanceMode"` } // Healthcheck returns the current health status of the server. func (s *Healthcheck) Healthcheck() *HealthcheckResponse { resp := &HealthcheckResponse{ Status: "ok", Now: time.Now().UTC().Format(time.RFC3339Nano), UptimeSeconds: int64(s.uptime().Seconds()), UptimeHuman: s.uptime().String(), Appname: s.params.Globals.Appname, Version: s.params.Globals.Version, } return resp } func (s *Healthcheck) uptime() time.Duration { return time.Since(s.StartupTime) }