// Dash is a single-binary uptime monitoring dashboard. package main import ( "context" "errors" "flag" "log" "net/http" "os/signal" "syscall" "time" "dash/internal/api" "dash/internal/config" "dash/internal/engine" "dash/internal/store" ) func main() { configPath := flag.String("config", "targets.yaml", "path to targets.yaml") listen := flag.String("listen", "", "listen address (overrides config)") dbPath := flag.String("db", "", "sqlite database path (overrides config)") flag.Parse() cfg, err := config.Load(*configPath) if err != nil { log.Fatalf("config: %v", err) } if *listen != "" { cfg.Settings.Listen = *listen } if *dbPath != "" { cfg.Settings.DB = *dbPath } st, err := store.Open(cfg.Settings.DB) if err != nil { log.Fatalf("store: %v", err) } defer st.Close() ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() hub := engine.NewHub() eng := engine.New(cfg, st, hub) go eng.Run(ctx) mux := http.NewServeMux() api.New(eng, st, hub).Register(mux) mux.Handle("/", webHandler()) srv := &http.Server{Addr: cfg.Settings.Listen, Handler: mux} go func() { <-ctx.Done() shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() srv.Shutdown(shutdownCtx) }() log.Printf("dash listening on %s — monitoring %d targets", cfg.Settings.Listen, len(cfg.Targets)) if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Fatalf("server: %v", err) } }