server

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 31, 2023 License: GPL-3.0 Imports: 27 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GenerateCert

func GenerateCert(cert TLSCert)

Types

type ClientMessage

type ClientMessage struct {
	Type     string `json:"type,omitempty"`
	Username string `json:"username,omitempty"`
	Token    string `json:"token,omitempty"`
	Data     any    `json:"data,omitempty"`
}

The socket server unmarshals the response from the browser client into this type.

type CurrentQuestion

type CurrentQuestion struct {
	Question  string   `json:"question,omitempty"`
	Answer    any      `json:"answer,omitempty"`
	Choices   []string `json:"choices,omitempty"`
	Weight    int      `json:"weight,omitempty"`
	Responses int      `json:"responses,omitempty"`
}

`Weight` is the amount of points awarded for a correct answer.

type Game

type Game struct {
	Name    string
	Players GamePlayers
	Benched GamePlayers
	Key     middleware.APIKey
	CurrentQuestion
}

func NewGame

func NewGame(name string, tokenExpiration float64) *Game

Constructor.

func (*Game) Bench

func (g *Game) Bench(p *Player) error

This function will move a `Player` out of the game's `Players` pool and into the Benched pool of the Game type. This will occur when a connection is lost due to the browser tab being closed. Since this could have occurred by accident (laptop shuts down, etc), the player should be able to log back into the game and resume where they left off, that is reclaim the points they had when the disconnect occurred. Note that this is different from a player choosing to exit the game by clicking exit or close (TODO).

func (*Game) CheckTokenExpiration

func (g *Game) CheckTokenExpiration() error

Called only when a new player logs in. It is legal for a logged in player to continue making requests after the game has expired, but not if they have not previously logged in. See [Game.CheckTokenEquality] for more information.

func (*Game) GetPlayer

func (g *Game) GetPlayer(v any) (*Player, error)

This function expects either a player name (string) or a player socket (*websocket.Conn). The most reliable way to lookup a player is by their socket, since this cannot be modified by the user. However, when calling an endpoint such as SocketServer.KillHandler, all we have is the player name.

func (*Game) GetScoreboard

func (g *Game) GetScoreboard() Scoreboard

func (*Game) HasPlayer

func (g *Game) HasPlayer(name string) (*Player, bool)

func (*Game) Unbench

func (g *Game) Unbench(p *Player) error

If a player logs back in after accidentally killing their browser session (at which point they are "benched"), move their player state from the .Benched pool to the .Players pool in the Game type. This has the effect of allowing them to resume where they left off and regain their points.

func (*Game) UpdatePlayerScore

func (g *Game) UpdatePlayerScore(socket *websocket.Conn, points int) (int, error)

Called every time a player guesses correctly. Currently, this happens immediately after a correct guess and so every player will see the updated score. This isn't optimal and should be changed to only update after everyone has guessed (TODO).

type GamePlayers

type GamePlayers []*Player

type Player

type Player struct {
	Location string          `json:"location,omitempty"`
	Name     string          `json:"name,omitempty"`
	UUID     string          `json:"uuid,omitempty"`
	Score    int             `json:"score"`
	Socket   *websocket.Conn `json:"conn,omitempty"`
}

Players can have a zero `Score`, so don't add the tag `omitempty` when marshaling to the browser.

The `Socket` is the only reliable way to lookup a particular player, and the functions in the package operate on it as often as it can. For example, the `player.Name` could be fiddled with in the browser before sending a request so it could be unreliable.

The `UUID` is set by the client (browser) and sent as part of the websocket URL. It's not currently used.

const socketURL = `{{ . }}?uuid=${getUUID()}`;
socket = new WebSocket(socketURL);

type PlayerScore

type PlayerScore struct {
	Name  string
	Score int
}

This is currently for an admin to get a quick view of the game state.

type Scoreboard

type Scoreboard []*PlayerScore

func (Scoreboard) Len

func (s Scoreboard) Len() int

func (Scoreboard) Less

func (s Scoreboard) Less(i, j int) bool

func (Scoreboard) Swap

func (s Scoreboard) Swap(i, j int)

