// Package notificationpublisher provides the Redis-Streams-backed // notification-intent publisher Game Master uses for the three GM-owned // types listed in `gamemaster/README.md §Notification Contracts`: // `game.turn.ready`, `game.finished`, `game.generation_failed`. // // The adapter is a thin shim over `galaxy/notificationintent.Publisher` // that drops the entry id at the wrapper boundary; it mirrors // `rtmanager/internal/adapters/notificationpublisher` byte-for-byte // (`rtmanager/docs/domain-and-ports.md §7` justifies that decision and // applies here for the same reason). package notificationpublisher import ( "context" "errors" "fmt" "github.com/redis/go-redis/v9" "galaxy/notificationintent" "galaxy/gamemaster/internal/ports" ) // Config groups the dependencies and stream name required to construct // a Publisher. type Config struct { // Client appends entries to Redis Streams. Must be non-nil. Client *redis.Client // Stream stores the Redis Stream key intents are published to. // When empty, `notificationintent.DefaultIntentsStream` is used. Stream string } // Publisher implements `ports.NotificationIntentPublisher` on top of // the shared `notificationintent.Publisher`. type Publisher struct { inner *notificationintent.Publisher } // NewPublisher constructs a Publisher from cfg. Validation errors and // transport errors propagate verbatim. func NewPublisher(cfg Config) (*Publisher, error) { if cfg.Client == nil { return nil, errors.New("new gamemaster notification publisher: nil redis client") } inner, err := notificationintent.NewPublisher(notificationintent.PublisherConfig{ Client: cfg.Client, Stream: cfg.Stream, }) if err != nil { return nil, fmt.Errorf("new gamemaster notification publisher: %w", err) } return &Publisher{inner: inner}, nil } // Publish forwards intent to the underlying notificationintent // publisher and discards the resulting Redis Stream entry id. A failed // publish surfaces as the underlying error. func (publisher *Publisher) Publish(ctx context.Context, intent notificationintent.Intent) error { if publisher == nil || publisher.inner == nil { return errors.New("publish notification intent: nil publisher") } if _, err := publisher.inner.Publish(ctx, intent); err != nil { return err } return nil } // Compile-time assertion: Publisher implements // ports.NotificationIntentPublisher. var _ ports.NotificationIntentPublisher = (*Publisher)(nil)