Linting #509
@@ -12,6 +12,9 @@ when:
|
||||
path:
|
||||
include:
|
||||
- api/server/**
|
||||
- api/payments/methods/client/**
|
||||
- api/payments/methods/go.mod
|
||||
- api/payments/methods/go.sum
|
||||
- api/proto/**
|
||||
- api/pkg/**
|
||||
ignore_message: '[rebuild]'
|
||||
@@ -41,6 +44,14 @@ steps:
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh bff
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
@@ -61,7 +72,7 @@ steps:
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ proto, secrets ]
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/bff/build-image.sh
|
||||
|
||||
|
||||
@@ -40,6 +40,14 @@ steps:
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh billing_documents
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
@@ -60,7 +68,7 @@ steps:
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ proto, secrets ]
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/billing_documents/build-image.sh
|
||||
|
||||
|
||||
@@ -40,6 +40,14 @@ steps:
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh billing_fees
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
@@ -60,7 +68,7 @@ steps:
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ proto, secrets ]
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/billing_fees/build-image.sh
|
||||
|
||||
|
||||
@@ -39,6 +39,14 @@ steps:
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh discovery
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
@@ -59,7 +67,7 @@ steps:
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ proto, secrets ]
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/discovery/build-image.sh
|
||||
|
||||
|
||||
@@ -45,6 +45,14 @@ steps:
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh fx_ingestor
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
@@ -65,7 +73,7 @@ steps:
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ proto, secrets ]
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/fx/build-image.sh
|
||||
|
||||
|
||||
@@ -46,6 +46,14 @@ steps:
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh fx_oracle
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
@@ -66,7 +74,7 @@ steps:
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ proto, secrets ]
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/fx/build-image.sh
|
||||
|
||||
|
||||
@@ -43,6 +43,14 @@ steps:
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh gateway_chain
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
@@ -63,7 +71,7 @@ steps:
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ proto, secrets ]
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/chain_gateway/build-image.sh
|
||||
|
||||
|
||||
@@ -42,6 +42,14 @@ steps:
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh gateway_mntx
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
@@ -62,7 +70,7 @@ steps:
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ proto, secrets ]
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/mntx/build-image.sh
|
||||
|
||||
|
||||
@@ -40,6 +40,14 @@ steps:
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh gateway_tgsettle
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
@@ -60,7 +68,7 @@ steps:
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ proto, secrets ]
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/tgsettle/build-image.sh
|
||||
|
||||
|
||||
@@ -43,6 +43,14 @@ steps:
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh gateway_tron
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
@@ -63,7 +71,7 @@ steps:
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ proto, secrets ]
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/tron_gateway/build-image.sh
|
||||
|
||||
|
||||
@@ -40,6 +40,14 @@ steps:
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh ledger
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
@@ -60,7 +68,7 @@ steps:
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ proto, secrets ]
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/ledger/build-image.sh
|
||||
|
||||
|
||||
@@ -43,6 +43,14 @@ steps:
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh notification
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
@@ -63,7 +71,7 @@ steps:
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ proto, secrets ]
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/notification/build-image.sh
|
||||
|
||||
|
||||
87
.woodpecker/payments_methods.yml
Normal file
87
.woodpecker/payments_methods.yml
Normal file
@@ -0,0 +1,87 @@
|
||||
matrix:
|
||||
include:
|
||||
- PAYMENTS_METHODS_IMAGE_PATH: payments/methods
|
||||
PAYMENTS_METHODS_DOCKERFILE: ci/prod/compose/payments_methods.dockerfile
|
||||
PAYMENTS_METHODS_MONGO_SECRET_PATH: sendico/db
|
||||
PAYMENTS_METHODS_ENV: prod
|
||||
|
||||
when:
|
||||
- event: push
|
||||
branch: main
|
||||
path:
|
||||
include:
|
||||
- api/payments/methods/**
|
||||
- api/proto/**
|
||||
- api/pkg/**
|
||||
ignore_message: '[rebuild]'
|
||||
|
||||
steps:
|
||||
- name: version
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- set -euo pipefail 2>/dev/null || set -eu
|
||||
- apk add --no-cache git
|
||||
- GIT_REV="$(git rev-parse --short HEAD)"
|
||||
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
||||
- APP_V="$(cat version)"
|
||||
- BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
- BUILD_USER="${WOODPECKER_MACHINE:-woodpecker}"
|
||||
- printf "GIT_REV=%s\nBUILD_BRANCH=%s\nAPP_V=%s\nBUILD_DATE=%s\nBUILD_USER=%s\n" \
|
||||
"$GIT_REV" "$BUILD_BRANCH" "$APP_V" "$BUILD_DATE" "$BUILD_USER" | tee .env.version
|
||||
|
||||
- name: proto
|
||||
image: golang:alpine
|
||||
depends_on: [ version ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base protoc protobuf-dev
|
||||
- go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||||
- go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh payments_methods
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
environment:
|
||||
VAULT_ADDR: { from_secret: VAULT_ADDR }
|
||||
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
|
||||
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
|
||||
commands:
|
||||
- set -euo pipefail
|
||||
- apk add --no-cache bash coreutils openssh-keygen curl sed python3
|
||||
- mkdir -p secrets
|
||||
- ./ci/vlt kv_to_file kv ops/deploy/ssh_key private_b64 secrets/SSH_KEY.b64 600
|
||||
- base64 -d secrets/SSH_KEY.b64 > secrets/SSH_KEY
|
||||
- chmod 600 secrets/SSH_KEY
|
||||
- ssh-keygen -y -f secrets/SSH_KEY >/dev/null
|
||||
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
|
||||
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/payments_methods/build-image.sh
|
||||
|
||||
- name: deploy
|
||||
image: alpine:latest
|
||||
depends_on: [ secrets, build-image ]
|
||||
environment:
|
||||
VAULT_ADDR: { from_secret: VAULT_ADDR }
|
||||
VAULT_ROLE_ID: { from_secret: VAULT_APP_ROLE }
|
||||
VAULT_SECRET_ID: { from_secret: VAULT_SECRET_ID }
|
||||
commands:
|
||||
- set -euo pipefail
|
||||
- apk add --no-cache bash openssh-client rsync coreutils curl sed python3
|
||||
- mkdir -p /root/.ssh
|
||||
- install -m 600 secrets/SSH_KEY /root/.ssh/id_rsa
|
||||
- sh ci/scripts/payments_methods/deploy.sh
|
||||
@@ -40,6 +40,14 @@ steps:
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh payments_orchestrator
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
@@ -60,7 +68,7 @@ steps:
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ proto, secrets ]
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/payments_orchestrator/build-image.sh
|
||||
|
||||
|
||||
@@ -42,6 +42,14 @@ steps:
|
||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||
- bash ci/scripts/proto/generate.sh
|
||||
|
||||
- name: backend-tests
|
||||
image: golang:alpine
|
||||
depends_on: [ proto ]
|
||||
commands:
|
||||
- set -eu
|
||||
- apk add --no-cache bash git build-base
|
||||
- sh ci/scripts/common/run_backend_tests.sh payments_quotation
|
||||
|
||||
- name: secrets
|
||||
image: alpine:latest
|
||||
depends_on: [ version ]
|
||||
@@ -62,7 +70,7 @@ steps:
|
||||
|
||||
- name: build-image
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
depends_on: [ proto, secrets ]
|
||||
depends_on: [ backend-tests, secrets ]
|
||||
commands:
|
||||
- sh ci/scripts/payments_quotation/build-image.sh
|
||||
|
||||
|
||||
6
Makefile
6
Makefile
@@ -218,6 +218,8 @@ services-up:
|
||||
dev-billing-documents \
|
||||
dev-ledger \
|
||||
dev-payments-orchestrator \
|
||||
dev-payments-quotation \
|
||||
dev-payments-methods \
|
||||
dev-chain-gateway \
|
||||
dev-tron-gateway \
|
||||
dev-mntx-gateway \
|
||||
@@ -245,6 +247,8 @@ list-services:
|
||||
@echo " - dev-billing-documents :50061, :9409 (Billing Documents)"
|
||||
@echo " - dev-ledger :50052, :9401 (Double-Entry Ledger)"
|
||||
@echo " - dev-payments-orchestrator :50062, :9403 (Payment Orchestration)"
|
||||
@echo " - dev-payments-quotation :50064, :9414 (Payment Quotation)"
|
||||
@echo " - dev-payments-methods :50066, :9416 (Payment Methods)"
|
||||
@echo " - dev-chain-gateway :50070, :9404 (EVM Blockchain Gateway)"
|
||||
@echo " - dev-tron-gateway :50071, :9408 (TRON Blockchain Gateway)"
|
||||
@echo " - dev-mntx-gateway :50075, :9405, :8084 (Card Payouts)"
|
||||
@@ -273,7 +277,7 @@ build-fx:
|
||||
|
||||
build-payments:
|
||||
@echo "$(GREEN)Building payment services...$(NC)"
|
||||
@$(COMPOSE) build dev-payments-orchestrator
|
||||
@$(COMPOSE) build dev-payments-orchestrator dev-payments-quotation dev-payments-methods
|
||||
|
||||
build-gateways:
|
||||
@echo "$(GREEN)Building gateway services...$(NC)"
|
||||
|
||||
@@ -17,6 +17,7 @@ Financial services platform providing payment orchestration, ledger accounting,
|
||||
| Ledger | `api/ledger/` | Double-entry accounting |
|
||||
| Orchestrator | `api/payments/orchestrator/` | Payment orchestration |
|
||||
| Quotation | `api/payments/quotation/` | Payment quotation |
|
||||
| Payment Methods | `api/payments/methods/` | Payment methods |
|
||||
| Billing Fees | `api/billing/fees/` | Fee calculation |
|
||||
| Billing Documents | `api/billing/documents/` | Billing documents |
|
||||
| FX Oracle | `api/fx/oracle/` | FX quote provider |
|
||||
@@ -24,7 +25,7 @@ Financial services platform providing payment orchestration, ledger accounting,
|
||||
| Gateway Chain | `api/gateway/chain/` | EVM blockchain gateway |
|
||||
| Gateway TRON | `api/gateway/tron/` | TRON blockchain gateway |
|
||||
| Gateway MNTX | `api/gateway/mntx/` | Card payouts |
|
||||
| Gateway TGSettle | `api/gateway/tgsettle/` | Settlements |
|
||||
| Gateway TGSettle | `api/gateway/tgsettle/` | Telegram settlements with MNTX |
|
||||
| Notification | `api/notification/` | Notifications |
|
||||
| BFF | `api/server/` | Backend for frontend |
|
||||
| Frontend | `frontend/pweb/` | Flutter web UI |
|
||||
|
||||
@@ -15,7 +15,7 @@ require (
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.78.0
|
||||
google.golang.org/grpc v1.79.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
|
||||
@@ -201,16 +201,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -260,8 +260,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -10,7 +10,7 @@ require (
|
||||
github.com/tech/sendico/fx/oracle v0.0.0
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.78.0
|
||||
google.golang.org/grpc v1.79.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
|
||||
@@ -152,16 +152,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -210,8 +210,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -44,6 +44,6 @@ require (
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect
|
||||
google.golang.org/grpc v1.78.0 // indirect
|
||||
google.golang.org/grpc v1.79.1 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
)
|
||||
|
||||
@@ -152,16 +152,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -210,8 +210,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -48,6 +48,6 @@ require (
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect
|
||||
google.golang.org/grpc v1.78.0 // indirect
|
||||
google.golang.org/grpc v1.79.1 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
)
|
||||
|
||||
@@ -152,16 +152,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -210,8 +210,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -68,6 +68,7 @@ type Quote struct {
|
||||
BaseAmount *moneyv1.Money
|
||||
QuoteAmount *moneyv1.Money
|
||||
ExpiresAt time.Time
|
||||
PricedAt time.Time
|
||||
Provider string
|
||||
RateRef string
|
||||
Firm bool
|
||||
@@ -237,6 +238,10 @@ func fromProtoQuote(quote *oraclev1.Quote) *Quote {
|
||||
if quote == nil {
|
||||
return nil
|
||||
}
|
||||
pricedAt := time.Time{}
|
||||
if ts := quote.GetPricedAt(); ts != nil {
|
||||
pricedAt = ts.AsTime()
|
||||
}
|
||||
return &Quote{
|
||||
QuoteRef: quote.GetQuoteRef(),
|
||||
Pair: quote.Pair,
|
||||
@@ -245,6 +250,7 @@ func fromProtoQuote(quote *oraclev1.Quote) *Quote {
|
||||
BaseAmount: quote.BaseAmount,
|
||||
QuoteAmount: quote.QuoteAmount,
|
||||
ExpiresAt: time.UnixMilli(quote.GetExpiresAtUnixMs()),
|
||||
PricedAt: pricedAt,
|
||||
Provider: quote.GetProvider(),
|
||||
RateRef: quote.GetRateRef(),
|
||||
Firm: quote.GetFirm(),
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||
oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
type stubOracle struct {
|
||||
@@ -75,6 +76,7 @@ func TestLatestRate(t *testing.T) {
|
||||
|
||||
func TestGetQuote(t *testing.T) {
|
||||
expiresAt := time.Date(2024, 2, 2, 12, 0, 0, 0, time.UTC)
|
||||
pricedAt := time.Date(2024, 2, 2, 11, 59, 0, 0, time.UTC)
|
||||
stub := &stubOracle{
|
||||
quoteResp: &oraclev1.GetQuoteResponse{
|
||||
Quote: &oraclev1.Quote{
|
||||
@@ -85,6 +87,7 @@ func TestGetQuote(t *testing.T) {
|
||||
BaseAmount: &moneyv1.Money{Amount: "100.00", Currency: "GBP"},
|
||||
QuoteAmount: &moneyv1.Money{Amount: "125.00", Currency: "USD"},
|
||||
ExpiresAtUnixMs: expiresAt.UnixMilli(),
|
||||
PricedAt: timestamppb.New(pricedAt),
|
||||
Provider: "Test",
|
||||
RateRef: "test-ref",
|
||||
Firm: true,
|
||||
@@ -113,4 +116,7 @@ func TestGetQuote(t *testing.T) {
|
||||
if resp.QuoteRef != "quote-123" || resp.Price != "1.2500" || !resp.ExpiresAt.Equal(expiresAt) {
|
||||
t.Fatalf("unexpected quote response: %+v", resp)
|
||||
}
|
||||
if !resp.PricedAt.Equal(pricedAt) {
|
||||
t.Fatalf("expected priced_at %s, got %s", pricedAt, resp.PricedAt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ require (
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.78.0
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -152,16 +152,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -210,8 +210,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -130,6 +130,10 @@ func (qc *quoteComputation) buildModelQuote(firm bool, expiryMillis int64, req *
|
||||
if qc.baseRounded == nil || qc.quoteRounded == nil || qc.priceRounded == nil {
|
||||
return nil, merrors.Internal("oracle: computation not executed")
|
||||
}
|
||||
pricedAtUnixMs := qc.rate.AsOfUnixMs
|
||||
if pricedAtUnixMs <= 0 {
|
||||
pricedAtUnixMs = time.Now().UnixMilli()
|
||||
}
|
||||
|
||||
quote := &model.Quote{
|
||||
QuoteRef: uuid.NewString(),
|
||||
@@ -147,6 +151,7 @@ func (qc *quoteComputation) buildModelQuote(firm bool, expiryMillis int64, req *
|
||||
Amount: formatRat(qc.quoteRounded, qc.quoteScale),
|
||||
},
|
||||
AmountType: qc.amountType,
|
||||
PricedAtUnixMs: pricedAtUnixMs,
|
||||
RateRef: qc.rate.RateRef,
|
||||
Provider: qc.provider,
|
||||
PreferredProvider: req.GetPreferredProvider(),
|
||||
|
||||
@@ -111,6 +111,7 @@ func (currencyStoreStub) List(ctx context.Context, codes ...string) ([]*model.Cu
|
||||
func (currencyStoreStub) Upsert(ctx context.Context, currency *model.Currency) error { return nil }
|
||||
|
||||
func TestServiceGetQuoteFirm(t *testing.T) {
|
||||
pricedAt := time.Date(2024, 1, 2, 3, 4, 5, 0, time.UTC)
|
||||
repo := &repositoryStub{}
|
||||
repo.pairs = &pairStoreStub{
|
||||
getFn: func(ctx context.Context, pair model.CurrencyPair) (*model.Pair, error) {
|
||||
@@ -129,7 +130,7 @@ func TestServiceGetQuoteFirm(t *testing.T) {
|
||||
Ask: "1.10",
|
||||
Bid: "1.08",
|
||||
RateRef: "rate#1",
|
||||
AsOfUnixMs: time.Now().UnixMilli(),
|
||||
AsOfUnixMs: pricedAt.UnixMilli(),
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
@@ -169,9 +170,15 @@ func TestServiceGetQuoteFirm(t *testing.T) {
|
||||
if resp.GetQuote().GetQuoteAmount().GetAmount() != "110.00" {
|
||||
t.Fatalf("unexpected quote amount: %s", resp.GetQuote().GetQuoteAmount().GetAmount())
|
||||
}
|
||||
if got := resp.GetQuote().GetPricedAt(); got == nil || !got.AsTime().Equal(pricedAt) {
|
||||
t.Fatalf("expected priced_at %s, got %v", pricedAt, got)
|
||||
}
|
||||
if savedQuote.QuoteRef == "" {
|
||||
t.Fatalf("expected quote persisted")
|
||||
}
|
||||
if savedQuote.PricedAtUnixMs != pricedAt.UnixMilli() {
|
||||
t.Fatalf("expected stored pricedAtUnixMs %d, got %d", pricedAt.UnixMilli(), savedQuote.PricedAtUnixMs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceGetQuoteRateNotFound(t *testing.T) {
|
||||
|
||||
@@ -2,12 +2,14 @@ package oracle
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/fx/storage/model"
|
||||
paymenttypes "github.com/tech/sendico/pkg/payments/types"
|
||||
fxv1 "github.com/tech/sendico/pkg/proto/common/fx/v1"
|
||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||
oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
func buildResponseMeta(meta *oraclev1.RequestMeta) *oraclev1.ResponseMeta {
|
||||
@@ -36,6 +38,7 @@ func quoteModelToProto(q *model.Quote) *oraclev1.Quote {
|
||||
BaseAmount: moneyModelToProto(&q.BaseAmount),
|
||||
QuoteAmount: moneyModelToProto(&q.QuoteAmount),
|
||||
ExpiresAtUnixMs: q.ExpiresAtUnixMs,
|
||||
PricedAt: timestampFromUnixMillis(q.PricedAtUnixMs, q.CreatedAt),
|
||||
Provider: q.Provider,
|
||||
RateRef: q.RateRef,
|
||||
Firm: q.Firm,
|
||||
@@ -117,3 +120,13 @@ func decimalStringToProto(value string) *moneyv1.Decimal {
|
||||
}
|
||||
return &moneyv1.Decimal{Value: value}
|
||||
}
|
||||
|
||||
func timestampFromUnixMillis(ms int64, fallback time.Time) *timestamppb.Timestamp {
|
||||
if ms > 0 {
|
||||
return timestamppb.New(time.UnixMilli(ms).UTC())
|
||||
}
|
||||
if !fallback.IsZero() {
|
||||
return timestamppb.New(fallback.UTC())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ github.com/casbin/mongodb-adapter/v4 v4.3.0 h1:yYXky9v1by6vj/0QK7OyHyd/xpz4vzh0l
|
||||
github.com/casbin/mongodb-adapter/v4 v4.3.0/go.mod h1:bOTSYZUjX7I9E0ExEvgq46m3mcDNRII7g8iWjrM1BHE=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||
@@ -120,12 +122,12 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
|
||||
@@ -21,6 +21,7 @@ type Quote struct {
|
||||
QuoteAmount paymenttypes.Money `bson:"quoteAmount" json:"quoteAmount"`
|
||||
AmountType QuoteAmountType `bson:"amountType" json:"amountType"`
|
||||
ExpiresAtUnixMs int64 `bson:"expiresAtUnixMs" json:"expiresAtUnixMs"`
|
||||
PricedAtUnixMs int64 `bson:"pricedAtUnixMs,omitempty" json:"pricedAtUnixMs,omitempty"`
|
||||
ExpiresAt *time.Time `bson:"expiresAt,omitempty" json:"expiresAt,omitempty"`
|
||||
RateRef string `bson:"rateRef" json:"rateRef"`
|
||||
Provider string `bson:"provider" json:"provider"`
|
||||
|
||||
@@ -95,6 +95,9 @@ func (q *quotesStore) Issue(ctx context.Context, quote *model.Quote) error {
|
||||
expiry := time.UnixMilli(quote.ExpiresAtUnixMs)
|
||||
quote.ExpiresAt = &expiry
|
||||
}
|
||||
if quote.PricedAtUnixMs <= 0 {
|
||||
quote.PricedAtUnixMs = time.Now().UnixMilli()
|
||||
}
|
||||
|
||||
quote.Status = model.QuoteStatusIssued
|
||||
quote.ConsumedByLedgerTxnRef = ""
|
||||
|
||||
@@ -32,6 +32,9 @@ func TestQuotesStoreIssue(t *testing.T) {
|
||||
if inserted == nil || inserted.Status != model.QuoteStatusIssued {
|
||||
t.Fatalf("expected issued quote to be inserted")
|
||||
}
|
||||
if inserted.PricedAtUnixMs <= 0 {
|
||||
t.Fatalf("expected pricedAtUnixMs to be populated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuotesStoreIssueSetsExpiryDate(t *testing.T) {
|
||||
|
||||
@@ -22,6 +22,7 @@ type repoStub struct {
|
||||
findOneFn func(ctx context.Context, query builder.Query, result storable.Storable) error
|
||||
findManyFn func(ctx context.Context, query builder.Query, decoder rd.DecodingFunc) error
|
||||
updateFn func(ctx context.Context, obj storable.Storable) error
|
||||
upsertFn func(ctx context.Context, obj storable.Storable) error
|
||||
patchManyFn func(ctx context.Context, filter builder.Query, patch builder.Patch) (int, error)
|
||||
createIdxFn func(def *ri.Definition) error
|
||||
}
|
||||
@@ -69,6 +70,13 @@ func (r *repoStub) Update(ctx context.Context, obj storable.Storable) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repoStub) Upsert(ctx context.Context, obj storable.Storable) error {
|
||||
if r.upsertFn != nil {
|
||||
return r.upsertFn(ctx, obj)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repoStub) Patch(ctx context.Context, id bson.ObjectID, patch builder.Patch) error {
|
||||
return merrors.NotImplemented("Patch not used")
|
||||
}
|
||||
|
||||
@@ -2,22 +2,17 @@ package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/fx/storage/model"
|
||||
)
|
||||
|
||||
type storageError string
|
||||
|
||||
func (e storageError) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
var (
|
||||
ErrQuoteExpired = storageError("fx.storage: quote expired")
|
||||
ErrQuoteConsumed = storageError("fx.storage: quote consumed")
|
||||
ErrQuoteNotFirm = storageError("fx.storage: quote is not firm")
|
||||
ErrQuoteConsumptionRace = storageError("fx.storage: quote consumption collision")
|
||||
ErrQuoteExpired = errors.New("fx.storage: quote expired")
|
||||
ErrQuoteConsumed = errors.New("fx.storage: quote consumed")
|
||||
ErrQuoteNotFirm = errors.New("fx.storage: quote is not firm")
|
||||
ErrQuoteConsumptionRace = errors.New("fx.storage: quote consumption collision")
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
|
||||
@@ -15,14 +15,14 @@ require (
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.78.0
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260212005555-3a7e5700f354 // indirect
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260213131322-086e44a26cf3 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.24.4 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect
|
||||
|
||||
@@ -6,8 +6,8 @@ github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
|
||||
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260212005555-3a7e5700f354 h1:BgaMXBpcqcW74afzqI3iKo07K3tC+VuyWU3/FIvLlNI=
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260212005555-3a7e5700f354/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI=
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260213131322-086e44a26cf3 h1:QD30TjDPWtvXb5PBZGZ6Wdvaq7HQixIBtZ/yuseNXc8=
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260213131322-086e44a26cf3/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI=
|
||||
github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0=
|
||||
github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
@@ -298,16 +298,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -362,8 +362,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -11,7 +11,7 @@ require (
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.78.0
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -154,16 +154,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -212,8 +212,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -8,7 +8,7 @@ require (
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.78.0
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -152,16 +152,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -210,8 +210,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -17,14 +17,14 @@ require (
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.78.0
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260212005555-3a7e5700f354 // indirect
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260213131322-086e44a26cf3 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.24.4 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect
|
||||
|
||||
@@ -6,8 +6,8 @@ github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
|
||||
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260212005555-3a7e5700f354 h1:BgaMXBpcqcW74afzqI3iKo07K3tC+VuyWU3/FIvLlNI=
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260212005555-3a7e5700f354/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI=
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260213131322-086e44a26cf3 h1:QD30TjDPWtvXb5PBZGZ6Wdvaq7HQixIBtZ/yuseNXc8=
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260213131322-086e44a26cf3/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI=
|
||||
github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0=
|
||||
github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
@@ -313,16 +313,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -383,8 +383,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -11,7 +11,7 @@ require (
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.78.0
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -154,16 +154,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -212,8 +212,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -19,6 +19,7 @@ type repositoryStub struct {
|
||||
InsertFunc func(ctx context.Context, object storable.Storable, filter builder.Query) error
|
||||
InsertManyFunc func(ctx context.Context, objects []storable.Storable) error
|
||||
UpdateFunc func(ctx context.Context, object storable.Storable) error
|
||||
UpsertFunc func(ctx context.Context, object storable.Storable) error
|
||||
DeleteFunc func(ctx context.Context, id bson.ObjectID) error
|
||||
FindOneByFilterFunc func(ctx context.Context, filter builder.Query, result storable.Storable) error
|
||||
FindManyByFilterFunc func(ctx context.Context, filter builder.Query, decoder rd.DecodingFunc) error
|
||||
@@ -64,6 +65,13 @@ func (r *repositoryStub) Update(ctx context.Context, object storable.Storable) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repositoryStub) Upsert(ctx context.Context, object storable.Storable) error {
|
||||
if r.UpsertFunc != nil {
|
||||
return r.UpsertFunc(ctx, object)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repositoryStub) Delete(ctx context.Context, id bson.ObjectID) error {
|
||||
if r.DeleteFunc != nil {
|
||||
return r.DeleteFunc(ctx, id)
|
||||
|
||||
@@ -51,6 +51,6 @@ require (
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect
|
||||
google.golang.org/grpc v1.78.0 // indirect
|
||||
google.golang.org/grpc v1.79.1 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
)
|
||||
|
||||
@@ -167,16 +167,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -227,8 +227,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
46
api/payments/methods/.air.toml
Normal file
46
api/payments/methods/.air.toml
Normal file
@@ -0,0 +1,46 @@
|
||||
root = "."
|
||||
testdata_dir = "testdata"
|
||||
tmp_dir = "tmp"
|
||||
|
||||
[build]
|
||||
args_bin = []
|
||||
entrypoint = "./tmp/main"
|
||||
cmd = "go build -o ./tmp/main ."
|
||||
delay = 1000
|
||||
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
|
||||
exclude_file = []
|
||||
exclude_regex = ["_test.go", "_templ.go"]
|
||||
exclude_unchanged = false
|
||||
follow_symlink = false
|
||||
full_bin = ""
|
||||
include_dir = []
|
||||
include_ext = ["go", "tpl", "tmpl", "html"]
|
||||
include_file = []
|
||||
kill_delay = "0s"
|
||||
log = "build-errors.log"
|
||||
poll = false
|
||||
poll_interval = 0
|
||||
post_cmd = []
|
||||
pre_cmd = []
|
||||
rerun = false
|
||||
rerun_delay = 500
|
||||
send_interrupt = false
|
||||
stop_on_error = false
|
||||
|
||||
[color]
|
||||
app = ""
|
||||
build = "yellow"
|
||||
main = "magenta"
|
||||
runner = "green"
|
||||
watcher = "cyan"
|
||||
|
||||
[log]
|
||||
main_only = false
|
||||
time = false
|
||||
|
||||
[misc]
|
||||
clean_on_exit = false
|
||||
|
||||
[screen]
|
||||
clear_on_rebuild = false
|
||||
keep_scroll = true
|
||||
131
api/payments/methods/client/client.go
Normal file
131
api/payments/methods/client/client.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
methodsv1 "github.com/tech/sendico/pkg/proto/payments/methods/v1"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
// Client exposes typed helpers around the payment methods gRPC API.
|
||||
type Client interface {
|
||||
CreatePaymentMethod(ctx context.Context, req *methodsv1.CreatePaymentMethodRequest) (*methodsv1.CreatePaymentMethodResponse, error)
|
||||
GetPaymentMethod(ctx context.Context, req *methodsv1.GetPaymentMethodRequest) (*methodsv1.GetPaymentMethodResponse, error)
|
||||
UpdatePaymentMethod(ctx context.Context, req *methodsv1.UpdatePaymentMethodRequest) (*methodsv1.UpdatePaymentMethodResponse, error)
|
||||
DeletePaymentMethod(ctx context.Context, req *methodsv1.DeletePaymentMethodRequest) (*methodsv1.DeletePaymentMethodResponse, error)
|
||||
SetPaymentMethodArchived(ctx context.Context, req *methodsv1.SetPaymentMethodArchivedRequest) (*methodsv1.SetPaymentMethodArchivedResponse, error)
|
||||
ListPaymentMethods(ctx context.Context, req *methodsv1.ListPaymentMethodsRequest) (*methodsv1.ListPaymentMethodsResponse, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
type grpcPaymentMethodsClient interface {
|
||||
CreatePaymentMethod(ctx context.Context, in *methodsv1.CreatePaymentMethodRequest, opts ...grpc.CallOption) (*methodsv1.CreatePaymentMethodResponse, error)
|
||||
GetPaymentMethod(ctx context.Context, in *methodsv1.GetPaymentMethodRequest, opts ...grpc.CallOption) (*methodsv1.GetPaymentMethodResponse, error)
|
||||
UpdatePaymentMethod(ctx context.Context, in *methodsv1.UpdatePaymentMethodRequest, opts ...grpc.CallOption) (*methodsv1.UpdatePaymentMethodResponse, error)
|
||||
DeletePaymentMethod(ctx context.Context, in *methodsv1.DeletePaymentMethodRequest, opts ...grpc.CallOption) (*methodsv1.DeletePaymentMethodResponse, error)
|
||||
SetPaymentMethodArchived(ctx context.Context, in *methodsv1.SetPaymentMethodArchivedRequest, opts ...grpc.CallOption) (*methodsv1.SetPaymentMethodArchivedResponse, error)
|
||||
ListPaymentMethods(ctx context.Context, in *methodsv1.ListPaymentMethodsRequest, opts ...grpc.CallOption) (*methodsv1.ListPaymentMethodsResponse, error)
|
||||
}
|
||||
|
||||
type paymentMethodsClient struct {
|
||||
cfg Config
|
||||
conn *grpc.ClientConn
|
||||
client grpcPaymentMethodsClient
|
||||
}
|
||||
|
||||
// New dials the payment methods endpoint and returns a ready client.
|
||||
func New(ctx context.Context, cfg Config, opts ...grpc.DialOption) (Client, error) {
|
||||
cfg.setDefaults()
|
||||
if strings.TrimSpace(cfg.Address) == "" {
|
||||
return nil, merrors.InvalidArgument("payment-methods: address is required")
|
||||
}
|
||||
|
||||
dialCtx, cancel := context.WithTimeout(ctx, cfg.DialTimeout)
|
||||
defer cancel()
|
||||
|
||||
dialOpts := make([]grpc.DialOption, 0, len(opts)+1)
|
||||
dialOpts = append(dialOpts, opts...)
|
||||
if cfg.Insecure {
|
||||
dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
} else {
|
||||
dialOpts = append(dialOpts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})))
|
||||
}
|
||||
|
||||
conn, err := grpc.DialContext(dialCtx, cfg.Address, dialOpts...)
|
||||
if err != nil {
|
||||
return nil, merrors.InternalWrap(err, fmt.Sprintf("payment-methods: dial %s", cfg.Address))
|
||||
}
|
||||
|
||||
return &paymentMethodsClient{
|
||||
cfg: cfg,
|
||||
conn: conn,
|
||||
client: methodsv1.NewPaymentMethodsServiceClient(conn),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewWithClient injects a pre-built payment methods client (useful for tests).
|
||||
func NewWithClient(cfg Config, c grpcPaymentMethodsClient) Client {
|
||||
cfg.setDefaults()
|
||||
return &paymentMethodsClient{
|
||||
cfg: cfg,
|
||||
client: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *paymentMethodsClient) Close() error {
|
||||
if c.conn != nil {
|
||||
return c.conn.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *paymentMethodsClient) callContext(ctx context.Context) (context.Context, context.CancelFunc) {
|
||||
timeout := c.cfg.CallTimeout
|
||||
if timeout <= 0 {
|
||||
timeout = 3 * time.Second
|
||||
}
|
||||
return context.WithTimeout(ctx, timeout)
|
||||
}
|
||||
|
||||
func (c *paymentMethodsClient) CreatePaymentMethod(ctx context.Context, req *methodsv1.CreatePaymentMethodRequest) (*methodsv1.CreatePaymentMethodResponse, error) {
|
||||
callCtx, cancel := c.callContext(ctx)
|
||||
defer cancel()
|
||||
return c.client.CreatePaymentMethod(callCtx, req)
|
||||
}
|
||||
|
||||
func (c *paymentMethodsClient) GetPaymentMethod(ctx context.Context, req *methodsv1.GetPaymentMethodRequest) (*methodsv1.GetPaymentMethodResponse, error) {
|
||||
callCtx, cancel := c.callContext(ctx)
|
||||
defer cancel()
|
||||
return c.client.GetPaymentMethod(callCtx, req)
|
||||
}
|
||||
|
||||
func (c *paymentMethodsClient) UpdatePaymentMethod(ctx context.Context, req *methodsv1.UpdatePaymentMethodRequest) (*methodsv1.UpdatePaymentMethodResponse, error) {
|
||||
callCtx, cancel := c.callContext(ctx)
|
||||
defer cancel()
|
||||
return c.client.UpdatePaymentMethod(callCtx, req)
|
||||
}
|
||||
|
||||
func (c *paymentMethodsClient) DeletePaymentMethod(ctx context.Context, req *methodsv1.DeletePaymentMethodRequest) (*methodsv1.DeletePaymentMethodResponse, error) {
|
||||
callCtx, cancel := c.callContext(ctx)
|
||||
defer cancel()
|
||||
return c.client.DeletePaymentMethod(callCtx, req)
|
||||
}
|
||||
|
||||
func (c *paymentMethodsClient) SetPaymentMethodArchived(ctx context.Context, req *methodsv1.SetPaymentMethodArchivedRequest) (*methodsv1.SetPaymentMethodArchivedResponse, error) {
|
||||
callCtx, cancel := c.callContext(ctx)
|
||||
defer cancel()
|
||||
return c.client.SetPaymentMethodArchived(callCtx, req)
|
||||
}
|
||||
|
||||
func (c *paymentMethodsClient) ListPaymentMethods(ctx context.Context, req *methodsv1.ListPaymentMethodsRequest) (*methodsv1.ListPaymentMethodsResponse, error) {
|
||||
callCtx, cancel := c.callContext(ctx)
|
||||
defer cancel()
|
||||
return c.client.ListPaymentMethods(callCtx, req)
|
||||
}
|
||||
20
api/payments/methods/client/config.go
Normal file
20
api/payments/methods/client/config.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package client
|
||||
|
||||
import "time"
|
||||
|
||||
// Config captures connection settings for the payment methods gRPC service.
|
||||
type Config struct {
|
||||
Address string
|
||||
DialTimeout time.Duration
|
||||
CallTimeout time.Duration
|
||||
Insecure bool
|
||||
}
|
||||
|
||||
func (c *Config) setDefaults() {
|
||||
if c.DialTimeout <= 0 {
|
||||
c.DialTimeout = 5 * time.Second
|
||||
}
|
||||
if c.CallTimeout <= 0 {
|
||||
c.CallTimeout = 3 * time.Second
|
||||
}
|
||||
}
|
||||
49
api/payments/methods/config.dev.yml
Normal file
49
api/payments/methods/config.dev.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
runtime:
|
||||
shutdown_timeout_seconds: 15
|
||||
|
||||
grpc:
|
||||
network: tcp
|
||||
address: ":50066"
|
||||
advertise_host: "dev-payments-methods"
|
||||
enable_reflection: true
|
||||
enable_health: true
|
||||
|
||||
metrics:
|
||||
address: ":9416"
|
||||
|
||||
messaging:
|
||||
driver: NATS
|
||||
settings:
|
||||
url_env: NATS_URL
|
||||
host_env: NATS_HOST
|
||||
port_env: NATS_PORT
|
||||
username_env: NATS_USER
|
||||
password_env: NATS_PASSWORD
|
||||
broker_name: Payments Methods Service
|
||||
max_reconnects: 10
|
||||
reconnect_wait: 5
|
||||
buffer_size: 1024
|
||||
|
||||
database:
|
||||
driver: mongodb
|
||||
settings:
|
||||
host_env: PAYMENTS_MONGO_HOST
|
||||
port_env: PAYMENTS_MONGO_PORT
|
||||
database_env: PAYMENTS_MONGO_DATABASE
|
||||
user_env: PAYMENTS_MONGO_USER
|
||||
password_env: PAYMENTS_MONGO_PASSWORD
|
||||
auth_source_env: PAYMENTS_MONGO_AUTH_SOURCE
|
||||
replica_set_env: PAYMENTS_MONGO_REPLICA_SET
|
||||
|
||||
permissions_database:
|
||||
driver: mongodb
|
||||
settings:
|
||||
host_env: MONGO_HOST
|
||||
port_env: MONGO_PORT
|
||||
database_env: MONGO_DATABASE
|
||||
user_env: MONGO_USER
|
||||
password_env: MONGO_PASSWORD
|
||||
auth_source_env: MONGO_AUTH_SOURCE
|
||||
replica_set_env: MONGO_REPLICA_SET
|
||||
enforcer:
|
||||
driver: native
|
||||
49
api/payments/methods/config.yml
Normal file
49
api/payments/methods/config.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
runtime:
|
||||
shutdown_timeout_seconds: 15
|
||||
|
||||
grpc:
|
||||
network: tcp
|
||||
address: ":50066"
|
||||
advertise_host: "sendico_payments_methods"
|
||||
enable_reflection: true
|
||||
enable_health: true
|
||||
|
||||
metrics:
|
||||
address: ":9416"
|
||||
|
||||
messaging:
|
||||
driver: NATS
|
||||
settings:
|
||||
url_env: NATS_URL
|
||||
host_env: NATS_HOST
|
||||
port_env: NATS_PORT
|
||||
username_env: NATS_USER
|
||||
password_env: NATS_PASSWORD
|
||||
broker_name: Payments Methods Service
|
||||
max_reconnects: 10
|
||||
reconnect_wait: 5
|
||||
buffer_size: 1024
|
||||
|
||||
database:
|
||||
driver: mongodb
|
||||
settings:
|
||||
host_env: PAYMENTS_MONGO_HOST
|
||||
port_env: PAYMENTS_MONGO_PORT
|
||||
database_env: PAYMENTS_MONGO_DATABASE
|
||||
user_env: PAYMENTS_MONGO_USER
|
||||
password_env: PAYMENTS_MONGO_PASSWORD
|
||||
auth_source_env: PAYMENTS_MONGO_AUTH_SOURCE
|
||||
replica_set_env: PAYMENTS_MONGO_REPLICA_SET
|
||||
|
||||
permissions_database:
|
||||
driver: mongodb
|
||||
settings:
|
||||
host_env: MONGO_HOST
|
||||
port_env: MONGO_PORT
|
||||
database_env: MONGO_DATABASE
|
||||
user_env: MONGO_USER
|
||||
password_env: MONGO_PASSWORD
|
||||
auth_source_env: MONGO_AUTH_SOURCE
|
||||
replica_set_env: MONGO_REPLICA_SET
|
||||
enforcer:
|
||||
driver: native
|
||||
1
api/payments/methods/env/.gitignore
vendored
Normal file
1
api/payments/methods/env/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.env.api
|
||||
52
api/payments/methods/go.mod
Normal file
52
api/payments/methods/go.mod
Normal file
@@ -0,0 +1,52 @@
|
||||
module github.com/tech/sendico/payments/methods
|
||||
|
||||
go 1.25.7
|
||||
|
||||
replace github.com/tech/sendico/pkg => ../../pkg
|
||||
|
||||
replace github.com/tech/sendico/payments/storage => ../storage
|
||||
|
||||
require (
|
||||
github.com/tech/sendico/payments/storage v0.0.0-00010101000000-000000000000
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect
|
||||
github.com/casbin/casbin/v2 v2.135.0 // indirect
|
||||
github.com/casbin/govaluate v1.10.0 // indirect
|
||||
github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/go-chi/chi/v5 v5.2.5 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/klauspost/compress v1.18.4 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nats-io/nats.go v1.48.0 // indirect
|
||||
github.com/nats-io/nkeys v0.4.15 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/prometheus/client_golang v1.23.2 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.67.5 // indirect
|
||||
github.com/prometheus/procfs v0.19.2 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.2.0 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
golang.org/x/crypto v0.48.0 // indirect
|
||||
golang.org/x/net v0.50.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect
|
||||
)
|
||||
221
api/payments/methods/go.sum
Normal file
221
api/payments/methods/go.sum
Normal file
@@ -0,0 +1,221 @@
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
github.com/casbin/casbin/v2 v2.135.0 h1:6BLkMQiGotYyS5yYeWgW19vxqugUlvHFkFiLnLR/bxk=
|
||||
github.com/casbin/casbin/v2 v2.135.0/go.mod h1:FmcfntdXLTcYXv/hxgNntcRPqAbwOG9xsism0yXT+18=
|
||||
github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
|
||||
github.com/casbin/govaluate v1.10.0 h1:ffGw51/hYH3w3rZcxO/KcaUIDOLP84w7nsidMVgaDG0=
|
||||
github.com/casbin/govaluate v1.10.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
|
||||
github.com/casbin/mongodb-adapter/v4 v4.3.0 h1:yYXky9v1by6vj/0QK7OyHyd/xpz4vzh0lCi7JKrS4qQ=
|
||||
github.com/casbin/mongodb-adapter/v4 v4.3.0/go.mod h1:bOTSYZUjX7I9E0ExEvgq46m3mcDNRII7g8iWjrM1BHE=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
|
||||
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
|
||||
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
|
||||
github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
|
||||
github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
|
||||
github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg=
|
||||
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
||||
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
|
||||
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
||||
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/nats-io/nats.go v1.48.0 h1:pSFyXApG+yWU/TgbKCjmm5K4wrHu86231/w84qRVR+U=
|
||||
github.com/nats-io/nats.go v1.48.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
|
||||
github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4=
|
||||
github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
|
||||
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
|
||||
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
|
||||
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw=
|
||||
github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8=
|
||||
github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0 h1:iXVA84s5hKMS5gn01GWOYHE3ymy/2b+0YkpFeTxB2XY=
|
||||
github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0/go.mod h1:R6tMjTojRiaoo89fh/hf7tOmfzohdqSU17R9DwSVSog=
|
||||
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
||||
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
||||
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs=
|
||||
github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8=
|
||||
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
||||
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
||||
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
28
api/payments/methods/internal/appversion/version.go
Normal file
28
api/payments/methods/internal/appversion/version.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package appversion
|
||||
|
||||
import (
|
||||
"github.com/tech/sendico/pkg/version"
|
||||
vf "github.com/tech/sendico/pkg/version/factory"
|
||||
)
|
||||
|
||||
// Build information populated via ldflags.
|
||||
var (
|
||||
Version string
|
||||
Revision string
|
||||
Branch string
|
||||
BuildUser string
|
||||
BuildDate string
|
||||
)
|
||||
|
||||
// Create returns a printer configured for the payment methods service.
|
||||
func Create() version.Printer {
|
||||
vi := version.Info{
|
||||
Program: "Sendico Payment Methods Service",
|
||||
Revision: Revision,
|
||||
Branch: Branch,
|
||||
BuildUser: BuildUser,
|
||||
BuildDate: BuildDate,
|
||||
Version: Version,
|
||||
}
|
||||
return vf.Create(&vi)
|
||||
}
|
||||
62
api/payments/methods/internal/server/internal/config.go
Normal file
62
api/payments/methods/internal/server/internal/config.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package serverimp
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/tech/sendico/pkg/api/routers"
|
||||
"github.com/tech/sendico/pkg/db"
|
||||
"github.com/tech/sendico/pkg/server/grpcapp"
|
||||
"go.uber.org/zap"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
*grpcapp.Config `yaml:",inline"`
|
||||
|
||||
// PermissionsDatabase points to the authorization store (policies/roles/assignments).
|
||||
// If omitted, startup falls back to Database for backward compatibility.
|
||||
PermissionsDatabase *db.Config `yaml:"permissions_database"`
|
||||
}
|
||||
|
||||
func (i *Imp) loadConfig() (*config, error) {
|
||||
data, err := os.ReadFile(i.file)
|
||||
if err != nil {
|
||||
i.logger.Error("Could not read configuration file", zap.String("config_file", i.file), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg := &config{Config: &grpcapp.Config{}}
|
||||
if err := yaml.Unmarshal(data, cfg); err != nil {
|
||||
i.logger.Error("Failed to parse configuration", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cfg.Runtime == nil {
|
||||
cfg.Runtime = &grpcapp.RuntimeConfig{ShutdownTimeoutSeconds: 15}
|
||||
}
|
||||
|
||||
if cfg.GRPC == nil {
|
||||
cfg.GRPC = &routers.GRPCConfig{
|
||||
Network: "tcp",
|
||||
Address: ":50066",
|
||||
EnableReflection: true,
|
||||
EnableHealth: true,
|
||||
}
|
||||
} else {
|
||||
if strings.TrimSpace(cfg.GRPC.Address) == "" {
|
||||
cfg.GRPC.Address = ":50066"
|
||||
}
|
||||
if strings.TrimSpace(cfg.GRPC.Network) == "" {
|
||||
cfg.GRPC.Network = "tcp"
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.Metrics == nil {
|
||||
cfg.Metrics = &grpcapp.MetricsConfig{Address: ":9416"}
|
||||
} else if strings.TrimSpace(cfg.Metrics.Address) == "" {
|
||||
cfg.Metrics.Address = ":9416"
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
88
api/payments/methods/internal/server/internal/discovery.go
Normal file
88
api/payments/methods/internal/server/internal/discovery.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package serverimp
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/tech/sendico/payments/methods/internal/appversion"
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
msg "github.com/tech/sendico/pkg/messaging"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const methodsDiscoverySender = "payment_methods"
|
||||
|
||||
func (i *Imp) initDiscovery(cfg *config) {
|
||||
if i == nil || cfg == nil || cfg.Messaging == nil || cfg.Messaging.Driver == "" {
|
||||
return
|
||||
}
|
||||
|
||||
logger := i.logger.Named("discovery")
|
||||
broker, err := msg.CreateMessagingBroker(logger.Named("bus"), cfg.Messaging)
|
||||
if err != nil {
|
||||
i.logger.Warn("Failed to initialise discovery broker", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
registry := discovery.NewRegistry()
|
||||
watcher, err := discovery.NewRegistryWatcher(logger, broker, registry)
|
||||
if err != nil {
|
||||
i.logger.Warn("Failed to initialise discovery registry watcher", zap.Error(err))
|
||||
return
|
||||
}
|
||||
if err := watcher.Start(); err != nil {
|
||||
i.logger.Warn("Failed to start discovery registry watcher", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
i.discoveryWatcher = watcher
|
||||
i.discoveryReg = registry
|
||||
i.logger.Info("Discovery registry watcher started")
|
||||
}
|
||||
|
||||
func (i *Imp) startDiscoveryAnnouncer(cfg *config, producer msg.Producer) {
|
||||
if i == nil || cfg == nil || producer == nil || cfg.GRPC == nil {
|
||||
return
|
||||
}
|
||||
|
||||
invokeURI := strings.TrimSpace(cfg.GRPC.DiscoveryInvokeURI())
|
||||
if invokeURI == "" {
|
||||
i.logger.Warn("Skipping discovery announcement: missing advertise host/port in gRPC config")
|
||||
return
|
||||
}
|
||||
|
||||
announce := discovery.Announcement{
|
||||
Service: "PAYMENTS_METHODS",
|
||||
Operations: []string{
|
||||
"payment_methods.manage",
|
||||
"payment_methods.read",
|
||||
},
|
||||
InvokeURI: invokeURI,
|
||||
Version: appversion.Create().Short(),
|
||||
}
|
||||
|
||||
i.discoveryAnnouncer = discovery.NewAnnouncer(i.logger, producer, methodsDiscoverySender, announce)
|
||||
i.discoveryAnnouncer.Start()
|
||||
i.logger.Info("Discovery announcer started",
|
||||
zap.String("service", announce.Service),
|
||||
zap.String("invoke_uri", announce.InvokeURI))
|
||||
}
|
||||
|
||||
func (i *Imp) stopDiscoveryAnnouncer() {
|
||||
if i == nil || i.discoveryAnnouncer == nil {
|
||||
return
|
||||
}
|
||||
i.discoveryAnnouncer.Stop()
|
||||
i.discoveryAnnouncer = nil
|
||||
}
|
||||
|
||||
func (i *Imp) stopDiscovery() {
|
||||
if i == nil {
|
||||
return
|
||||
}
|
||||
i.stopDiscoveryAnnouncer()
|
||||
if i.discoveryWatcher != nil {
|
||||
i.discoveryWatcher.Stop()
|
||||
i.discoveryWatcher = nil
|
||||
}
|
||||
i.discoveryReg = nil
|
||||
}
|
||||
16
api/payments/methods/internal/server/internal/lifecycle.go
Normal file
16
api/payments/methods/internal/server/internal/lifecycle.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package serverimp
|
||||
|
||||
import "context"
|
||||
|
||||
func (i *Imp) shutdownApp() {
|
||||
if i == nil || i.app == nil {
|
||||
return
|
||||
}
|
||||
|
||||
timeout := i.config.Runtime.ShutdownTimeout()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
i.app.Shutdown(ctx)
|
||||
i.app = nil
|
||||
}
|
||||
117
api/payments/methods/internal/server/internal/serverimp.go
Normal file
117
api/payments/methods/internal/server/internal/serverimp.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package serverimp
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/payments/methods/internal/service/methods"
|
||||
"github.com/tech/sendico/payments/storage"
|
||||
mongostorage "github.com/tech/sendico/payments/storage/mongo"
|
||||
"github.com/tech/sendico/pkg/db"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
msg "github.com/tech/sendico/pkg/messaging"
|
||||
mb "github.com/tech/sendico/pkg/messaging/broker"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
"github.com/tech/sendico/pkg/server/grpcapp"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func Create(logger mlogger.Logger, file string, debug bool) (*Imp, error) {
|
||||
return &Imp{
|
||||
logger: logger.Named("server"),
|
||||
file: file,
|
||||
debug: debug,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (i *Imp) Shutdown() {
|
||||
i.stopDiscovery()
|
||||
if i.service != nil {
|
||||
i.service.Shutdown()
|
||||
}
|
||||
i.shutdownApp()
|
||||
if i.dbFactory != nil {
|
||||
i.dbFactory.CloseConnection()
|
||||
i.dbFactory = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Imp) Start() error {
|
||||
cfg, err := i.loadConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.config = cfg
|
||||
|
||||
i.initDiscovery(cfg)
|
||||
|
||||
if cfg.Database == nil {
|
||||
return merrors.InvalidArgument("database configuration is required")
|
||||
}
|
||||
|
||||
permissionsDB := cfg.PermissionsDatabase
|
||||
if permissionsDB == nil {
|
||||
i.logger.Info("permissions_database is not configured, falling back to database settings")
|
||||
permissionsDB = cfg.Database
|
||||
}
|
||||
|
||||
i.dbFactory, err = db.NewConnection(i.logger, permissionsDB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
policy, err := i.dbFactory.Permissions().GetPolicyDescription(context.Background(), mservice.PaymentMethods)
|
||||
if err != nil {
|
||||
i.dbFactory.CloseConnection()
|
||||
i.dbFactory = nil
|
||||
return err
|
||||
}
|
||||
|
||||
var broker mb.Broker
|
||||
if cfg.Messaging != nil && cfg.Messaging.Driver != "" {
|
||||
broker, err = msg.CreateMessagingBroker(i.logger, cfg.Messaging)
|
||||
if err != nil {
|
||||
i.logger.Warn("Failed to create recipient notifications broker", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
repoFactory := func(logger mlogger.Logger, conn *db.MongoConnection) (storage.Repository, error) {
|
||||
return mongostorage.New(
|
||||
logger,
|
||||
conn,
|
||||
mongostorage.WithPaymentMethodsAuth(i.dbFactory.Permissions().Enforcer(), policy.ID),
|
||||
)
|
||||
}
|
||||
|
||||
serviceFactory := func(logger mlogger.Logger, repo storage.Repository, producer msg.Producer) (grpcapp.Service, error) {
|
||||
opts := []methods.Option{}
|
||||
if broker != nil {
|
||||
opts = append(opts, methods.WithRecipientEventsBroker(broker))
|
||||
}
|
||||
|
||||
i.startDiscoveryAnnouncer(cfg, producer)
|
||||
svc, err := methods.NewService(logger, repo, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i.service = svc
|
||||
return svc, nil
|
||||
}
|
||||
|
||||
app, err := grpcapp.NewApp(i.logger, "payments_methods", cfg.Config, i.debug, repoFactory, serviceFactory)
|
||||
if err != nil {
|
||||
i.dbFactory.CloseConnection()
|
||||
i.dbFactory = nil
|
||||
return err
|
||||
}
|
||||
i.app = app
|
||||
|
||||
if err := i.app.Start(); err != nil {
|
||||
if i.dbFactory != nil {
|
||||
i.dbFactory.CloseConnection()
|
||||
i.dbFactory = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
29
api/payments/methods/internal/server/internal/types.go
Normal file
29
api/payments/methods/internal/server/internal/types.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package serverimp
|
||||
|
||||
import (
|
||||
"github.com/tech/sendico/payments/storage"
|
||||
"github.com/tech/sendico/pkg/db"
|
||||
"github.com/tech/sendico/pkg/discovery"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/server/grpcapp"
|
||||
)
|
||||
|
||||
type methodsService interface {
|
||||
grpcapp.Service
|
||||
Shutdown()
|
||||
}
|
||||
|
||||
type Imp struct {
|
||||
logger mlogger.Logger
|
||||
file string
|
||||
debug bool
|
||||
|
||||
config *config
|
||||
app *grpcapp.App[storage.Repository]
|
||||
service methodsService
|
||||
dbFactory db.Factory
|
||||
|
||||
discoveryWatcher *discovery.RegistryWatcher
|
||||
discoveryReg *discovery.Registry
|
||||
discoveryAnnouncer *discovery.Announcer
|
||||
}
|
||||
12
api/payments/methods/internal/server/server.go
Normal file
12
api/payments/methods/internal/server/server.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
serverimp "github.com/tech/sendico/payments/methods/internal/server/internal"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/server"
|
||||
)
|
||||
|
||||
// Create initialises the payment methods server implementation.
|
||||
func Create(logger mlogger.Logger, file string, debug bool) (server.Application, error) {
|
||||
return serverimp.Create(logger, file, debug)
|
||||
}
|
||||
36
api/payments/methods/internal/service/methods/archive.go
Normal file
36
api/payments/methods/internal/service/methods/archive.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package methods
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
methodsv1 "github.com/tech/sendico/pkg/proto/payments/methods/v1"
|
||||
)
|
||||
|
||||
func (s *Service) SetPaymentMethodArchived(ctx context.Context, req *methodsv1.SetPaymentMethodArchivedRequest) (*methodsv1.SetPaymentMethodArchivedResponse, error) {
|
||||
if req == nil {
|
||||
return autoError[methodsv1.SetPaymentMethodArchivedResponse](ctx, s.logger, merrors.InvalidArgument("request is required"))
|
||||
}
|
||||
if s.pmstore == nil {
|
||||
return autoError[methodsv1.SetPaymentMethodArchivedResponse](ctx, s.logger, errStoreUnavailable)
|
||||
}
|
||||
|
||||
accountRef, err := parseObjectID(req.GetAccountRef(), "account_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.SetPaymentMethodArchivedResponse](ctx, s.logger, err)
|
||||
}
|
||||
organizationRef, err := parseObjectID(req.GetOrganizationRef(), "organization_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.SetPaymentMethodArchivedResponse](ctx, s.logger, err)
|
||||
}
|
||||
methodRef, err := parseObjectID(req.GetPaymentMethodRef(), "payment_method_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.SetPaymentMethodArchivedResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
if err := s.pmstore.SetArchived(ctx, accountRef, organizationRef, methodRef, req.GetArchived(), req.GetCascade()); err != nil {
|
||||
return autoError[methodsv1.SetPaymentMethodArchivedResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
return &methodsv1.SetPaymentMethodArchivedResponse{}, nil
|
||||
}
|
||||
41
api/payments/methods/internal/service/methods/create.go
Normal file
41
api/payments/methods/internal/service/methods/create.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package methods
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
methodsv1 "github.com/tech/sendico/pkg/proto/payments/methods/v1"
|
||||
)
|
||||
|
||||
func (s *Service) CreatePaymentMethod(ctx context.Context, req *methodsv1.CreatePaymentMethodRequest) (*methodsv1.CreatePaymentMethodResponse, error) {
|
||||
if req == nil {
|
||||
return autoError[methodsv1.CreatePaymentMethodResponse](ctx, s.logger, merrors.InvalidArgument("request is required"))
|
||||
}
|
||||
if s.pmstore == nil {
|
||||
return autoError[methodsv1.CreatePaymentMethodResponse](ctx, s.logger, errStoreUnavailable)
|
||||
}
|
||||
|
||||
accountRef, err := parseObjectID(req.GetAccountRef(), "account_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.CreatePaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
organizationRef, err := parseObjectID(req.GetOrganizationRef(), "organization_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.CreatePaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
pm, err := decodePaymentMethodPayload(req.GetPaymentMethod(), "payment_method")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.CreatePaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
if err := s.pmstore.Create(ctx, accountRef, organizationRef, pm); err != nil {
|
||||
return autoError[methodsv1.CreatePaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
record, err := encodePaymentMethodRecord(pm)
|
||||
if err != nil {
|
||||
return autoError[methodsv1.CreatePaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
return &methodsv1.CreatePaymentMethodResponse{PaymentMethodRecord: record}, nil
|
||||
}
|
||||
37
api/payments/methods/internal/service/methods/delete.go
Normal file
37
api/payments/methods/internal/service/methods/delete.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package methods
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
methodsv1 "github.com/tech/sendico/pkg/proto/payments/methods/v1"
|
||||
)
|
||||
|
||||
func (s *Service) DeletePaymentMethod(ctx context.Context, req *methodsv1.DeletePaymentMethodRequest) (*methodsv1.DeletePaymentMethodResponse, error) {
|
||||
if req == nil {
|
||||
return autoError[methodsv1.DeletePaymentMethodResponse](ctx, s.logger, merrors.InvalidArgument("request is required"))
|
||||
}
|
||||
if s.pmstore == nil {
|
||||
return autoError[methodsv1.DeletePaymentMethodResponse](ctx, s.logger, errStoreUnavailable)
|
||||
}
|
||||
|
||||
accountRef, err := parseObjectID(req.GetAccountRef(), "account_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.DeletePaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
methodRef, err := parseObjectID(req.GetPaymentMethodRef(), "payment_method_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.DeletePaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
if req.GetCascade() {
|
||||
err = s.pmstore.DeleteCascade(ctx, accountRef, methodRef)
|
||||
} else {
|
||||
err = s.pmstore.Delete(ctx, accountRef, methodRef)
|
||||
}
|
||||
if err != nil {
|
||||
return autoError[methodsv1.DeletePaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
return &methodsv1.DeletePaymentMethodResponse{}, nil
|
||||
}
|
||||
38
api/payments/methods/internal/service/methods/get.go
Normal file
38
api/payments/methods/internal/service/methods/get.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package methods
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
methodsv1 "github.com/tech/sendico/pkg/proto/payments/methods/v1"
|
||||
)
|
||||
|
||||
func (s *Service) GetPaymentMethod(ctx context.Context, req *methodsv1.GetPaymentMethodRequest) (*methodsv1.GetPaymentMethodResponse, error) {
|
||||
if req == nil {
|
||||
return autoError[methodsv1.GetPaymentMethodResponse](ctx, s.logger, merrors.InvalidArgument("request is required"))
|
||||
}
|
||||
if s.pmstore == nil {
|
||||
return autoError[methodsv1.GetPaymentMethodResponse](ctx, s.logger, errStoreUnavailable)
|
||||
}
|
||||
|
||||
accountRef, err := parseObjectID(req.GetAccountRef(), "account_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.GetPaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
methodRef, err := parseObjectID(req.GetPaymentMethodRef(), "payment_method_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.GetPaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
pm, err := s.pmstore.Get(ctx, accountRef, methodRef)
|
||||
if err != nil {
|
||||
return autoError[methodsv1.GetPaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
record, err := encodePaymentMethodRecord(pm)
|
||||
if err != nil {
|
||||
return autoError[methodsv1.GetPaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
return &methodsv1.GetPaymentMethodResponse{PaymentMethodRecord: record}, nil
|
||||
}
|
||||
49
api/payments/methods/internal/service/methods/list.go
Normal file
49
api/payments/methods/internal/service/methods/list.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package methods
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
endpointv1 "github.com/tech/sendico/pkg/proto/payments/endpoint/v1"
|
||||
methodsv1 "github.com/tech/sendico/pkg/proto/payments/methods/v1"
|
||||
)
|
||||
|
||||
func (s *Service) ListPaymentMethods(ctx context.Context, req *methodsv1.ListPaymentMethodsRequest) (*methodsv1.ListPaymentMethodsResponse, error) {
|
||||
if req == nil {
|
||||
return autoError[methodsv1.ListPaymentMethodsResponse](ctx, s.logger, merrors.InvalidArgument("request is required"))
|
||||
}
|
||||
if s.pmstore == nil {
|
||||
return autoError[methodsv1.ListPaymentMethodsResponse](ctx, s.logger, errStoreUnavailable)
|
||||
}
|
||||
|
||||
accountRef, err := parseObjectID(req.GetAccountRef(), "account_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.ListPaymentMethodsResponse](ctx, s.logger, err)
|
||||
}
|
||||
organizationRef, err := parseObjectID(req.GetOrganizationRef(), "organization_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.ListPaymentMethodsResponse](ctx, s.logger, err)
|
||||
}
|
||||
recipientRef, err := parseObjectID(req.GetRecipientRef(), "recipient_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.ListPaymentMethodsResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
items, err := s.pmstore.List(ctx, accountRef, organizationRef, recipientRef, toModelCursor(req.GetCursor()))
|
||||
if err != nil {
|
||||
return autoError[methodsv1.ListPaymentMethodsResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
result := make([]*endpointv1.PaymentMethodRecord, 0, len(items))
|
||||
for i := range items {
|
||||
record, err := encodePaymentMethodRecord(&items[i])
|
||||
if err != nil {
|
||||
return autoError[methodsv1.ListPaymentMethodsResponse](ctx, s.logger, err)
|
||||
}
|
||||
result = append(result, record)
|
||||
}
|
||||
|
||||
return &methodsv1.ListPaymentMethodsResponse{
|
||||
PaymentMethods: result,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package methods
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
cons "github.com/tech/sendico/pkg/messaging/consumer"
|
||||
objectnotifications "github.com/tech/sendico/pkg/messaging/notifications/object"
|
||||
np "github.com/tech/sendico/pkg/messaging/notifications/processor"
|
||||
nm "github.com/tech/sendico/pkg/model/notification"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (s *Service) startRecipientConsumers() {
|
||||
if s == nil || s.recipientBroker == nil {
|
||||
s.logger.Warn("Missing broker. Recipient cascade consumers have NOT started")
|
||||
return
|
||||
}
|
||||
|
||||
s.consumeRecipientProcessor(
|
||||
objectnotifications.NewObjectChangedMessageProcessor(s.logger, mservice.Recipients, nm.NAArchived, s.onRecipientNotification),
|
||||
)
|
||||
s.consumeRecipientProcessor(
|
||||
objectnotifications.NewObjectChangedMessageProcessor(s.logger, mservice.Recipients, nm.NADeleted, s.onRecipientNotification),
|
||||
)
|
||||
|
||||
s.logger.Info("Recipient cascade consumers started")
|
||||
}
|
||||
|
||||
func (s *Service) consumeRecipientProcessor(processor np.EnvelopeProcessor) {
|
||||
consumer, err := cons.NewConsumer(s.logger, s.recipientBroker, processor.GetSubject())
|
||||
if err != nil {
|
||||
s.logger.Warn("Failed to create recipient consumer", zap.Error(err), zap.String("event", processor.GetSubject().ToString()))
|
||||
return
|
||||
}
|
||||
s.recipientConsumers = append(s.recipientConsumers, consumer)
|
||||
|
||||
go func() {
|
||||
if err := consumer.ConsumeMessages(processor.Process); err != nil {
|
||||
s.logger.Warn("Recipient consumer stopped", zap.Error(err), zap.String("event", processor.GetSubject().ToString()))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *Service) onRecipientNotification(
|
||||
ctx context.Context,
|
||||
objectType mservice.Type,
|
||||
recipientRef, actorAccountRef bson.ObjectID,
|
||||
action nm.NotificationAction,
|
||||
) error {
|
||||
if s.pmstore == nil {
|
||||
return errStoreUnavailable
|
||||
}
|
||||
if objectType != mservice.Recipients || recipientRef == bson.NilObjectID {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch action {
|
||||
case nm.NAArchived:
|
||||
updated, err := s.pmstore.SetArchivedByRecipient(ctx, recipientRef, true)
|
||||
if err != nil {
|
||||
s.logger.Warn("Failed to cascade archive payment methods by recipient",
|
||||
zap.Error(err),
|
||||
zap.String("recipient_ref", recipientRef.Hex()),
|
||||
zap.String("actor_account_ref", actorAccountRef.Hex()))
|
||||
return err
|
||||
}
|
||||
s.logger.Info("Recipient archive cascade applied to payment methods",
|
||||
zap.String("recipient_ref", recipientRef.Hex()),
|
||||
zap.String("actor_account_ref", actorAccountRef.Hex()),
|
||||
zap.Int("updated_count", updated))
|
||||
case nm.NADeleted:
|
||||
if err := s.pmstore.DeleteByRecipient(ctx, recipientRef); err != nil {
|
||||
s.logger.Warn("Failed to cascade delete payment methods by recipient",
|
||||
zap.Error(err),
|
||||
zap.String("recipient_ref", recipientRef.Hex()),
|
||||
zap.String("actor_account_ref", actorAccountRef.Hex()))
|
||||
return err
|
||||
}
|
||||
s.logger.Info("Recipient delete cascade applied to payment methods",
|
||||
zap.String("recipient_ref", recipientRef.Hex()),
|
||||
zap.String("actor_account_ref", actorAccountRef.Hex()))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
90
api/payments/methods/internal/service/methods/service.go
Normal file
90
api/payments/methods/internal/service/methods/service.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package methods
|
||||
|
||||
import (
|
||||
"github.com/tech/sendico/payments/storage"
|
||||
"github.com/tech/sendico/pkg/api/routers"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
msg "github.com/tech/sendico/pkg/messaging"
|
||||
mb "github.com/tech/sendico/pkg/messaging/broker"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
methodsv1 "github.com/tech/sendico/pkg/proto/payments/methods/v1"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var errStoreUnavailable = merrors.Internal("payment-methods: storage is not initialised")
|
||||
|
||||
// Option configures service dependencies.
|
||||
type Option func(*Service)
|
||||
|
||||
// WithRecipientEventsBroker wires the broker used to consume recipient events.
|
||||
func WithRecipientEventsBroker(broker mb.Broker) Option {
|
||||
return func(s *Service) {
|
||||
if broker != nil {
|
||||
s.recipientBroker = broker
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Service implements payments.methods.v1.PaymentMethodsService.
|
||||
type Service struct {
|
||||
logger mlogger.Logger
|
||||
storage storage.Repository
|
||||
pmstore storage.PaymentMethodsStore
|
||||
|
||||
recipientBroker mb.Broker
|
||||
recipientConsumers []msg.Consumer
|
||||
|
||||
methodsv1.UnimplementedPaymentMethodsServiceServer
|
||||
}
|
||||
|
||||
// NewService creates a payment methods gRPC service.
|
||||
func NewService(logger mlogger.Logger, repo storage.Repository, opts ...Option) (*Service, error) {
|
||||
if logger == nil {
|
||||
return nil, merrors.InvalidArgument("payment-methods: logger is required")
|
||||
}
|
||||
if repo == nil {
|
||||
return nil, merrors.InvalidArgument("payment-methods: storage repository is required")
|
||||
}
|
||||
|
||||
pmstore := repo.PaymentMethods()
|
||||
if pmstore == nil {
|
||||
return nil, errStoreUnavailable
|
||||
}
|
||||
|
||||
svc := &Service{
|
||||
logger: logger.Named("payment_methods"),
|
||||
storage: repo,
|
||||
pmstore: pmstore,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
opt(svc)
|
||||
}
|
||||
}
|
||||
|
||||
svc.startRecipientConsumers()
|
||||
return svc, nil
|
||||
}
|
||||
|
||||
// Register attaches the service to the supplied gRPC router.
|
||||
func (s *Service) Register(router routers.GRPC) error {
|
||||
return router.Register(func(reg grpc.ServiceRegistrar) {
|
||||
methodsv1.RegisterPaymentMethodsServiceServer(reg, s)
|
||||
})
|
||||
}
|
||||
|
||||
// Shutdown releases underlying resources.
|
||||
func (s *Service) Shutdown() {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
for _, consumer := range s.recipientConsumers {
|
||||
if consumer != nil {
|
||||
consumer.Close()
|
||||
}
|
||||
}
|
||||
s.recipientConsumers = nil
|
||||
s.pmstore = nil
|
||||
s.storage = nil
|
||||
}
|
||||
37
api/payments/methods/internal/service/methods/update.go
Normal file
37
api/payments/methods/internal/service/methods/update.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package methods
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
methodsv1 "github.com/tech/sendico/pkg/proto/payments/methods/v1"
|
||||
)
|
||||
|
||||
func (s *Service) UpdatePaymentMethod(ctx context.Context, req *methodsv1.UpdatePaymentMethodRequest) (*methodsv1.UpdatePaymentMethodResponse, error) {
|
||||
if req == nil {
|
||||
return autoError[methodsv1.UpdatePaymentMethodResponse](ctx, s.logger, merrors.InvalidArgument("request is required"))
|
||||
}
|
||||
if s.pmstore == nil {
|
||||
return autoError[methodsv1.UpdatePaymentMethodResponse](ctx, s.logger, errStoreUnavailable)
|
||||
}
|
||||
|
||||
accountRef, err := parseObjectID(req.GetAccountRef(), "account_ref")
|
||||
if err != nil {
|
||||
return autoError[methodsv1.UpdatePaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
pm, err := decodePaymentMethodRecord(req.GetPaymentMethodRecord())
|
||||
if err != nil {
|
||||
return autoError[methodsv1.UpdatePaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
if err := s.pmstore.Update(ctx, accountRef, pm); err != nil {
|
||||
return autoError[methodsv1.UpdatePaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
record, err := encodePaymentMethodRecord(pm)
|
||||
if err != nil {
|
||||
return autoError[methodsv1.UpdatePaymentMethodResponse](ctx, s.logger, err)
|
||||
}
|
||||
|
||||
return &methodsv1.UpdatePaymentMethodResponse{PaymentMethodRecord: record}, nil
|
||||
}
|
||||
292
api/payments/methods/internal/service/methods/util.go
Normal file
292
api/payments/methods/internal/service/methods/util.go
Normal file
@@ -0,0 +1,292 @@
|
||||
package methods
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/pkg/api/routers/gsresponse"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
archivablev1 "github.com/tech/sendico/pkg/proto/common/archivable/v1"
|
||||
describablev1 "github.com/tech/sendico/pkg/proto/common/describable/v1"
|
||||
oboundv1 "github.com/tech/sendico/pkg/proto/common/organization_bound/v1"
|
||||
paginationv2 "github.com/tech/sendico/pkg/proto/common/pagination/v2"
|
||||
pboundv1 "github.com/tech/sendico/pkg/proto/common/permission_bound/v1"
|
||||
storablev1 "github.com/tech/sendico/pkg/proto/common/storable/v1"
|
||||
endpointv1 "github.com/tech/sendico/pkg/proto/payments/endpoint/v1"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
func autoError[T any](ctx context.Context, logger mlogger.Logger, err error) (*T, error) {
|
||||
return gsresponse.Execute(ctx, gsresponse.Auto[T](logger, mservice.PaymentMethods, err))
|
||||
}
|
||||
|
||||
func parseObjectID(value, field string) (bson.ObjectID, error) {
|
||||
trimmed := strings.TrimSpace(value)
|
||||
if trimmed == "" {
|
||||
return bson.NilObjectID, merrors.InvalidArgument(fmt.Sprintf("%s is required", field), field)
|
||||
}
|
||||
ref, err := bson.ObjectIDFromHex(trimmed)
|
||||
if err != nil {
|
||||
return bson.NilObjectID, merrors.InvalidArgument(fmt.Sprintf("%s must be a valid object id", field), field)
|
||||
}
|
||||
return ref, nil
|
||||
}
|
||||
|
||||
func decodePaymentMethodRecord(record *endpointv1.PaymentMethodRecord) (*model.PaymentMethod, error) {
|
||||
if record == nil {
|
||||
return nil, merrors.InvalidArgument("payment_method_record is required", "payment_method_record")
|
||||
}
|
||||
res, err := decodePaymentMethodPayload(record.GetPaymentMethod(), "payment_method_record.payment_method")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := applyPermissionBoundRecord(res, record.GetPermissionBound()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func decodePaymentMethodPayload(method *endpointv1.PaymentMethod, field string) (*model.PaymentMethod, error) {
|
||||
if method == nil {
|
||||
return nil, merrors.InvalidArgument(field+" is required", field)
|
||||
}
|
||||
|
||||
recipientRef, err := parseObjectID(method.GetRecipientRef(), field+".recipient_ref")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pt, err := paymentTypeFromProto(method.GetType(), field+".type")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &model.PaymentMethod{
|
||||
Describable: describableFromProto(method.GetDescribable()),
|
||||
RecipientRef: recipientRef,
|
||||
Type: pt,
|
||||
Data: cloneBytes(method.GetData()),
|
||||
IsMain: method.GetIsMain(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func encodePaymentMethodRecord(pm *model.PaymentMethod) (*endpointv1.PaymentMethodRecord, error) {
|
||||
if pm == nil {
|
||||
return nil, merrors.InvalidArgument("payment method is required")
|
||||
}
|
||||
pt, err := paymentTypeToProto(pm.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &endpointv1.PaymentMethodRecord{
|
||||
PermissionBound: permissionBoundFromModel(pm),
|
||||
PaymentMethod: &endpointv1.PaymentMethod{
|
||||
Describable: describableToProto(pm.Describable),
|
||||
RecipientRef: toObjectHex(pm.RecipientRef),
|
||||
Type: pt,
|
||||
Data: cloneBytes(pm.Data),
|
||||
IsMain: pm.IsMain,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func paymentTypeFromProto(value endpointv1.PaymentMethodType, field string) (model.PaymentType, error) {
|
||||
switch value {
|
||||
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_IBAN:
|
||||
return model.PaymentTypeIban, nil
|
||||
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD:
|
||||
return model.PaymentTypeCard, nil
|
||||
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD_TOKEN:
|
||||
return model.PaymentTypeCardToken, nil
|
||||
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_BANK_ACCOUNT:
|
||||
return model.PaymentTypeBankAccount, nil
|
||||
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_WALLET:
|
||||
return model.PaymentTypeWallet, nil
|
||||
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CRYPTO_ADDRESS:
|
||||
return model.PaymentTypeCryptoAddress, nil
|
||||
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_LEDGER:
|
||||
return model.PaymentTypeLedger, nil
|
||||
default:
|
||||
return model.PaymentTypeIban, merrors.InvalidArgument(fmt.Sprintf("%s has unsupported value: %s", field, value.String()), field)
|
||||
}
|
||||
}
|
||||
|
||||
func paymentTypeToProto(value model.PaymentType) (endpointv1.PaymentMethodType, error) {
|
||||
switch value {
|
||||
case model.PaymentTypeIban:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_IBAN, nil
|
||||
case model.PaymentTypeCard:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD, nil
|
||||
case model.PaymentTypeCardToken:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD_TOKEN, nil
|
||||
case model.PaymentTypeBankAccount:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_BANK_ACCOUNT, nil
|
||||
case model.PaymentTypeWallet:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_WALLET, nil
|
||||
case model.PaymentTypeCryptoAddress:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CRYPTO_ADDRESS, nil
|
||||
case model.PaymentTypeLedger:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_LEDGER, nil
|
||||
default:
|
||||
return endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_UNSPECIFIED, merrors.InvalidArgument(fmt.Sprintf("unsupported payment method type: %s", value.String()), "type")
|
||||
}
|
||||
}
|
||||
|
||||
func describableFromProto(src *describablev1.Describable) model.Describable {
|
||||
if src == nil {
|
||||
return model.Describable{}
|
||||
}
|
||||
res := model.Describable{Name: src.GetName()}
|
||||
if src.Description != nil {
|
||||
v := src.GetDescription()
|
||||
res.Description = &v
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func describableToProto(src model.Describable) *describablev1.Describable {
|
||||
if strings.TrimSpace(src.Name) == "" && src.Description == nil {
|
||||
return nil
|
||||
}
|
||||
res := &describablev1.Describable{
|
||||
Name: src.Name,
|
||||
}
|
||||
if src.Description != nil {
|
||||
v := *src.Description
|
||||
res.Description = &v
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func cloneBytes(src []byte) []byte {
|
||||
if len(src) == 0 {
|
||||
return nil
|
||||
}
|
||||
dst := make([]byte, len(src))
|
||||
copy(dst, src)
|
||||
return dst
|
||||
}
|
||||
|
||||
func applyPermissionBoundRecord(pm *model.PaymentMethod, src *pboundv1.PermissionBound) error {
|
||||
if pm == nil || src == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if storable := src.GetStorable(); storable != nil {
|
||||
if methodRef, err := parseOptionalObjectID(storable.GetId(), "payment_method_record.permission_bound.storable.id"); err != nil {
|
||||
return err
|
||||
} else if methodRef != bson.NilObjectID {
|
||||
pm.ID = methodRef
|
||||
}
|
||||
pm.CreatedAt = fromProtoTime(storable.GetCreatedAt())
|
||||
pm.UpdatedAt = fromProtoTime(storable.GetUpdatedAt())
|
||||
}
|
||||
|
||||
if archivable := src.GetArchivable(); archivable != nil {
|
||||
pm.Archived = archivable.GetIsArchived()
|
||||
}
|
||||
|
||||
if orgBound := src.GetOrganizationBound(); orgBound != nil {
|
||||
if orgRef, err := parseOptionalObjectID(orgBound.GetOrganizationRef(), "payment_method_record.permission_bound.organization_bound.organization_ref"); err != nil {
|
||||
return err
|
||||
} else if orgRef != bson.NilObjectID {
|
||||
pm.SetOrganizationRef(orgRef)
|
||||
}
|
||||
}
|
||||
|
||||
if permissionRef, err := parseOptionalObjectID(src.GetPermissionRef(), "payment_method_record.permission_bound.permission_ref"); err != nil {
|
||||
return err
|
||||
} else if permissionRef != bson.NilObjectID {
|
||||
pm.SetPermissionRef(permissionRef)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func permissionBoundFromModel(pm *model.PaymentMethod) *pboundv1.PermissionBound {
|
||||
if pm == nil {
|
||||
return nil
|
||||
}
|
||||
return &pboundv1.PermissionBound{
|
||||
Storable: &storablev1.Storable{
|
||||
Id: toObjectHex(pm.ID),
|
||||
CreatedAt: toProtoTime(pm.CreatedAt),
|
||||
UpdatedAt: toProtoTime(pm.UpdatedAt),
|
||||
},
|
||||
Archivable: &archivablev1.Archivable{
|
||||
IsArchived: pm.Archived,
|
||||
},
|
||||
OrganizationBound: &oboundv1.OrganizationBound{
|
||||
OrganizationRef: toObjectHex(pm.GetOrganizationRef()),
|
||||
},
|
||||
PermissionRef: toObjectHex(pm.GetPermissionRef()),
|
||||
}
|
||||
}
|
||||
|
||||
func parseOptionalObjectID(value, field string) (bson.ObjectID, error) {
|
||||
trimmed := strings.TrimSpace(value)
|
||||
if trimmed == "" {
|
||||
return bson.NilObjectID, nil
|
||||
}
|
||||
ref, err := bson.ObjectIDFromHex(trimmed)
|
||||
if err != nil {
|
||||
return bson.NilObjectID, merrors.InvalidArgument(fmt.Sprintf("%s must be a valid object id", field), field)
|
||||
}
|
||||
return ref, nil
|
||||
}
|
||||
|
||||
func toObjectHex(value bson.ObjectID) string {
|
||||
if value == bson.NilObjectID {
|
||||
return ""
|
||||
}
|
||||
return value.Hex()
|
||||
}
|
||||
|
||||
func toProtoTime(value time.Time) *timestamppb.Timestamp {
|
||||
if value.IsZero() {
|
||||
return nil
|
||||
}
|
||||
return timestamppb.New(value)
|
||||
}
|
||||
|
||||
func fromProtoTime(value *timestamppb.Timestamp) time.Time {
|
||||
if value == nil {
|
||||
return time.Time{}
|
||||
}
|
||||
return value.AsTime()
|
||||
}
|
||||
|
||||
func toModelCursor(cursor *paginationv2.ViewCursor) *model.ViewCursor {
|
||||
if cursor == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := &model.ViewCursor{}
|
||||
hasAny := false
|
||||
|
||||
if limit := cursor.GetLimit(); limit != nil {
|
||||
v := limit.GetValue()
|
||||
res.Limit = &v
|
||||
hasAny = true
|
||||
}
|
||||
if offset := cursor.GetOffset(); offset != nil {
|
||||
v := offset.GetValue()
|
||||
res.Offset = &v
|
||||
hasAny = true
|
||||
}
|
||||
if archived := cursor.GetIsArchived(); archived != nil {
|
||||
v := archived.GetValue()
|
||||
res.IsArchived = &v
|
||||
hasAny = true
|
||||
}
|
||||
if !hasAny {
|
||||
return nil
|
||||
}
|
||||
return res
|
||||
}
|
||||
17
api/payments/methods/main.go
Normal file
17
api/payments/methods/main.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/tech/sendico/payments/methods/internal/appversion"
|
||||
si "github.com/tech/sendico/payments/methods/internal/server"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/server"
|
||||
smain "github.com/tech/sendico/pkg/server/main"
|
||||
)
|
||||
|
||||
func factory(logger mlogger.Logger, file string, debug bool) (server.Application, error) {
|
||||
return si.Create(logger, file, debug)
|
||||
}
|
||||
|
||||
func main() {
|
||||
smain.RunServer("main", appversion.Create(), factory)
|
||||
}
|
||||
@@ -28,7 +28,7 @@ require (
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.78.0
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
@@ -57,8 +57,6 @@ require (
|
||||
github.com/xdg-go/scram v1.2.0 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
go.opentelemetry.io/otel v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
golang.org/x/crypto v0.48.0 // indirect
|
||||
|
||||
@@ -213,8 +213,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
fxv1 "github.com/tech/sendico/pkg/proto/common/fx/v1"
|
||||
gatewayv1 "github.com/tech/sendico/pkg/proto/common/gateway/v1"
|
||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||
paymentv1 "github.com/tech/sendico/pkg/proto/common/payment/v1"
|
||||
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
|
||||
oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1"
|
||||
orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestration/v1"
|
||||
@@ -553,25 +554,25 @@ func protoFailureFromModel(code model.PaymentFailureCode) sharedv1.PaymentFailur
|
||||
}
|
||||
}
|
||||
|
||||
func settlementModeFromProto(mode sharedv1.SettlementMode) model.SettlementMode {
|
||||
func settlementModeFromProto(mode paymentv1.SettlementMode) model.SettlementMode {
|
||||
switch mode {
|
||||
case sharedv1.SettlementMode_SETTLEMENT_FIX_SOURCE:
|
||||
case paymentv1.SettlementMode_SETTLEMENT_FIX_SOURCE:
|
||||
return model.SettlementModeFixSource
|
||||
case sharedv1.SettlementMode_SETTLEMENT_FIX_RECEIVED:
|
||||
case paymentv1.SettlementMode_SETTLEMENT_FIX_RECEIVED:
|
||||
return model.SettlementModeFixReceived
|
||||
default:
|
||||
return model.SettlementModeUnspecified
|
||||
}
|
||||
}
|
||||
|
||||
func settlementModeToProto(mode model.SettlementMode) sharedv1.SettlementMode {
|
||||
func settlementModeToProto(mode model.SettlementMode) paymentv1.SettlementMode {
|
||||
switch mode {
|
||||
case model.SettlementModeFixSource:
|
||||
return sharedv1.SettlementMode_SETTLEMENT_FIX_SOURCE
|
||||
return paymentv1.SettlementMode_SETTLEMENT_FIX_SOURCE
|
||||
case model.SettlementModeFixReceived:
|
||||
return sharedv1.SettlementMode_SETTLEMENT_FIX_RECEIVED
|
||||
return paymentv1.SettlementMode_SETTLEMENT_FIX_RECEIVED
|
||||
default:
|
||||
return sharedv1.SettlementMode_SETTLEMENT_UNSPECIFIED
|
||||
return paymentv1.SettlementMode_SETTLEMENT_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
@@ -685,6 +686,10 @@ func fxQuoteFromProto(quote *oraclev1.Quote) *paymenttypes.FXQuote {
|
||||
if quote == nil {
|
||||
return nil
|
||||
}
|
||||
pricedAtUnixMs := int64(0)
|
||||
if ts := quote.GetPricedAt(); ts != nil {
|
||||
pricedAtUnixMs = ts.AsTime().UnixMilli()
|
||||
}
|
||||
return &paymenttypes.FXQuote{
|
||||
QuoteRef: strings.TrimSpace(quote.GetQuoteRef()),
|
||||
Pair: pairFromProto(quote.GetPair()),
|
||||
@@ -693,6 +698,7 @@ func fxQuoteFromProto(quote *oraclev1.Quote) *paymenttypes.FXQuote {
|
||||
BaseAmount: moneyFromProto(quote.GetBaseAmount()),
|
||||
QuoteAmount: moneyFromProto(quote.GetQuoteAmount()),
|
||||
ExpiresAtUnixMs: quote.GetExpiresAtUnixMs(),
|
||||
PricedAtUnixMs: pricedAtUnixMs,
|
||||
Provider: strings.TrimSpace(quote.GetProvider()),
|
||||
RateRef: strings.TrimSpace(quote.GetRateRef()),
|
||||
Firm: quote.GetFirm(),
|
||||
@@ -703,6 +709,10 @@ func fxQuoteToProto(quote *paymenttypes.FXQuote) *oraclev1.Quote {
|
||||
if quote == nil {
|
||||
return nil
|
||||
}
|
||||
var pricedAt *timestamppb.Timestamp
|
||||
if quote.PricedAtUnixMs > 0 {
|
||||
pricedAt = timestamppb.New(time.UnixMilli(quote.PricedAtUnixMs).UTC())
|
||||
}
|
||||
return &oraclev1.Quote{
|
||||
QuoteRef: strings.TrimSpace(quote.QuoteRef),
|
||||
Pair: pairToProto(quote.Pair),
|
||||
@@ -711,6 +721,7 @@ func fxQuoteToProto(quote *paymenttypes.FXQuote) *oraclev1.Quote {
|
||||
BaseAmount: protoMoney(quote.BaseAmount),
|
||||
QuoteAmount: protoMoney(quote.QuoteAmount),
|
||||
ExpiresAtUnixMs: quote.ExpiresAtUnixMs,
|
||||
PricedAt: pricedAt,
|
||||
Provider: strings.TrimSpace(quote.Provider),
|
||||
RateRef: strings.TrimSpace(quote.RateRef),
|
||||
Firm: quote.Firm,
|
||||
|
||||
@@ -2,6 +2,7 @@ package orchestrator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
paymenttypes "github.com/tech/sendico/pkg/payments/types"
|
||||
feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
|
||||
oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
func TestMoneyConversionRoundTrip(t *testing.T) {
|
||||
@@ -69,6 +71,7 @@ func TestFeeLineConversionRoundTrip(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFXQuoteConversionRoundTrip(t *testing.T) {
|
||||
pricedAt := int64(1700000000000)
|
||||
proto := &oraclev1.Quote{
|
||||
QuoteRef: "q1",
|
||||
Pair: &fxv1.CurrencyPair{Base: "USD", Quote: "EUR"},
|
||||
@@ -77,6 +80,7 @@ func TestFXQuoteConversionRoundTrip(t *testing.T) {
|
||||
BaseAmount: &moneyv1.Money{Currency: "USD", Amount: "100"},
|
||||
QuoteAmount: &moneyv1.Money{Currency: "EUR", Amount: "90"},
|
||||
ExpiresAtUnixMs: 1700000000000,
|
||||
PricedAt: timestamppb.New(time.UnixMilli(pricedAt).UTC()),
|
||||
Provider: "provider",
|
||||
RateRef: "rate",
|
||||
Firm: true,
|
||||
@@ -88,6 +92,9 @@ func TestFXQuoteConversionRoundTrip(t *testing.T) {
|
||||
if model.Side != paymenttypes.FXSideSellBaseBuyQuote || model.Price.GetValue() != "0.9" {
|
||||
t.Fatalf("fxQuoteFromProto enums mismatch: %#v", model)
|
||||
}
|
||||
if model.PricedAtUnixMs != pricedAt {
|
||||
t.Fatalf("fxQuoteFromProto priced_at mismatch: %#v", model)
|
||||
}
|
||||
back := fxQuoteToProto(model)
|
||||
if back == nil || back.GetQuoteRef() != "q1" || back.GetPair().GetBase() != "USD" || back.GetPair().GetQuote() != "EUR" {
|
||||
t.Fatalf("fxQuoteToProto mismatch: %#v", back)
|
||||
@@ -95,6 +102,9 @@ func TestFXQuoteConversionRoundTrip(t *testing.T) {
|
||||
if back.GetSide() != fxv1.Side_SELL_BASE_BUY_QUOTE || back.GetPrice().GetValue() != "0.9" {
|
||||
t.Fatalf("fxQuoteToProto enums mismatch: %#v", back)
|
||||
}
|
||||
if got := back.GetPricedAt(); got == nil || got.AsTime().UnixMilli() != pricedAt {
|
||||
t.Fatalf("fxQuoteToProto priced_at mismatch: %#v", back)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAssetConversionRoundTrip(t *testing.T) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
accountingv1 "github.com/tech/sendico/pkg/proto/common/accounting/v1"
|
||||
fxv1 "github.com/tech/sendico/pkg/proto/common/fx/v1"
|
||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||
paymentv1 "github.com/tech/sendico/pkg/proto/common/payment/v1"
|
||||
)
|
||||
|
||||
type moneyGetter interface {
|
||||
@@ -100,7 +101,7 @@ func resolveTradeAmounts(intentAmount *moneyv1.Money, fxQuote *oraclev1.Quote, s
|
||||
}
|
||||
}
|
||||
|
||||
func computeAggregates(pay, settlement, fee *moneyv1.Money, network *chainv1.EstimateTransferFeeResponse, fxQuote *oraclev1.Quote, mode sharedv1.SettlementMode) (*moneyv1.Money, *moneyv1.Money) {
|
||||
func computeAggregates(pay, settlement, fee *moneyv1.Money, network *chainv1.EstimateTransferFeeResponse, fxQuote *oraclev1.Quote, mode paymentv1.SettlementMode) (*moneyv1.Money, *moneyv1.Money) {
|
||||
if pay == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -142,7 +143,7 @@ func computeAggregates(pay, settlement, fee *moneyv1.Money, network *chainv1.Est
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case sharedv1.SettlementMode_SETTLEMENT_FIX_RECEIVED:
|
||||
case paymentv1.SettlementMode_SETTLEMENT_FIX_RECEIVED:
|
||||
// Sender pays the fee: keep settlement fixed, increase debit.
|
||||
applyChargeToDebit(fee)
|
||||
default:
|
||||
@@ -152,7 +153,7 @@ func computeAggregates(pay, settlement, fee *moneyv1.Money, network *chainv1.Est
|
||||
|
||||
if network != nil && network.GetNetworkFee() != nil {
|
||||
switch mode {
|
||||
case sharedv1.SettlementMode_SETTLEMENT_FIX_RECEIVED:
|
||||
case paymentv1.SettlementMode_SETTLEMENT_FIX_RECEIVED:
|
||||
applyChargeToDebit(network.GetNetworkFee())
|
||||
default:
|
||||
applyChargeToSettlement(network.GetNetworkFee())
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
accountingv1 "github.com/tech/sendico/pkg/proto/common/accounting/v1"
|
||||
fxv1 "github.com/tech/sendico/pkg/proto/common/fx/v1"
|
||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||
paymentv1 "github.com/tech/sendico/pkg/proto/common/payment/v1"
|
||||
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
|
||||
oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1"
|
||||
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
|
||||
)
|
||||
|
||||
func TestResolveTradeAmountsBuyBase(t *testing.T) {
|
||||
@@ -50,7 +50,7 @@ func TestComputeAggregatesConvertsCurrencies(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
debit, settlement := computeAggregates(pay, settle, fee, network, fxQuote, sharedv1.SettlementMode_SETTLEMENT_FIX_RECEIVED)
|
||||
debit, settlement := computeAggregates(pay, settle, fee, network, fxQuote, paymentv1.SettlementMode_SETTLEMENT_FIX_RECEIVED)
|
||||
if debit.GetCurrency() != "USD" || debit.GetAmount() != "115" {
|
||||
t.Fatalf("expected debit 115 USD, got %s %s", debit.GetCurrency(), debit.GetAmount())
|
||||
}
|
||||
@@ -71,7 +71,7 @@ func TestComputeAggregatesRecipientPaysFee(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
debit, settlement := computeAggregates(pay, settle, fee, nil, fxQuote, sharedv1.SettlementMode_SETTLEMENT_FIX_SOURCE)
|
||||
debit, settlement := computeAggregates(pay, settle, fee, nil, fxQuote, paymentv1.SettlementMode_SETTLEMENT_FIX_SOURCE)
|
||||
if debit.GetCurrency() != "USDT" || debit.GetAmount() != "100" {
|
||||
t.Fatalf("expected debit 100 USDT, got %s %s", debit.GetCurrency(), debit.GetAmount())
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package orchestrator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
mntxclient "github.com/tech/sendico/gateway/mntx/client"
|
||||
@@ -216,64 +215,3 @@ func TestExecutePaymentPlan_SourceBeforeDestination(t *testing.T) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestExecutePaymentPlan_RejectsLegacyLedgerOperations(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
store := newStubPaymentsStore()
|
||||
repo := &stubRepository{store: store}
|
||||
|
||||
ledgerFake := &ledgerclient.Fake{}
|
||||
|
||||
svc := &Service{
|
||||
logger: zap.NewNop(),
|
||||
storage: repo,
|
||||
deps: serviceDependencies{
|
||||
ledger: ledgerDependency{
|
||||
client: ledgerFake,
|
||||
internal: ledgerFake,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
executor := newPaymentExecutor(&svc.deps, svc.logger, svc)
|
||||
|
||||
payment := &model.Payment{
|
||||
PaymentRef: "pay-legacy-1",
|
||||
IdempotencyKey: "pay-legacy-1",
|
||||
OrganizationBoundBase: mo.OrganizationBoundBase{
|
||||
OrganizationRef: bson.NewObjectID(),
|
||||
},
|
||||
Intent: model.PaymentIntent{
|
||||
Ref: "ref-legacy-1",
|
||||
Kind: model.PaymentKindPayout,
|
||||
Source: model.PaymentEndpoint{
|
||||
Type: model.EndpointTypeManagedWallet,
|
||||
ManagedWallet: &model.ManagedWalletEndpoint{
|
||||
ManagedWalletRef: "wallet-src",
|
||||
},
|
||||
},
|
||||
Destination: model.PaymentEndpoint{
|
||||
Type: model.EndpointTypeCard,
|
||||
Card: &model.CardEndpoint{MaskedPan: "4111"},
|
||||
},
|
||||
},
|
||||
PaymentPlan: &model.PaymentPlan{
|
||||
ID: "pay-legacy-1",
|
||||
IdempotencyKey: "pay-legacy-1",
|
||||
Steps: []*model.PaymentStep{
|
||||
{StepID: "ledger_block", Rail: model.RailLedger, Action: model.RailOperationBlock, Amount: &paymenttypes.Money{Currency: "USD", Amount: "100"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
store.payments[payment.PaymentRef] = payment
|
||||
|
||||
err := executor.executePaymentPlan(ctx, store, payment, &sharedv1.PaymentQuote{})
|
||||
if err == nil {
|
||||
t.Fatal("expected legacy ledger operation error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "unsupported action") {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ func cloneStoredFXQuote(src *paymenttypes.FXQuote) *paymenttypes.FXQuote {
|
||||
QuoteRef: strings.TrimSpace(src.QuoteRef),
|
||||
Side: src.Side,
|
||||
ExpiresAtUnixMs: src.ExpiresAtUnixMs,
|
||||
PricedAtUnixMs: src.PricedAtUnixMs,
|
||||
Provider: strings.TrimSpace(src.Provider),
|
||||
RateRef: strings.TrimSpace(src.RateRef),
|
||||
Firm: src.Firm,
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/tech/sendico/payments/storage"
|
||||
"github.com/tech/sendico/payments/storage/model"
|
||||
quotestorage "github.com/tech/sendico/payments/storage/quote"
|
||||
"github.com/tech/sendico/pkg/api/routers/gsresponse"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
@@ -72,7 +73,7 @@ func ensurePaymentsStore(repo storage.Repository) (storage.PaymentsStore, error)
|
||||
return store, nil
|
||||
}
|
||||
|
||||
func ensureQuotesStore(repo storage.Repository) (storage.QuotesStore, error) {
|
||||
func ensureQuotesStore(repo storage.Repository) (quotestorage.QuotesStore, error) {
|
||||
if repo == nil {
|
||||
return nil, errStorageUnavailable
|
||||
}
|
||||
|
||||
@@ -8,11 +8,13 @@ import (
|
||||
ledgerclient "github.com/tech/sendico/ledger/client"
|
||||
"github.com/tech/sendico/payments/storage"
|
||||
"github.com/tech/sendico/payments/storage/model"
|
||||
quotestorage "github.com/tech/sendico/payments/storage/quote"
|
||||
clockpkg "github.com/tech/sendico/pkg/clock"
|
||||
mloggerfactory "github.com/tech/sendico/pkg/mlogger/factory"
|
||||
"github.com/tech/sendico/pkg/model/account_role"
|
||||
paymenttypes "github.com/tech/sendico/pkg/payments/types"
|
||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||
paymentv1 "github.com/tech/sendico/pkg/proto/common/payment/v1"
|
||||
connectorv1 "github.com/tech/sendico/pkg/proto/connector/v1"
|
||||
ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1"
|
||||
orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestration/v1"
|
||||
@@ -59,7 +61,7 @@ func TestNewPayment(t *testing.T) {
|
||||
intent := &sharedv1.PaymentIntent{
|
||||
Ref: "ref-1",
|
||||
Amount: &moneyv1.Money{Currency: "USD", Amount: "10"},
|
||||
SettlementMode: sharedv1.SettlementMode_SETTLEMENT_FIX_RECEIVED,
|
||||
SettlementMode: paymentv1.SettlementMode_SETTLEMENT_FIX_RECEIVED,
|
||||
SettlementCurrency: "USD",
|
||||
}
|
||||
quote := &sharedv1.PaymentQuote{QuoteRef: "q1"}
|
||||
@@ -380,7 +382,7 @@ func TestInitiatePaymentByQuoteRef(t *testing.T) {
|
||||
|
||||
type stubRepo struct {
|
||||
payments storage.PaymentsStore
|
||||
quotes storage.QuotesStore
|
||||
quotes quotestorage.QuotesStore
|
||||
routes storage.RoutesStore
|
||||
plans storage.PlanTemplatesStore
|
||||
pingErr error
|
||||
@@ -388,7 +390,10 @@ type stubRepo struct {
|
||||
|
||||
func (s stubRepo) Ping(context.Context) error { return s.pingErr }
|
||||
func (s stubRepo) Payments() storage.PaymentsStore { return s.payments }
|
||||
func (s stubRepo) Quotes() storage.QuotesStore { return s.quotes }
|
||||
func (s stubRepo) PaymentMethods() storage.PaymentMethodsStore {
|
||||
return nil
|
||||
}
|
||||
func (s stubRepo) Quotes() quotestorage.QuotesStore { return s.quotes }
|
||||
func (s stubRepo) Routes() storage.RoutesStore { return s.routes }
|
||||
func (s stubRepo) PlanTemplates() storage.PlanTemplatesStore {
|
||||
if s.plans != nil {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
ledgerclient "github.com/tech/sendico/ledger/client"
|
||||
"github.com/tech/sendico/payments/storage"
|
||||
"github.com/tech/sendico/payments/storage/model"
|
||||
quotestorage "github.com/tech/sendico/payments/storage/quote"
|
||||
"github.com/tech/sendico/pkg/api/routers/gsresponse"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
mo "github.com/tech/sendico/pkg/model"
|
||||
@@ -399,14 +400,17 @@ func TestProcessDepositObservedHandler_MatchesPayment(t *testing.T) {
|
||||
|
||||
type stubRepository struct {
|
||||
store *stubPaymentsStore
|
||||
quotes storage.QuotesStore
|
||||
quotes quotestorage.QuotesStore
|
||||
routes storage.RoutesStore
|
||||
plans storage.PlanTemplatesStore
|
||||
}
|
||||
|
||||
func (r *stubRepository) Ping(context.Context) error { return nil }
|
||||
func (r *stubRepository) Payments() storage.PaymentsStore { return r.store }
|
||||
func (r *stubRepository) Quotes() storage.QuotesStore {
|
||||
func (r *stubRepository) PaymentMethods() storage.PaymentMethodsStore {
|
||||
return nil
|
||||
}
|
||||
func (r *stubRepository) Quotes() quotestorage.QuotesStore {
|
||||
if r.quotes != nil {
|
||||
return r.quotes
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package plan_builder
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/tech/sendico/payments/storage/model"
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
|
||||
oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1"
|
||||
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
type moneyGetter interface {
|
||||
@@ -226,6 +228,10 @@ func fxQuoteFromProto(quote *oraclev1.Quote) *paymenttypes.FXQuote {
|
||||
if quote == nil {
|
||||
return nil
|
||||
}
|
||||
pricedAtUnixMs := int64(0)
|
||||
if ts := quote.GetPricedAt(); ts != nil {
|
||||
pricedAtUnixMs = ts.AsTime().UnixMilli()
|
||||
}
|
||||
return &paymenttypes.FXQuote{
|
||||
QuoteRef: strings.TrimSpace(quote.GetQuoteRef()),
|
||||
Pair: pairFromProto(quote.GetPair()),
|
||||
@@ -234,6 +240,7 @@ func fxQuoteFromProto(quote *oraclev1.Quote) *paymenttypes.FXQuote {
|
||||
BaseAmount: moneyFromProto(quote.GetBaseAmount()),
|
||||
QuoteAmount: moneyFromProto(quote.GetQuoteAmount()),
|
||||
ExpiresAtUnixMs: quote.GetExpiresAtUnixMs(),
|
||||
PricedAtUnixMs: pricedAtUnixMs,
|
||||
Provider: strings.TrimSpace(quote.GetProvider()),
|
||||
RateRef: strings.TrimSpace(quote.GetRateRef()),
|
||||
Firm: quote.GetFirm(),
|
||||
@@ -244,6 +251,10 @@ func fxQuoteToProto(quote *paymenttypes.FXQuote) *oraclev1.Quote {
|
||||
if quote == nil {
|
||||
return nil
|
||||
}
|
||||
var pricedAt *timestamppb.Timestamp
|
||||
if quote.PricedAtUnixMs > 0 {
|
||||
pricedAt = timestamppb.New(time.UnixMilli(quote.PricedAtUnixMs).UTC())
|
||||
}
|
||||
return &oraclev1.Quote{
|
||||
QuoteRef: strings.TrimSpace(quote.QuoteRef),
|
||||
Pair: pairToProto(quote.Pair),
|
||||
@@ -252,6 +263,7 @@ func fxQuoteToProto(quote *paymenttypes.FXQuote) *oraclev1.Quote {
|
||||
BaseAmount: protoMoney(quote.BaseAmount),
|
||||
QuoteAmount: protoMoney(quote.QuoteAmount),
|
||||
ExpiresAtUnixMs: quote.ExpiresAtUnixMs,
|
||||
PricedAt: pricedAt,
|
||||
Provider: strings.TrimSpace(quote.Provider),
|
||||
RateRef: strings.TrimSpace(quote.RateRef),
|
||||
Firm: quote.Firm,
|
||||
|
||||
@@ -26,7 +26,7 @@ require (
|
||||
github.com/tech/sendico/pkg v0.1.0
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||
go.uber.org/zap v1.27.1
|
||||
google.golang.org/grpc v1.78.0
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -155,16 +155,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -213,8 +213,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/tech/sendico/pkg/server"
|
||||
)
|
||||
|
||||
// Create initialises the payment quotation server implementation.
|
||||
// Create initialises the payment quotation server implementation
|
||||
func Create(logger mlogger.Logger, file string, debug bool) (server.Application, error) {
|
||||
return serverimp.Create(logger, file, debug)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package plan
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/tech/sendico/payments/storage/model"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||
oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1"
|
||||
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
type moneyGetter interface {
|
||||
@@ -158,6 +160,10 @@ func fxQuoteFromProto(quote *oraclev1.Quote) *paymenttypes.FXQuote {
|
||||
if quote == nil {
|
||||
return nil
|
||||
}
|
||||
pricedAtUnixMs := int64(0)
|
||||
if ts := quote.GetPricedAt(); ts != nil {
|
||||
pricedAtUnixMs = ts.AsTime().UnixMilli()
|
||||
}
|
||||
return &paymenttypes.FXQuote{
|
||||
QuoteRef: strings.TrimSpace(quote.GetQuoteRef()),
|
||||
Pair: pairFromProto(quote.GetPair()),
|
||||
@@ -166,6 +172,7 @@ func fxQuoteFromProto(quote *oraclev1.Quote) *paymenttypes.FXQuote {
|
||||
BaseAmount: moneyFromProto(quote.GetBaseAmount()),
|
||||
QuoteAmount: moneyFromProto(quote.GetQuoteAmount()),
|
||||
ExpiresAtUnixMs: quote.GetExpiresAtUnixMs(),
|
||||
PricedAtUnixMs: pricedAtUnixMs,
|
||||
Provider: strings.TrimSpace(quote.GetProvider()),
|
||||
RateRef: strings.TrimSpace(quote.GetRateRef()),
|
||||
Firm: quote.GetFirm(),
|
||||
@@ -176,6 +183,10 @@ func fxQuoteToProto(quote *paymenttypes.FXQuote) *oraclev1.Quote {
|
||||
if quote == nil {
|
||||
return nil
|
||||
}
|
||||
var pricedAt *timestamppb.Timestamp
|
||||
if quote.PricedAtUnixMs > 0 {
|
||||
pricedAt = timestamppb.New(time.UnixMilli(quote.PricedAtUnixMs).UTC())
|
||||
}
|
||||
return &oraclev1.Quote{
|
||||
QuoteRef: strings.TrimSpace(quote.QuoteRef),
|
||||
Pair: pairToProto(quote.Pair),
|
||||
@@ -184,6 +195,7 @@ func fxQuoteToProto(quote *paymenttypes.FXQuote) *oraclev1.Quote {
|
||||
BaseAmount: protoMoney(quote.BaseAmount),
|
||||
QuoteAmount: protoMoney(quote.QuoteAmount),
|
||||
ExpiresAtUnixMs: quote.ExpiresAtUnixMs,
|
||||
PricedAt: pricedAt,
|
||||
Provider: strings.TrimSpace(quote.Provider),
|
||||
RateRef: strings.TrimSpace(quote.RateRef),
|
||||
Firm: quote.Firm,
|
||||
|
||||
@@ -2,6 +2,7 @@ package quotation
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/payments/storage/model"
|
||||
chainasset "github.com/tech/sendico/pkg/chain"
|
||||
@@ -10,9 +11,11 @@ import (
|
||||
accountingv1 "github.com/tech/sendico/pkg/proto/common/accounting/v1"
|
||||
fxv1 "github.com/tech/sendico/pkg/proto/common/fx/v1"
|
||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||
paymentv1 "github.com/tech/sendico/pkg/proto/common/payment/v1"
|
||||
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
|
||||
oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1"
|
||||
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
func intentFromProto(src *sharedv1.PaymentIntent) model.PaymentIntent {
|
||||
@@ -291,25 +294,25 @@ func modelKindFromProto(kind sharedv1.PaymentKind) model.PaymentKind {
|
||||
}
|
||||
}
|
||||
|
||||
func settlementModeFromProto(mode sharedv1.SettlementMode) model.SettlementMode {
|
||||
func settlementModeFromProto(mode paymentv1.SettlementMode) model.SettlementMode {
|
||||
switch mode {
|
||||
case sharedv1.SettlementMode_SETTLEMENT_FIX_SOURCE:
|
||||
case paymentv1.SettlementMode_SETTLEMENT_FIX_SOURCE:
|
||||
return model.SettlementModeFixSource
|
||||
case sharedv1.SettlementMode_SETTLEMENT_FIX_RECEIVED:
|
||||
case paymentv1.SettlementMode_SETTLEMENT_FIX_RECEIVED:
|
||||
return model.SettlementModeFixReceived
|
||||
default:
|
||||
return model.SettlementModeUnspecified
|
||||
}
|
||||
}
|
||||
|
||||
func settlementModeToProto(mode model.SettlementMode) sharedv1.SettlementMode {
|
||||
func settlementModeToProto(mode model.SettlementMode) paymentv1.SettlementMode {
|
||||
switch mode {
|
||||
case model.SettlementModeFixSource:
|
||||
return sharedv1.SettlementMode_SETTLEMENT_FIX_SOURCE
|
||||
return paymentv1.SettlementMode_SETTLEMENT_FIX_SOURCE
|
||||
case model.SettlementModeFixReceived:
|
||||
return sharedv1.SettlementMode_SETTLEMENT_FIX_RECEIVED
|
||||
return paymentv1.SettlementMode_SETTLEMENT_FIX_RECEIVED
|
||||
default:
|
||||
return sharedv1.SettlementMode_SETTLEMENT_UNSPECIFIED
|
||||
return paymentv1.SettlementMode_SETTLEMENT_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,6 +426,10 @@ func fxQuoteFromProto(quote *oraclev1.Quote) *paymenttypes.FXQuote {
|
||||
if quote == nil {
|
||||
return nil
|
||||
}
|
||||
pricedAtUnixMs := int64(0)
|
||||
if ts := quote.GetPricedAt(); ts != nil {
|
||||
pricedAtUnixMs = ts.AsTime().UnixMilli()
|
||||
}
|
||||
return &paymenttypes.FXQuote{
|
||||
QuoteRef: strings.TrimSpace(quote.GetQuoteRef()),
|
||||
Pair: pairFromProto(quote.GetPair()),
|
||||
@@ -431,6 +438,7 @@ func fxQuoteFromProto(quote *oraclev1.Quote) *paymenttypes.FXQuote {
|
||||
BaseAmount: moneyFromProto(quote.GetBaseAmount()),
|
||||
QuoteAmount: moneyFromProto(quote.GetQuoteAmount()),
|
||||
ExpiresAtUnixMs: quote.GetExpiresAtUnixMs(),
|
||||
PricedAtUnixMs: pricedAtUnixMs,
|
||||
Provider: strings.TrimSpace(quote.GetProvider()),
|
||||
RateRef: strings.TrimSpace(quote.GetRateRef()),
|
||||
Firm: quote.GetFirm(),
|
||||
@@ -441,6 +449,10 @@ func fxQuoteToProto(quote *paymenttypes.FXQuote) *oraclev1.Quote {
|
||||
if quote == nil {
|
||||
return nil
|
||||
}
|
||||
var pricedAt *timestamppb.Timestamp
|
||||
if quote.PricedAtUnixMs > 0 {
|
||||
pricedAt = timestamppb.New(time.UnixMilli(quote.PricedAtUnixMs).UTC())
|
||||
}
|
||||
return &oraclev1.Quote{
|
||||
QuoteRef: strings.TrimSpace(quote.QuoteRef),
|
||||
Pair: pairToProto(quote.Pair),
|
||||
@@ -449,6 +461,7 @@ func fxQuoteToProto(quote *paymenttypes.FXQuote) *oraclev1.Quote {
|
||||
BaseAmount: protoMoney(quote.BaseAmount),
|
||||
QuoteAmount: protoMoney(quote.QuoteAmount),
|
||||
ExpiresAtUnixMs: quote.ExpiresAtUnixMs,
|
||||
PricedAt: pricedAt,
|
||||
Provider: strings.TrimSpace(quote.Provider),
|
||||
RateRef: strings.TrimSpace(quote.RateRef),
|
||||
Firm: quote.Firm,
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/tech/sendico/payments/storage"
|
||||
"github.com/tech/sendico/payments/storage/model"
|
||||
quotestorage "github.com/tech/sendico/payments/storage/quote"
|
||||
"github.com/tech/sendico/pkg/api/routers/gsresponse"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
@@ -114,7 +115,7 @@ func (h *quotePaymentCommand) prepareQuoteCtx(req *quotationv1.QuotePaymentReque
|
||||
|
||||
func (h *quotePaymentCommand) quotePayment(
|
||||
ctx context.Context,
|
||||
quotesStore storage.QuotesStore,
|
||||
quotesStore quotestorage.QuotesStore,
|
||||
qc *quoteCtx,
|
||||
req *quotationv1.QuotePaymentRequest,
|
||||
) (*quotePaymentResult, error) {
|
||||
@@ -415,7 +416,7 @@ func (h *quotePaymentsCommand) prepare(req *quotationv1.QuotePaymentsRequest) (*
|
||||
|
||||
func (h *quotePaymentsCommand) tryReuse(
|
||||
ctx context.Context,
|
||||
quotesStore storage.QuotesStore,
|
||||
quotesStore quotestorage.QuotesStore,
|
||||
qc *quotePaymentsCtx,
|
||||
) (*model.PaymentQuoteRecord, bool, error) {
|
||||
|
||||
@@ -515,7 +516,7 @@ func (h *quotePaymentsCommand) aggregate(
|
||||
|
||||
func (h *quotePaymentsCommand) storeBatch(
|
||||
ctx context.Context,
|
||||
quotesStore storage.QuotesStore,
|
||||
quotesStore quotestorage.QuotesStore,
|
||||
qc *quotePaymentsCtx,
|
||||
quoteRef string,
|
||||
intents []*sharedv1.PaymentIntent,
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/tech/sendico/payments/storage"
|
||||
"github.com/tech/sendico/payments/storage/model"
|
||||
quotestorage "github.com/tech/sendico/payments/storage/quote"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
mloggerfactory "github.com/tech/sendico/pkg/mlogger/factory"
|
||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||
@@ -155,12 +156,13 @@ func (e *quoteCommandTestEngine) ResolvePaymentQuote(context.Context, quoteResol
|
||||
func (e *quoteCommandTestEngine) Repository() storage.Repository { return e.repo }
|
||||
|
||||
type quoteCommandTestRepo struct {
|
||||
quotes storage.QuotesStore
|
||||
quotes quotestorage.QuotesStore
|
||||
}
|
||||
|
||||
func (r quoteCommandTestRepo) Ping(context.Context) error { return nil }
|
||||
func (r quoteCommandTestRepo) Payments() storage.PaymentsStore { return nil }
|
||||
func (r quoteCommandTestRepo) Quotes() storage.QuotesStore { return r.quotes }
|
||||
func (r quoteCommandTestRepo) PaymentMethods() storage.PaymentMethodsStore { return nil }
|
||||
func (r quoteCommandTestRepo) Quotes() quotestorage.QuotesStore { return r.quotes }
|
||||
func (r quoteCommandTestRepo) Routes() storage.RoutesStore { return nil }
|
||||
func (r quoteCommandTestRepo) PlanTemplates() storage.PlanTemplatesStore { return nil }
|
||||
|
||||
|
||||
@@ -8,13 +8,14 @@ import (
|
||||
oracleclient "github.com/tech/sendico/fx/oracle/client"
|
||||
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
|
||||
oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1"
|
||||
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1"
|
||||
accountingv1 "github.com/tech/sendico/pkg/proto/common/accounting/v1"
|
||||
fxv1 "github.com/tech/sendico/pkg/proto/common/fx/v1"
|
||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||
paymentv1 "github.com/tech/sendico/pkg/proto/common/payment/v1"
|
||||
)
|
||||
|
||||
type moneyGetter interface {
|
||||
@@ -173,7 +174,7 @@ func resolveTradeAmounts(intentAmount *moneyv1.Money, fxQuote *oraclev1.Quote, s
|
||||
}
|
||||
}
|
||||
|
||||
func computeAggregates(pay, settlement, fee *moneyv1.Money, network *chainv1.EstimateTransferFeeResponse, fxQuote *oraclev1.Quote, mode sharedv1.SettlementMode) (*moneyv1.Money, *moneyv1.Money) {
|
||||
func computeAggregates(pay, settlement, fee *moneyv1.Money, network *chainv1.EstimateTransferFeeResponse, fxQuote *oraclev1.Quote, mode paymentv1.SettlementMode) (*moneyv1.Money, *moneyv1.Money) {
|
||||
if pay == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -215,7 +216,7 @@ func computeAggregates(pay, settlement, fee *moneyv1.Money, network *chainv1.Est
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case sharedv1.SettlementMode_SETTLEMENT_FIX_RECEIVED:
|
||||
case paymentv1.SettlementMode_SETTLEMENT_FIX_RECEIVED:
|
||||
// Sender pays the fee: keep settlement fixed, increase debit.
|
||||
applyChargeToDebit(fee)
|
||||
default:
|
||||
@@ -225,7 +226,7 @@ func computeAggregates(pay, settlement, fee *moneyv1.Money, network *chainv1.Est
|
||||
|
||||
if network != nil && network.GetNetworkFee() != nil {
|
||||
switch mode {
|
||||
case sharedv1.SettlementMode_SETTLEMENT_FIX_RECEIVED:
|
||||
case paymentv1.SettlementMode_SETTLEMENT_FIX_RECEIVED:
|
||||
applyChargeToDebit(network.GetNetworkFee())
|
||||
default:
|
||||
applyChargeToSettlement(network.GetNetworkFee())
|
||||
@@ -293,6 +294,10 @@ func quoteToProto(src *oracleclient.Quote) *oraclev1.Quote {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
var pricedAt *timestamppb.Timestamp
|
||||
if !src.PricedAt.IsZero() {
|
||||
pricedAt = timestamppb.New(src.PricedAt.UTC())
|
||||
}
|
||||
return &oraclev1.Quote{
|
||||
QuoteRef: src.QuoteRef,
|
||||
Pair: src.Pair,
|
||||
@@ -301,6 +306,7 @@ func quoteToProto(src *oracleclient.Quote) *oraclev1.Quote {
|
||||
BaseAmount: cloneProtoMoney(src.BaseAmount),
|
||||
QuoteAmount: cloneProtoMoney(src.QuoteAmount),
|
||||
ExpiresAtUnixMs: src.ExpiresAt.UnixMilli(),
|
||||
PricedAt: pricedAt,
|
||||
Provider: src.Provider,
|
||||
RateRef: src.RateRef,
|
||||
Firm: src.Firm,
|
||||
|
||||
@@ -119,6 +119,7 @@ func cloneStoredFXQuote(src *paymenttypes.FXQuote) *paymenttypes.FXQuote {
|
||||
QuoteRef: strings.TrimSpace(src.QuoteRef),
|
||||
Side: src.Side,
|
||||
ExpiresAtUnixMs: src.ExpiresAtUnixMs,
|
||||
PricedAtUnixMs: src.PricedAtUnixMs,
|
||||
Provider: strings.TrimSpace(src.Provider),
|
||||
RateRef: strings.TrimSpace(src.RateRef),
|
||||
Firm: src.Firm,
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/tech/sendico/payments/storage"
|
||||
"github.com/tech/sendico/payments/storage/model"
|
||||
quotestorage "github.com/tech/sendico/payments/storage/quote"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
quotationv1 "github.com/tech/sendico/pkg/proto/payments/quotation/v1"
|
||||
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
|
||||
@@ -42,7 +43,7 @@ func requireNonNilIntent(intent *sharedv1.PaymentIntent) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureQuotesStore(repo storage.Repository) (storage.QuotesStore, error) {
|
||||
func ensureQuotesStore(repo storage.Repository) (quotestorage.QuotesStore, error) {
|
||||
if repo == nil {
|
||||
return nil, errStorageUnavailable
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ github.com/casbin/mongodb-adapter/v4 v4.3.0 h1:yYXky9v1by6vj/0QK7OyHyd/xpz4vzh0l
|
||||
github.com/casbin/mongodb-adapter/v4 v4.3.0/go.mod h1:bOTSYZUjX7I9E0ExEvgq46m3mcDNRII7g8iWjrM1BHE=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||
@@ -120,12 +122,12 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
|
||||
@@ -7,11 +7,15 @@ import (
|
||||
"github.com/tech/sendico/payments/storage"
|
||||
"github.com/tech/sendico/payments/storage/model"
|
||||
"github.com/tech/sendico/payments/storage/mongo/store"
|
||||
quotestorage "github.com/tech/sendico/payments/storage/quote"
|
||||
quotemongo "github.com/tech/sendico/payments/storage/quote/mongo"
|
||||
"github.com/tech/sendico/pkg/auth"
|
||||
"github.com/tech/sendico/pkg/db"
|
||||
"github.com/tech/sendico/pkg/db/repository"
|
||||
"github.com/tech/sendico/pkg/merrors"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
// Store implements storage.Repository backed by MongoDB.
|
||||
@@ -20,13 +24,20 @@ type Store struct {
|
||||
ping func(context.Context) error
|
||||
|
||||
payments storage.PaymentsStore
|
||||
quotes storage.QuotesStore
|
||||
methods storage.PaymentMethodsStore
|
||||
quotes quotestorage.QuotesStore
|
||||
routes storage.RoutesStore
|
||||
plans storage.PlanTemplatesStore
|
||||
}
|
||||
|
||||
type paymentMethodsConfig struct {
|
||||
enforcer auth.Enforcer
|
||||
permissionRef bson.ObjectID
|
||||
}
|
||||
|
||||
type options struct {
|
||||
quoteRetention time.Duration
|
||||
paymentMethodsAuth *paymentMethodsConfig
|
||||
}
|
||||
|
||||
// Option configures the Mongo-backed payments repository.
|
||||
@@ -39,6 +50,16 @@ func WithQuoteRetention(retention time.Duration) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithPaymentMethodsAuth enables the payment-methods store and permission checks.
|
||||
func WithPaymentMethodsAuth(enforcer auth.Enforcer, permissionRef bson.ObjectID) Option {
|
||||
return func(opts *options) {
|
||||
opts.paymentMethodsAuth = &paymentMethodsConfig{
|
||||
enforcer: enforcer,
|
||||
permissionRef: permissionRef,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New constructs a Mongo-backed payments repository from a Mongo connection.
|
||||
func New(logger mlogger.Logger, conn *db.MongoConnection, opts ...Option) (*Store, error) {
|
||||
if conn == nil {
|
||||
@@ -48,11 +69,22 @@ func New(logger mlogger.Logger, conn *db.MongoConnection, opts ...Option) (*Stor
|
||||
quotesRepo := repository.CreateMongoRepository(conn.Database(), (&model.PaymentQuoteRecord{}).Collection())
|
||||
routesRepo := repository.CreateMongoRepository(conn.Database(), (&model.PaymentRoute{}).Collection())
|
||||
plansRepo := repository.CreateMongoRepository(conn.Database(), (&model.PaymentPlanTemplate{}).Collection())
|
||||
return NewWithRepository(logger, conn.Ping, paymentsRepo, quotesRepo, routesRepo, plansRepo, opts...)
|
||||
methodsRepo := repository.CreateMongoRepository(conn.Database(), mservice.PaymentMethods)
|
||||
|
||||
return newWithRepository(logger, conn.Ping, paymentsRepo, methodsRepo, quotesRepo, routesRepo, plansRepo, opts...)
|
||||
}
|
||||
|
||||
// NewWithRepository constructs a payments repository using the provided primitives.
|
||||
func NewWithRepository(logger mlogger.Logger, ping func(context.Context) error, paymentsRepo repository.Repository, quotesRepo repository.Repository, routesRepo repository.Repository, plansRepo repository.Repository, opts ...Option) (*Store, error) {
|
||||
return newWithRepository(logger, ping, paymentsRepo, nil, quotesRepo, routesRepo, plansRepo, opts...)
|
||||
}
|
||||
|
||||
func newWithRepository(
|
||||
logger mlogger.Logger,
|
||||
ping func(context.Context) error,
|
||||
paymentsRepo, methodsRepo, quotesRepo, routesRepo, plansRepo repository.Repository,
|
||||
opts ...Option,
|
||||
) (*Store, error) {
|
||||
if ping == nil {
|
||||
return nil, merrors.InvalidArgument("payments.storage.mongo: ping func is nil")
|
||||
}
|
||||
@@ -93,10 +125,30 @@ func NewWithRepository(logger mlogger.Logger, ping func(context.Context) error,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var methodsStore storage.PaymentMethodsStore
|
||||
if cfg.paymentMethodsAuth != nil {
|
||||
if methodsRepo == nil {
|
||||
return nil, merrors.InvalidArgument("payments.storage.mongo: payment methods repository is nil")
|
||||
}
|
||||
if cfg.paymentMethodsAuth.enforcer == nil {
|
||||
return nil, merrors.InvalidArgument("payments.storage.mongo: payment methods enforcer is nil")
|
||||
}
|
||||
if cfg.paymentMethodsAuth.permissionRef == bson.NilObjectID {
|
||||
return nil, merrors.InvalidArgument("payments.storage.mongo: payment methods permission reference is required")
|
||||
}
|
||||
|
||||
methodsStore, err = store.NewPaymentMethods(childLogger, methodsRepo, cfg.paymentMethodsAuth.enforcer, cfg.paymentMethodsAuth.permissionRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
result := &Store{
|
||||
logger: childLogger,
|
||||
ping: ping,
|
||||
payments: paymentsStore,
|
||||
methods: methodsStore,
|
||||
quotes: quotesRepoStore.Quotes(),
|
||||
routes: routesStore,
|
||||
plans: plansStore,
|
||||
@@ -118,8 +170,13 @@ func (s *Store) Payments() storage.PaymentsStore {
|
||||
return s.payments
|
||||
}
|
||||
|
||||
// PaymentMethods returns the payment-methods store.
|
||||
func (s *Store) PaymentMethods() storage.PaymentMethodsStore {
|
||||
return s.methods
|
||||
}
|
||||
|
||||
// Quotes returns the quotes store.
|
||||
func (s *Store) Quotes() storage.QuotesStore {
|
||||
func (s *Store) Quotes() quotestorage.QuotesStore {
|
||||
return s.quotes
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user