stillbox/pkg/server/server.go

187 lines
4.2 KiB
Go
Raw Normal View History

2024-07-14 13:47:48 -04:00
package server
import (
2024-08-06 11:19:30 -04:00
"context"
2024-07-14 13:47:48 -04:00
"net/http"
2024-10-22 08:39:15 -04:00
"os"
2024-10-21 13:49:20 -04:00
"time"
2024-07-14 13:47:48 -04:00
2024-11-03 07:19:03 -05:00
"dynatron.me/x/stillbox/pkg/alerting"
"dynatron.me/x/stillbox/pkg/auth"
2024-12-28 18:32:13 -05:00
"dynatron.me/x/stillbox/pkg/calls/callstore"
2024-11-03 07:19:03 -05:00
"dynatron.me/x/stillbox/pkg/config"
"dynatron.me/x/stillbox/pkg/database"
"dynatron.me/x/stillbox/pkg/database/partman"
2024-12-28 18:32:13 -05:00
"dynatron.me/x/stillbox/pkg/incidents/incstore"
2024-11-03 07:19:03 -05:00
"dynatron.me/x/stillbox/pkg/nexus"
"dynatron.me/x/stillbox/pkg/notify"
2024-11-10 14:44:52 -05:00
"dynatron.me/x/stillbox/pkg/rest"
2024-11-03 07:19:03 -05:00
"dynatron.me/x/stillbox/pkg/sinks"
"dynatron.me/x/stillbox/pkg/sources"
2024-11-20 19:59:24 -05:00
"dynatron.me/x/stillbox/pkg/talkgroups/tgstore"
"dynatron.me/x/stillbox/pkg/users"
2024-11-20 19:59:24 -05:00
2024-07-14 13:47:48 -04:00
"github.com/go-chi/chi/v5"
2024-10-18 00:15:21 -04:00
"github.com/go-chi/chi/v5/middleware"
2024-08-14 19:12:20 -04:00
"github.com/go-chi/cors"
2024-10-21 13:49:20 -04:00
"github.com/rs/zerolog/log"
2024-07-14 13:47:48 -04:00
)
2024-10-21 13:49:20 -04:00
const shutdownTimeout = 5 * time.Second
2024-07-14 13:47:48 -04:00
type Server struct {
2024-12-28 18:32:13 -05:00
auth *auth.Auth
conf *config.Configuration
db database.Store
r *chi.Mux
sources sources.Sources
sinks sinks.Sinks
relayer *sinks.RelayManager
nex *nexus.Nexus
logger *Logger
alerter alerting.Alerter
notifier notify.Notifier
hup chan os.Signal
tgs tgstore.Store
rest rest.API
partman partman.PartitionManager
users users.Store
calls callstore.Store
incidents incstore.Store
2024-07-14 13:47:48 -04:00
}
2024-11-24 08:40:14 -05:00
func New(ctx context.Context, cfg *config.Configuration) (*Server, error) {
2024-10-22 08:39:15 -04:00
logger, err := NewLogger(cfg.Log)
2024-10-17 10:00:23 -04:00
if err != nil {
return nil, err
}
2024-10-21 14:11:08 -04:00
db, err := database.NewClient(ctx, cfg.DB)
2024-07-14 17:39:03 -04:00
if err != nil {
return nil, err
}
2024-07-14 13:47:48 -04:00
r := chi.NewRouter()
2024-10-31 00:10:53 -04:00
2024-08-04 09:07:31 -04:00
authenticator := auth.NewAuthenticator(cfg.Auth)
2024-10-31 00:10:53 -04:00
notifier, err := notify.New(cfg.Notify)
if err != nil {
return nil, err
}
2024-11-20 19:59:24 -05:00
tgCache := tgstore.NewCache()
2024-12-29 15:08:06 -05:00
api := rest.New(cfg.BaseURL.URL())
2024-11-02 11:39:02 -04:00
2024-07-14 13:47:48 -04:00
srv := &Server{
2024-12-28 18:32:13 -05:00
auth: authenticator,
conf: cfg,
db: db,
r: r,
nex: nexus.New(),
logger: logger,
alerter: alerting.New(cfg.Alerting, tgCache, alerting.WithNotifier(notifier)),
notifier: notifier,
tgs: tgCache,
sinks: sinks.NewSinkManager(),
rest: api,
users: users.NewStore(),
calls: callstore.NewStore(),
incidents: incstore.NewStore(),
2024-07-14 13:47:48 -04:00
}
2024-08-01 01:01:08 -04:00
if cfg.DB.Partition.Enabled {
srv.partman, err = partman.New(db, cfg.DB.Partition)
if err != nil {
return nil, err
}
err = srv.partman.Check(ctx, time.Now())
if err != nil {
return nil, err
}
}
srv.sinks.Register("database", sinks.NewDatabaseSink(srv.db, tgCache), true)
srv.sinks.Register("nexus", sinks.NewNexusSink(srv.nex), false)
if srv.alerter.Enabled() {
srv.sinks.Register("alerting", srv.alerter, false)
}
2024-08-01 01:01:08 -04:00
srv.sources.Register("rdio-http", sources.NewRdioHTTP(authenticator, srv))
2024-11-18 18:31:17 -05:00
relayer, err := sinks.NewRelayManager(srv.sinks, cfg.Relay)
if err != nil {
return nil, err
}
srv.relayer = relayer
2024-07-14 13:47:48 -04:00
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
2024-10-18 00:15:21 -04:00
r.Use(RequestLogger())
2024-10-22 10:21:11 -04:00
r.Use(ServerHeaderAdd)
2024-08-14 19:12:20 -04:00
r.Use(cors.Handler(cors.Options{
AllowedOrigins: srv.conf.CORS.AllowedOrigins,
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token", "Upgrade"},
ExposedHeaders: []string{"Link"},
2024-08-15 13:28:03 -04:00
AllowCredentials: true,
2024-08-14 19:12:20 -04:00
MaxAge: 300, // Maximum value not ignored by any of major browsers
}))
2024-07-14 13:47:48 -04:00
srv.setupRoutes()
return srv, nil
}
2024-12-28 18:32:13 -05:00
func (s *Server) addStoresTo(ctx context.Context) context.Context {
ctx = database.CtxWithDB(ctx, s.db)
ctx = tgstore.CtxWithStore(ctx, s.tgs)
ctx = users.CtxWithStore(ctx, s.users)
ctx = callstore.CtxWithStore(ctx, s.calls)
ctx = incstore.CtxWithStore(ctx, s.incidents)
return ctx
}
2024-10-21 13:49:20 -04:00
func (s *Server) Go(ctx context.Context) error {
2024-11-17 21:46:10 -05:00
defer database.Close(s.db)
2024-08-04 10:56:46 -04:00
2024-10-22 08:39:15 -04:00
s.installHupHandler()
2024-12-28 18:32:13 -05:00
ctx = s.addStoresTo(ctx)
2024-10-21 13:49:20 -04:00
httpSrv := &http.Server{
Addr: s.conf.Listen,
Handler: s.r,
}
2024-08-06 11:19:30 -04:00
go s.nex.Go(ctx)
go s.alerter.Go(ctx)
2024-07-14 17:39:03 -04:00
if pm := s.partman; pm != nil {
go pm.Go(ctx)
}
2024-10-21 13:49:20 -04:00
var err error
go func() {
err = httpSrv.ListenAndServe()
}()
<-ctx.Done()
s.sinks.Shutdown()
2024-10-21 13:49:20 -04:00
ctxShutdown, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
defer cancel()
if err := httpSrv.Shutdown(ctxShutdown); err != nil {
log.Fatal().Err(err).Msg("shutdown failed")
}
if err == http.ErrServerClosed {
err = nil
}
return err
2024-07-14 13:47:48 -04:00
}