Documentation
¶
Index ¶
- Variables
- func GenerateGameID() string
- func GeneratePubsubID() string
- type AlwaysAcceptTokenStore
- func (s AlwaysAcceptTokenStore) ConsumeCSRFToken(ctx context.Context, playerId api.PlayerId, token string) (bool, error)
- func (s AlwaysAcceptTokenStore) NewCSRFToken(ctx context.Context, playerId api.PlayerId, ttl time.Duration) (string, error)
- func (s AlwaysAcceptTokenStore) TokenBucketGet(ctx context.Context, bucket string, tokens int, refillRate float64, ...) (bool, error)
- type Clock
- type FlashMessage
- type FlashStore
- type GameInfo
- type GameStore
- type InMemFlashStore
- type InMemoryGameStore
- func (s *InMemoryGameStore) ListActiveGames(ctx context.Context, limit int) ([]*GameInfo, error)
- func (s *InMemoryGameStore) ListOpenGames(ctx context.Context, limit int) ([]*GameInfo, error)
- func (s *InMemoryGameStore) LookupGame(ctx context.Context, gameId string) (*pb.GameState, error)
- func (s *InMemoryGameStore) Publish(ctx context.Context, pubsubId string, event *pb.GameStorePubsubEvent) error
- func (s *InMemoryGameStore) StoreNewGame(ctx context.Context, state *pb.GameState) error
- func (s *InMemoryGameStore) Subscribe(ctx context.Context, pubsubId string) <-chan *pb.GameStorePubsubEvent
- func (s *InMemoryGameStore) UpdateGame(ctx context.Context, state *pb.GameState) error
- type InMemoryPlayerStore
- func (s *InMemoryPlayerStore) Login(ctx context.Context, player Player) error
- func (s *InMemoryPlayerStore) Logout(ctx context.Context, playerId api.PlayerId) error
- func (s *InMemoryPlayerStore) Lookup(ctx context.Context, playerId api.PlayerId) (Player, error)
- func (s *InMemoryPlayerStore) NumPlayers() int
- type Player
- type PlayerStore
- type RealClock
- type RedisClient
- func (c *RedisClient) AddMessage(ctx context.Context, flashID string, msg FlashMessage) error
- func (c *RedisClient) ConsumeCSRFToken(ctx context.Context, playerId api.PlayerId, token string) (bool, error)
- func (c *RedisClient) DeleteGame(ctx context.Context, gameId string) error
- func (c *RedisClient) ListActiveGames(ctx context.Context, limit int) ([]*GameInfo, error)
- func (c *RedisClient) ListOpenGames(ctx context.Context, limit int) ([]*GameInfo, error)
- func (c *RedisClient) LoginPlayer(ctx context.Context, player Player) error
- func (c *RedisClient) LogoutPlayer(ctx context.Context, playerId api.PlayerId) error
- func (c *RedisClient) LookupGame(ctx context.Context, gameId string) (*pb.GameState, error)
- func (c *RedisClient) LookupPlayer(ctx context.Context, playerId api.PlayerId) (Player, error)
- func (c *RedisClient) NewCSRFToken(ctx context.Context, playerId api.PlayerId, ttl time.Duration) (string, error)
- func (c *RedisClient) Ping() error
- func (c *RedisClient) PopMessages(ctx context.Context, flashID string) ([]FlashMessage, error)
- func (c *RedisClient) Publish(ctx context.Context, pubsubId string, event *pb.GameStorePubsubEvent) error
- func (c *RedisClient) StoreNewGame(ctx context.Context, state *pb.GameState) error
- func (c *RedisClient) Subscribe(ctx context.Context, pubsubId string) <-chan *pb.GameStorePubsubEvent
- func (c *RedisClient) TokenBucketGet(ctx context.Context, bucket string, tokens int, refillRate float64, ...) (bool, error)
- func (c *RedisClient) UpdateGame(ctx context.Context, s *pb.GameState) error
- type RedisClientConfig
- type RemotePlayerStore
- type TokenStore
Constants ¶
This section is empty.
Variables ¶
var (
ErrGameNotExist = fmt.Errorf("game does not exist in store")
)
Functions ¶
func GenerateGameID ¶
func GenerateGameID() string
Generates a game ID consisting of 6 uppercase ASCII letters.
func GeneratePubsubID ¶
func GeneratePubsubID() string
Types ¶
type AlwaysAcceptTokenStore ¶
type AlwaysAcceptTokenStore struct{}
AlwaysAcceptTokenStore is an implementation of TokenStore that accepts everything.
func (AlwaysAcceptTokenStore) ConsumeCSRFToken ¶
func (AlwaysAcceptTokenStore) NewCSRFToken ¶
type FlashMessage ¶
type FlashStore ¶
type FlashStore interface {
// AddMessage adds a flash message for the given flashID.
// Given the short-lived nature of flash messages, implementations should
// ensure that messages associated with a flashID have a short TTL
// (1 minute should be enough).
AddMessage(ctx context.Context, flashID string, msg FlashMessage) error
// PopMessages retrieves all flash messages for the flashID and removes them from the store.
PopMessages(ctx context.Context, flashID string) ([]FlashMessage, error)
}
type GameInfo ¶
GameInfo contains essential summary info about a game. It is stored in serialized form for open and active games.
type GameStore ¶
type GameStore interface {
// StoreNewGame stores a new game under a randomly chosen new game ID.
// The game ID will be returned, and also stored in state.GameInfo.Id.
// If that field is already set in the input, an error is returned
// and the game is not stored.
StoreNewGame(ctx context.Context, state *pb.GameState) error
// LookupGame looks up the current game state for the given gameId.
LookupGame(ctx context.Context, gameId string) (*pb.GameState, error)
// UpdateGame updates the game state for game ID s.GameInfo.Id.
// Existing states are overwritten unconditionally.
UpdateGame(ctx context.Context, state *pb.GameState) error
// ListOpenGames lists games that are waiting for more players to join.
ListOpenGames(ctx context.Context, limit int) ([]*GameInfo, error)
// ListActiveGames lists the limit most recently played games.
ListActiveGames(ctx context.Context, limit int) ([]*GameInfo, error)
// Publish publishes the given game event on the GameStore's pubsub topic.
Publish(ctx context.Context, pubsubId string, event *pb.GameStorePubsubEvent) error
// Subscribe subscribes to game events for the given game ID. Events will be
// sent to the returned channel. This method internaly spawns a goroutine
// and returns immediately. The goroutine will close the returned channel
// and terminate when the provided context ctx is cancelled.
Subscribe(ctx context.Context, pubsubId string) <-chan *pb.GameStorePubsubEvent
}
GameStore is an interface for local or remote game stores, e.g. Redis.
type InMemFlashStore ¶
type InMemFlashStore struct {
// contains filtered or unexported fields
}
InMemFlashStore is an in-memory implementation of a FlashStore. Its methods can safely be called by multiple goroutines.
func NewInMemFlashStore ¶
func NewInMemFlashStore() *InMemFlashStore
func (*InMemFlashStore) AddMessage ¶
func (s *InMemFlashStore) AddMessage(ctx context.Context, flashID string, msg FlashMessage) error
func (*InMemFlashStore) PopMessages ¶
func (s *InMemFlashStore) PopMessages(ctx context.Context, flashID string) ([]FlashMessage, error)
type InMemoryGameStore ¶
type InMemoryGameStore struct {
// contains filtered or unexported fields
}
An in-memory replacement for a RedisClient, to enable purely local, single-server gameplay.
func NewInMemoryGameStore ¶
func NewInMemoryGameStore(gameTTL time.Duration) *InMemoryGameStore
func (*InMemoryGameStore) ListActiveGames ¶
func (*InMemoryGameStore) ListOpenGames ¶
func (*InMemoryGameStore) LookupGame ¶
func (*InMemoryGameStore) Publish ¶
func (s *InMemoryGameStore) Publish(ctx context.Context, pubsubId string, event *pb.GameStorePubsubEvent) error
func (*InMemoryGameStore) StoreNewGame ¶
func (*InMemoryGameStore) Subscribe ¶
func (s *InMemoryGameStore) Subscribe(ctx context.Context, pubsubId string) <-chan *pb.GameStorePubsubEvent
func (*InMemoryGameStore) UpdateGame ¶
type InMemoryPlayerStore ¶
type InMemoryPlayerStore struct {
// contains filtered or unexported fields
}
func NewInMemoryPlayerStore ¶
func NewInMemoryPlayerStore(loginTTL time.Duration) (*InMemoryPlayerStore, error)
Creates a new in-memory player store and loads the player DB from the given file. If dbPath is empty, no persistent storage is used.
func (*InMemoryPlayerStore) Login ¶
func (s *InMemoryPlayerStore) Login(ctx context.Context, player Player) error
func (*InMemoryPlayerStore) NumPlayers ¶
func (s *InMemoryPlayerStore) NumPlayers() int
type Player ¶
type Player struct {
// A randomly generated unique ID.
// This ID may be used in cookies.
Id api.PlayerId `json:"id"`
Name string `json:"name"`
LastActive time.Time `json:"lastActive"`
// Only set for registered users. For guests, this field is empty.
UserID string `json:"userId"`
}
Player contains the data that is stored in the PlayerStore for a given player. It has JSON annotations for serialization (to disk or in memory storage).
type PlayerStore ¶
type PlayerStore interface {
// Lookup looks up the given player by ID.
Lookup(ctx context.Context, playerId api.PlayerId) (Player, error)
// Login logs in the given player. If the player is already logged in,
// the existing data will be overwritten with the new data.
// LastActive will be updated internally and does not need to be set by the caller.
Login(ctx context.Context, player Player) error
// Deletes the player from the store.
Logout(ctx context.Context, playerId api.PlayerId) error
}
type RedisClient ¶
type RedisClient struct {
// contains filtered or unexported fields
}
func NewRedisClient ¶
func NewRedisClient(config *RedisClientConfig) (*RedisClient, error)
func (*RedisClient) AddMessage ¶
func (c *RedisClient) AddMessage(ctx context.Context, flashID string, msg FlashMessage) error
func (*RedisClient) ConsumeCSRFToken ¶
func (*RedisClient) DeleteGame ¶
func (c *RedisClient) DeleteGame(ctx context.Context, gameId string) error
func (*RedisClient) ListActiveGames ¶
func (*RedisClient) ListOpenGames ¶
func (*RedisClient) LoginPlayer ¶
func (c *RedisClient) LoginPlayer(ctx context.Context, player Player) error
func (*RedisClient) LogoutPlayer ¶
func (*RedisClient) LookupGame ¶
func (*RedisClient) LookupPlayer ¶
func (*RedisClient) NewCSRFToken ¶
func (*RedisClient) Ping ¶
func (c *RedisClient) Ping() error
func (*RedisClient) PopMessages ¶
func (c *RedisClient) PopMessages(ctx context.Context, flashID string) ([]FlashMessage, error)
func (*RedisClient) Publish ¶
func (c *RedisClient) Publish(ctx context.Context, pubsubId string, event *pb.GameStorePubsubEvent) error
Sends a message to the channel for the given game. Returns the number of subscribers that received the message.
func (*RedisClient) StoreNewGame ¶
Stores the given game state in Redis. Game ID and pubsub ID are taken from the game state's GameInfo. If any of them is not set, it is assigned an appropriate random value. This method also updates the state's Modified field.
func (*RedisClient) Subscribe ¶
func (c *RedisClient) Subscribe(ctx context.Context, pubsubId string) <-chan *pb.GameStorePubsubEvent
func (*RedisClient) TokenBucketGet ¶
func (*RedisClient) UpdateGame ¶
Stores the given game state in Redis, overwriting any existing game with the same ID. This method updates the Modified field of the game state.
type RedisClientConfig ¶
type RemotePlayerStore ¶
type RemotePlayerStore struct {
*RedisClient
}
RemotePlayerStore is an interface adapter that lets RedisClient implement PlayerStore.
func (*RemotePlayerStore) Login ¶
func (s *RemotePlayerStore) Login(ctx context.Context, player Player) error
type TokenStore ¶
type TokenStore interface {
// NewCSRFToken creates and returns a new token with the specified TTL.
NewCSRFToken(ctx context.Context, playerId api.PlayerId, ttl time.Duration) (string, error)
// ConsumeCSRFToken checks if the given CSRF token is known, and consumes it.
ConsumeCSRFToken(ctx context.Context, playerId api.PlayerId, token string) (bool, error)
// TokenBucketGet atomically gets the requested number of tokens from bucket.
// Before removing any tokens, it refills the bucket according to the
// given refillRate (in tokens per second) and the most recent refill time.
// On the first call (ever or after the max TTL for any bucket), the bucket
// is assumed to contain capacity tokens. The bucket will never contain
// more than capacity tokens.
TokenBucketGet(ctx context.Context, bucket string, tokens int, refillRate float64, capacity int) (bool, error)
}
TokenStore is the interface for a store of tokens. Tokens can be used for CSRF prevention and rate limiting.