/
root.go
147 lines (132 loc) · 3.77 KB
/
root.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
package gate
import (
"errors"
"fmt"
"math"
"os"
"strings"
"github.com/go-logr/logr"
"github.com/go-logr/zapr"
"github.com/spf13/viper"
"github.com/urfave/cli/v2"
"go.minekube.com/gate/pkg/gate"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// Execute runs App() and calls os.Exit when finished.
func Execute() {
if err := App().Run(os.Args); err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
os.Exit(0)
}
func App() *cli.App {
app := cli.NewApp()
app.Name = "gate"
app.Usage = "Gate is an extensible Minecraft proxy."
app.Description = `A high performant & paralleled Minecraft proxy server with
scalability, flexibility & excelled server version support.
Visit the website https://gate.minekube.com/ for more information.`
var (
debug bool
configFile string
verbosity int
)
app.Flags = []cli.Flag{
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Usage: `config file (default: ./config.yml) Supports: yaml, json, env`,
EnvVars: []string{"GATE_CONFIG"},
Destination: &configFile,
},
&cli.BoolFlag{
Name: "debug",
Aliases: []string{"d"},
Usage: "Enable debug mode and highest log verbosity",
Destination: &debug,
EnvVars: []string{"GATE_DEBUG"},
},
&cli.IntFlag{
Name: "verbosity",
Aliases: []string{"v"},
Usage: "The higher the verbosity the more logs are shown",
EnvVars: []string{"GATE_VERBOSITY"},
Destination: &verbosity,
},
}
app.Action = func(c *cli.Context) error {
// Init viper
v, err := initViper(c, configFile)
if err != nil {
return cli.Exit(err, 1)
}
// Load config
cfg, err := gate.LoadConfig(v)
if err != nil {
// A config file is only required to exist when explicit config flag was specified.
// Otherwise, we just use the default config.
if !(errors.As(err, &viper.ConfigFileNotFoundError{}) || os.IsNotExist(err)) || c.IsSet("config") {
err = fmt.Errorf("error reading config file %q: %w", v.ConfigFileUsed(), err)
return cli.Exit(err, 2)
}
}
// Flags overwrite config
debug = debug || cfg.Editions.Java.Config.Debug
cfg.Editions.Java.Config.Debug = debug
if !c.IsSet("verbosity") && debug {
verbosity = math.MaxInt8
}
// Create logger
log, err := newLogger(debug, verbosity)
if err != nil {
return cli.Exit(fmt.Errorf("error creating zap logger: %w", err), 1)
}
c.Context = logr.NewContext(c.Context, log)
log.Info("logging verbosity", "verbosity", verbosity)
log.Info("using config file", "config", v.ConfigFileUsed())
// Start Gate
if err = gate.Start(c.Context,
gate.WithConfig(*cfg),
gate.WithAutoConfigReload(v.ConfigFileUsed()),
); err != nil {
return cli.Exit(fmt.Errorf("error running Gate: %w", err), 1)
}
return nil
}
return app
}
func initViper(c *cli.Context, configFile string) (*viper.Viper, error) {
v := gate.Viper
if c.IsSet("config") {
v.SetConfigFile(configFile)
} else {
v.SetConfigName("config")
v.AddConfigPath(".")
}
// Load Environment Variables
v.SetEnvPrefix("GATE")
v.AutomaticEnv() // read in environment variables that match
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
return v, nil
}
// newLogger returns a new zap logger with a modified production
// or development default config to ensure human readability.
func newLogger(debug bool, v int) (l logr.Logger, err error) {
var cfg zap.Config
if debug {
cfg = zap.NewDevelopmentConfig()
} else {
cfg = zap.NewProductionConfig()
}
cfg.Level = zap.NewAtomicLevelAt(zapcore.Level(-v))
cfg.Encoding = "console"
cfg.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
zl, err := cfg.Build()
if err != nil {
return logr.Discard(), err
}
return zapr.NewLogger(zl), nil
}