diff --git a/api/gateway/mntx/client/client.go b/api/gateway/mntx/client/client.go index e0d967a..ce29920 100644 --- a/api/gateway/mntx/client/client.go +++ b/api/gateway/mntx/client/client.go @@ -7,6 +7,7 @@ import ( "github.com/tech/sendico/pkg/merrors" mntxv1 "github.com/tech/sendico/pkg/proto/gateway/mntx/v1" + "go.uber.org/zap" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) @@ -23,6 +24,7 @@ type gatewayClient struct { conn *grpc.ClientConn client mntxv1.MntxGatewayServiceClient cfg Config + logger *zap.Logger } // New dials the Monetix gateway. @@ -47,6 +49,7 @@ func New(ctx context.Context, cfg Config, opts ...grpc.DialOption) (Client, erro conn: conn, client: mntxv1.NewMntxGatewayServiceClient(conn), cfg: cfg, + logger: cfg.Logger, }, nil } @@ -57,28 +60,39 @@ func (g *gatewayClient) Close() error { 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 if timeout <= 0 { 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) } 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() return g.client.CreateCardPayout(ctx, req) } 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() return g.client.CreateCardTokenPayout(ctx, req) } 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() return g.client.GetCardPayoutStatus(ctx, req) } diff --git a/api/gateway/mntx/client/config.go b/api/gateway/mntx/client/config.go index 08a4c7e..0701d8a 100644 --- a/api/gateway/mntx/client/config.go +++ b/api/gateway/mntx/client/config.go @@ -1,12 +1,17 @@ package client -import "time" +import ( + "time" + + "go.uber.org/zap" +) // Config holds Monetix gateway client settings. type Config struct { Address string DialTimeout time.Duration CallTimeout time.Duration + Logger *zap.Logger } func (c *Config) setDefaults() { @@ -16,4 +21,7 @@ func (c *Config) setDefaults() { if c.CallTimeout <= 0 { c.CallTimeout = 10 * time.Second } + if c.Logger == nil { + c.Logger = zap.NewNop() + } } diff --git a/api/gateway/mntx/internal/service/gateway/card_processor.go b/api/gateway/mntx/internal/service/gateway/card_processor.go index 857e736..a74a7c4 100644 --- a/api/gateway/mntx/internal/service/gateway/card_processor.go +++ b/api/gateway/mntx/internal/service/gateway/card_processor.go @@ -343,7 +343,12 @@ func (p *cardPayoutProcessor) ProcessCallback(ctx context.Context, payload []byt return http.StatusBadRequest, merrors.InvalidArgument("signature is missing") } 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 } diff --git a/api/gateway/mntx/internal/service/monetix/sender.go b/api/gateway/mntx/internal/service/monetix/sender.go index 90cc406..f5682e7 100644 --- a/api/gateway/mntx/internal/service/monetix/sender.go +++ b/api/gateway/mntx/internal/service/monetix/sender.go @@ -106,12 +106,23 @@ func (c *Client) sendTokenization(ctx context.Context, req CardTokenizeRequest) zap.String("masked_pan", MaskPAN(req.Card.PAN)), ) + logRequestDeadline(c.logger, ctx, url) start := time.Now() resp, err := c.client.Do(httpReq) duration := time.Since(start) if err != nil { 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()) } defer resp.Body.Close() @@ -221,11 +232,23 @@ func (c *Client) send(ctx context.Context, req any, path string, dispatchLog fun dispatchLog() } + logRequestDeadline(c.logger, ctx, url) start := time.Now() resp, err := c.client.Do(httpReq) duration := time.Since(start) if err != nil { 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()) } 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") } } + +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)), + ) +} diff --git a/api/payments/orchestrator/config.yml b/api/payments/orchestrator/config.yml index dcc995c..c78f6f0 100644 --- a/api/payments/orchestrator/config.yml +++ b/api/payments/orchestrator/config.yml @@ -54,7 +54,7 @@ gateway: mntx: address: "sendico_mntx_gateway:50075" dial_timeout_seconds: 5 - call_timeout_seconds: 3 + call_timeout_seconds: 15 insecure: true oracle: diff --git a/api/payments/orchestrator/internal/server/internal/serverimp.go b/api/payments/orchestrator/internal/server/internal/serverimp.go index 1e26c44..b025934 100644 --- a/api/payments/orchestrator/internal/server/internal/serverimp.go +++ b/api/payments/orchestrator/internal/server/internal/serverimp.go @@ -273,6 +273,7 @@ func (i *Imp) initMntxClient(cfg clientConfig) mntxclient.Client { Address: addr, DialTimeout: cfg.dialTimeout(), CallTimeout: cfg.callTimeout(), + Logger: i.logger.Named("client.mntx"), }) if err != nil { i.logger.Warn("Failed to connect to mntx gateway service", zap.String("address", addr), zap.Error(err)) diff --git a/frontend/pweb/caddy/Caddyfile b/frontend/pweb/caddy/Caddyfile index 4b3246d..966c834 100644 --- a/frontend/pweb/caddy/Caddyfile +++ b/frontend/pweb/caddy/Caddyfile @@ -39,7 +39,7 @@ @monetixSuccess { path /gateway/m/success* 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 { rewrite * /monetix/callback @@ -50,7 +50,7 @@ @monetixFail { path /gateway/m/fail* 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 { rewrite * /monetix/callback diff --git a/frontend/pweb/lib/providers/mock_payment.dart b/frontend/pweb/lib/providers/mock_payment.dart deleted file mode 100644 index 6c8ed24..0000000 --- a/frontend/pweb/lib/providers/mock_payment.dart +++ /dev/null @@ -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(); - } -} \ No newline at end of file