-
Notifications
You must be signed in to change notification settings - Fork 186
/
config.go
130 lines (117 loc) · 4.19 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package config
import (
"fmt"
"log"
"os"
"reflect"
"strings"
"time"
"github.com/caarlos0/env/v10"
"github.com/subosito/gotenv"
)
type LobbySettingDefaults struct {
Public string `env:"PUBLIC"`
DrawingTime string `env:"DRAWING_TIME"`
Rounds string `env:"ROUNDS"`
MaxPlayers string `env:"MAX_PLAYERS"`
CustomWords string `env:"CUSTOM_WORDS"`
CustomWordsPerTurn string `env:"CUSTOM_WORDS_PER_TURN"`
ClientsPerIPLimit string `env:"CLIENTS_PER_IP_LIMIT"`
Language string `env:"LANGUAGE"`
}
type CORS struct {
AllowedOrigins []string `env:"ALLOWED_ORIGINS"`
AllowCredentials bool `env:"ALLOW_CREDENTIALS"`
}
type LobbyCleanup struct {
// Interval is the interval in which the cleanup routine will run. If set
// to `0`, the cleanup routine will be disabled.
Interval time.Duration `env:"INTERVAL"`
// PlayerInactivityThreshold is the time after which a player counts as
// inactivity and won't keep the lobby up. Note that cleaning up a lobby can
// therefore take up to Interval + PlayerInactivityThreshold.
PlayerInactivityThreshold time.Duration `env:"PLAYER_INACTIVITY_THRESHOLD"`
}
type Config struct {
// NetworkAddress is empty by default, since that implies listening on
// all interfaces. For development usecases, on windows for example, this
// is very annoying, as windows will nag you with firewall prompts.
NetworkAddress string `env:"NETWORK_ADDRESS"`
// RootPath is the path directly after the domain and before the
// scribblers paths. For example if you host scribblers on painting.com
// but already host a different website on that domain, then your API paths
// might have to look like this: painting.com/scribblers/v1
RootPath string `env:"ROOT_PATH"`
CPUProfilePath string `env:"CPU_PROFILE_PATH"`
// LobbySettingDefaults is used for the server side rendering of the lobby
// creation page. It doesn't affect the default values of lobbies created
// via the API.
LobbySettingDefaults LobbySettingDefaults `envPrefix:"LOBBY_SETTING_DEFAULTS_"`
Port uint16 `env:"PORT"`
CORS CORS `envPrefix:"CORS_"`
LobbyCleanup LobbyCleanup `envPrefix:"LOBBY_CLEANUP_"`
}
var Default = Config{
Port: 8080,
LobbySettingDefaults: LobbySettingDefaults{
Public: "false",
DrawingTime: "120",
Rounds: "4",
MaxPlayers: "12",
CustomWordsPerTurn: "3",
ClientsPerIPLimit: "1",
Language: "english",
},
CORS: CORS{
AllowedOrigins: []string{"*"},
AllowCredentials: false,
},
LobbyCleanup: LobbyCleanup{
Interval: 90 * time.Second,
PlayerInactivityThreshold: 75 * time.Second,
},
}
// Load loads the configuration from the environment. If a .env file is
// available, it will be loaded as well. Values found in the environment
// will overwrite whatever is load from the .env file.
func Load() (*Config, error) {
envVars := make(map[string]string)
dotEnvPath := ".env"
if _, err := os.Stat(dotEnvPath); err != nil {
if !os.IsNotExist(err) {
return nil, fmt.Errorf("error checking for existence of .env file: %w", err)
}
} else {
envFileContent, err := gotenv.Read(dotEnvPath)
if err != nil {
return nil, fmt.Errorf("error reading .env file: %w", err)
}
for key, value := range envFileContent {
envVars[key] = value
}
}
// Add local environment variables to EnvVars map
for _, keyValuePair := range os.Environ() {
pair := strings.SplitN(keyValuePair, "=", 2)
// For some reason, gitbash can contain the variable `=::=::\` which
// gives us a pair where the first entry is empty.
if pair[0] == "" {
continue
}
envVars[pair[0]] = pair[1]
}
config := Default
if err := env.ParseWithOptions(&config, env.Options{
Environment: envVars,
OnSet: func(key string, value any, isDefault bool) {
if !reflect.ValueOf(value).IsZero() {
log.Printf("Setting '%s' to '%v' (isDefault: %v)\n", key, value, isDefault)
}
},
}); err != nil {
return nil, fmt.Errorf("error parsing environment variables: %w", err)
}
// Prevent user error and let the code decide when we need slashes.
config.RootPath = strings.Trim(config.RootPath, "/")
return &config, nil
}