Skip to content

Commit

Permalink
The REST API now allows specfiying the Lobby ID
Browse files Browse the repository at this point in the history
The ID is limited to an unused valid UUIDv4.
This does not allow specifying a lobby owner as of now. However, due to
the recent changes to the start / restart system, this is not as much of
a hurdle as it used to be.

Fixes #207
Fixes #194
  • Loading branch information
Bios-Marcel committed Oct 12, 2024
1 parent 2cb7f26 commit 005ba66
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 7 deletions.
32 changes: 28 additions & 4 deletions internal/api/v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,22 @@ func (handler *V1Handler) postLobby(writer http.ResponseWriter, request *http.Re
return
}

var requestErrors []string

// The lobby ID is normally autogenerated and it isn't advisble to set it
// yourself, but for certain integrations / automations this can be useful.
// However, to avoid any kind of abuse, this needs to be a valid UUID at
// least.
desiredLobbyId := uuid.Nil
lobbyId := request.Form.Get("lobby_id")
if lobbyId != "" {
var err error
desiredLobbyId, err = uuid.FromString(lobbyId)
if err != nil {
requestErrors = append(requestErrors, err.Error())
}
}

languageData, languageKey, languageInvalid := ParseLanguage(request.Form.Get("language"))
drawingTime, drawingTimeInvalid := ParseDrawingTime(request.Form.Get("drawing_time"))
rounds, roundsInvalid := ParseRounds(request.Form.Get("rounds"))
Expand All @@ -104,7 +120,6 @@ func (handler *V1Handler) postLobby(writer http.ResponseWriter, request *http.Re
}
customWords, customWordsInvalid := ParseCustomWords(lowercaser, request.Form.Get("custom_words"))

var requestErrors []string
if languageInvalid != nil {
requestErrors = append(requestErrors, languageInvalid.Error())
}
Expand Down Expand Up @@ -136,14 +151,23 @@ func (handler *V1Handler) postLobby(writer http.ResponseWriter, request *http.Re
}

playerName := GetPlayername(request)
player, lobby, err := game.CreateLobby(playerName, languageKey,
publicLobby, drawingTime, rounds, maxPlayers, customWordsPerTurn,
clientsPerIPLimit, customWords)
player, lobby, err := game.CreateLobby(desiredLobbyId, playerName,
languageKey, publicLobby, drawingTime, rounds, maxPlayers,
customWordsPerTurn, clientsPerIPLimit, customWords)
if err != nil {
http.Error(writer, err.Error(), http.StatusBadRequest)
return
}

// Due to the fact the IDs can be chosen manually, there's a big clash
// potential! However, since we only allow specifying this via the rest API
// we treat this here. This can't be treated in the game package right now
// anyway though, as there'd be an import cycle.
if state.GetLobby(lobby.LobbyID) != nil {
http.Error(writer, "lobby id already in use", http.StatusBadRequest)
return
}

lobby.WriteObject = WriteObject
lobby.WritePreparedMessage = WritePreparedMessage
player.SetLastKnownAddress(GetIPAddressFromRequest(request))
Expand Down
3 changes: 2 additions & 1 deletion internal/frontend/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"log"
"net/http"

"github.com/gofrs/uuid/v5"
"github.com/scribble-rs/scribble.rs/internal/api"
"github.com/scribble-rs/scribble.rs/internal/config"
"github.com/scribble-rs/scribble.rs/internal/game"
Expand Down Expand Up @@ -171,7 +172,7 @@ func (handler *SSRHandler) ssrCreateLobby(writer http.ResponseWriter, request *h

playerName := api.GetPlayername(request)

player, lobby, err := game.CreateLobby(playerName, languageKey,
player, lobby, err := game.CreateLobby(uuid.Nil, playerName, languageKey,
publicLobby, drawingTime, rounds, maxPlayers, customWordsPerTurn,
clientsPerIPLimit, customWords)
if err != nil {
Expand Down
6 changes: 5 additions & 1 deletion internal/game/lobby.go
Original file line number Diff line number Diff line change
Expand Up @@ -908,13 +908,17 @@ func (lobby *Lobby) selectWord(wordChoiceIndex int) {
// CreateLobby creates a new lobby including the initial player (owner) and
// optionally returns an error, if any occurred during creation.
func CreateLobby(
desiredLobbyId uuid.UUID,
playerName, chosenLanguage string,
publicLobby bool,
drawingTime, rounds, maxPlayers, customWordsPerTurn, clientsPerIPLimit int,
customWords []string,
) (*Player, *Lobby, error) {
if desiredLobbyId == uuid.Nil {
desiredLobbyId = uuid.Must(uuid.NewV4())
}
lobby := &Lobby{
LobbyID: uuid.Must(uuid.NewV4()).String(),
LobbyID: desiredLobbyId.String(),
EditableLobbySettings: EditableLobbySettings{
Rounds: rounds,
DrawingTime: drawingTime,
Expand Down
3 changes: 2 additions & 1 deletion internal/state/lobbies_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package state
import (
"testing"

"github.com/gofrs/uuid/v5"
"github.com/scribble-rs/scribble.rs/internal/config"
"github.com/scribble-rs/scribble.rs/internal/game"
"github.com/stretchr/testify/require"
Expand All @@ -13,7 +14,7 @@ func TestAddAndRemove(t *testing.T) {
require.Empty(t, lobbies, "Lobbies should be empty when test starts")

createLobby := func() *game.Lobby {
player, lobby, err := game.CreateLobby("player", "dutch", true, 100, 10, 10, 3, 1, nil)
player, lobby, err := game.CreateLobby(uuid.Nil, "player", "dutch", true, 100, 10, 10, 3, 1, nil)
require.NoError(t, err)
lobby.OnPlayerDisconnect(player)
return lobby
Expand Down

0 comments on commit 005ba66

Please sign in to comment.