Files
galaxy-game/pkg/notificationintent/publisher.go
T
2026-04-22 08:49:45 +02:00

74 lines
1.9 KiB
Go

package notificationintent
import (
"context"
"errors"
"fmt"
"github.com/redis/go-redis/v9"
)
// RedisClient stores the minimal Redis command surface required by Publisher.
type RedisClient interface {
// XAdd appends one entry to a Redis Stream.
XAdd(context.Context, *redis.XAddArgs) *redis.StringCmd
}
// PublisherConfig stores the dependencies and stream name used by Publisher.
type PublisherConfig struct {
// Client appends normalized intents to Redis Streams.
Client RedisClient
// Stream stores the Redis Stream name. When empty, DefaultIntentsStream is
// used.
Stream string
}
// Publisher publishes normalized notification intents into the Notification
// Service ingress stream.
type Publisher struct {
client RedisClient
stream string
}
// NewPublisher constructs a Publisher from cfg.
func NewPublisher(cfg PublisherConfig) (*Publisher, error) {
if cfg.Client == nil {
return nil, errors.New("new notification intent publisher: nil redis client")
}
if cfg.Stream == "" {
cfg.Stream = DefaultIntentsStream
}
return &Publisher{
client: cfg.Client,
stream: cfg.Stream,
}, nil
}
// Publish validates intent and appends it with plain XADD. It does not trim
// the stream and does not perform hidden retries.
func (publisher *Publisher) Publish(ctx context.Context, intent Intent) (string, error) {
if ctx == nil {
return "", errors.New("publish notification intent: nil context")
}
if publisher == nil || publisher.client == nil {
return "", errors.New("publish notification intent: nil publisher")
}
values, err := intent.Values()
if err != nil {
return "", fmt.Errorf("publish notification intent: %w", err)
}
entryID, err := publisher.client.XAdd(ctx, &redis.XAddArgs{
Stream: publisher.stream,
Values: values,
}).Result()
if err != nil {
return "", fmt.Errorf("publish notification intent: xadd: %w", err)
}
return entryID, nil
}