|
|
|
|
@@ -12,7 +12,6 @@ import (
|
|
|
|
|
|
|
|
|
|
oracleclient "github.com/tech/sendico/fx/oracle/client"
|
|
|
|
|
chainclient "github.com/tech/sendico/gateway/chain/client"
|
|
|
|
|
mntxclient "github.com/tech/sendico/gateway/mntx/client"
|
|
|
|
|
ledgerclient "github.com/tech/sendico/ledger/client"
|
|
|
|
|
"github.com/tech/sendico/pkg/discovery"
|
|
|
|
|
"github.com/tech/sendico/pkg/merrors"
|
|
|
|
|
@@ -28,15 +27,9 @@ import (
|
|
|
|
|
const discoveryLogThrottle = 30 * time.Second
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
feesServiceNames = []string{"BILLING_FEES", string(mservice.FeePlans)}
|
|
|
|
|
ledgerServiceNames = []string{"LEDGER", string(mservice.Ledger)}
|
|
|
|
|
oracleServiceNames = []string{"FX_ORACLE", string(mservice.FXOracle)}
|
|
|
|
|
mntxServiceNames = []string{discovery.RailCardPayout, string(mservice.MntxGateway)}
|
|
|
|
|
|
|
|
|
|
feesRequiredOps = []string{discovery.OperationFeeCalc}
|
|
|
|
|
ledgerRequiredOps = discovery.LedgerServiceOperations()
|
|
|
|
|
oracleRequiredOps = []string{discovery.OperationFXQuote}
|
|
|
|
|
mntxRequiredOps = discovery.CardPayoutRailGatewayOperations()
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type discoveryEndpoint struct {
|
|
|
|
|
@@ -64,9 +57,6 @@ type discoveryClientResolver struct {
|
|
|
|
|
oracleClient oracleclient.Client
|
|
|
|
|
oracleEndpoint discoveryEndpoint
|
|
|
|
|
|
|
|
|
|
mntxClient mntxclient.Client
|
|
|
|
|
mntxEndpoint discoveryEndpoint
|
|
|
|
|
|
|
|
|
|
chainClients map[string]chainclient.Client
|
|
|
|
|
|
|
|
|
|
lastSelection map[string]string
|
|
|
|
|
@@ -101,10 +91,6 @@ func (r *discoveryClientResolver) Close() {
|
|
|
|
|
_ = r.oracleClient.Close()
|
|
|
|
|
r.oracleClient = nil
|
|
|
|
|
}
|
|
|
|
|
if r.mntxClient != nil {
|
|
|
|
|
_ = r.mntxClient.Close()
|
|
|
|
|
r.mntxClient = nil
|
|
|
|
|
}
|
|
|
|
|
for key, client := range r.chainClients {
|
|
|
|
|
if client != nil {
|
|
|
|
|
_ = client.Close()
|
|
|
|
|
@@ -114,27 +100,22 @@ func (r *discoveryClientResolver) Close() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *discoveryClientResolver) FeesAvailable() bool {
|
|
|
|
|
_, ok := r.findEntry("fees", feesServiceNames, "", "", feesRequiredOps)
|
|
|
|
|
_, ok := r.findEntry(mservice.BillingFees, "", "", feesRequiredOps)
|
|
|
|
|
return ok
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *discoveryClientResolver) LedgerAvailable() bool {
|
|
|
|
|
_, ok := r.findEntry("ledger", ledgerServiceNames, "", "", ledgerRequiredOps)
|
|
|
|
|
_, ok := r.findEntry(mservice.Ledger, "", "", ledgerRequiredOps)
|
|
|
|
|
return ok
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *discoveryClientResolver) OracleAvailable() bool {
|
|
|
|
|
_, ok := r.findEntry("oracle", oracleServiceNames, "", "", oracleRequiredOps)
|
|
|
|
|
return ok
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *discoveryClientResolver) MntxAvailable() bool {
|
|
|
|
|
_, ok := r.findEntry("mntx", mntxServiceNames, "", "", mntxRequiredOps)
|
|
|
|
|
_, ok := r.findEntry(mservice.FXOracle, "", "", oracleRequiredOps)
|
|
|
|
|
return ok
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *discoveryClientResolver) FeesClient(ctx context.Context) (feesv1.FeeEngineClient, error) {
|
|
|
|
|
entry, ok := r.findEntry("fees", feesServiceNames, "", "", feesRequiredOps)
|
|
|
|
|
entry, ok := r.findEntry(mservice.BillingFees, "", "", feesRequiredOps)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, merrors.NoData("discovery: fees service unavailable")
|
|
|
|
|
}
|
|
|
|
|
@@ -154,7 +135,7 @@ func (r *discoveryClientResolver) FeesClient(ctx context.Context) (feesv1.FeeEng
|
|
|
|
|
}
|
|
|
|
|
conn, dialErr := dialGrpc(ctx, endpoint)
|
|
|
|
|
if dialErr != nil {
|
|
|
|
|
r.logMissing("fees", "failed to dial fees service", endpoint.raw, dialErr)
|
|
|
|
|
r.logMissing("fees", "Failed to dial fees service", endpoint.raw, dialErr)
|
|
|
|
|
return nil, dialErr
|
|
|
|
|
}
|
|
|
|
|
r.feesConn = conn
|
|
|
|
|
@@ -165,13 +146,13 @@ func (r *discoveryClientResolver) FeesClient(ctx context.Context) (feesv1.FeeEng
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *discoveryClientResolver) LedgerClient(ctx context.Context) (ledgerclient.Client, error) {
|
|
|
|
|
entry, ok := r.findEntry("ledger", ledgerServiceNames, "", "", ledgerRequiredOps)
|
|
|
|
|
entry, ok := r.findEntry(mservice.Ledger, "", "", ledgerRequiredOps)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, merrors.NoData("discovery: ledger service unavailable")
|
|
|
|
|
}
|
|
|
|
|
endpoint, err := parseDiscoveryEndpoint(entry.InvokeURI)
|
|
|
|
|
if err != nil {
|
|
|
|
|
r.logMissing("ledger", "invalid ledger invoke uri", entry.InvokeURI, err)
|
|
|
|
|
r.logMissing("ledger", "Invalid ledger invoke uri", entry.InvokeURI, err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -188,7 +169,7 @@ func (r *discoveryClientResolver) LedgerClient(ctx context.Context) (ledgerclien
|
|
|
|
|
Insecure: endpoint.insecure,
|
|
|
|
|
})
|
|
|
|
|
if dialErr != nil {
|
|
|
|
|
r.logMissing("ledger", "failed to dial ledger service", endpoint.raw, dialErr)
|
|
|
|
|
r.logMissing("ledger", "Failed to dial ledger service", endpoint.raw, dialErr)
|
|
|
|
|
return nil, dialErr
|
|
|
|
|
}
|
|
|
|
|
r.ledgerClient = client
|
|
|
|
|
@@ -199,13 +180,13 @@ func (r *discoveryClientResolver) LedgerClient(ctx context.Context) (ledgerclien
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *discoveryClientResolver) OracleClient(ctx context.Context) (oracleclient.Client, error) {
|
|
|
|
|
entry, ok := r.findEntry("oracle", oracleServiceNames, "", "", oracleRequiredOps)
|
|
|
|
|
entry, ok := r.findEntry(mservice.FXOracle, "", "", oracleRequiredOps)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, merrors.NoData("discovery: oracle service unavailable")
|
|
|
|
|
}
|
|
|
|
|
endpoint, err := parseDiscoveryEndpoint(entry.InvokeURI)
|
|
|
|
|
if err != nil {
|
|
|
|
|
r.logMissing("oracle", "invalid oracle invoke uri", entry.InvokeURI, err)
|
|
|
|
|
r.logMissing("oracle", "Invalid oracle invoke uri", entry.InvokeURI, err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -222,7 +203,7 @@ func (r *discoveryClientResolver) OracleClient(ctx context.Context) (oracleclien
|
|
|
|
|
Insecure: endpoint.insecure,
|
|
|
|
|
})
|
|
|
|
|
if dialErr != nil {
|
|
|
|
|
r.logMissing("oracle", "failed to dial oracle service", endpoint.raw, dialErr)
|
|
|
|
|
r.logMissing("oracle", "Failed to dial oracle service", endpoint.raw, dialErr)
|
|
|
|
|
return nil, dialErr
|
|
|
|
|
}
|
|
|
|
|
r.oracleClient = client
|
|
|
|
|
@@ -232,47 +213,10 @@ func (r *discoveryClientResolver) OracleClient(ctx context.Context) (oracleclien
|
|
|
|
|
return r.oracleClient, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *discoveryClientResolver) MntxClient(ctx context.Context) (mntxclient.Client, error) {
|
|
|
|
|
entry, ok := r.findEntry("mntx", mntxServiceNames, "", "", mntxRequiredOps)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, merrors.NoData("discovery: mntx service unavailable")
|
|
|
|
|
}
|
|
|
|
|
endpoint, err := parseDiscoveryEndpoint(entry.InvokeURI)
|
|
|
|
|
if err != nil {
|
|
|
|
|
r.logMissing("mntx", "invalid mntx invoke uri", entry.InvokeURI, err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r.mu.Lock()
|
|
|
|
|
defer r.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
if r.mntxClient == nil || r.mntxEndpoint.key() != endpoint.key() || r.mntxEndpoint.address != endpoint.address {
|
|
|
|
|
if r.mntxClient != nil {
|
|
|
|
|
_ = r.mntxClient.Close()
|
|
|
|
|
r.mntxClient = nil
|
|
|
|
|
}
|
|
|
|
|
if !endpoint.insecure && r.logger != nil {
|
|
|
|
|
r.logger.Warn("Mntx gateway does not support TLS, falling back to insecure transport",
|
|
|
|
|
zap.String("invoke_uri", endpoint.raw))
|
|
|
|
|
}
|
|
|
|
|
client, dialErr := mntxclient.New(ctx, mntxclient.Config{
|
|
|
|
|
Address: endpoint.address,
|
|
|
|
|
})
|
|
|
|
|
if dialErr != nil {
|
|
|
|
|
r.logMissing("mntx", "failed to dial mntx service", endpoint.raw, dialErr)
|
|
|
|
|
return nil, dialErr
|
|
|
|
|
}
|
|
|
|
|
r.mntxClient = client
|
|
|
|
|
r.mntxEndpoint = endpoint
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return r.mntxClient, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *discoveryClientResolver) ChainClient(ctx context.Context, invokeURI string) (chainclient.Client, error) {
|
|
|
|
|
endpoint, err := parseDiscoveryEndpoint(invokeURI)
|
|
|
|
|
if err != nil {
|
|
|
|
|
r.logMissing("chain", "invalid chain gateway invoke uri", invokeURI, err)
|
|
|
|
|
r.logMissing("chain", "Invalid chain gateway invoke uri", invokeURI, err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -288,7 +232,7 @@ func (r *discoveryClientResolver) ChainClient(ctx context.Context, invokeURI str
|
|
|
|
|
Insecure: endpoint.insecure,
|
|
|
|
|
})
|
|
|
|
|
if dialErr != nil {
|
|
|
|
|
r.logMissing("chain", "failed to dial chain gateway", endpoint.raw, dialErr)
|
|
|
|
|
r.logMissing("chain", "Failed to dial chain gateway", endpoint.raw, dialErr)
|
|
|
|
|
return nil, dialErr
|
|
|
|
|
}
|
|
|
|
|
r.chainClients[endpoint.key()] = client
|
|
|
|
|
@@ -298,7 +242,7 @@ func (r *discoveryClientResolver) ChainClient(ctx context.Context, invokeURI str
|
|
|
|
|
func (r *discoveryClientResolver) PaymentGatewayClient(ctx context.Context, invokeURI string) (chainclient.Client, error) {
|
|
|
|
|
endpoint, err := parseDiscoveryEndpoint(invokeURI)
|
|
|
|
|
if err != nil {
|
|
|
|
|
r.logMissing("payment_gateway", "invalid payment gateway invoke uri", invokeURI, err)
|
|
|
|
|
r.logMissing("payment_gateway", "Invalid payment gateway invoke uri", invokeURI, err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -314,16 +258,18 @@ func (r *discoveryClientResolver) PaymentGatewayClient(ctx context.Context, invo
|
|
|
|
|
Insecure: endpoint.insecure,
|
|
|
|
|
})
|
|
|
|
|
if dialErr != nil {
|
|
|
|
|
r.logMissing("payment_gateway", "failed to dial payment gateway", endpoint.raw, dialErr)
|
|
|
|
|
r.logMissing("payment_gateway", "Failed to dial payment gateway", endpoint.raw, dialErr)
|
|
|
|
|
return nil, dialErr
|
|
|
|
|
}
|
|
|
|
|
r.chainClients[endpoint.key()] = client
|
|
|
|
|
return client, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *discoveryClientResolver) findEntry(key string, services []string, rail string, network string, requiredOps []string) (*discovery.RegistryEntry, bool) {
|
|
|
|
|
func (r *discoveryClientResolver) findEntry(service mservice.Type, rail string, network string, requiredOps []string) (*discovery.RegistryEntry, bool) {
|
|
|
|
|
key := discoverySelectionKey(service, rail, network)
|
|
|
|
|
|
|
|
|
|
if r == nil || r.registry == nil {
|
|
|
|
|
r.logMissing(key, "discovery registry unavailable", "", nil)
|
|
|
|
|
r.logMissing(key, "Discovery registry unavailable", "", nil)
|
|
|
|
|
return nil, false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -335,7 +281,7 @@ func (r *discoveryClientResolver) findEntry(key string, services []string, rail
|
|
|
|
|
entries := r.registry.List(time.Now(), true)
|
|
|
|
|
matches := make([]discoveryMatch, 0)
|
|
|
|
|
for _, entry := range entries {
|
|
|
|
|
if !matchesService(entry.Service, services) {
|
|
|
|
|
if service != "" && !matchesService(entry.Service, service) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if rail != "" && !strings.EqualFold(strings.TrimSpace(entry.Rail), rail) {
|
|
|
|
|
@@ -351,7 +297,7 @@ func (r *discoveryClientResolver) findEntry(key string, services []string, rail
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(matches) == 0 {
|
|
|
|
|
r.logMissing(key, "discovery entry missing", "", nil)
|
|
|
|
|
r.logMissing(key, "Discovery entry missing", "", nil)
|
|
|
|
|
return nil, false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -374,6 +320,27 @@ func (r *discoveryClientResolver) findEntry(key string, services []string, rail
|
|
|
|
|
return &entry, true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func discoverySelectionKey(service mservice.Type, rail, network string) string {
|
|
|
|
|
serviceName := strings.TrimSpace(string(service))
|
|
|
|
|
railName := strings.ToUpper(strings.TrimSpace(rail))
|
|
|
|
|
networkName := strings.ToUpper(strings.TrimSpace(network))
|
|
|
|
|
|
|
|
|
|
switch {
|
|
|
|
|
case serviceName != "" && railName != "" && networkName != "":
|
|
|
|
|
return fmt.Sprintf("%s|%s|%s", serviceName, railName, networkName)
|
|
|
|
|
case serviceName != "" && railName != "":
|
|
|
|
|
return fmt.Sprintf("%s|%s", serviceName, railName)
|
|
|
|
|
case serviceName != "":
|
|
|
|
|
return serviceName
|
|
|
|
|
case railName != "" && networkName != "":
|
|
|
|
|
return fmt.Sprintf("rail:%s|%s", railName, networkName)
|
|
|
|
|
case railName != "":
|
|
|
|
|
return "rail:" + railName
|
|
|
|
|
default:
|
|
|
|
|
return "discovery"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *discoveryClientResolver) logSelection(key, entryKey string, entry discovery.RegistryEntry) {
|
|
|
|
|
r.mu.Lock()
|
|
|
|
|
last := r.lastSelection[key]
|
|
|
|
|
@@ -423,17 +390,12 @@ func discoveryEntryKey(entry discovery.RegistryEntry) string {
|
|
|
|
|
strings.TrimSpace(entry.InvokeURI))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func matchesService(service string, candidates []string) bool {
|
|
|
|
|
func matchesService(service string, candidate mservice.Type) bool {
|
|
|
|
|
service = strings.TrimSpace(service)
|
|
|
|
|
if service == "" || len(candidates) == 0 {
|
|
|
|
|
if service == "" || strings.TrimSpace(string(candidate)) == "" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
for _, candidate := range candidates {
|
|
|
|
|
if strings.EqualFold(service, strings.TrimSpace(candidate)) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
return strings.EqualFold(service, strings.TrimSpace(string(candidate)))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parseDiscoveryEndpoint(raw string) (discoveryEndpoint, error) {
|
|
|
|
|
|