165 lines
4.4 KiB
Go
165 lines
4.4 KiB
Go
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"
|
|
coinglassapi "cryptoHermes/internal/repo/webapi/coinglass"
|
|
"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)
|
|
cgLiqRepo := postgres.NewCoinglassLiqHeatMapRepo(pool)
|
|
|
|
contextUC := usecase.NewMarketContextUsecase(
|
|
binanceClient,
|
|
binanceClient,
|
|
klineRepo,
|
|
fundingRepo,
|
|
oiRepo,
|
|
lsRepo,
|
|
usecase.NewIndicatorUsecase(),
|
|
usecase.NewDerivativesSignalUsecase(),
|
|
log,
|
|
)
|
|
|
|
queryUC := usecase.NewMarketQueryUsecase(
|
|
binanceClient,
|
|
fundingRepo,
|
|
oiRepo,
|
|
lsRepo,
|
|
)
|
|
|
|
cgQueryUC := usecase.NewCoinglassQueryUsecase(cgLiqRepo)
|
|
|
|
var collector *worker.Collector
|
|
if cfg.Collector.Enabled {
|
|
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 cgCollector *worker.CoinglassCollector
|
|
if cfg.Coinglass.Enabled {
|
|
cgClient, err := coinglassapi.NewClient(coinglassapi.ClientOptions{
|
|
BaseURL: cfg.Coinglass.BaseURL,
|
|
TOTPSecret: cfg.Coinglass.TOTPSecret,
|
|
DataAESKey: cfg.Coinglass.DataAESKey,
|
|
Timeout: cfg.Coinglass.Timeout,
|
|
FakeSuccessRetry: cfg.Coinglass.FakeSuccessRetry,
|
|
FakeSuccessRetryWait: cfg.Coinglass.FakeSuccessRetryWait,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("coinglass client: %w", err)
|
|
}
|
|
cgCollector = worker.NewCoinglassCollector(worker.CoinglassCollectorDeps{
|
|
Provider: cgClient,
|
|
LiqHeatMapRepo: cgLiqRepo,
|
|
Symbols: cfg.Collector.Symbols,
|
|
LiqHeatMapInterval: cfg.Coinglass.LiqHeatMapInterval,
|
|
LiqHeatMapLimit: cfg.Coinglass.LiqHeatMapLimit,
|
|
BackoffInitial: cfg.Coinglass.BackoffInitial,
|
|
BackoffMax: cfg.Coinglass.BackoffMax,
|
|
Logger: log,
|
|
})
|
|
}
|
|
|
|
var sched *Scheduler
|
|
if collector != nil || cgCollector != nil {
|
|
sched = NewScheduler(collector, log)
|
|
if cgCollector != nil {
|
|
sched.WithCoinglass(cgCollector, cfg.Coinglass.LiqHeatMapCron, cfg.Coinglass.StartupJitterMax)
|
|
}
|
|
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,
|
|
CoinglassQuery: cgQueryUC,
|
|
CoinglassEnabled: cfg.Coinglass.Enabled,
|
|
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)
|
|
}
|