package main import ( "log/slog" "net/http" "os" "os/signal" "syscall" "time" apiv1 "git.ar21.de/yolokube/country-geo-locations/api/v1" "git.ar21.de/yolokube/country-geo-locations/internal/cache" "git.ar21.de/yolokube/country-geo-locations/internal/cmd" csvimporter "git.ar21.de/yolokube/country-geo-locations/internal/csv_importer" "git.ar21.de/yolokube/country-geo-locations/internal/database" "git.ar21.de/yolokube/country-geo-locations/internal/downloader" "git.ar21.de/yolokube/country-geo-locations/internal/exporter" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/render" ) func main() { cli := cmd.CLI{} config, err := cli.Parse() if err != nil { panic(err) } handleGracefulShutdown() r := chi.NewRouter() r.Use(middleware.RequestID) r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(render.SetContentType(render.ContentTypeJSON)) ctx := downloader.NewContext(config.DataFile, config.DataURL) if !ctx.FileExists() { if downloadErr := ctx.Download(); downloadErr != nil { panic(err) } slog.Info("saved file", "path", ctx.Filename) } cache := cache.NewCache(config.CacheTTL) db, err := database.NewDatabase(config) if err != nil { slog.Error("database creation failed") panic(err) } if config.EnableExporter { exporter := exporter.NewExporter(config, cache, db) r.Use(exporter.Middleware()) ticker := time.NewTicker(config.ExporterInterval) exit := make(chan struct{}) go func() { for { select { case <-ticker.C: exporter.Collect() case <-exit: ticker.Stop() return } } }() slog.Info("prometheus exporter refreshes metric data", "interval", config.ExporterInterval) go func() { err = exporter.Start() if err != nil { panic(err) } }() slog.Info("prometheus exporter started", "address", config.ExporterAddress) } slog.Info("importing data from file", "path", config.DataFile) err = csvimporter.ImportCSV(config.DataFile, db) if err != nil { slog.Error("data import from file failed") panic(err) } slog.Info("imported data from file successfully") lh := apiv1.NewLocationHandler(cache, db) r.Mount("/api/v1", apiv1.NewRouter(lh)) server := &http.Server{ Addr: config.ServerAddress, Handler: r, ReadHeaderTimeout: config.ReadHeaderTimeout, } slog.Info("starting server", "address", server.Addr) if err = server.ListenAndServe(); err != nil { panic(err) } } func handleGracefulShutdown() { var signals = make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT) go func() { sig := <-signals slog.Info("caught signal", "signal", sig) os.Exit(0) }() }