package main import ( "context" "fmt" "os" "os/signal" "syscall" "time" "predictor-refactored/internal/downloader" "predictor-refactored/internal/service" "predictor-refactored/internal/transport/rest" "predictor-refactored/internal/transport/rest/handler" "github.com/go-co-op/gocron" "go.uber.org/zap" ) func main() { log, err := zap.NewProduction() if err != nil { panic(err) } defer log.Sync() cfg := downloader.LoadConfig() log.Info("configuration loaded", zap.String("data_dir", cfg.DataDir), zap.Int("parallel", cfg.Parallel), zap.Duration("update_interval", cfg.UpdateInterval), zap.Duration("dataset_ttl", cfg.DatasetTTL)) if err := os.MkdirAll(cfg.DataDir, 0o755); err != nil { log.Fatal("failed to create data directory", zap.Error(err)) } svc := service.New(cfg, log) defer svc.Close() // Load elevation dataset (optional — falls back to sea-level termination) elevPath := "/srv/ruaumoko-dataset" if v := os.Getenv("PREDICTOR_ELEVATION_DATASET"); v != "" { elevPath = v } svc.LoadElevation(elevPath) // Initial dataset load (async so the server starts immediately) go func() { log.Info("performing initial dataset update...") if err := svc.Update(context.Background()); err != nil { log.Error("initial dataset update failed", zap.Error(err)) } else { log.Info("initial dataset update complete") } }() // Scheduler for periodic dataset updates scheduler := gocron.NewScheduler(time.UTC) scheduler.Every(cfg.UpdateInterval).Do(func() { ctx, cancel := context.WithTimeout(context.Background(), 60*time.Minute) defer cancel() log.Info("scheduled dataset update starting") if err := svc.Update(ctx); err != nil { log.Error("scheduled dataset update failed", zap.Error(err)) } else { log.Info("scheduled dataset update complete") } }) scheduler.StartAsync() defer scheduler.Stop() // HTTP transport (ogen) port := 8080 if p := os.Getenv("PREDICTOR_PORT"); p != "" { fmt.Sscanf(p, "%d", &port) } h := handler.New(svc, log) transport, err := rest.New(h, port, log) if err != nil { log.Fatal("failed to create transport", zap.Error(err)) } go func() { if err := transport.Run(); err != nil { log.Fatal("HTTP server error", zap.Error(err)) } }() log.Info("service started") // Graceful shutdown sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) sig := <-sigChan log.Info("received shutdown signal", zap.String("signal", sig.String())) }