feat: game lobby service
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
package redisstate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// registeredRecord stores the strict Redis JSON shape of one registered
|
||||
// race name. The canonical key is stored only as the Redis key suffix and
|
||||
// is not duplicated inside the blob.
|
||||
type registeredRecord struct {
|
||||
UserID string `json:"user_id"`
|
||||
RaceName string `json:"race_name"`
|
||||
SourceGameID string `json:"source_game_id"`
|
||||
RegisteredAtMS int64 `json:"registered_at_ms"`
|
||||
}
|
||||
|
||||
// reservationStatusReserved marks a per-game race name reservation that
|
||||
// has not yet been promoted by capability evaluation.
|
||||
const reservationStatusReserved = "reserved"
|
||||
|
||||
// reservationStatusPending marks a reservation that has been promoted to
|
||||
// pending_registration by the capability evaluator at game_finished.
|
||||
const reservationStatusPending = "pending_registration"
|
||||
|
||||
// reservationRecord stores the strict Redis JSON shape of one per-game
|
||||
// race name reservation. The game_id and canonical key are carried by the
|
||||
// Redis key suffix; the blob never duplicates them.
|
||||
type reservationRecord struct {
|
||||
UserID string `json:"user_id"`
|
||||
RaceName string `json:"race_name"`
|
||||
ReservedAtMS int64 `json:"reserved_at_ms"`
|
||||
Status string `json:"status"`
|
||||
EligibleUntilMS *int64 `json:"eligible_until_ms,omitempty"`
|
||||
}
|
||||
|
||||
// canonicalLookupRecord stores the eager canonical-lookup cache entry
|
||||
// used by Check to return availability without scanning the authoritative
|
||||
// keys. GameID is populated only for reservation and pending_registration
|
||||
// kinds; it is omitted for registered bindings.
|
||||
type canonicalLookupRecord struct {
|
||||
Kind string `json:"kind"`
|
||||
HolderUserID string `json:"holder_user_id"`
|
||||
GameID string `json:"game_id,omitempty"`
|
||||
}
|
||||
|
||||
// marshalRegisteredRecord encodes record into the strict Redis JSON shape
|
||||
// used for registered race names.
|
||||
func marshalRegisteredRecord(record registeredRecord) ([]byte, error) {
|
||||
payload, err := json.Marshal(record)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("marshal redis registered race name record: %w", err)
|
||||
}
|
||||
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
// unmarshalRegisteredRecord decodes payload from the strict Redis JSON
|
||||
// shape used for registered race names.
|
||||
func unmarshalRegisteredRecord(payload []byte) (registeredRecord, error) {
|
||||
var record registeredRecord
|
||||
if err := decodeStrictJSON("decode redis registered race name record", payload, &record); err != nil {
|
||||
return registeredRecord{}, err
|
||||
}
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// marshalReservationRecord encodes record into the strict Redis JSON
|
||||
// shape used for per-game race name reservations.
|
||||
func marshalReservationRecord(record reservationRecord) ([]byte, error) {
|
||||
payload, err := json.Marshal(record)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("marshal redis race name reservation record: %w", err)
|
||||
}
|
||||
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
// unmarshalReservationRecord decodes payload from the strict Redis JSON
|
||||
// shape used for per-game race name reservations.
|
||||
func unmarshalReservationRecord(payload []byte) (reservationRecord, error) {
|
||||
var record reservationRecord
|
||||
if err := decodeStrictJSON("decode redis race name reservation record", payload, &record); err != nil {
|
||||
return reservationRecord{}, err
|
||||
}
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// marshalCanonicalLookupRecord encodes record into the strict Redis JSON
|
||||
// shape used for canonical-lookup cache entries.
|
||||
func marshalCanonicalLookupRecord(record canonicalLookupRecord) ([]byte, error) {
|
||||
payload, err := json.Marshal(record)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("marshal redis race name canonical lookup record: %w", err)
|
||||
}
|
||||
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
// unmarshalCanonicalLookupRecord decodes payload from the strict Redis
|
||||
// JSON shape used for canonical-lookup cache entries.
|
||||
func unmarshalCanonicalLookupRecord(payload []byte) (canonicalLookupRecord, error) {
|
||||
var record canonicalLookupRecord
|
||||
if err := decodeStrictJSON("decode redis race name canonical lookup record", payload, &record); err != nil {
|
||||
return canonicalLookupRecord{}, err
|
||||
}
|
||||
|
||||
return record, nil
|
||||
}
|
||||
Reference in New Issue
Block a user