// Package rest defines all API rest functionality package rest import ( "log/slog" "time" "github.com/gin-gonic/gin" "github.com/gomodule/redigo/redis" "github.com/shopspring/decimal" "quantex.com/qfixdpl/src/app" "quantex.com/qfixdpl/src/app/version" "quantex.com/qfixdpl/src/client/store" "quantex.com/qfixdpl/src/common/logger" "quantex.com/qfixdpl/src/common/tracerr" "quantex.com/qfixdpl/src/domain" ) // TradeProvider exposes trade data from the FIX manager. type TradeProvider interface { GetTrades() []domain.ListTrade GetPendingQuoteRequests() []domain.ListTrade SendQuote(quoteReqID string, price decimal.Decimal) error GetAllMessages() []domain.Message } const RedisMaxIdle = 3000 // In ms type API struct { Router *gin.Engine Controller *Controller Port string } type Config struct { AllowedOrigins []string External map[string]app.ExtAuth `toml:"External"` AuthorizedServices map[string]app.AuthorizedService `toml:"AuthorizedServices"` Port string EnableJWTAuth bool } func New(userData app.UserDataProvider, storeInstance *store.Store, tradeProvider TradeProvider, config Config, notify domain.Notifier) *API { // Set up Gin var engine *gin.Engine if version.Environment() == version.EnvironmentTypeProd { gin.SetMode(gin.ReleaseMode) engine = gin.New() engine.Use(gin.Recovery()) // Use a custom logger middleware engine.Use(logger.GinLoggerMiddleware(slog.Default())) } else { gin.SetMode(gin.DebugMode) engine = gin.New() // Don't use recovery middleware in debug mode engine.Use(gin.Logger()) } err := engine.SetTrustedProxies([]string{"127.0.0.1"}) if err != nil { panic("error setting trusted proxies: %v" + err.Error()) } if config.Port == "" { panic("API Base Port can not be empty!") } api := &API{ Controller: newController(NewPool(), userData, storeInstance, tradeProvider, config, notify), Router: engine, Port: config.Port, } SetRoutes(api) return api } func NewPool() *redis.Pool { return &redis.Pool{ MaxIdle: RedisMaxIdle, IdleTimeout: 1 * time.Second, Dial: func() (redis.Conn, error) { c, err := redis.DialURL("redis://localhost") if err != nil { return nil, tracerr.Errorf("error connecting to Redis: %w", err) } return c, nil }, } } // Run starts the API func (api *API) Run() { // Gin blocks the calling gorutine, so we start it in its own gorutine // calling directly go api.Router.Run doesn't prevent having to press double // ctrl+c to stop the service go func() { // start the server slog.Error(api.Router.Run("localhost:" + api.Port).Error()) }() }