-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmain.go
More file actions
161 lines (140 loc) · 4.18 KB
/
Copy pathmain.go
File metadata and controls
161 lines (140 loc) · 4.18 KB
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
package main
import (
"embed"
"flag"
"fmt"
"io/fs"
"log/slog"
"os"
"os/signal"
"strings"
"syscall"
"github.com/tsaarni/echoserver/server"
)
const (
defaultHTTPAddr = ":8080"
defaultHTTPSAddr = ":8443"
)
type Config struct {
Live bool
HTTPAddr string
HTTPSAddr string
CertFile string
KeyFile string
KeyLogFile string
LogLevel string
}
var (
//go:embed apps/*
staticFiles embed.FS
// File system object to serve either live files from parsedStaticFiles or embedded files.
files fs.FS
// Environment variables used as context info in the echo response.
envContext map[string]string
)
func newConfig() *Config {
live := flag.Bool("live", false, "Serve live static files")
httpAddr := flag.String("http-addr", "", "Address to bind the HTTP server socket")
httpsAddr := flag.String("https-addr", "", "Address to bind the HTTPS server socket")
certFile := flag.String("tls-cert-file", "", "Path to TLS certificate file")
keyFile := flag.String("tls-key-file", "", "Path to TLS key file")
logLevel := flag.String("log-level", "", "Log level (debug, info, warn, error, none)")
flag.Usage = func() {
fmt.Fprintln(os.Stderr, "Usage:")
flag.PrintDefaults()
fmt.Fprintf(os.Stderr, "\nEnvironment variables:\n")
fmt.Fprintf(os.Stderr, " HTTP_ADDR\n\tAddress to bind the HTTP server socket\n")
fmt.Fprintf(os.Stderr, " HTTPS_ADDR\n\tAddress to bind the HTTPS server socket\n")
fmt.Fprintf(os.Stderr, " TLS_CERT_FILE\n\tPath to TLS certificate file\n")
fmt.Fprintf(os.Stderr, " TLS_KEY_FILE\n\tPath to TLS key file\n")
fmt.Fprintf(os.Stderr, " ENV_*\n\tEnvironment variables to be used as context info in the echo response\n")
fmt.Fprintf(os.Stderr, " SSLKEYLOGFILE\n\tPath to write the TLS master secret log file\n")
}
flag.Parse()
getEnv := func(key, flagValue, defaultValue string) string {
if flagValue != "" {
return flagValue
}
if value, exists := os.LookupEnv(key); exists {
return value
}
return defaultValue
}
return &Config{
Live: *live,
HTTPAddr: getEnv("HTTP_ADDR", *httpAddr, defaultHTTPAddr),
HTTPSAddr: getEnv("HTTPS_ADDR", *httpsAddr, defaultHTTPSAddr),
CertFile: getEnv("TLS_CERT_FILE", *certFile, ""),
KeyFile: getEnv("TLS_KEY_FILE", *keyFile, ""),
KeyLogFile: os.Getenv("SSLKEYLOGFILE"),
LogLevel: getEnv("LOG_LEVEL", *logLevel, "debug"),
}
}
func parseLogLevel(level *string) slog.Level {
if level == nil {
return slog.LevelInfo
}
switch strings.ToLower(*level) {
case "debug":
return slog.LevelDebug
case "info":
return slog.LevelInfo
case "warn", "warning":
return slog.LevelWarn
case "error":
return slog.LevelError
case "none":
return slog.Level(999) // Higher than any defined level.
default:
slog.Warn("Unknown log level, defaulting to info", "log-level", *level)
return slog.LevelInfo
}
}
func setupFilesystem(live bool) {
if live {
slog.Info("Serving live static files")
files = os.DirFS("./apps")
} else {
slog.Info("Serving embedded static files")
files, _ = fs.Sub(staticFiles, "apps")
}
}
// parseEnvContext reads environment variables that start with "ENV_" and stores them to be used
// as context info in the echo response.
func parseEnvContext() {
const prefix = "ENV_"
env := map[string]string{}
var envLog []any
for _, e := range os.Environ() {
if strings.HasPrefix(e, prefix) {
pair := strings.SplitN(e, "=", 2)
env[pair[0]] = pair[1]
envLog = append(envLog, pair[0], pair[1])
}
}
if len(env) > 0 {
envContext = env
slog.Info("Environment context", envLog...)
}
}
func main() {
config := newConfig()
slog.SetLogLoggerLevel(parseLogLevel(&config.LogLevel))
setupFilesystem(config.Live)
parseEnvContext()
stop, errChan, err := server.Start(files, envContext, config.HTTPAddr, config.HTTPSAddr, config.CertFile, config.KeyFile, config.KeyLogFile)
if err != nil {
slog.Error("Failed to start servers", "error", err)
os.Exit(1)
}
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
// Block until a signal is received or an error occurs.
select {
case <-errChan:
slog.Error("Server error, shutting down")
case sig := <-sigCh:
slog.Info("Signal received, shutting down", "signal", sig)
stop()
}
}