feat: game lobby service
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
package ports
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"galaxy/user/internal/domain/common"
|
||||
)
|
||||
|
||||
// UserLifecycleEventType identifies one user-lifecycle event kind propagated
|
||||
// to `Game Lobby` through the dedicated Redis Stream.
|
||||
type UserLifecycleEventType string
|
||||
|
||||
const (
|
||||
// UserLifecyclePermanentBlockedEventType identifies the post-commit event
|
||||
// emitted when `SanctionCodePermanentBlock` becomes active on an account.
|
||||
UserLifecyclePermanentBlockedEventType UserLifecycleEventType = "user.lifecycle.permanent_blocked"
|
||||
|
||||
// UserLifecycleDeletedEventType identifies the post-commit event emitted
|
||||
// when a trusted `DeleteUser` command soft-deletes an account.
|
||||
UserLifecycleDeletedEventType UserLifecycleEventType = "user.lifecycle.deleted"
|
||||
)
|
||||
|
||||
// IsKnown reports whether the event type belongs to the frozen vocabulary.
|
||||
func (eventType UserLifecycleEventType) IsKnown() bool {
|
||||
switch eventType {
|
||||
case UserLifecyclePermanentBlockedEventType, UserLifecycleDeletedEventType:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// UserLifecycleEvent stores one post-commit user-lifecycle event envelope
|
||||
// published to the `user:lifecycle_events` Redis Stream and consumed by
|
||||
// `Game Lobby` for Race Name Directory cascade release.
|
||||
type UserLifecycleEvent struct {
|
||||
// EventType stores the frozen lifecycle event discriminator.
|
||||
EventType UserLifecycleEventType
|
||||
|
||||
// UserID identifies the regular user whose lifecycle state changed.
|
||||
UserID common.UserID
|
||||
|
||||
// OccurredAt stores the committed mutation timestamp.
|
||||
OccurredAt time.Time
|
||||
|
||||
// Source stores the machine-readable mutation source. For Stage 22 this is
|
||||
// always `admin_internal_api`.
|
||||
Source common.Source
|
||||
|
||||
// Actor stores the audit actor metadata attached to the committed
|
||||
// mutation.
|
||||
Actor common.ActorRef
|
||||
|
||||
// ReasonCode stores the committed reason_code for the mutation.
|
||||
ReasonCode common.ReasonCode
|
||||
|
||||
// TraceID stores the optional OpenTelemetry trace identifier propagated
|
||||
// from the current request context.
|
||||
TraceID string
|
||||
}
|
||||
|
||||
// Validate reports whether event is structurally complete.
|
||||
func (event UserLifecycleEvent) Validate() error {
|
||||
if !event.EventType.IsKnown() {
|
||||
return fmt.Errorf("user lifecycle event type %q is unsupported", event.EventType)
|
||||
}
|
||||
if err := event.UserID.Validate(); err != nil {
|
||||
return fmt.Errorf("user lifecycle event user id: %w", err)
|
||||
}
|
||||
if err := common.ValidateTimestamp("user lifecycle event occurred at", event.OccurredAt); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := event.Source.Validate(); err != nil {
|
||||
return fmt.Errorf("user lifecycle event source: %w", err)
|
||||
}
|
||||
if err := event.Actor.Validate(); err != nil {
|
||||
return fmt.Errorf("user lifecycle event actor: %w", err)
|
||||
}
|
||||
if err := event.ReasonCode.Validate(); err != nil {
|
||||
return fmt.Errorf("user lifecycle event reason code: %w", err)
|
||||
}
|
||||
if event.TraceID != "" && strings.TrimSpace(event.TraceID) != event.TraceID {
|
||||
return fmt.Errorf("user lifecycle event trace id must not contain surrounding whitespace")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UserLifecyclePublisher publishes one committed user-lifecycle event to the
|
||||
// dedicated `user:lifecycle_events` Redis Stream.
|
||||
type UserLifecyclePublisher interface {
|
||||
// PublishUserLifecycleEvent propagates one committed lifecycle event. The
|
||||
// implementation must validate the event envelope and perform exactly one
|
||||
// idempotent append per call.
|
||||
PublishUserLifecycleEvent(ctx context.Context, event UserLifecycleEvent) error
|
||||
}
|
||||
Reference in New Issue
Block a user