Skip to content

Commit 242c800

Browse files
committed
Lobby setting bounds now adjustable via env config
* 2 clients per ip is now the default setting * 24 max players is now the default setting * The fly.io deployment now defaults to 100 max players
1 parent c5651bd commit 242c800

File tree

10 files changed

+84
-76
lines changed

10 files changed

+84
-76
lines changed

fly.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ dockerfile = "linux.Dockerfile"
1010
[deploy]
1111
strategy = "canary"
1212

13+
[env]
14+
LOBBY_SETTING_BOUNDS_MAX_MAX_PLAYERS=100
15+
1316
[http_service]
1417
internal_port = 8080
1518
force_https = true

internal/api/createparse.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"strconv"
77
"strings"
88

9+
"github.com/scribble-rs/scribble.rs/internal/config"
910
"github.com/scribble-rs/scribble.rs/internal/game"
1011
"golang.org/x/text/cases"
1112
)
@@ -38,25 +39,25 @@ func ParseLanguage(value string) (*game.LanguageData, string, error) {
3839
// ParseDrawingTime checks whether the given value is an integer between
3940
// the lower and upper bound of drawing time. All other invalid
4041
// input, including empty strings, will return an error.
41-
func ParseDrawingTime(value string) (int, error) {
42-
return parseIntValue(value, game.LobbySettingBounds.MinDrawingTime,
43-
game.LobbySettingBounds.MaxDrawingTime, "drawing time")
42+
func ParseDrawingTime(cfg *config.Config, value string) (int, error) {
43+
return parseIntValue(value, cfg.LobbySettingBounds.MinDrawingTime,
44+
cfg.LobbySettingBounds.MaxDrawingTime, "drawing time")
4445
}
4546

4647
// ParseRounds checks whether the given value is an integer between
4748
// the lower and upper bound of rounds played. All other invalid
4849
// input, including empty strings, will return an error.
49-
func ParseRounds(value string) (int, error) {
50-
return parseIntValue(value, game.LobbySettingBounds.MinRounds,
51-
game.LobbySettingBounds.MaxRounds, "rounds")
50+
func ParseRounds(cfg *config.Config, value string) (int, error) {
51+
return parseIntValue(value, cfg.LobbySettingBounds.MinRounds,
52+
cfg.LobbySettingBounds.MaxRounds, "rounds")
5253
}
5354

5455
// ParseMaxPlayers checks whether the given value is an integer between
5556
// the lower and upper bound of maximum players per lobby. All other invalid
5657
// input, including empty strings, will return an error.
57-
func ParseMaxPlayers(value string) (int, error) {
58-
return parseIntValue(value, game.LobbySettingBounds.MinMaxPlayers,
59-
game.LobbySettingBounds.MaxMaxPlayers, "max players amount")
58+
func ParseMaxPlayers(cfg *config.Config, value string) (int, error) {
59+
return parseIntValue(value, cfg.LobbySettingBounds.MinMaxPlayers,
60+
cfg.LobbySettingBounds.MaxMaxPlayers, "max players amount")
6061
}
6162

6263
// ParseCustomWords checks whether the given value is a string containing comma
@@ -88,9 +89,9 @@ func ParseCustomWords(lowercaser cases.Caser, value string) ([]string, error) {
8889
// ParseClientsPerIPLimit checks whether the given value is an integer between
8990
// the lower and upper bound of maximum clients per IP. All other invalid
9091
// input, including empty strings, will return an error.
91-
func ParseClientsPerIPLimit(value string) (int, error) {
92-
return parseIntValue(value, game.LobbySettingBounds.MinClientsPerIPLimit,
93-
game.LobbySettingBounds.MaxClientsPerIPLimit, "clients per IP limit")
92+
func ParseClientsPerIPLimit(cfg *config.Config, value string) (int, error) {
93+
return parseIntValue(value, cfg.LobbySettingBounds.MinClientsPerIPLimit,
94+
cfg.LobbySettingBounds.MaxClientsPerIPLimit, "clients per IP limit")
9495
}
9596

9697
// ParseCustomWordsPerTurn checks whether the given value is an integer between

internal/api/createparse_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"reflect"
55
"testing"
66

7+
"github.com/scribble-rs/scribble.rs/internal/config"
78
"golang.org/x/text/cases"
89
"golang.org/x/text/language"
910
)
@@ -60,7 +61,7 @@ func Test_parseDrawingTime(t *testing.T) {
6061
t.Run(testCase.name, func(t *testing.T) {
6162
t.Parallel()
6263

63-
got, err := ParseDrawingTime(testCase.value)
64+
got, err := ParseDrawingTime(&config.Default, testCase.value)
6465
if (err != nil) != testCase.wantErr {
6566
t.Errorf("parseDrawingTime() error = %v, wantErr %v", err, testCase.wantErr)
6667
return
@@ -93,7 +94,7 @@ func Test_parseRounds(t *testing.T) {
9394
t.Run(testCase.name, func(t *testing.T) {
9495
t.Parallel()
9596

96-
got, err := ParseRounds(testCase.value)
97+
got, err := ParseRounds(&config.Default, testCase.value)
9798
if (err != nil) != testCase.wantErr {
9899
t.Errorf("parseRounds() error = %v, wantErr %v", err, testCase.wantErr)
99100
return
@@ -126,7 +127,7 @@ func Test_parseMaxPlayers(t *testing.T) {
126127
t.Run(testCase.name, func(t *testing.T) {
127128
t.Parallel()
128129

129-
got, err := ParseMaxPlayers(testCase.value)
130+
got, err := ParseMaxPlayers(&config.Default, testCase.value)
130131
if (err != nil) != testCase.wantErr {
131132
t.Errorf("parseMaxPlayers() error = %v, wantErr %v", err, testCase.wantErr)
132133
return

internal/api/v1.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,11 @@ func (handler *V1Handler) postLobby(writer http.ResponseWriter, request *http.Re
105105
}
106106

107107
languageData, languageKey, languageInvalid := ParseLanguage(request.Form.Get("language"))
108-
drawingTime, drawingTimeInvalid := ParseDrawingTime(request.Form.Get("drawing_time"))
109-
rounds, roundsInvalid := ParseRounds(request.Form.Get("rounds"))
110-
maxPlayers, maxPlayersInvalid := ParseMaxPlayers(request.Form.Get("max_players"))
108+
drawingTime, drawingTimeInvalid := ParseDrawingTime(handler.cfg, request.Form.Get("drawing_time"))
109+
rounds, roundsInvalid := ParseRounds(handler.cfg, request.Form.Get("rounds"))
110+
maxPlayers, maxPlayersInvalid := ParseMaxPlayers(handler.cfg, request.Form.Get("max_players"))
111111
customWordsPerTurn, customWordsPerTurnInvalid := ParseCustomWordsPerTurn(request.Form.Get("custom_words_per_turn"))
112-
clientsPerIPLimit, clientsPerIPLimitInvalid := ParseClientsPerIPLimit(request.Form.Get("clients_per_ip_limit"))
112+
clientsPerIPLimit, clientsPerIPLimitInvalid := ParseClientsPerIPLimit(handler.cfg, request.Form.Get("clients_per_ip_limit"))
113113
publicLobby, publicLobbyInvalid := ParseBoolean("public", request.Form.Get("public"))
114114

115115
var lowercaser cases.Caser
@@ -174,7 +174,7 @@ func (handler *V1Handler) postLobby(writer http.ResponseWriter, request *http.Re
174174

175175
SetUsersessionCookie(writer, player)
176176

177-
lobbyData := CreateLobbyData(lobby)
177+
lobbyData := CreateLobbyData(handler.cfg, lobby)
178178

179179
if started, _, err := easyjson.MarshalToHTTPResponseWriter(lobbyData, writer); err != nil {
180180
if !started {
@@ -221,7 +221,7 @@ func (handler *V1Handler) postPlayer(writer http.ResponseWriter, request *http.R
221221
player.SetLastKnownAddress(GetIPAddressFromRequest(request))
222222
}
223223

224-
lobbyData = CreateLobbyData(lobby)
224+
lobbyData = CreateLobbyData(handler.cfg, lobby)
225225
})
226226

227227
if lobbyData != nil {
@@ -280,11 +280,11 @@ func (handler *V1Handler) patchLobby(writer http.ResponseWriter, request *http.R
280280
}
281281

282282
// Editable properties
283-
maxPlayers, maxPlayersInvalid := ParseMaxPlayers(request.Form.Get("max_players"))
284-
drawingTime, drawingTimeInvalid := ParseDrawingTime(request.Form.Get("drawing_time"))
285-
rounds, roundsInvalid := ParseRounds(request.Form.Get("rounds"))
283+
maxPlayers, maxPlayersInvalid := ParseMaxPlayers(handler.cfg, request.Form.Get("max_players"))
284+
drawingTime, drawingTimeInvalid := ParseDrawingTime(handler.cfg, request.Form.Get("drawing_time"))
285+
rounds, roundsInvalid := ParseRounds(handler.cfg, request.Form.Get("rounds"))
286286
customWordsPerTurn, customWordsPerTurnInvalid := ParseCustomWordsPerTurn(request.Form.Get("custom_words_per_turn"))
287-
clientsPerIPLimit, clientsPerIPLimitInvalid := ParseClientsPerIPLimit(request.Form.Get("clients_per_ip_limit"))
287+
clientsPerIPLimit, clientsPerIPLimitInvalid := ParseClientsPerIPLimit(handler.cfg, request.Form.Get("clients_per_ip_limit"))
288288
publicLobby, publicLobbyInvalid := ParseBoolean("public", request.Form.Get("public"))
289289

290290
owner := lobby.Owner
@@ -389,9 +389,9 @@ type LobbyData struct {
389389

390390
// CreateLobbyData creates a ready to use LobbyData object containing data
391391
// from the passed Lobby.
392-
func CreateLobbyData(lobby *game.Lobby) *LobbyData {
392+
func CreateLobbyData(cfg *config.Config, lobby *game.Lobby) *LobbyData {
393393
return &LobbyData{
394-
SettingBounds: game.LobbySettingBounds,
394+
SettingBounds: cfg.LobbySettingBounds,
395395
EditableLobbySettings: lobby.EditableLobbySettings,
396396
LobbyID: lobby.LobbyID,
397397
DrawingBoardBaseWidth: game.DrawingBoardBaseWidth,

internal/config/config.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"time"
1010

1111
"github.com/caarlos0/env/v10"
12+
"github.com/scribble-rs/scribble.rs/internal/game"
1213
"github.com/subosito/gotenv"
1314
)
1415

@@ -53,6 +54,7 @@ type Config struct {
5354
// creation page. It doesn't affect the default values of lobbies created
5455
// via the API.
5556
LobbySettingDefaults LobbySettingDefaults `envPrefix:"LOBBY_SETTING_DEFAULTS_"`
57+
LobbySettingBounds game.SettingBounds `envPrefix:"LOBBY_SETTING_BOUNDS_"`
5658
Port uint16 `env:"PORT"`
5759
CORS CORS `envPrefix:"CORS_"`
5860
LobbyCleanup LobbyCleanup `envPrefix:"LOBBY_CLEANUP_"`
@@ -64,11 +66,23 @@ var Default = Config{
6466
Public: "false",
6567
DrawingTime: "120",
6668
Rounds: "4",
67-
MaxPlayers: "12",
69+
MaxPlayers: "24",
6870
CustomWordsPerTurn: "3",
69-
ClientsPerIPLimit: "1",
71+
ClientsPerIPLimit: "2",
7072
Language: "english",
7173
},
74+
LobbySettingBounds: game.SettingBounds{
75+
MinDrawingTime: 60,
76+
MaxDrawingTime: 300,
77+
MinRounds: 1,
78+
MaxRounds: 20,
79+
MinMaxPlayers: 2,
80+
MaxMaxPlayers: 24,
81+
MinClientsPerIPLimit: 1,
82+
MaxClientsPerIPLimit: 24,
83+
MinCustomWordsPerTurn: 1,
84+
MaxCustomWordsPerTurn: 3,
85+
},
7286
CORS: CORS{
7387
AllowedOrigins: []string{"*"},
7488
AllowCredentials: false,

internal/frontend/create.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func (handler *SSRHandler) homePageHandler(writer http.ResponseWriter, request *
7878
func (handler *SSRHandler) createDefaultLobbyCreatePageData() *LobbyCreatePageData {
7979
return &LobbyCreatePageData{
8080
BasePageConfig: handler.basePageConfig,
81-
SettingBounds: game.LobbySettingBounds,
81+
SettingBounds: handler.cfg.LobbySettingBounds,
8282
Languages: game.SupportedLanguages,
8383
LobbySettingDefaults: handler.cfg.LobbySettingDefaults,
8484
}
@@ -105,11 +105,11 @@ func (handler *SSRHandler) ssrCreateLobby(writer http.ResponseWriter, request *h
105105
}
106106

107107
languageData, languageKey, languageInvalid := api.ParseLanguage(request.Form.Get("language"))
108-
drawingTime, drawingTimeInvalid := api.ParseDrawingTime(request.Form.Get("drawing_time"))
109-
rounds, roundsInvalid := api.ParseRounds(request.Form.Get("rounds"))
110-
maxPlayers, maxPlayersInvalid := api.ParseMaxPlayers(request.Form.Get("max_players"))
108+
drawingTime, drawingTimeInvalid := api.ParseDrawingTime(handler.cfg, request.Form.Get("drawing_time"))
109+
rounds, roundsInvalid := api.ParseRounds(handler.cfg, request.Form.Get("rounds"))
110+
maxPlayers, maxPlayersInvalid := api.ParseMaxPlayers(handler.cfg, request.Form.Get("max_players"))
111111
customWordsPerTurn, customWordsPerTurnInvalid := api.ParseCustomWordsPerTurn(request.Form.Get("custom_words_per_turn"))
112-
clientsPerIPLimit, clientsPerIPLimitInvalid := api.ParseClientsPerIPLimit(request.Form.Get("clients_per_ip_limit"))
112+
clientsPerIPLimit, clientsPerIPLimitInvalid := api.ParseClientsPerIPLimit(handler.cfg, request.Form.Get("clients_per_ip_limit"))
113113
publicLobby, publicLobbyInvalid := api.ParseBoolean("public", request.Form.Get("public"))
114114

115115
var lowercaser cases.Caser
@@ -123,7 +123,7 @@ func (handler *SSRHandler) ssrCreateLobby(writer http.ResponseWriter, request *h
123123
// Prevent resetting the form, since that would be annoying as hell.
124124
pageData := LobbyCreatePageData{
125125
BasePageConfig: handler.basePageConfig,
126-
SettingBounds: game.LobbySettingBounds,
126+
SettingBounds: handler.cfg.LobbySettingBounds,
127127
LobbySettingDefaults: config.LobbySettingDefaults{
128128
Public: request.Form.Get("public"),
129129
DrawingTime: request.Form.Get("drawing_time"),

internal/frontend/lobby.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func (handler *SSRHandler) ssrEnterLobby(writer http.ResponseWriter, request *ht
3737
if !(strings.Contains(userAgent, "gecko") || strings.Contains(userAgent, "chrome") || strings.Contains(userAgent, "opera") || strings.Contains(userAgent, "safari")) {
3838
err := pageTemplates.ExecuteTemplate(writer, "robot-page", &robotPageData{
3939
BasePageConfig: handler.basePageConfig,
40-
LobbyData: api.CreateLobbyData(lobby),
40+
LobbyData: api.CreateLobbyData(handler.cfg, lobby),
4141
})
4242
if err != nil {
4343
log.Printf("error templating robot page: %d\n", err)
@@ -76,7 +76,7 @@ func (handler *SSRHandler) ssrEnterLobby(writer http.ResponseWriter, request *ht
7676

7777
pageData = &lobbyPageData{
7878
BasePageConfig: handler.basePageConfig,
79-
LobbyData: api.CreateLobbyData(lobby),
79+
LobbyData: api.CreateLobbyData(handler.cfg, lobby),
8080
Translation: translation,
8181
Locale: locale,
8282
}

internal/frontend/lobby_test.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@ import (
44
"testing"
55

66
"github.com/scribble-rs/scribble.rs/internal/api"
7+
"github.com/scribble-rs/scribble.rs/internal/config"
78
"github.com/scribble-rs/scribble.rs/internal/game"
89
)
910

1011
func TestCreateLobby(t *testing.T) {
1112
t.Parallel()
1213

13-
data := api.CreateLobbyData(&game.Lobby{
14-
LobbyID: "TEST",
15-
})
14+
data := api.CreateLobbyData(
15+
&config.Default,
16+
&game.Lobby{
17+
LobbyID: "TEST",
18+
})
1619

1720
var previousSize uint8
1821
for _, suggestedSize := range data.SuggestedBrushSizes {

internal/frontend/templating_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func Test_templateLobbyPage(t *testing.T) {
2121
CacheBust: "lol",
2222
},
2323
LobbyData: &api.LobbyData{
24-
SettingBounds: game.LobbySettingBounds,
24+
SettingBounds: config.Default.LobbySettingBounds,
2525
},
2626
Translation: translations.DefaultTranslation,
2727
})

internal/game/lobby.go

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,31 +20,17 @@ import (
2020
"github.com/gofrs/uuid/v5"
2121
)
2222

23-
var (
24-
LobbySettingBounds = SettingBounds{
25-
MinDrawingTime: 60,
26-
MaxDrawingTime: 300,
27-
MinRounds: 1,
28-
MaxRounds: 20,
29-
MinMaxPlayers: 2,
30-
MaxMaxPlayers: 24,
31-
MinClientsPerIPLimit: 1,
32-
MaxClientsPerIPLimit: 24,
33-
MinCustomWordsPerTurn: 1,
34-
MaxCustomWordsPerTurn: 3,
35-
}
36-
SupportedLanguages = map[string]string{
37-
"english_gb": "English (GB)",
38-
"english": "English (US)",
39-
"italian": "Italian",
40-
"german": "German",
41-
"french": "French",
42-
"dutch": "Dutch",
43-
"ukrainian": "Ukrainian",
44-
"russian": "Russian",
45-
"polish": "Polish",
46-
}
47-
)
23+
var SupportedLanguages = map[string]string{
24+
"english_gb": "English (GB)",
25+
"english": "English (US)",
26+
"italian": "Italian",
27+
"german": "German",
28+
"french": "French",
29+
"dutch": "Dutch",
30+
"ukrainian": "Ukrainian",
31+
"russian": "Russian",
32+
"polish": "Polish",
33+
}
4834

4935
const (
5036
DrawingBoardBaseWidth = 1600
@@ -59,16 +45,16 @@ const (
5945
// SettingBounds defines the lower and upper bounds for the user-specified
6046
// lobby creation input.
6147
type SettingBounds struct {
62-
MinDrawingTime int `json:"minDrawingTime"`
63-
MaxDrawingTime int `json:"maxDrawingTime"`
64-
MinRounds int `json:"minRounds"`
65-
MaxRounds int `json:"maxRounds"`
66-
MinMaxPlayers int `json:"minMaxPlayers"`
67-
MaxMaxPlayers int `json:"maxMaxPlayers"`
68-
MinClientsPerIPLimit int `json:"minClientsPerIpLimit"`
69-
MaxClientsPerIPLimit int `json:"maxClientsPerIpLimit"`
70-
MinCustomWordsPerTurn int `json:"minCustomWordsPerTurn"`
71-
MaxCustomWordsPerTurn int `json:"maxCustomWordsPerTurn"`
48+
MinDrawingTime int `json:"minDrawingTime" env:"MIN_DRAWING_TIME"`
49+
MaxDrawingTime int `json:"maxDrawingTime" env:"MAX_DRAWING_TIME"`
50+
MinRounds int `json:"minRounds" env:"MIN_ROUNDS"`
51+
MaxRounds int `json:"maxRounds" env:"MAX_ROUNDS"`
52+
MinMaxPlayers int `json:"minMaxPlayers" env:"MIN_MAX_PLAYERS"`
53+
MaxMaxPlayers int `json:"maxMaxPlayers" env:"MAX_MAX_PLAYERS"`
54+
MinClientsPerIPLimit int `json:"minClientsPerIpLimit" env:"MIN_CLIENTS_PER_IP_LIMIT"`
55+
MaxClientsPerIPLimit int `json:"maxClientsPerIpLimit" env:"MAX_CLIENTS_PER_IP_LIMIT"`
56+
MinCustomWordsPerTurn int `json:"minCustomWordsPerTurn" env:"MIN_CUSTOM_WORDS_PER_TURN"`
57+
MaxCustomWordsPerTurn int `json:"maxCustomWordsPerTurn" env:"MAX_CUSTOM_WORDS_PER_TURN"`
7258
}
7359

7460
func (lobby *Lobby) HandleEvent(eventType string, payload []byte, player *Player) error {

0 commit comments

Comments
 (0)