package main import ( "context" "flag" "fmt" "net/http" "os" "os/signal" "syscall" "time" "github.com/fujin/music-agregator/internal/api" "github.com/fujin/music-agregator/internal/config" "github.com/fujin/music-agregator/internal/database" "github.com/fujin/music-agregator/internal/metadata" "github.com/fujin/music-agregator/internal/services" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) func main() { configPath := flag.String("c", "config.yaml", "path to config file") port := flag.Int("p", 0, "port to listen on (overrides config)") flag.Parse() log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}) cfg, err := config.Load(*configPath) if err != nil { log.Fatal().Err(err).Msg("failed to load config") } if *port != 0 { cfg.App.Port = *port } ctx, cancel := context.WithCancel(context.Background()) defer cancel() indexerService, err := services.NewIndexerService(cfg.Indexers) if err != nil { log.Fatal().Err(err).Msg("failed to create indexer service") } log.Info().Int("count", len(cfg.Indexers)).Msg("initialized indexer service") torrentService, err := services.NewTorrentService(cfg.Torrent) if err != nil { log.Fatal().Err(err).Msg("failed to create torrent service") } if torrentService.IsConfigured() { if err := torrentService.Connect(ctx); err != nil { log.Warn().Err(err).Msg("failed to connect to torrent client") } else { log.Info().Str("type", string(cfg.Torrent.ClientType)).Msg("connected to torrent client") } } else { log.Warn().Msg("no torrent client configured") } metadataClient, err := metadata.NewClient(cfg.Metadata.Endpoint) if err != nil { log.Fatal().Err(err).Msg("failed to create metadata client") } log.Info().Str("endpoint", cfg.Metadata.Endpoint).Msg("initialized metadata client") var db *database.DB if cfg.Database.URL != "" { db, err = database.New(ctx, cfg.Database.URL) if err != nil { log.Warn().Err(err).Msg("failed to connect to database (continuing without db)") } else { log.Info().Msg("connected to database") } } handlers := &api.Handlers{ IndexerService: indexerService, TorrentService: torrentService, MetadataClient: metadataClient, DB: db, } router := api.NewRouter(handlers) server := &http.Server{ Addr: fmt.Sprintf(":%d", cfg.App.Port), Handler: router, } go func() { log.Info().Int("port", cfg.App.Port).Msg("starting server") if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatal().Err(err).Msg("server error") } }() quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Info().Msg("shutting down server...") shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 30*time.Second) defer shutdownCancel() if err := server.Shutdown(shutdownCtx); err != nil { log.Error().Err(err).Msg("server forced to shutdown") } if db != nil { db.Close() } if torrentService.IsConfigured() { torrentService.Disconnect(context.Background()) } metadataClient.Close() log.Info().Msg("server stopped") }