adding project logic

This commit is contained in:
Ramiro Paz
2026-03-09 16:26:58 -03:00
parent f4ef52e154
commit 557c04436d
11 changed files with 461 additions and 15 deletions

View File

@ -29,23 +29,27 @@ const (
)
type Controller struct {
pool *redis.Pool
userData app.UserDataProvider
store *store.Store
config Config
notify domain.Notifier
authMutex deadlock.Mutex
pool *redis.Pool
userData app.UserDataProvider
store *store.Store
orderStore domain.OrderStore
fixSender domain.FIXSender
config Config
notify domain.Notifier
authMutex deadlock.Mutex
}
func newController(pool *redis.Pool, userData app.UserDataProvider,
s *store.Store, config Config, n domain.Notifier,
s *store.Store, orderStore domain.OrderStore, fixSender domain.FIXSender, config Config, n domain.Notifier,
) *Controller {
return &Controller{
pool: pool,
userData: userData,
store: s,
config: config,
notify: n,
pool: pool,
userData: userData,
store: s,
orderStore: orderStore,
fixSender: fixSender,
config: config,
notify: n,
}
}
@ -288,3 +292,51 @@ func allowed(origin string, config Config) bool {
return false
}
// GetOrders godoc
// @Summary List received FIX orders
// @Description Returns all NewOrderSingle messages received via FIX
// @Tags fix
// @Produce json
// @Success 200 {array} domain.Order
// @Router /qfixdpl/v1/orders [get]
func (cont *Controller) GetOrders(ctx *gin.Context) {
orders := cont.orderStore.GetOrders()
ctx.JSON(http.StatusOK, orders)
}
// SendQuote godoc
// @Summary Send a FIX Quote
// @Description Sends a Quote (MsgType S) back to the FIX client for a given order
// @Tags fix
// @Accept json
// @Produce json
// @Param quote body QuoteRequest true "Quote details"
// @Success 200 {object} Msg
// @Failure 400 {object} HTTPError
// @Failure 404 {object} HTTPError
// @Failure 500 {object} HTTPError
// @Router /qfixdpl/v1/quotes [post]
func (cont *Controller) SendQuote(ctx *gin.Context) {
var req QuoteRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(http.StatusBadRequest, HTTPError{Error: err.Error()})
return
}
bidPx, offerPx, bidSize, offerSize, err := req.toDecimals()
if err != nil {
ctx.JSON(http.StatusBadRequest, HTTPError{Error: err.Error()})
return
}
if err = cont.fixSender.SendQuote(req.ClOrdID, req.QuoteID, req.Symbol, req.Currency, bidPx, offerPx, bidSize, offerSize); err != nil {
ctx.JSON(http.StatusInternalServerError, HTTPError{Error: err.Error()})
return
}
ctx.JSON(http.StatusOK, Msg{Text: "quote sent"})
}

View File

@ -1,5 +1,11 @@
package rest
import (
"fmt"
"github.com/shopspring/decimal"
)
type HTTPError struct {
Error string
}
@ -16,3 +22,42 @@ type Credentials struct {
type Session struct {
Email string
}
type QuoteRequest struct {
ClOrdID string `json:"cl_ord_id" binding:"required"`
QuoteID string `json:"quote_id" binding:"required"`
Symbol string `json:"symbol" binding:"required"`
Currency string `json:"currency"`
BidPx string `json:"bid_px" binding:"required"`
OfferPx string `json:"offer_px" binding:"required"`
BidSize string `json:"bid_size"`
OfferSize string `json:"offer_size"`
}
func (r QuoteRequest) toDecimals() (bidPx, offerPx, bidSize, offerSize decimal.Decimal, err error) {
bidPx, err = decimal.NewFromString(r.BidPx)
if err != nil {
return bidPx, offerPx, bidSize, offerSize, fmt.Errorf("invalid bid_px: %w", err)
}
offerPx, err = decimal.NewFromString(r.OfferPx)
if err != nil {
return bidPx, offerPx, bidSize, offerSize, fmt.Errorf("invalid offer_px: %w", err)
}
if r.BidSize != "" {
bidSize, err = decimal.NewFromString(r.BidSize)
if err != nil {
return bidPx, offerPx, bidSize, offerSize, fmt.Errorf("invalid bid_size: %w", err)
}
}
if r.OfferSize != "" {
offerSize, err = decimal.NewFromString(r.OfferSize)
if err != nil {
return bidPx, offerPx, bidSize, offerSize, fmt.Errorf("invalid offer_size: %w", err)
}
}
return bidPx, offerPx, bidSize, offerSize, nil
}

View File

@ -21,6 +21,8 @@ func SetRoutes(api *API) {
qfixdpl := v1.Group("/")
qfixdpl.Use(cont.AuthRequired)
qfixdpl.GET("/health", cont.HealthCheck)
qfixdpl.GET("/orders", cont.GetOrders)
qfixdpl.POST("/quotes", cont.SendQuote)
backoffice := qfixdpl.Group("/backoffice")
backoffice.Use(cont.BackOfficeUser)

View File

@ -32,7 +32,7 @@ type Config struct {
EnableJWTAuth bool
}
func New(userData app.UserDataProvider, storeInstance *store.Store, config Config, notify domain.Notifier) *API {
func New(userData app.UserDataProvider, storeInstance *store.Store, orderStore domain.OrderStore, fixSender domain.FIXSender, config Config, notify domain.Notifier) *API {
// Set up Gin
var engine *gin.Engine
if version.Environment() == version.EnvironmentTypeProd {
@ -58,7 +58,7 @@ func New(userData app.UserDataProvider, storeInstance *store.Store, config Confi
}
api := &API{
Controller: newController(NewPool(), userData, storeInstance, config, notify),
Controller: newController(NewPool(), userData, storeInstance, orderStore, fixSender, config, notify),
Router: engine,
Port: config.Port,
}