feat: game lobby service

This commit is contained in:
Ilia Denisov
2026-04-25 23:20:55 +02:00
committed by GitHub
parent 32dc29359a
commit 48b0056b49
336 changed files with 57074 additions and 1418 deletions
@@ -58,6 +58,10 @@ const (
// `lobby.membership.rejected` notification.
NotificationTypeLobbyMembershipRejected = notificationintent.NotificationTypeLobbyMembershipRejected
// NotificationTypeLobbyMembershipBlocked identifies the
// `lobby.membership.blocked` notification.
NotificationTypeLobbyMembershipBlocked = notificationintent.NotificationTypeLobbyMembershipBlocked
// NotificationTypeLobbyInviteCreated identifies the
// `lobby.invite.created` notification.
NotificationTypeLobbyInviteCreated = notificationintent.NotificationTypeLobbyInviteCreated
@@ -69,6 +73,18 @@ const (
// NotificationTypeLobbyInviteExpired identifies the
// `lobby.invite.expired` notification.
NotificationTypeLobbyInviteExpired = notificationintent.NotificationTypeLobbyInviteExpired
// NotificationTypeLobbyRaceNameRegistrationEligible identifies the
// `lobby.race_name.registration_eligible` notification.
NotificationTypeLobbyRaceNameRegistrationEligible = notificationintent.NotificationTypeLobbyRaceNameRegistrationEligible
// NotificationTypeLobbyRaceNameRegistered identifies the
// `lobby.race_name.registered` notification.
NotificationTypeLobbyRaceNameRegistered = notificationintent.NotificationTypeLobbyRaceNameRegistered
// NotificationTypeLobbyRaceNameRegistrationDenied identifies the
// `lobby.race_name.registration_denied` notification.
NotificationTypeLobbyRaceNameRegistrationDenied = notificationintent.NotificationTypeLobbyRaceNameRegistrationDenied
)
// Producer identifies one supported upstream producer.
@@ -133,7 +149,10 @@ func ClassifyDecodeError(err error) malformedintent.FailureCode {
strings.Contains(message, "applicant_name"),
strings.Contains(message, "inviter_name"),
strings.Contains(message, "invitee_name"),
strings.Contains(message, "review_reason"):
strings.Contains(message, "review_reason"),
strings.Contains(message, "race_name"),
strings.Contains(message, "eligible_until_ms"),
strings.Contains(message, "reason"):
return malformedintent.FailureCodeInvalidPayload
default:
return malformedintent.FailureCodeInvalidIntent
@@ -154,6 +154,29 @@ func encodePayload(notificationType intentstream.NotificationType, payloadJSON s
return wrapPayloadEncoding(transcoder.LobbyMembershipRejectedEventToPayload(&transcoder.LobbyMembershipRejectedEvent{
GameID: payload.GameID,
}))
case intentstream.NotificationTypeLobbyMembershipBlocked:
var payload struct {
GameID string `json:"game_id"`
MembershipUserID string `json:"membership_user_id"`
Reason string `json:"reason"`
}
if err := decodePayload(payloadJSON, &payload); err != nil {
return nil, err
}
if payload.GameID == "" {
return nil, errors.New("payload_encoding_failed: game_id is empty")
}
if payload.MembershipUserID == "" {
return nil, errors.New("payload_encoding_failed: membership_user_id is empty")
}
if payload.Reason == "" {
return nil, errors.New("payload_encoding_failed: reason is empty")
}
return wrapPayloadEncoding(transcoder.LobbyMembershipBlockedEventToPayload(&transcoder.LobbyMembershipBlockedEvent{
GameID: payload.GameID,
MembershipUserID: payload.MembershipUserID,
Reason: payload.Reason,
}))
case intentstream.NotificationTypeLobbyInviteCreated:
var payload struct {
GameID string `json:"game_id"`
@@ -190,6 +213,42 @@ func encodePayload(notificationType intentstream.NotificationType, payloadJSON s
GameID: payload.GameID,
InviteeUserID: payload.InviteeUserID,
}))
case intentstream.NotificationTypeLobbyRaceNameRegistrationEligible:
var payload struct {
GameID string `json:"game_id"`
RaceName string `json:"race_name"`
EligibleUntilMs int64 `json:"eligible_until_ms"`
}
if err := decodePayload(payloadJSON, &payload); err != nil {
return nil, err
}
if payload.GameID == "" {
return nil, errors.New("payload_encoding_failed: game_id is empty")
}
if payload.RaceName == "" {
return nil, errors.New("payload_encoding_failed: race_name is empty")
}
if payload.EligibleUntilMs < 1 {
return nil, errors.New("payload_encoding_failed: eligible_until_ms must be at least 1")
}
return wrapPayloadEncoding(transcoder.LobbyRaceNameRegistrationEligibleEventToPayload(&transcoder.LobbyRaceNameRegistrationEligibleEvent{
GameID: payload.GameID,
RaceName: payload.RaceName,
EligibleUntilMs: payload.EligibleUntilMs,
}))
case intentstream.NotificationTypeLobbyRaceNameRegistered:
var payload struct {
RaceName string `json:"race_name"`
}
if err := decodePayload(payloadJSON, &payload); err != nil {
return nil, err
}
if payload.RaceName == "" {
return nil, errors.New("payload_encoding_failed: race_name is empty")
}
return wrapPayloadEncoding(transcoder.LobbyRaceNameRegisteredEventToPayload(&transcoder.LobbyRaceNameRegisteredEvent{
RaceName: payload.RaceName,
}))
default:
return nil, fmt.Errorf("payload_encoding_failed: notification type %q does not support push", notificationType)
}
@@ -103,6 +103,30 @@ func TestEncoderEncodesSupportedPushNotificationTypes(t *testing.T) {
require.Equal(t, "user-10", event.InviteeUserID)
},
},
{
name: "lobby race name registration eligible",
notificationType: intentstream.NotificationTypeLobbyRaceNameRegistrationEligible,
payloadJSON: `{"eligible_until_ms":1775208100000,"game_id":"game-8","game_name":"Aurora","race_name":"Skylancer"}`,
assertPayload: func(t *testing.T, payload []byte) {
t.Helper()
event, err := transcoder.PayloadToLobbyRaceNameRegistrationEligibleEvent(payload)
require.NoError(t, err)
require.Equal(t, "game-8", event.GameID)
require.Equal(t, "Skylancer", event.RaceName)
require.Equal(t, int64(1775208100000), event.EligibleUntilMs)
},
},
{
name: "lobby race name registered",
notificationType: intentstream.NotificationTypeLobbyRaceNameRegistered,
payloadJSON: `{"race_name":"Skylancer"}`,
assertPayload: func(t *testing.T, payload []byte) {
t.Helper()
event, err := transcoder.PayloadToLobbyRaceNameRegisteredEvent(payload)
require.NoError(t, err)
require.Equal(t, "Skylancer", event.RaceName)
},
},
}
for _, tt := range tests {