118 lines
3.6 KiB
Go
118 lines
3.6 KiB
Go
package redisstate
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"galaxy/mail/internal/domain/common"
|
|
deliverydomain "galaxy/mail/internal/domain/delivery"
|
|
"galaxy/mail/internal/domain/idempotency"
|
|
"galaxy/mail/internal/service/acceptauthdelivery"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
// AcceptanceStore provides the Redis-backed durable storage used by the
|
|
// auth-delivery acceptance use case.
|
|
type AcceptanceStore struct {
|
|
client *redis.Client
|
|
writer *AtomicWriter
|
|
keys Keyspace
|
|
}
|
|
|
|
// NewAcceptanceStore constructs one Redis-backed auth acceptance store.
|
|
func NewAcceptanceStore(client *redis.Client) (*AcceptanceStore, error) {
|
|
if client == nil {
|
|
return nil, errors.New("new auth acceptance store: nil redis client")
|
|
}
|
|
|
|
writer, err := NewAtomicWriter(client)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("new auth acceptance store: %w", err)
|
|
}
|
|
|
|
return &AcceptanceStore{
|
|
client: client,
|
|
writer: writer,
|
|
keys: Keyspace{},
|
|
}, nil
|
|
}
|
|
|
|
// CreateAcceptance stores one auth-delivery acceptance write set in Redis.
|
|
func (store *AcceptanceStore) CreateAcceptance(ctx context.Context, input acceptauthdelivery.CreateAcceptanceInput) error {
|
|
if store == nil || store.client == nil || store.writer == nil {
|
|
return errors.New("create auth acceptance: nil store")
|
|
}
|
|
if ctx == nil {
|
|
return errors.New("create auth acceptance: nil context")
|
|
}
|
|
if err := input.Validate(); err != nil {
|
|
return fmt.Errorf("create auth acceptance: %w", err)
|
|
}
|
|
|
|
err := store.writer.CreateAcceptance(ctx, CreateAcceptanceInput{
|
|
Delivery: input.Delivery,
|
|
FirstAttempt: input.FirstAttempt,
|
|
Idempotency: &input.Idempotency,
|
|
})
|
|
if errors.Is(err, ErrConflict) {
|
|
return fmt.Errorf("create auth acceptance: %w", acceptauthdelivery.ErrConflict)
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("create auth acceptance: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetIdempotency loads one accepted idempotency scope from Redis.
|
|
func (store *AcceptanceStore) GetIdempotency(ctx context.Context, source deliverydomain.Source, key common.IdempotencyKey) (idempotency.Record, bool, error) {
|
|
if store == nil || store.client == nil {
|
|
return idempotency.Record{}, false, errors.New("get auth acceptance idempotency: nil store")
|
|
}
|
|
if ctx == nil {
|
|
return idempotency.Record{}, false, errors.New("get auth acceptance idempotency: nil context")
|
|
}
|
|
|
|
payload, err := store.client.Get(ctx, store.keys.Idempotency(source, key)).Bytes()
|
|
switch {
|
|
case errors.Is(err, redis.Nil):
|
|
return idempotency.Record{}, false, nil
|
|
case err != nil:
|
|
return idempotency.Record{}, false, fmt.Errorf("get auth acceptance idempotency: %w", err)
|
|
}
|
|
|
|
record, err := UnmarshalIdempotency(payload)
|
|
if err != nil {
|
|
return idempotency.Record{}, false, fmt.Errorf("get auth acceptance idempotency: %w", err)
|
|
}
|
|
|
|
return record, true, nil
|
|
}
|
|
|
|
// GetDelivery loads one accepted delivery from Redis.
|
|
func (store *AcceptanceStore) GetDelivery(ctx context.Context, deliveryID common.DeliveryID) (deliverydomain.Delivery, bool, error) {
|
|
if store == nil || store.client == nil {
|
|
return deliverydomain.Delivery{}, false, errors.New("get auth acceptance delivery: nil store")
|
|
}
|
|
if ctx == nil {
|
|
return deliverydomain.Delivery{}, false, errors.New("get auth acceptance delivery: nil context")
|
|
}
|
|
|
|
payload, err := store.client.Get(ctx, store.keys.Delivery(deliveryID)).Bytes()
|
|
switch {
|
|
case errors.Is(err, redis.Nil):
|
|
return deliverydomain.Delivery{}, false, nil
|
|
case err != nil:
|
|
return deliverydomain.Delivery{}, false, fmt.Errorf("get auth acceptance delivery: %w", err)
|
|
}
|
|
|
|
record, err := UnmarshalDelivery(payload)
|
|
if err != nil {
|
|
return deliverydomain.Delivery{}, false, fmt.Errorf("get auth acceptance delivery: %w", err)
|
|
}
|
|
|
|
return record, true, nil
|
|
}
|