increased payout timeout
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/tech/sendico/pkg/merrors"
|
"github.com/tech/sendico/pkg/merrors"
|
||||||
mntxv1 "github.com/tech/sendico/pkg/proto/gateway/mntx/v1"
|
mntxv1 "github.com/tech/sendico/pkg/proto/gateway/mntx/v1"
|
||||||
|
"go.uber.org/zap"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
)
|
)
|
||||||
@@ -23,6 +24,7 @@ type gatewayClient struct {
|
|||||||
conn *grpc.ClientConn
|
conn *grpc.ClientConn
|
||||||
client mntxv1.MntxGatewayServiceClient
|
client mntxv1.MntxGatewayServiceClient
|
||||||
cfg Config
|
cfg Config
|
||||||
|
logger *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// New dials the Monetix gateway.
|
// New dials the Monetix gateway.
|
||||||
@@ -47,6 +49,7 @@ func New(ctx context.Context, cfg Config, opts ...grpc.DialOption) (Client, erro
|
|||||||
conn: conn,
|
conn: conn,
|
||||||
client: mntxv1.NewMntxGatewayServiceClient(conn),
|
client: mntxv1.NewMntxGatewayServiceClient(conn),
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
logger: cfg.Logger,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,28 +60,39 @@ func (g *gatewayClient) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *gatewayClient) callContext(ctx context.Context) (context.Context, context.CancelFunc) {
|
func (g *gatewayClient) callContext(ctx context.Context, method string) (context.Context, context.CancelFunc) {
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
timeout := g.cfg.CallTimeout
|
timeout := g.cfg.CallTimeout
|
||||||
if timeout <= 0 {
|
if timeout <= 0 {
|
||||||
timeout = 5 * time.Second
|
timeout = 5 * time.Second
|
||||||
}
|
}
|
||||||
|
fields := []zap.Field{
|
||||||
|
zap.String("method", method),
|
||||||
|
zap.Duration("timeout", timeout),
|
||||||
|
}
|
||||||
|
if deadline, ok := ctx.Deadline(); ok {
|
||||||
|
fields = append(fields, zap.Time("parent_deadline", deadline), zap.Duration("parent_deadline_in", time.Until(deadline)))
|
||||||
|
}
|
||||||
|
g.logger.Info("Mntx gateway client call timeout applied", fields...)
|
||||||
return context.WithTimeout(ctx, timeout)
|
return context.WithTimeout(ctx, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *gatewayClient) CreateCardPayout(ctx context.Context, req *mntxv1.CardPayoutRequest) (*mntxv1.CardPayoutResponse, error) {
|
func (g *gatewayClient) CreateCardPayout(ctx context.Context, req *mntxv1.CardPayoutRequest) (*mntxv1.CardPayoutResponse, error) {
|
||||||
ctx, cancel := g.callContext(ctx)
|
ctx, cancel := g.callContext(ctx, "CreateCardPayout")
|
||||||
defer cancel()
|
defer cancel()
|
||||||
return g.client.CreateCardPayout(ctx, req)
|
return g.client.CreateCardPayout(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *gatewayClient) CreateCardTokenPayout(ctx context.Context, req *mntxv1.CardTokenPayoutRequest) (*mntxv1.CardTokenPayoutResponse, error) {
|
func (g *gatewayClient) CreateCardTokenPayout(ctx context.Context, req *mntxv1.CardTokenPayoutRequest) (*mntxv1.CardTokenPayoutResponse, error) {
|
||||||
ctx, cancel := g.callContext(ctx)
|
ctx, cancel := g.callContext(ctx, "CreateCardTokenPayout")
|
||||||
defer cancel()
|
defer cancel()
|
||||||
return g.client.CreateCardTokenPayout(ctx, req)
|
return g.client.CreateCardTokenPayout(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *gatewayClient) GetCardPayoutStatus(ctx context.Context, req *mntxv1.GetCardPayoutStatusRequest) (*mntxv1.GetCardPayoutStatusResponse, error) {
|
func (g *gatewayClient) GetCardPayoutStatus(ctx context.Context, req *mntxv1.GetCardPayoutStatusRequest) (*mntxv1.GetCardPayoutStatusResponse, error) {
|
||||||
ctx, cancel := g.callContext(ctx)
|
ctx, cancel := g.callContext(ctx, "GetCardPayoutStatus")
|
||||||
defer cancel()
|
defer cancel()
|
||||||
return g.client.GetCardPayoutStatus(ctx, req)
|
return g.client.GetCardPayoutStatus(ctx, req)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
// Config holds Monetix gateway client settings.
|
// Config holds Monetix gateway client settings.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Address string
|
Address string
|
||||||
DialTimeout time.Duration
|
DialTimeout time.Duration
|
||||||
CallTimeout time.Duration
|
CallTimeout time.Duration
|
||||||
|
Logger *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) setDefaults() {
|
func (c *Config) setDefaults() {
|
||||||
@@ -16,4 +21,7 @@ func (c *Config) setDefaults() {
|
|||||||
if c.CallTimeout <= 0 {
|
if c.CallTimeout <= 0 {
|
||||||
c.CallTimeout = 10 * time.Second
|
c.CallTimeout = 10 * time.Second
|
||||||
}
|
}
|
||||||
|
if c.Logger == nil {
|
||||||
|
c.Logger = zap.NewNop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -343,7 +343,12 @@ func (p *cardPayoutProcessor) ProcessCallback(ctx context.Context, payload []byt
|
|||||||
return http.StatusBadRequest, merrors.InvalidArgument("signature is missing")
|
return http.StatusBadRequest, merrors.InvalidArgument("signature is missing")
|
||||||
}
|
}
|
||||||
if err := verifyCallbackSignature(cb, p.config.SecretKey); err != nil {
|
if err := verifyCallbackSignature(cb, p.config.SecretKey); err != nil {
|
||||||
p.logger.Warn("Monetix callback signature check failed", zap.Error(err))
|
p.logger.Warn("Monetix callback signature check failed",
|
||||||
|
zap.String("payout_id", cb.Payment.ID),
|
||||||
|
zap.String("signature", cb.Signature),
|
||||||
|
zap.String("payload", string(payload)),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
return http.StatusForbidden, err
|
return http.StatusForbidden, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,12 +106,23 @@ func (c *Client) sendTokenization(ctx context.Context, req CardTokenizeRequest)
|
|||||||
zap.String("masked_pan", MaskPAN(req.Card.PAN)),
|
zap.String("masked_pan", MaskPAN(req.Card.PAN)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logRequestDeadline(c.logger, ctx, url)
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
resp, err := c.client.Do(httpReq)
|
resp, err := c.client.Do(httpReq)
|
||||||
duration := time.Since(start)
|
duration := time.Since(start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
observeRequest(outcomeNetworkError, duration)
|
observeRequest(outcomeNetworkError, duration)
|
||||||
c.logger.Warn("Monetix tokenization request failed", zap.Error(err))
|
fields := []zap.Field{
|
||||||
|
zap.String("url", url),
|
||||||
|
zap.Error(err),
|
||||||
|
}
|
||||||
|
if ctxErr := ctx.Err(); ctxErr != nil {
|
||||||
|
fields = append(fields, zap.NamedError("ctx_error", ctxErr))
|
||||||
|
}
|
||||||
|
if deadline, ok := ctx.Deadline(); ok {
|
||||||
|
fields = append(fields, zap.Time("deadline", deadline), zap.Duration("time_until_deadline", time.Until(deadline)))
|
||||||
|
}
|
||||||
|
c.logger.Warn("Monetix tokenization request failed", fields...)
|
||||||
return nil, merrors.Internal("monetix tokenization request failed: " + err.Error())
|
return nil, merrors.Internal("monetix tokenization request failed: " + err.Error())
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@@ -221,11 +232,23 @@ func (c *Client) send(ctx context.Context, req any, path string, dispatchLog fun
|
|||||||
dispatchLog()
|
dispatchLog()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logRequestDeadline(c.logger, ctx, url)
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
resp, err := c.client.Do(httpReq)
|
resp, err := c.client.Do(httpReq)
|
||||||
duration := time.Since(start)
|
duration := time.Since(start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
observeRequest(outcomeNetworkError, duration)
|
observeRequest(outcomeNetworkError, duration)
|
||||||
|
fields := []zap.Field{
|
||||||
|
zap.String("url", url),
|
||||||
|
zap.Error(err),
|
||||||
|
}
|
||||||
|
if ctxErr := ctx.Err(); ctxErr != nil {
|
||||||
|
fields = append(fields, zap.NamedError("ctx_error", ctxErr))
|
||||||
|
}
|
||||||
|
if deadline, ok := ctx.Deadline(); ok {
|
||||||
|
fields = append(fields, zap.Time("deadline", deadline), zap.Duration("time_until_deadline", time.Until(deadline)))
|
||||||
|
}
|
||||||
|
c.logger.Warn("Monetix request failed", fields...)
|
||||||
return nil, merrors.Internal("monetix request failed: " + err.Error())
|
return nil, merrors.Internal("monetix request failed: " + err.Error())
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@@ -288,3 +311,23 @@ func clearSignature(req any) (func(string), error) {
|
|||||||
return nil, merrors.Internal("unsupported monetix payload type for signing")
|
return nil, merrors.Internal("unsupported monetix payload type for signing")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func logRequestDeadline(logger *zap.Logger, ctx context.Context, url string) {
|
||||||
|
if logger == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ctx == nil {
|
||||||
|
logger.Info("Monetix request context is nil", zap.String("url", url))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
deadline, ok := ctx.Deadline()
|
||||||
|
if !ok {
|
||||||
|
logger.Info("Monetix request context has no deadline", zap.String("url", url))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.Info("Monetix request context deadline",
|
||||||
|
zap.String("url", url),
|
||||||
|
zap.Time("deadline", deadline),
|
||||||
|
zap.Duration("time_until_deadline", time.Until(deadline)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ gateway:
|
|||||||
mntx:
|
mntx:
|
||||||
address: "sendico_mntx_gateway:50075"
|
address: "sendico_mntx_gateway:50075"
|
||||||
dial_timeout_seconds: 5
|
dial_timeout_seconds: 5
|
||||||
call_timeout_seconds: 3
|
call_timeout_seconds: 15
|
||||||
insecure: true
|
insecure: true
|
||||||
|
|
||||||
oracle:
|
oracle:
|
||||||
|
|||||||
@@ -273,6 +273,7 @@ func (i *Imp) initMntxClient(cfg clientConfig) mntxclient.Client {
|
|||||||
Address: addr,
|
Address: addr,
|
||||||
DialTimeout: cfg.dialTimeout(),
|
DialTimeout: cfg.dialTimeout(),
|
||||||
CallTimeout: cfg.callTimeout(),
|
CallTimeout: cfg.callTimeout(),
|
||||||
|
Logger: i.logger.Named("client.mntx"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
i.logger.Warn("Failed to connect to mntx gateway service", zap.String("address", addr), zap.Error(err))
|
i.logger.Warn("Failed to connect to mntx gateway service", zap.String("address", addr), zap.Error(err))
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
@monetixSuccess {
|
@monetixSuccess {
|
||||||
path /gateway/m/success*
|
path /gateway/m/success*
|
||||||
method POST
|
method POST
|
||||||
# remote_ip 88.218.112.16 88.218.112.16/32 88.218.113.16 88.218.113.16/32 93.179.90.141 93.179.90.128/25 93.179.90.161 93.179.91.0/24 178.57.67.47 178.57.66.128/25 178.57.67.154 178.57.67.0/24 178.57.68.244
|
remote_ip 88.218.112.16 88.218.112.16/32 88.218.113.16 88.218.113.16/32 93.179.90.141 93.179.90.128/25 93.179.90.161 93.179.91.0/24 178.57.67.47 178.57.66.128/25 178.57.67.154 178.57.67.0/24 178.57.68.244
|
||||||
}
|
}
|
||||||
handle @monetixSuccess {
|
handle @monetixSuccess {
|
||||||
rewrite * /monetix/callback
|
rewrite * /monetix/callback
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
@monetixFail {
|
@monetixFail {
|
||||||
path /gateway/m/fail*
|
path /gateway/m/fail*
|
||||||
method POST
|
method POST
|
||||||
# remote_ip 88.218.112.16 88.218.112.16/32 88.218.113.16 88.218.113.16/32 93.179.90.141 93.179.90.128/25 93.179.90.161 93.179.91.0/24 178.57.67.47 178.57.66.128/25 178.57.67.154 178.57.67.0/24 178.57.68.244
|
remote_ip 88.218.112.16 88.218.112.16/32 88.218.113.16 88.218.113.16/32 93.179.90.141 93.179.90.128/25 93.179.90.161 93.179.91.0/24 178.57.67.47 178.57.66.128/25 178.57.67.154 178.57.67.0/24 178.57.68.244
|
||||||
}
|
}
|
||||||
handle @monetixFail {
|
handle @monetixFail {
|
||||||
rewrite * /monetix/callback
|
rewrite * /monetix/callback
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class MockPaymentProvider with ChangeNotifier {
|
|
||||||
double _amount = 10.0;
|
|
||||||
bool _payerCoversFee = true;
|
|
||||||
|
|
||||||
double get amount => _amount;
|
|
||||||
bool get payerCoversFee => _payerCoversFee;
|
|
||||||
|
|
||||||
double get fee => _amount * 0.05;
|
|
||||||
double get total => payerCoversFee ? (_amount + fee) : _amount;
|
|
||||||
double get recipientGets => payerCoversFee ? _amount : (_amount - fee);
|
|
||||||
|
|
||||||
void setAmount(double value) {
|
|
||||||
_amount = value;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPayerCoversFee(bool value) {
|
|
||||||
_payerCoversFee = value;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user