TG settlement service
This commit is contained in:
@@ -93,7 +93,13 @@ func (s *RegistryService) Start() {
|
||||
return
|
||||
}
|
||||
s.startOnce.Do(func() {
|
||||
s.logInfo("Discovery registry service starting", zap.Int("consumers", len(s.consumers)), zap.Bool("kv_enabled", s.kv != nil))
|
||||
fields := []zap.Field{zap.Int("consumers", len(s.consumers)), zap.Bool("kv_enabled", s.kv != nil)}
|
||||
if s.kv != nil {
|
||||
if bucket := s.kv.Bucket(); bucket != "" {
|
||||
fields = append(fields, zap.String("kv_bucket", bucket))
|
||||
}
|
||||
}
|
||||
s.logInfo("Discovery registry service starting", fields...)
|
||||
for _, ch := range s.consumers {
|
||||
ch := ch
|
||||
go func() {
|
||||
@@ -130,6 +136,12 @@ func (s *RegistryService) handleAnnounce(_ context.Context, env me.Envelope) err
|
||||
s.logWarn("Failed to decode discovery announce payload", fields...)
|
||||
return err
|
||||
}
|
||||
s.logDebug("Discovery announce received", append(envelopeFields(env), announcementFields(payload)...)...)
|
||||
if strings.TrimSpace(payload.InstanceID) == "" && strings.TrimSpace(payload.ID) == "" {
|
||||
fields := append(envelopeFields(env), announcementFields(payload)...)
|
||||
s.logWarn("Discovery announce missing id and instance id", fields...)
|
||||
return nil
|
||||
}
|
||||
if strings.TrimSpace(payload.InstanceID) == "" {
|
||||
fields := append(envelopeFields(env), announcementFields(payload)...)
|
||||
s.logWarn("Discovery announce missing instance id", fields...)
|
||||
@@ -151,6 +163,7 @@ func (s *RegistryService) handleHeartbeat(_ context.Context, env me.Envelope) er
|
||||
s.logWarn("Failed to decode discovery heartbeat payload", fields...)
|
||||
return err
|
||||
}
|
||||
s.logDebug("Discovery heartbeat received", append(envelopeFields(env), zap.String("id", payload.ID), zap.String("instance_id", payload.InstanceID), zap.String("status", payload.Status))...)
|
||||
if strings.TrimSpace(payload.InstanceID) == "" && strings.TrimSpace(payload.ID) == "" {
|
||||
return nil
|
||||
}
|
||||
@@ -163,6 +176,10 @@ func (s *RegistryService) handleHeartbeat(_ context.Context, env me.Envelope) er
|
||||
ts = time.Now()
|
||||
}
|
||||
results := s.registry.UpdateHeartbeat(payload.ID, payload.InstanceID, strings.TrimSpace(payload.Status), ts, time.Now())
|
||||
if len(results) == 0 {
|
||||
s.logDebug("Discovery heartbeat ignored: entry not found", zap.String("id", payload.ID), zap.String("instance_id", payload.InstanceID))
|
||||
return nil
|
||||
}
|
||||
for _, result := range results {
|
||||
if result.BecameHealthy {
|
||||
s.logInfo("Discovery registry entry became healthy", append(entryFields(result.Entry), zap.String("status", result.Entry.Status))...)
|
||||
@@ -186,6 +203,7 @@ func (s *RegistryService) handleLookup(_ context.Context, env me.Envelope) error
|
||||
}
|
||||
resp := s.registry.Lookup(time.Now())
|
||||
resp.RequestID = strings.TrimSpace(payload.RequestID)
|
||||
s.logDebug("Discovery lookup prepared", zap.String("request_id", resp.RequestID), zap.Int("services", len(resp.Services)), zap.Int("gateways", len(resp.Gateways)))
|
||||
if err := s.producer.SendMessage(NewLookupResponseEnvelope(s.sender, resp)); err != nil {
|
||||
fields := []zap.Field{zap.String("request_id", resp.RequestID), zap.Error(err)}
|
||||
s.logWarn("Failed to publish discovery lookup response", fields...)
|
||||
@@ -221,10 +239,12 @@ func (s *RegistryService) initKV(msgBroker mb.Broker) {
|
||||
}
|
||||
provider, ok := msgBroker.(jetStreamProvider)
|
||||
if !ok {
|
||||
s.logInfo("Discovery KV disabled: broker does not support JetStream")
|
||||
return
|
||||
}
|
||||
js := provider.JetStream()
|
||||
if js == nil {
|
||||
s.logWarn("Discovery KV disabled: JetStream not configured")
|
||||
return
|
||||
}
|
||||
store, err := NewKVStore(s.logger, js, "")
|
||||
@@ -255,10 +275,25 @@ func (s *RegistryService) consumeKVUpdates(watcher nats.KeyWatcher) {
|
||||
if s == nil || watcher == nil {
|
||||
return
|
||||
}
|
||||
initial := true
|
||||
initialCount := 0
|
||||
for entry := range watcher.Updates() {
|
||||
if entry == nil {
|
||||
if initial {
|
||||
fields := []zap.Field{zap.Int("entries", initialCount)}
|
||||
if s.kv != nil {
|
||||
if bucket := s.kv.Bucket(); bucket != "" {
|
||||
fields = append(fields, zap.String("bucket", bucket))
|
||||
}
|
||||
}
|
||||
s.logInfo("Discovery KV initial sync complete", fields...)
|
||||
initial = false
|
||||
}
|
||||
continue
|
||||
}
|
||||
if initial && entry.Operation() == nats.KeyValuePut {
|
||||
initialCount++
|
||||
}
|
||||
switch entry.Operation() {
|
||||
case nats.KeyValueDelete, nats.KeyValuePurge:
|
||||
key := registryKeyFromKVKey(entry.Key())
|
||||
@@ -302,6 +337,13 @@ func (s *RegistryService) logWarn(message string, fields ...zap.Field) {
|
||||
s.logger.Warn(message, fields...)
|
||||
}
|
||||
|
||||
func (s *RegistryService) logDebug(message string, fields ...zap.Field) {
|
||||
if s.logger == nil {
|
||||
return
|
||||
}
|
||||
s.logger.Debug(message, fields...)
|
||||
}
|
||||
|
||||
func (s *RegistryService) logInfo(message string, fields ...zap.Field) {
|
||||
if s.logger == nil {
|
||||
return
|
||||
|
||||
@@ -92,10 +92,23 @@ func (w *RegistryWatcher) consume(watcher nats.KeyWatcher) {
|
||||
if w == nil || watcher == nil {
|
||||
return
|
||||
}
|
||||
initial := true
|
||||
initialCount := 0
|
||||
for entry := range watcher.Updates() {
|
||||
if entry == nil {
|
||||
if initial && w.logger != nil {
|
||||
fields := []zap.Field{zap.Int("entries", initialCount)}
|
||||
if w.kv != nil {
|
||||
fields = append(fields, zap.String("bucket", w.kv.Bucket()))
|
||||
}
|
||||
w.logger.Info("Discovery registry watcher initial sync complete", fields...)
|
||||
initial = false
|
||||
}
|
||||
continue
|
||||
}
|
||||
if initial && entry.Operation() == nats.KeyValuePut {
|
||||
initialCount++
|
||||
}
|
||||
switch entry.Operation() {
|
||||
case nats.KeyValueDelete, nats.KeyValuePurge:
|
||||
key := registryKeyFromKVKey(entry.Key())
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
messaging "github.com/tech/sendico/pkg/messaging/envelope"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
nm "github.com/tech/sendico/pkg/model/notification"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
)
|
||||
|
||||
type ConfirmationRequestNotification struct {
|
||||
messaging.Envelope
|
||||
payload model.ConfirmationRequest
|
||||
}
|
||||
|
||||
func (crn *ConfirmationRequestNotification) Serialize() ([]byte, error) {
|
||||
data, err := json.Marshal(crn.payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return crn.Envelope.Wrap(data)
|
||||
}
|
||||
|
||||
type ConfirmationResultNotification struct {
|
||||
messaging.Envelope
|
||||
payload model.ConfirmationResult
|
||||
}
|
||||
|
||||
func (crn *ConfirmationResultNotification) Serialize() ([]byte, error) {
|
||||
data, err := json.Marshal(crn.payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return crn.Envelope.Wrap(data)
|
||||
}
|
||||
|
||||
func confirmationRequestEvent() model.NotificationEvent {
|
||||
return model.NewNotification(mservice.Notifications, nm.NAConfirmationRequest)
|
||||
}
|
||||
|
||||
func confirmationResultEvent(sourceService, rail string) model.NotificationEvent {
|
||||
action := strings.TrimSpace(sourceService)
|
||||
if action == "" {
|
||||
action = "unknown"
|
||||
}
|
||||
action = strings.ToLower(action)
|
||||
rail = strings.TrimSpace(rail)
|
||||
if rail == "" {
|
||||
rail = "default"
|
||||
}
|
||||
rail = strings.ToLower(rail)
|
||||
return model.NewNotification(mservice.Confirmations, nm.NotificationAction(action+"."+rail))
|
||||
}
|
||||
|
||||
func NewConfirmationRequestEnvelope(sender string, request *model.ConfirmationRequest) messaging.Envelope {
|
||||
var payload model.ConfirmationRequest
|
||||
if request != nil {
|
||||
payload = *request
|
||||
}
|
||||
return &ConfirmationRequestNotification{
|
||||
Envelope: messaging.CreateEnvelope(sender, confirmationRequestEvent()),
|
||||
payload: payload,
|
||||
}
|
||||
}
|
||||
|
||||
func NewConfirmationResultEnvelope(sender string, result *model.ConfirmationResult, sourceService, rail string) messaging.Envelope {
|
||||
var payload model.ConfirmationResult
|
||||
if result != nil {
|
||||
payload = *result
|
||||
}
|
||||
return &ConfirmationResultNotification{
|
||||
Envelope: messaging.CreateEnvelope(sender, confirmationResultEvent(sourceService, rail)),
|
||||
payload: payload,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
me "github.com/tech/sendico/pkg/messaging/envelope"
|
||||
ch "github.com/tech/sendico/pkg/messaging/notifications/confirmations/handler"
|
||||
np "github.com/tech/sendico/pkg/messaging/notifications/processor"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type ConfirmationRequestProcessor struct {
|
||||
logger mlogger.Logger
|
||||
handler ch.ConfirmationRequestHandler
|
||||
event model.NotificationEvent
|
||||
}
|
||||
|
||||
func (crp *ConfirmationRequestProcessor) Process(ctx context.Context, envelope me.Envelope) error {
|
||||
var msg model.ConfirmationRequest
|
||||
if err := json.Unmarshal(envelope.GetData(), &msg); err != nil {
|
||||
crp.logger.Warn("Failed to decode confirmation request envelope", zap.Error(err), zap.String("topic", crp.event.ToString()))
|
||||
return err
|
||||
}
|
||||
if crp.handler == nil {
|
||||
crp.logger.Warn("Confirmation request handler is not configured", zap.String("topic", crp.event.ToString()))
|
||||
return nil
|
||||
}
|
||||
return crp.handler(ctx, &msg)
|
||||
}
|
||||
|
||||
func (crp *ConfirmationRequestProcessor) GetSubject() model.NotificationEvent {
|
||||
return crp.event
|
||||
}
|
||||
|
||||
type ConfirmationResultProcessor struct {
|
||||
logger mlogger.Logger
|
||||
handler ch.ConfirmationResultHandler
|
||||
event model.NotificationEvent
|
||||
}
|
||||
|
||||
func (crp *ConfirmationResultProcessor) Process(ctx context.Context, envelope me.Envelope) error {
|
||||
var msg model.ConfirmationResult
|
||||
if err := json.Unmarshal(envelope.GetData(), &msg); err != nil {
|
||||
crp.logger.Warn("Failed to decode confirmation result envelope", zap.Error(err), zap.String("topic", crp.event.ToString()))
|
||||
return err
|
||||
}
|
||||
if crp.handler == nil {
|
||||
crp.logger.Warn("Confirmation result handler is not configured", zap.String("topic", crp.event.ToString()))
|
||||
return nil
|
||||
}
|
||||
return crp.handler(ctx, &msg)
|
||||
}
|
||||
|
||||
func (crp *ConfirmationResultProcessor) GetSubject() model.NotificationEvent {
|
||||
return crp.event
|
||||
}
|
||||
|
||||
func NewConfirmationRequestProcessor(logger mlogger.Logger, handler ch.ConfirmationRequestHandler) np.EnvelopeProcessor {
|
||||
if logger != nil {
|
||||
logger = logger.Named("confirmation_request_processor")
|
||||
}
|
||||
return &ConfirmationRequestProcessor{
|
||||
logger: logger,
|
||||
handler: handler,
|
||||
event: confirmationRequestEvent(),
|
||||
}
|
||||
}
|
||||
|
||||
func NewConfirmationResultProcessor(logger mlogger.Logger, sourceService, rail string, handler ch.ConfirmationResultHandler) np.EnvelopeProcessor {
|
||||
if logger != nil {
|
||||
logger = logger.Named("confirmation_result_processor")
|
||||
}
|
||||
return &ConfirmationResultProcessor{
|
||||
logger: logger,
|
||||
handler: handler,
|
||||
event: confirmationResultEvent(sourceService, rail),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
messaging "github.com/tech/sendico/pkg/messaging/envelope"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
nm "github.com/tech/sendico/pkg/model/notification"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
)
|
||||
|
||||
type PaymentGatewayIntentNotification struct {
|
||||
messaging.Envelope
|
||||
payload model.PaymentGatewayIntent
|
||||
}
|
||||
|
||||
func (pgn *PaymentGatewayIntentNotification) Serialize() ([]byte, error) {
|
||||
data, err := json.Marshal(pgn.payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pgn.Envelope.Wrap(data)
|
||||
}
|
||||
|
||||
type PaymentGatewayExecutionNotification struct {
|
||||
messaging.Envelope
|
||||
payload model.PaymentGatewayExecution
|
||||
}
|
||||
|
||||
func (pgn *PaymentGatewayExecutionNotification) Serialize() ([]byte, error) {
|
||||
data, err := json.Marshal(pgn.payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pgn.Envelope.Wrap(data)
|
||||
}
|
||||
|
||||
func intentEvent() model.NotificationEvent {
|
||||
return model.NewNotification(mservice.PaymentGateway, nm.NAPaymentGatewayIntent)
|
||||
}
|
||||
|
||||
func executionEvent() model.NotificationEvent {
|
||||
return model.NewNotification(mservice.PaymentGateway, nm.NAPaymentGatewayExecution)
|
||||
}
|
||||
|
||||
func NewPaymentGatewayIntentEnvelope(sender string, intent *model.PaymentGatewayIntent) messaging.Envelope {
|
||||
var payload model.PaymentGatewayIntent
|
||||
if intent != nil {
|
||||
payload = *intent
|
||||
}
|
||||
return &PaymentGatewayIntentNotification{
|
||||
Envelope: messaging.CreateEnvelope(sender, intentEvent()),
|
||||
payload: payload,
|
||||
}
|
||||
}
|
||||
|
||||
func NewPaymentGatewayExecutionEnvelope(sender string, exec *model.PaymentGatewayExecution) messaging.Envelope {
|
||||
var payload model.PaymentGatewayExecution
|
||||
if exec != nil {
|
||||
payload = *exec
|
||||
}
|
||||
return &PaymentGatewayExecutionNotification{
|
||||
Envelope: messaging.CreateEnvelope(sender, executionEvent()),
|
||||
payload: payload,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
me "github.com/tech/sendico/pkg/messaging/envelope"
|
||||
ch "github.com/tech/sendico/pkg/messaging/notifications/paymentgateway/handler"
|
||||
np "github.com/tech/sendico/pkg/messaging/notifications/processor"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type PaymentGatewayIntentProcessor struct {
|
||||
logger mlogger.Logger
|
||||
handler ch.PaymentGatewayIntentHandler
|
||||
event model.NotificationEvent
|
||||
}
|
||||
|
||||
func (pgp *PaymentGatewayIntentProcessor) Process(ctx context.Context, envelope me.Envelope) error {
|
||||
var msg model.PaymentGatewayIntent
|
||||
if err := json.Unmarshal(envelope.GetData(), &msg); err != nil {
|
||||
pgp.logger.Warn("Failed to decode payment gateway intent envelope", zap.Error(err), zap.String("topic", pgp.event.ToString()))
|
||||
return err
|
||||
}
|
||||
if pgp.handler == nil {
|
||||
pgp.logger.Warn("Payment gateway intent handler is not configured", zap.String("topic", pgp.event.ToString()))
|
||||
return nil
|
||||
}
|
||||
return pgp.handler(ctx, &msg)
|
||||
}
|
||||
|
||||
func (pgp *PaymentGatewayIntentProcessor) GetSubject() model.NotificationEvent {
|
||||
return pgp.event
|
||||
}
|
||||
|
||||
type PaymentGatewayExecutionProcessor struct {
|
||||
logger mlogger.Logger
|
||||
handler ch.PaymentGatewayExecutionHandler
|
||||
event model.NotificationEvent
|
||||
}
|
||||
|
||||
func (pgp *PaymentGatewayExecutionProcessor) Process(ctx context.Context, envelope me.Envelope) error {
|
||||
var msg model.PaymentGatewayExecution
|
||||
if err := json.Unmarshal(envelope.GetData(), &msg); err != nil {
|
||||
pgp.logger.Warn("Failed to decode payment gateway execution envelope", zap.Error(err), zap.String("topic", pgp.event.ToString()))
|
||||
return err
|
||||
}
|
||||
if pgp.handler == nil {
|
||||
pgp.logger.Warn("Payment gateway execution handler is not configured", zap.String("topic", pgp.event.ToString()))
|
||||
return nil
|
||||
}
|
||||
return pgp.handler(ctx, &msg)
|
||||
}
|
||||
|
||||
func (pgp *PaymentGatewayExecutionProcessor) GetSubject() model.NotificationEvent {
|
||||
return pgp.event
|
||||
}
|
||||
|
||||
func NewPaymentGatewayIntentProcessor(logger mlogger.Logger, handler ch.PaymentGatewayIntentHandler) np.EnvelopeProcessor {
|
||||
if logger != nil {
|
||||
logger = logger.Named("payment_gateway_intent_processor")
|
||||
}
|
||||
return &PaymentGatewayIntentProcessor{
|
||||
logger: logger,
|
||||
handler: handler,
|
||||
event: intentEvent(),
|
||||
}
|
||||
}
|
||||
|
||||
func NewPaymentGatewayExecutionProcessor(logger mlogger.Logger, handler ch.PaymentGatewayExecutionHandler) np.EnvelopeProcessor {
|
||||
if logger != nil {
|
||||
logger = logger.Named("payment_gateway_execution_processor")
|
||||
}
|
||||
return &PaymentGatewayExecutionProcessor{
|
||||
logger: logger,
|
||||
handler: handler,
|
||||
event: executionEvent(),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package notifications
|
||||
|
||||
import (
|
||||
messaging "github.com/tech/sendico/pkg/messaging/envelope"
|
||||
cinternal "github.com/tech/sendico/pkg/messaging/internal/notifications/confirmations"
|
||||
ch "github.com/tech/sendico/pkg/messaging/notifications/confirmations/handler"
|
||||
np "github.com/tech/sendico/pkg/messaging/notifications/processor"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
)
|
||||
|
||||
func ConfirmationRequest(sender string, request *model.ConfirmationRequest) messaging.Envelope {
|
||||
return cinternal.NewConfirmationRequestEnvelope(sender, request)
|
||||
}
|
||||
|
||||
func ConfirmationResult(sender string, result *model.ConfirmationResult, sourceService, rail string) messaging.Envelope {
|
||||
return cinternal.NewConfirmationResultEnvelope(sender, result, sourceService, rail)
|
||||
}
|
||||
|
||||
func NewConfirmationRequestProcessor(logger mlogger.Logger, handler ch.ConfirmationRequestHandler) np.EnvelopeProcessor {
|
||||
return cinternal.NewConfirmationRequestProcessor(logger, handler)
|
||||
}
|
||||
|
||||
func NewConfirmationResultProcessor(logger mlogger.Logger, sourceService, rail string, handler ch.ConfirmationResultHandler) np.EnvelopeProcessor {
|
||||
return cinternal.NewConfirmationResultProcessor(logger, sourceService, rail, handler)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
)
|
||||
|
||||
type ConfirmationRequestHandler = func(context.Context, *model.ConfirmationRequest) error
|
||||
|
||||
type ConfirmationResultHandler = func(context.Context, *model.ConfirmationResult) error
|
||||
@@ -0,0 +1,11 @@
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
)
|
||||
|
||||
type PaymentGatewayIntentHandler = func(context.Context, *model.PaymentGatewayIntent) error
|
||||
|
||||
type PaymentGatewayExecutionHandler = func(context.Context, *model.PaymentGatewayExecution) error
|
||||
@@ -0,0 +1,26 @@
|
||||
package notifications
|
||||
|
||||
import (
|
||||
messaging "github.com/tech/sendico/pkg/messaging/envelope"
|
||||
pinternal "github.com/tech/sendico/pkg/messaging/internal/notifications/paymentgateway"
|
||||
ch "github.com/tech/sendico/pkg/messaging/notifications/paymentgateway/handler"
|
||||
np "github.com/tech/sendico/pkg/messaging/notifications/processor"
|
||||
"github.com/tech/sendico/pkg/mlogger"
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
)
|
||||
|
||||
func PaymentGatewayIntent(sender string, intent *model.PaymentGatewayIntent) messaging.Envelope {
|
||||
return pinternal.NewPaymentGatewayIntentEnvelope(sender, intent)
|
||||
}
|
||||
|
||||
func PaymentGatewayExecution(sender string, exec *model.PaymentGatewayExecution) messaging.Envelope {
|
||||
return pinternal.NewPaymentGatewayExecutionEnvelope(sender, exec)
|
||||
}
|
||||
|
||||
func NewPaymentGatewayIntentProcessor(logger mlogger.Logger, handler ch.PaymentGatewayIntentHandler) np.EnvelopeProcessor {
|
||||
return pinternal.NewPaymentGatewayIntentProcessor(logger, handler)
|
||||
}
|
||||
|
||||
func NewPaymentGatewayExecutionProcessor(logger mlogger.Logger, handler ch.PaymentGatewayExecutionHandler) np.EnvelopeProcessor {
|
||||
return pinternal.NewPaymentGatewayExecutionProcessor(logger, handler)
|
||||
}
|
||||
@@ -1,38 +1,42 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
import paymenttypes "github.com/tech/sendico/pkg/payments/types"
|
||||
|
||||
"github.com/tech/sendico/pkg/db/storable"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
type ConfirmationTarget string
|
||||
type ConfirmationStatus string
|
||||
|
||||
const (
|
||||
ConfirmationTargetLogin ConfirmationTarget = "login"
|
||||
ConfirmationTargetPayout ConfirmationTarget = "payout"
|
||||
ConfirmationStatusConfirmed ConfirmationStatus = "CONFIRMED"
|
||||
ConfirmationStatusClarified ConfirmationStatus = "CLARIFIED"
|
||||
ConfirmationStatusTimeout ConfirmationStatus = "TIMEOUT"
|
||||
ConfirmationStatusRejected ConfirmationStatus = "REJECTED"
|
||||
)
|
||||
|
||||
// ConfirmationCode stores verification codes for operations like login or payouts.
|
||||
type ConfirmationCode struct {
|
||||
storable.Base `bson:",inline" json:",inline"`
|
||||
|
||||
AccountRef primitive.ObjectID `bson:"accountRef" json:"accountRef"`
|
||||
Destination string `bson:"destination" json:"destination"`
|
||||
Target ConfirmationTarget `bson:"target" json:"target"`
|
||||
CodeHash []byte `bson:"codeHash" json:"-"`
|
||||
Salt []byte `bson:"salt" json:"-"`
|
||||
ExpiresAt time.Time `bson:"expiresAt" json:"expiresAt"`
|
||||
Attempts int `bson:"attempts" json:"attempts"`
|
||||
MaxAttempts int `bson:"maxAttempts" json:"maxAttempts"`
|
||||
ResendCount int `bson:"resendCount" json:"resendCount"`
|
||||
ResendLimit int `bson:"resendLimit" json:"resendLimit"`
|
||||
CooldownUntil time.Time `bson:"cooldownUntil" json:"cooldownUntil"`
|
||||
Used bool `bson:"used" json:"used"`
|
||||
type ConfirmationRequest struct {
|
||||
RequestID string `bson:"requestId,omitempty" json:"request_id,omitempty"`
|
||||
TargetChatID string `bson:"targetChatId,omitempty" json:"target_chat_id,omitempty"`
|
||||
RequestedMoney *paymenttypes.Money `bson:"requestedMoney,omitempty" json:"requested_money,omitempty"`
|
||||
PaymentIntentID string `bson:"paymentIntentId,omitempty" json:"payment_intent_id,omitempty"`
|
||||
QuoteRef string `bson:"quoteRef,omitempty" json:"quote_ref,omitempty"`
|
||||
AcceptedUserIDs []string `bson:"acceptedUserIds,omitempty" json:"accepted_user_ids,omitempty"`
|
||||
TimeoutSeconds int32 `bson:"timeoutSeconds,omitempty" json:"timeout_seconds,omitempty"`
|
||||
SourceService string `bson:"sourceService,omitempty" json:"source_service,omitempty"`
|
||||
Rail string `bson:"rail,omitempty" json:"rail,omitempty"`
|
||||
}
|
||||
|
||||
func (c *ConfirmationCode) Collection() string {
|
||||
return mservice.Confirmations
|
||||
type ConfirmationResult struct {
|
||||
RequestID string `bson:"requestId,omitempty" json:"request_id,omitempty"`
|
||||
Money *paymenttypes.Money `bson:"money,omitempty" json:"money,omitempty"`
|
||||
RawReply *TelegramMessage `bson:"rawReply,omitempty" json:"raw_reply,omitempty"`
|
||||
Status ConfirmationStatus `bson:"status,omitempty" json:"status,omitempty"`
|
||||
ParseError string `bson:"parseError,omitempty" json:"parse_error,omitempty"`
|
||||
}
|
||||
|
||||
type TelegramMessage struct {
|
||||
ChatID string `bson:"chatId,omitempty" json:"chat_id,omitempty"`
|
||||
MessageID string `bson:"messageId,omitempty" json:"message_id,omitempty"`
|
||||
ReplyToMessageID string `bson:"replyToMessageId,omitempty" json:"reply_to_message_id,omitempty"`
|
||||
FromUserID string `bson:"fromUserId,omitempty" json:"from_user_id,omitempty"`
|
||||
FromUsername string `bson:"fromUsername,omitempty" json:"from_username,omitempty"`
|
||||
Text string `bson:"text,omitempty" json:"text,omitempty"`
|
||||
SentAt int64 `bson:"sentAt,omitempty" json:"sent_at,omitempty"`
|
||||
}
|
||||
|
||||
36
api/pkg/model/confirmation_code.go
Normal file
36
api/pkg/model/confirmation_code.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/tech/sendico/pkg/db/storable"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
type ConfirmationTarget string
|
||||
|
||||
const (
|
||||
ConfirmationTargetLogin ConfirmationTarget = "login"
|
||||
ConfirmationTargetPayout ConfirmationTarget = "payout"
|
||||
)
|
||||
|
||||
type ConfirmationCode struct {
|
||||
storable.Base `bson:",inline" json:",inline"`
|
||||
AccountRef primitive.ObjectID `bson:"accountRef" json:"accountRef"`
|
||||
Destination string `bson:"destination" json:"destination"`
|
||||
Target ConfirmationTarget `bson:"target" json:"target"`
|
||||
CodeHash []byte `bson:"codeHash" json:"codeHash,omitempty"`
|
||||
Salt []byte `bson:"salt" json:"salt,omitempty"`
|
||||
ExpiresAt time.Time `bson:"expiresAt" json:"expiresAt"`
|
||||
MaxAttempts int `bson:"maxAttempts" json:"maxAttempts"`
|
||||
ResendLimit int `bson:"resendLimit" json:"resendLimit"`
|
||||
CooldownUntil time.Time `bson:"cooldownUntil" json:"cooldownUntil"`
|
||||
Used bool `bson:"used" json:"used"`
|
||||
Attempts int `bson:"attempts" json:"attempts"`
|
||||
ResendCount int `bson:"resendCount" json:"resendCount"`
|
||||
}
|
||||
|
||||
func (*ConfirmationCode) Collection() string {
|
||||
return mservice.Confirmations
|
||||
}
|
||||
@@ -12,6 +12,10 @@ const (
|
||||
NASent NotificationAction = "sent"
|
||||
NAPasswordReset NotificationAction = "password_reset"
|
||||
|
||||
NAConfirmationRequest NotificationAction = "confirmation.request"
|
||||
NAPaymentGatewayIntent NotificationAction = "intent.request"
|
||||
NAPaymentGatewayExecution NotificationAction = "execution.result"
|
||||
|
||||
NADiscoveryServiceAnnounce NotificationAction = "service.announce"
|
||||
NADiscoveryGatewayAnnounce NotificationAction = "gateway.announce"
|
||||
NADiscoveryHeartbeat NotificationAction = "service.heartbeat"
|
||||
|
||||
@@ -81,6 +81,9 @@ func StringToNotificationAction(s string) (nm.NotificationAction, error) {
|
||||
nm.NADeleted,
|
||||
nm.NAAssigned,
|
||||
nm.NAPasswordReset,
|
||||
nm.NAConfirmationRequest,
|
||||
nm.NAPaymentGatewayIntent,
|
||||
nm.NAPaymentGatewayExecution,
|
||||
nm.NADiscoveryServiceAnnounce,
|
||||
nm.NADiscoveryGatewayAnnounce,
|
||||
nm.NADiscoveryHeartbeat,
|
||||
@@ -99,8 +102,15 @@ func StringToNotificationEvent(eventType, eventAction string) (NotificationEvent
|
||||
return nil, err
|
||||
}
|
||||
ea, err := StringToNotificationAction(eventAction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if err == nil {
|
||||
return NewNotification(et, ea), nil
|
||||
}
|
||||
return NewNotification(et, ea), nil
|
||||
if et == mservice.Confirmations {
|
||||
action := strings.TrimSpace(eventAction)
|
||||
if action == "" {
|
||||
return nil, err
|
||||
}
|
||||
return &NotificationEventImp{nType: et, nAction: nm.NotificationAction(action)}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
22
api/pkg/model/payment_gateway.go
Normal file
22
api/pkg/model/payment_gateway.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package model
|
||||
|
||||
import paymenttypes "github.com/tech/sendico/pkg/payments/types"
|
||||
|
||||
type PaymentGatewayIntent struct {
|
||||
PaymentIntentID string `bson:"paymentIntentId,omitempty" json:"payment_intent_id,omitempty"`
|
||||
IdempotencyKey string `bson:"idempotencyKey,omitempty" json:"idempotency_key,omitempty"`
|
||||
OutgoingLeg string `bson:"outgoingLeg,omitempty" json:"outgoing_leg,omitempty"`
|
||||
QuoteRef string `bson:"quoteRef,omitempty" json:"quote_ref,omitempty"`
|
||||
RequestedMoney *paymenttypes.Money `bson:"requestedMoney,omitempty" json:"requested_money,omitempty"`
|
||||
TargetChatID string `bson:"targetChatId,omitempty" json:"target_chat_id,omitempty"`
|
||||
}
|
||||
|
||||
type PaymentGatewayExecution struct {
|
||||
PaymentIntentID string `bson:"paymentIntentId,omitempty" json:"payment_intent_id,omitempty"`
|
||||
IdempotencyKey string `bson:"idempotencyKey,omitempty" json:"idempotency_key,omitempty"`
|
||||
QuoteRef string `bson:"quoteRef,omitempty" json:"quote_ref,omitempty"`
|
||||
ExecutedMoney *paymenttypes.Money `bson:"executedMoney,omitempty" json:"executed_money,omitempty"`
|
||||
Status ConfirmationStatus `bson:"status,omitempty" json:"status,omitempty"`
|
||||
RequestID string `bson:"requestId,omitempty" json:"request_id,omitempty"`
|
||||
RawReply *TelegramMessage `bson:"rawReply,omitempty" json:"raw_reply,omitempty"`
|
||||
}
|
||||
@@ -14,6 +14,7 @@ const (
|
||||
Clients Type = "clients" // Represents client information
|
||||
ChainGateway Type = "chain_gateway" // Represents chain gateway microservice
|
||||
MntxGateway Type = "mntx_gateway" // Represents Monetix gateway microservice
|
||||
PaymentGateway Type = "payment_gateway" // Represents payment gateway microservice
|
||||
FXOracle Type = "fx_oracle" // Represents FX oracle microservice
|
||||
FeePlans Type = "fee_plans" // Represents fee plans microservice
|
||||
FilterProjects Type = "filter_projects" // Represents comments on tasks or other resources
|
||||
@@ -36,6 +37,7 @@ const (
|
||||
Organizations Type = "organizations" // Represents organizations in the system
|
||||
Payments Type = "payments" // Represents payments service
|
||||
PaymentRoutes Type = "payment_routes" // Represents payment routing definitions
|
||||
PaymentPlanTemplates Type = "payment_plan_templates" // Represents payment plan templates
|
||||
PaymentMethods Type = "payment_methods" // Represents payment methods service
|
||||
Permissions Type = "permissions" // Represents permissiosns service
|
||||
Policies Type = "policies" // Represents access control policies
|
||||
@@ -52,9 +54,9 @@ const (
|
||||
func StringToSType(s string) (Type, error) {
|
||||
switch Type(s) {
|
||||
case Accounts, Confirmations, Amplitude, Site, Changes, Clients, ChainGateway, ChainWallets, ChainWalletBalances,
|
||||
ChainTransfers, ChainDeposits, MntxGateway, FXOracle, FeePlans, FilterProjects, Invitations, Invoices, Logo, Ledger,
|
||||
ChainTransfers, ChainDeposits, MntxGateway, PaymentGateway, FXOracle, FeePlans, FilterProjects, Invitations, Invoices, Logo, Ledger,
|
||||
LedgerAccounts, LedgerBalances, LedgerEntries, LedgerOutbox, LedgerParties, LedgerPlines, Notifications,
|
||||
Organizations, Payments, PaymentRoutes, PaymentOrchestrator, Permissions, Policies, PolicyAssignements,
|
||||
Organizations, Payments, PaymentRoutes, PaymentPlanTemplates, PaymentOrchestrator, Permissions, Policies, PolicyAssignements,
|
||||
RefreshTokens, Roles, Storage, Tenants, Workflows, Discovery:
|
||||
return Type(s), nil
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user