unified gateway interface
This commit is contained in:
@@ -12,12 +12,14 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/tech/sendico/gateway/mntx/internal/appversion"
|
||||
mntxservice "github.com/tech/sendico/gateway/mntx/internal/service/gateway"
|
||||
"github.com/tech/sendico/gateway/mntx/internal/service/monetix"
|
||||
"github.com/tech/sendico/pkg/api/routers"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
msg "github.com/tech/sendico/pkg/messaging"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
gatewayv1 "github.com/tech/sendico/pkg/proto/common/gateway/v1"
|
||||
"github.com/tech/sendico/pkg/server/grpcapp"
|
||||
"go.uber.org/zap"
|
||||
"gopkg.in/yaml.v3"
|
||||
@@ -28,14 +30,16 @@ type Imp struct {
|
||||
file string
|
||||
debug bool
|
||||
|
||||
config *config
|
||||
app *grpcapp.App[struct{}]
|
||||
http *http.Server
|
||||
config *config
|
||||
app *grpcapp.App[struct{}]
|
||||
http *http.Server
|
||||
service *mntxservice.Service
|
||||
}
|
||||
|
||||
type config struct {
|
||||
*grpcapp.Config `yaml:",inline"`
|
||||
Monetix monetixConfig `yaml:"monetix"`
|
||||
Gateway gatewayConfig `yaml:"gateway"`
|
||||
HTTP httpConfig `yaml:"http"`
|
||||
}
|
||||
|
||||
@@ -53,6 +57,33 @@ type monetixConfig struct {
|
||||
StatusProcessing string `yaml:"status_processing"`
|
||||
}
|
||||
|
||||
type gatewayConfig struct {
|
||||
ID string `yaml:"id"`
|
||||
Network string `yaml:"network"`
|
||||
Currencies []string `yaml:"currencies"`
|
||||
IsEnabled *bool `yaml:"is_enabled"`
|
||||
Limits limitsConfig `yaml:"limits"`
|
||||
}
|
||||
|
||||
type limitsConfig struct {
|
||||
MinAmount string `yaml:"min_amount"`
|
||||
MaxAmount string `yaml:"max_amount"`
|
||||
PerTxMaxFee string `yaml:"per_tx_max_fee"`
|
||||
PerTxMinAmount string `yaml:"per_tx_min_amount"`
|
||||
PerTxMaxAmount string `yaml:"per_tx_max_amount"`
|
||||
VolumeLimit map[string]string `yaml:"volume_limit"`
|
||||
VelocityLimit map[string]int `yaml:"velocity_limit"`
|
||||
CurrencyLimits map[string]limitsOverrideCfg `yaml:"currency_limits"`
|
||||
}
|
||||
|
||||
type limitsOverrideCfg struct {
|
||||
MaxVolume string `yaml:"max_volume"`
|
||||
MinAmount string `yaml:"min_amount"`
|
||||
MaxAmount string `yaml:"max_amount"`
|
||||
MaxFee string `yaml:"max_fee"`
|
||||
MaxOps int `yaml:"max_ops"`
|
||||
}
|
||||
|
||||
type httpConfig struct {
|
||||
Callback callbackConfig `yaml:"callback"`
|
||||
}
|
||||
@@ -86,6 +117,9 @@ func (i *Imp) Shutdown() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
if i.service != nil {
|
||||
i.service.Shutdown()
|
||||
}
|
||||
if i.http != nil {
|
||||
_ = i.http.Shutdown(ctx)
|
||||
i.http = nil
|
||||
@@ -131,6 +165,17 @@ func (i *Imp) Start() error {
|
||||
zap.String("status_processing", monetixCfg.ProcessingStatus()),
|
||||
)
|
||||
|
||||
gatewayDescriptor := resolveGatewayDescriptor(cfg.Gateway, monetixCfg)
|
||||
if gatewayDescriptor != nil {
|
||||
i.logger.Info("Gateway descriptor resolved",
|
||||
zap.String("id", gatewayDescriptor.GetId()),
|
||||
zap.String("rail", gatewayDescriptor.GetRail().String()),
|
||||
zap.String("network", gatewayDescriptor.GetNetwork()),
|
||||
zap.Int("currencies", len(gatewayDescriptor.GetCurrencies())),
|
||||
zap.Bool("enabled", gatewayDescriptor.GetIsEnabled()),
|
||||
)
|
||||
}
|
||||
|
||||
i.logger.Info("Callback configuration resolved",
|
||||
zap.String("address", callbackCfg.Address),
|
||||
zap.String("path", callbackCfg.Path),
|
||||
@@ -142,8 +187,10 @@ func (i *Imp) Start() error {
|
||||
svc := mntxservice.NewService(logger,
|
||||
mntxservice.WithProducer(producer),
|
||||
mntxservice.WithMonetixConfig(monetixCfg),
|
||||
mntxservice.WithGatewayDescriptor(gatewayDescriptor),
|
||||
mntxservice.WithHTTPClient(&http.Client{Timeout: monetixCfg.Timeout()}),
|
||||
)
|
||||
i.service = svc
|
||||
|
||||
if err := i.startHTTPCallbackServer(svc, callbackCfg); err != nil {
|
||||
return nil, err
|
||||
@@ -243,6 +290,129 @@ func (i *Imp) resolveMonetixConfig(cfg monetixConfig) (monetix.Config, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func resolveGatewayDescriptor(cfg gatewayConfig, monetixCfg monetix.Config) *gatewayv1.GatewayInstanceDescriptor {
|
||||
id := strings.TrimSpace(cfg.ID)
|
||||
if id == "" {
|
||||
id = "monetix"
|
||||
}
|
||||
|
||||
network := strings.ToUpper(strings.TrimSpace(cfg.Network))
|
||||
currencies := normalizeCurrencies(cfg.Currencies)
|
||||
if len(currencies) == 0 {
|
||||
currencies = normalizeCurrencies(monetixCfg.AllowedCurrencies)
|
||||
}
|
||||
|
||||
enabled := true
|
||||
if cfg.IsEnabled != nil {
|
||||
enabled = *cfg.IsEnabled
|
||||
}
|
||||
|
||||
limits := buildGatewayLimits(cfg.Limits)
|
||||
if limits == nil {
|
||||
limits = &gatewayv1.Limits{MinAmount: "0"}
|
||||
}
|
||||
|
||||
version := strings.TrimSpace(appversion.Version)
|
||||
|
||||
return &gatewayv1.GatewayInstanceDescriptor{
|
||||
Id: id,
|
||||
Rail: gatewayv1.Rail_RAIL_CARD_PAYOUT,
|
||||
Network: network,
|
||||
Currencies: currencies,
|
||||
Capabilities: &gatewayv1.RailCapabilities{
|
||||
CanPayOut: true,
|
||||
CanPayIn: false,
|
||||
CanReadBalance: false,
|
||||
CanSendFee: false,
|
||||
RequiresObserveConfirm: false,
|
||||
},
|
||||
Limits: limits,
|
||||
Version: version,
|
||||
IsEnabled: enabled,
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeCurrencies(values []string) []string {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
result := make([]string, 0, len(values))
|
||||
for _, value := range values {
|
||||
clean := strings.ToUpper(strings.TrimSpace(value))
|
||||
if clean == "" || seen[clean] {
|
||||
continue
|
||||
}
|
||||
seen[clean] = true
|
||||
result = append(result, clean)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func buildGatewayLimits(cfg limitsConfig) *gatewayv1.Limits {
|
||||
hasValue := strings.TrimSpace(cfg.MinAmount) != "" ||
|
||||
strings.TrimSpace(cfg.MaxAmount) != "" ||
|
||||
strings.TrimSpace(cfg.PerTxMaxFee) != "" ||
|
||||
strings.TrimSpace(cfg.PerTxMinAmount) != "" ||
|
||||
strings.TrimSpace(cfg.PerTxMaxAmount) != "" ||
|
||||
len(cfg.VolumeLimit) > 0 ||
|
||||
len(cfg.VelocityLimit) > 0 ||
|
||||
len(cfg.CurrencyLimits) > 0
|
||||
if !hasValue {
|
||||
return nil
|
||||
}
|
||||
|
||||
limits := &gatewayv1.Limits{
|
||||
MinAmount: strings.TrimSpace(cfg.MinAmount),
|
||||
MaxAmount: strings.TrimSpace(cfg.MaxAmount),
|
||||
PerTxMaxFee: strings.TrimSpace(cfg.PerTxMaxFee),
|
||||
PerTxMinAmount: strings.TrimSpace(cfg.PerTxMinAmount),
|
||||
PerTxMaxAmount: strings.TrimSpace(cfg.PerTxMaxAmount),
|
||||
}
|
||||
|
||||
if len(cfg.VolumeLimit) > 0 {
|
||||
limits.VolumeLimit = map[string]string{}
|
||||
for key, value := range cfg.VolumeLimit {
|
||||
bucket := strings.TrimSpace(key)
|
||||
amount := strings.TrimSpace(value)
|
||||
if bucket == "" || amount == "" {
|
||||
continue
|
||||
}
|
||||
limits.VolumeLimit[bucket] = amount
|
||||
}
|
||||
}
|
||||
|
||||
if len(cfg.VelocityLimit) > 0 {
|
||||
limits.VelocityLimit = map[string]int32{}
|
||||
for key, value := range cfg.VelocityLimit {
|
||||
bucket := strings.TrimSpace(key)
|
||||
if bucket == "" {
|
||||
continue
|
||||
}
|
||||
limits.VelocityLimit[bucket] = int32(value)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cfg.CurrencyLimits) > 0 {
|
||||
limits.CurrencyLimits = map[string]*gatewayv1.LimitsOverride{}
|
||||
for key, override := range cfg.CurrencyLimits {
|
||||
currency := strings.ToUpper(strings.TrimSpace(key))
|
||||
if currency == "" {
|
||||
continue
|
||||
}
|
||||
limits.CurrencyLimits[currency] = &gatewayv1.LimitsOverride{
|
||||
MaxVolume: strings.TrimSpace(override.MaxVolume),
|
||||
MinAmount: strings.TrimSpace(override.MinAmount),
|
||||
MaxAmount: strings.TrimSpace(override.MaxAmount),
|
||||
MaxFee: strings.TrimSpace(override.MaxFee),
|
||||
MaxOps: int32(override.MaxOps),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return limits
|
||||
}
|
||||
|
||||
type callbackRuntimeConfig struct {
|
||||
Address string
|
||||
Path string
|
||||
|
||||
Reference in New Issue
Block a user