type ServerMessage

type ServerMessage struct {
	Type string `json:"type,omitempty"`
	Data any    `json:"data,omitempty"`
}

This is marshaled to the browser client. See SocketServer.Publish.

type Socket

type Socket struct {
	Protocol string
	Domain   string
	Port     int
}

func (Socket) String

func (s Socket) String() string

type SocketServer

type SocketServer struct {
	Location URL
	Games    map[string]*Game
	Tpl      *template.Template
	Mux      *http.ServeMux
}

A socket server instance is set up to handle multiple (concurrent) games.

func NewSocketServer

func NewSocketServer(url URL) *SocketServer

func (*SocketServer) BaseHandler

func (s *SocketServer) BaseHandler(w http.ResponseWriter, r *http.Request)

func (*SocketServer) DefaultHandler

func (s *SocketServer) DefaultHandler(socket *websocket.Conn)

func (*SocketServer) GetGame

func (s *SocketServer) GetGame(key string) (*Game, error)

A socket server instance can potentially have multiple games. Note this only checks for token equality **not** expiration.

func (*SocketServer) GetPlayerBySocket

func (s *SocketServer) GetPlayerBySocket(socket *websocket.Conn) (*Player, *Game, error)

When a connection is suddenly disconnected, for instance when the browser crashes, we don't have any information about the player that closed the session other than the socket. This means that we need to range over all of the games and the players within each game until we find the matching player.

func (*SocketServer) HealthHandler

func (s *SocketServer) HealthHandler(w http.ResponseWriter, r *http.Request)

func (*SocketServer) KillHandler

func (s *SocketServer) KillHandler(w http.ResponseWriter, r *http.Request)

func (*SocketServer) Message

func (s *SocketServer) Message(socket *websocket.Conn, msg ServerMessage) error

Notify a single player of an event.

func (*SocketServer) MessageHandler

func (s *SocketServer) MessageHandler(w http.ResponseWriter, r *http.Request)

func (*SocketServer) NotifyHandler

func (s *SocketServer) NotifyHandler(w http.ResponseWriter, r *http.Request)

func (*SocketServer) Publish

func (s *SocketServer) Publish(game *Game, msg ServerMessage) error

Notifies every player of an event.

func (*SocketServer) QueryHandler

func (s *SocketServer) QueryHandler(w http.ResponseWriter, r *http.Request)

TODO: Use a CSV package for this?

func (*SocketServer) RegisterAndStartGame

func (s *SocketServer) RegisterAndStartGame(game *Game)

func (*SocketServer) RegisterGame

func (s *SocketServer) RegisterGame(game *Game)

Registers a new game. A socket server can host multiple games.

func (*SocketServer) ResetHandler

func (s *SocketServer) ResetHandler(w http.ResponseWriter, r *http.Request)

func (*SocketServer) ScoreboardHandler

func (s *SocketServer) ScoreboardHandler(w http.ResponseWriter, r *http.Request)

func (*SocketServer) StartGame

func (s *SocketServer) StartGame(game *Game)

Registers all the handlers with the new mux, adds the middleware and starts starts the game server.

func (*SocketServer) UpdateScoreHandler

func (s *SocketServer) UpdateScoreHandler(w http.ResponseWriter, r *http.Request)

type TLSCert

type TLSCert struct {
	Host       string
	ValidFrom  string
	ValidFor   time.Duration
	IsCA       bool
	RsaBits    int
	EcdsaCurve string
	Ed25519Key bool
}

Host is the comma-separated hostnames and IPs to generate a certificate for. ValidFrom is start date is the creation date formatted as Jan 1 15:04:05 2011. ValidFor is the time.Duration the certificate is valid for. Defaults to 365*24*time.Hour. IsCA is whether this cert should be its own Certificate Authority. Defaults to false. RsaBits is the size of RSA key to generate. Ignored if Ecdsacurve is set. Defaults to 2048. Ecdsacurve is the ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521. Ed25519Key. Generates an Ed25519 key: Defaults to false.

type URL

type URL struct {
	Sock Socket
	Path string
}

func (URL) String

func (u URL) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL