forked from Argus-Labs/world-engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconfig.go
162 lines (131 loc) · 5.32 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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package cardinal
import (
"net"
"os"
"slices"
"strings"
"github.com/JeremyLoy/config"
"github.com/rotisserie/eris"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"pkg.world.dev/world-engine/rift/credentials"
)
const (
DefaultCardinalNamespace = "world-1"
DefaultCardinalLogLevel = "info"
DefaultRedisAddress = "localhost:6379"
DefaultBaseShardSequencerAddress = "localhost:9601"
)
var (
validLogLevels = []string{
zerolog.DebugLevel.String(),
zerolog.InfoLevel.String(),
zerolog.WarnLevel.String(),
zerolog.ErrorLevel.String(),
zerolog.Disabled.String(),
}
defaultConfig = WorldConfig{
CardinalNamespace: DefaultCardinalNamespace,
CardinalRollupEnabled: false,
CardinalLogPretty: false,
CardinalLogLevel: DefaultCardinalLogLevel,
RedisAddress: DefaultRedisAddress,
RedisPassword: "",
BaseShardSequencerAddress: DefaultBaseShardSequencerAddress,
BaseShardRouterKey: "",
TelemetryEnabled: false,
TelemetryStatsdAddress: "",
TelemetryTraceAddress: "",
}
)
type WorldConfig struct {
// CardinalNamespace The shard namespace for Cardinal. This needs to be unique to prevent signature replay attacks.
CardinalNamespace string `config:"CARDINAL_NAMESPACE"`
// CardinalRollupEnabled When true, Cardinal will sequence and recover to/from base shard.
CardinalRollupEnabled bool `config:"CARDINAL_ROLLUP_ENABLED"`
// CardinalLogLevel Determines the log level for Cardinal.
CardinalLogLevel string `config:"CARDINAL_LOG_LEVEL"`
// CardinalLogPretty Pretty logging, disable by default due to performance impact.
CardinalLogPretty bool `config:"CARDINAL_LOG_PRETTY"`
// RedisAddress The address of the redis server, supports unix sockets.
RedisAddress string `config:"REDIS_ADDRESS"`
// RedisPassword The password for the redis server. Make sure to use a password in production.
RedisPassword string `config:"REDIS_PASSWORD"`
// BaseShardSequencerAddress This is the address that Cardinal will use to sequence and recover to/from base shard.
BaseShardSequencerAddress string `config:"BASE_SHARD_SEQUENCER_ADDRESS"`
// BaseShardRouterKey is a token used to secure communications between the game shard and the base shard.
BaseShardRouterKey string `config:"BASE_SHARD_ROUTER_KEY"`
// TelemetryEnabled When true, Cardinal will send telemetry to a telemetry agent.
TelemetryEnabled bool `config:"TELEMETRY_ENABLED"`
// TelemetryStatsdAddress The address of a statsd metric agent that will collect stats from Cardinal.
TelemetryStatsdAddress string `config:"TELEMETRY_STATSD_ADDRESS"`
// TelemetryTraceAddress The address of an agent that supports the collection of traces (e.g. a DataDog agent).
TelemetryTraceAddress string `config:"TELEMETRY_TRACE_ADDRESS"`
}
func loadWorldConfig() (*WorldConfig, error) {
cfg := defaultConfig
if err := config.FromEnv().To(&cfg); err != nil {
return nil, eris.Wrap(err, "Failed to load config")
}
if err := cfg.Validate(); err != nil {
return nil, eris.Wrap(err, "Invalid config")
}
if err := cfg.setLogger(); err != nil {
return nil, eris.Wrap(err, "Failed to set log level")
}
return &cfg, nil
}
// Validate validates the config values.
// If CARDINAL_ROLLUP=true, the BASE_SHARD_SEQUENCER_ADDRESS and BASE_SHARD_ROUTER_KEY are required.
func (w *WorldConfig) Validate() error { //nolint:gocognit
// Validate Cardinal configs
if err := Namespace(w.CardinalNamespace).Validate(); err != nil {
return eris.Wrap(err, "CARDINAL_NAMESPACE is not a valid namespace")
}
if w.CardinalLogLevel == "" || !slices.Contains(validLogLevels, w.CardinalLogLevel) {
return eris.New("CARDINAL_LOG_LEVEL must be one of the following: " + strings.Join(validLogLevels, ", "))
}
// Validate Redis address
if _, _, err := net.SplitHostPort(w.RedisAddress); err != nil {
return eris.New("REDIS_ADDRESS must follow the format <host>:<port>")
}
// Validate base shard configs (only required when rollup mode is enabled)
if w.CardinalRollupEnabled {
if _, _, err := net.SplitHostPort(w.BaseShardSequencerAddress); err != nil {
return eris.Wrap(err, "BASE_SHARD_SEQUENCER_ADDRESS must follow the format <host>:<port>")
}
if w.BaseShardRouterKey == "" {
return eris.New("BASE_SHARD_ROUTER_KEY must be when rollup mode is enabled")
}
if err := credentials.ValidateKey(w.BaseShardRouterKey); err != nil {
return err
}
}
// Validate telemetry configs
if w.TelemetryEnabled { //nolint:nestif // better consistency and readability
if w.TelemetryStatsdAddress != "" {
if _, _, err := net.SplitHostPort(w.TelemetryStatsdAddress); err != nil {
return eris.New("TELEMETRY_STATSD_ADDRESS must follow the format <host>:<port>")
}
}
if w.TelemetryTraceAddress != "" {
if _, _, err := net.SplitHostPort(w.TelemetryTraceAddress); err != nil {
return eris.New("TELEMETRY_TRACE_ADDRESS must follow the format <host>:<port>")
}
}
}
return nil
}
func (w *WorldConfig) setLogger() error {
// Set global logger level
level, err := zerolog.ParseLevel(w.CardinalLogLevel)
if err != nil {
return eris.Wrap(err, "CARDINAL_LOG_LEVEL is not a valid log level")
}
zerolog.SetGlobalLevel(level)
// Override global logger to console writer if pretty logging is enabled
if w.CardinalLogPretty {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
}
return nil
}