Files
ntfy-discord/internal/server/server.go
Billy D. 1c1a9cc35f
Some checks failed
CI / Lint (push) Successful in 58s
CI / Test (push) Successful in 1m15s
CI / Release (push) Successful in 6s
CI / Docker Build & Push (push) Failing after 23s
CI / Notify (push) Successful in 1s
fix: add golangci-lint config and fix all lint errors
- Add .golangci.yml with v2 config (errcheck, govet, staticcheck, misspell, etc.)
- Fix 32 errcheck issues across config, discord, ntfy, server packages
- Fix misspelling: cancelled → canceled
- Fix staticcheck: use append(slice...) instead of loop
- Fix staticcheck: remove empty error branch
- Use t.Setenv instead of os.Setenv/Unsetenv in tests
- Update CI workflow: add lint job, release tagging, ntfy notifications
2026-02-14 09:15:01 -05:00

94 lines
2.1 KiB
Go

package server
import (
"context"
"encoding/json"
"log/slog"
"net/http"
"time"
"git.daviestechlabs.io/daviestechlabs/ntfy-discord/internal/bridge"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Server provides health and metrics endpoints
type Server struct {
httpServer *http.Server
bridge *bridge.Bridge
}
// New creates a new HTTP server
func New(port string, b *bridge.Bridge) *Server {
mux := http.NewServeMux()
s := &Server{
bridge: b,
httpServer: &http.Server{
Addr: ":" + port,
Handler: mux,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
},
}
mux.HandleFunc("/health", s.handleHealth)
mux.HandleFunc("/ready", s.handleReady)
mux.Handle("/metrics", promhttp.Handler())
return s
}
// Start begins serving HTTP requests
func (s *Server) Start() {
slog.Info("starting HTTP server", "addr", s.httpServer.Addr)
if err := s.httpServer.ListenAndServe(); err != http.ErrServerClosed {
slog.Error("HTTP server error", "error", err)
}
}
// Shutdown gracefully stops the server
func (s *Server) Shutdown(ctx context.Context) {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
if err := s.httpServer.Shutdown(ctx); err != nil {
slog.Error("HTTP server shutdown error", "error", err)
}
}
func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
status := struct {
Status string `json:"status"`
Healthy bool `json:"healthy"`
}{
Status: "ok",
Healthy: s.bridge.IsHealthy(),
}
if !status.Healthy {
status.Status = "unhealthy"
w.WriteHeader(http.StatusServiceUnavailable)
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(status)
}
func (s *Server) handleReady(w http.ResponseWriter, r *http.Request) {
status := struct {
Status string `json:"status"`
Ready bool `json:"ready"`
}{
Status: "ok",
Ready: s.bridge.IsReady(),
}
if !status.Ready {
status.Status = "not ready"
w.WriteHeader(http.StatusServiceUnavailable)
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(status)
}