package main import ( "context" "log" "net/http" "os/signal" "syscall" "time" "git.ryuvia.com/niklas/terdut-server/internal/api" "git.ryuvia.com/niklas/terdut-server/internal/config" "git.ryuvia.com/niklas/terdut-server/internal/db" ) var version = "dev" func main() { cfg := config.Load() database, err := db.Open(cfg.DSN) if err != nil { log.Fatalf("open db: %v", err) } defer database.Close() if err := db.Migrate(database); err != nil { log.Fatalf("migrate: %v", err) } notify := api.NotifyConfig{ BaseURL: cfg.NtfyURL, Token: cfg.NtfyToken, FallbackTopic: cfg.NtfyFallbackTopic, PublicURL: cfg.PublicURL, RepeatEvery: cfg.NotifyRepeat, } // Dead man's switches live per team now. The environment variables are the // defaults a team starts from: every team without a configuration of its // own gets one from them here, and an owner's later edit is never // overwritten by a redeploy. deadman := api.ParseDeadmanConfig(cfg.DeadmanMatchers, cfg.DeadmanTimeout, cfg.DeadmanSeverity) if err := api.SeedDeadmanConfigs(context.Background(), database, deadman); err != nil { log.Fatalf("seed dead man's switch defaults: %v", err) } // The behaviour knobs move into the database on first start, after which an // administrator owns them and a redeploy leaves them alone. if err := api.SeedSettings(context.Background(), database, cfg); err != nil { log.Fatalf("seed settings: %v", err) } router := api.NewRouter(database, notify, cfg) srv := &http.Server{ Addr: cfg.Addr, Handler: router, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, } ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() go api.StartArchiver(ctx, database, cfg.ArchiveAfter, cfg.StaleAfter, notify) go api.StartNotifier(ctx, database, notify) go func() { log.Printf("terdut-server %s listening on %s", version, cfg.Addr) if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("listen: %v", err) } }() <-ctx.Done() log.Println("shutting down") shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(shutdownCtx); err != nil { log.Printf("shutdown: %v", err) } }