package app import ( "context" "fmt" "log/slog" "os" "os/signal" "syscall" "time" "github.com/gofiber/fiber/v2" "cryptoHermes/config" "cryptoHermes/internal/controller/restapi" "cryptoHermes/internal/repo/persistent/postgres" "cryptoHermes/internal/repo/webapi/binance" "cryptoHermes/internal/usecase" "cryptoHermes/internal/worker" pgpkg "cryptoHermes/pkg/postgres" ) func Run(cfg *config.Config, log *slog.Logger) error { rootCtx, cancel := context.WithCancel(context.Background()) defer cancel() pool, err := pgpkg.NewPool(rootCtx, pgpkg.Options{ DSN: cfg.Postgres.DSN, MaxConns: cfg.Postgres.MaxConns, MinConns: cfg.Postgres.MinConns, }) if err != nil { return fmt.Errorf("postgres: %w", err) } defer pool.Close() binanceClient := binance.NewClient(binance.ClientOptions{ BaseURL: cfg.Binance.BaseURL, Timeout: cfg.Binance.Timeout, RetryCount: cfg.Binance.RetryCount, RPS: cfg.Binance.RPS, Burst: cfg.Binance.Burst, }) klineRepo := postgres.NewKlineRepo(pool) fundingRepo := postgres.NewFundingRepo(pool) oiRepo := postgres.NewOpenInterestRepo(pool) lsRepo := postgres.NewLongShortRatioRepo(pool) takerRepo := postgres.NewTakerVolumeRepo(pool) contextUC := usecase.NewMarketContextUsecase( binanceClient, binanceClient, klineRepo, fundingRepo, oiRepo, lsRepo, usecase.NewIndicatorUsecase(), usecase.NewDerivativesSignalUsecase(), log, ) queryUC := usecase.NewMarketQueryUsecase( binanceClient, fundingRepo, oiRepo, lsRepo, ) collector := worker.NewCollector(worker.Deps{ MarketData: binanceClient, Derivatives: binanceClient, KlineRepo: klineRepo, FundingRepo: fundingRepo, OIRepo: oiRepo, LSRepo: lsRepo, TakerRepo: takerRepo, Symbols: cfg.Collector.Symbols, Intervals: cfg.Collector.Intervals, Limit: cfg.Collector.DefaultLimit, Logger: log, }) var sched *Scheduler if cfg.Collector.Enabled { sched = NewScheduler(collector, log) sched.Start(rootCtx) defer sched.Stop() } fiberApp := fiber.New(fiber.Config{ AppName: cfg.App.Name, ReadTimeout: cfg.HTTP.ReadTimeout, WriteTimeout: cfg.HTTP.WriteTimeout, IdleTimeout: cfg.HTTP.IdleTimeout, ErrorHandler: restapi.ErrorHandler, }) restapi.Register(fiberApp, restapi.Deps{ Logger: log, MarketContext: contextUC, MarketQuery: queryUC, MarketData: binanceClient, KlineRepo: klineRepo, }) listenErr := make(chan error, 1) go func() { addr := fmt.Sprintf(":%d", cfg.App.Port) log.Info("http_listening", "addr", addr) listenErr <- fiberApp.Listen(addr) }() stop := make(chan os.Signal, 1) signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM) select { case err := <-listenErr: return err case sig := <-stop: log.Info("shutdown_signal", "signal", sig.String()) } shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 10*time.Second) defer shutdownCancel() return fiberApp.ShutdownWithContext(shutdownCtx) }