232 lines
6.7 KiB
Go
232 lines
6.7 KiB
Go
package serverimp
|
|
|
|
import (
|
|
"strings"
|
|
|
|
chainclient "github.com/tech/sendico/gateway/chain/client"
|
|
"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrator"
|
|
"github.com/tech/sendico/payments/orchestrator/storage/model"
|
|
"github.com/tech/sendico/pkg/discovery"
|
|
"github.com/tech/sendico/pkg/mlogger"
|
|
"github.com/tech/sendico/pkg/payments/rail"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func buildCardGatewayRoutes(src map[string]cardGatewayRouteConfig) map[string]orchestrator.CardGatewayRoute {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
result := make(map[string]orchestrator.CardGatewayRoute, len(src))
|
|
for key, route := range src {
|
|
trimmedKey := strings.TrimSpace(key)
|
|
if trimmedKey == "" {
|
|
continue
|
|
}
|
|
result[trimmedKey] = orchestrator.CardGatewayRoute{
|
|
FundingAddress: strings.TrimSpace(route.FundingAddress),
|
|
FeeAddress: strings.TrimSpace(route.FeeAddress),
|
|
FeeWalletRef: strings.TrimSpace(route.FeeWalletRef),
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func buildFeeLedgerAccounts(src map[string]string) map[string]string {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
result := make(map[string]string, len(src))
|
|
for key, account := range src {
|
|
k := strings.ToLower(strings.TrimSpace(key))
|
|
v := strings.TrimSpace(account)
|
|
if k == "" || v == "" {
|
|
continue
|
|
}
|
|
result[k] = v
|
|
}
|
|
return result
|
|
}
|
|
|
|
func buildGatewayRegistry(logger mlogger.Logger, src []gatewayInstanceConfig, registry *discovery.Registry) orchestrator.GatewayRegistry {
|
|
static := buildGatewayInstances(logger, src)
|
|
staticRegistry := orchestrator.NewGatewayRegistry(logger, static)
|
|
discoveryRegistry := orchestrator.NewDiscoveryGatewayRegistry(logger, registry)
|
|
return orchestrator.NewCompositeGatewayRegistry(logger, staticRegistry, discoveryRegistry)
|
|
}
|
|
|
|
func buildRailGateways(chainClient chainclient.Client, paymentGatewayClient chainclient.Client, src []gatewayInstanceConfig) map[string]rail.RailGateway {
|
|
if len(src) == 0 || (chainClient == nil && paymentGatewayClient == nil) {
|
|
return nil
|
|
}
|
|
instances := buildGatewayInstances(nil, src)
|
|
if len(instances) == 0 {
|
|
return nil
|
|
}
|
|
result := map[string]rail.RailGateway{}
|
|
for _, inst := range instances {
|
|
if inst == nil || !inst.IsEnabled {
|
|
continue
|
|
}
|
|
cfg := chainclient.RailGatewayConfig{
|
|
Rail: string(inst.Rail),
|
|
Network: inst.Network,
|
|
Capabilities: rail.RailCapabilities{
|
|
CanPayIn: inst.Capabilities.CanPayIn,
|
|
CanPayOut: inst.Capabilities.CanPayOut,
|
|
CanReadBalance: inst.Capabilities.CanReadBalance,
|
|
CanSendFee: inst.Capabilities.CanSendFee,
|
|
RequiresObserveConfirm: inst.Capabilities.RequiresObserveConfirm,
|
|
},
|
|
}
|
|
switch inst.Rail {
|
|
case model.RailCrypto:
|
|
if chainClient == nil {
|
|
continue
|
|
}
|
|
result[inst.ID] = chainclient.NewRailGateway(chainClient, cfg)
|
|
case model.RailProviderSettlement:
|
|
if paymentGatewayClient == nil {
|
|
continue
|
|
}
|
|
result[inst.ID] = orchestrator.NewProviderSettlementGateway(paymentGatewayClient, cfg)
|
|
}
|
|
}
|
|
if len(result) == 0 {
|
|
return nil
|
|
}
|
|
return result
|
|
}
|
|
|
|
func buildGatewayInstances(logger mlogger.Logger, src []gatewayInstanceConfig) []*model.GatewayInstanceDescriptor {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
if logger != nil {
|
|
logger = logger.Named("gateway_instances")
|
|
}
|
|
result := make([]*model.GatewayInstanceDescriptor, 0, len(src))
|
|
for _, cfg := range src {
|
|
id := strings.TrimSpace(cfg.ID)
|
|
if id == "" {
|
|
if logger != nil {
|
|
logger.Warn("Gateway instance skipped: missing id")
|
|
}
|
|
continue
|
|
}
|
|
rail := parseRail(cfg.Rail)
|
|
if rail == model.RailUnspecified {
|
|
if logger != nil {
|
|
logger.Warn("Gateway instance skipped: invalid rail", zap.String("id", id), zap.String("rail", cfg.Rail))
|
|
}
|
|
continue
|
|
}
|
|
enabled := true
|
|
if cfg.IsEnabled != nil {
|
|
enabled = *cfg.IsEnabled
|
|
}
|
|
result = append(result, &model.GatewayInstanceDescriptor{
|
|
ID: id,
|
|
Rail: rail,
|
|
Network: strings.ToUpper(strings.TrimSpace(cfg.Network)),
|
|
Currencies: normalizeCurrencies(cfg.Currencies),
|
|
Capabilities: model.RailCapabilities{
|
|
CanPayIn: cfg.Capabilities.CanPayIn,
|
|
CanPayOut: cfg.Capabilities.CanPayOut,
|
|
CanReadBalance: cfg.Capabilities.CanReadBalance,
|
|
CanSendFee: cfg.Capabilities.CanSendFee,
|
|
RequiresObserveConfirm: cfg.Capabilities.RequiresObserveConfirm,
|
|
},
|
|
Limits: buildGatewayLimits(cfg.Limits),
|
|
Version: strings.TrimSpace(cfg.Version),
|
|
IsEnabled: enabled,
|
|
})
|
|
}
|
|
return result
|
|
}
|
|
|
|
func parseRail(value string) model.Rail {
|
|
switch strings.ToUpper(strings.TrimSpace(value)) {
|
|
case string(model.RailCrypto):
|
|
return model.RailCrypto
|
|
case string(model.RailProviderSettlement):
|
|
return model.RailProviderSettlement
|
|
case string(model.RailLedger):
|
|
return model.RailLedger
|
|
case string(model.RailCardPayout):
|
|
return model.RailCardPayout
|
|
case string(model.RailFiatOnRamp):
|
|
return model.RailFiatOnRamp
|
|
default:
|
|
return model.RailUnspecified
|
|
}
|
|
}
|
|
|
|
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) model.Limits {
|
|
limits := model.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]int{}
|
|
for key, value := range cfg.VelocityLimit {
|
|
bucket := strings.TrimSpace(key)
|
|
if bucket == "" {
|
|
continue
|
|
}
|
|
limits.VelocityLimit[bucket] = value
|
|
}
|
|
}
|
|
|
|
if len(cfg.CurrencyLimits) > 0 {
|
|
limits.CurrencyLimits = map[string]model.LimitsOverride{}
|
|
for key, override := range cfg.CurrencyLimits {
|
|
currency := strings.ToUpper(strings.TrimSpace(key))
|
|
if currency == "" {
|
|
continue
|
|
}
|
|
limits.CurrencyLimits[currency] = model.LimitsOverride{
|
|
MaxVolume: strings.TrimSpace(override.MaxVolume),
|
|
MinAmount: strings.TrimSpace(override.MinAmount),
|
|
MaxAmount: strings.TrimSpace(override.MaxAmount),
|
|
MaxFee: strings.TrimSpace(override.MaxFee),
|
|
MaxOps: override.MaxOps,
|
|
}
|
|
}
|
|
}
|
|
|
|
return limits
|
|
}
|