Skip to content

Commit aa09e5a

Browse files
committed
ref: refactor the server code to be a bit more maintainable
Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>
1 parent 857208b commit aa09e5a

1 file changed

Lines changed: 105 additions & 35 deletions

File tree

src/server.go

Lines changed: 105 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package main
22

33
import (
4-
"fmt"
4+
"html/template"
55
"net/http"
66
"os"
77
"time"
@@ -11,87 +11,157 @@ import (
1111

1212
type server struct {
1313
config *appConfig
14+
mux *http.ServeMux
15+
tmpl *template.Template
1416
}
1517

18+
// TemplateData holds all the data needed for the HTML template
19+
type TemplateData struct {
20+
ApplicationName string
21+
ApplicationVersion string
22+
ApplicationMessage string
23+
Color string
24+
Alive bool
25+
Ready bool
26+
RootDelaySeconds int
27+
StartUpDelaySeconds int
28+
TearDownDelaySeconds int
29+
LogToFileOnly bool
30+
ProcessID int
31+
UserID int
32+
Hostname string
33+
CatImageURL string
34+
}
35+
36+
const htmlTemplate = `<!DOCTYPE html>
37+
<html>
38+
<head>
39+
<title>{{.ApplicationName}} {{.ApplicationVersion}}</title>
40+
</head>
41+
<body style='background-color:{{.Color}};'>
42+
<h1>{{.ApplicationName}}</h1>
43+
44+
<h2>Configuration</h2>
45+
Application Version: {{.ApplicationVersion}}<br>
46+
Application Message: {{.ApplicationMessage}}<br>
47+
Application Liveness: {{.Alive}}<br>
48+
Application Readiness: {{.Ready}}<br>
49+
Delay seconds of root endpoint ('/'): {{.RootDelaySeconds}}<br>
50+
Seconds the application needs to start up: {{.StartUpDelaySeconds}}<br>
51+
Seconds the application needs to shut down gracefully: {{.TearDownDelaySeconds}}<br>
52+
Only log to file: {{.LogToFileOnly}}<br>
53+
54+
<h2>Tech Details</h2>
55+
Process Id of the application: {{.ProcessID}}<br>
56+
User Id the application is using: {{.UserID}}<br>
57+
Hostname: {{.Hostname}}<br>
58+
59+
{{if .CatImageURL}}
60+
<h2>The cute cat</h2>
61+
<img src='{{.CatImageURL}}' width='500px'></img>
62+
{{end}}
63+
</body>
64+
</html>`
65+
1666
func newServer(appConfig *appConfig) *server {
67+
// Parse the HTML template
68+
tmpl, err := template.New("index").Parse(htmlTemplate)
69+
if err != nil {
70+
log.Fatalf("Failed to parse template: %v", err)
71+
}
72+
73+
// Create a new ServeMux
74+
mux := http.NewServeMux()
1775

1876
server := &server{
1977
config: appConfig,
78+
mux: mux,
79+
tmpl: tmpl,
2080
}
2181

22-
http.HandleFunc("/", server.handleRoot)
23-
http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
24-
http.NotFound(w, r)
25-
})
26-
http.HandleFunc("/liveness", server.handleLiveness)
27-
http.HandleFunc("/readiness", server.handleReadiness)
82+
// Register handlers with the mux
83+
mux.HandleFunc("/", server.handleRoot)
84+
mux.HandleFunc("/favicon.ico", server.handleFavicon)
85+
mux.HandleFunc("/liveness", server.handleLiveness)
86+
mux.HandleFunc("/readiness", server.handleReadiness)
2887

2988
return server
3089
}
3190

3291
func (s *server) run() {
33-
err := http.ListenAndServe(":8080", nil)
92+
err := http.ListenAndServe(":8080", s.mux)
3493
if err != nil {
3594
log.Errorf("Error on starting the server: '%s'", err)
3695
}
3796
}
3897

3998
func (s *server) handleRoot(w http.ResponseWriter, r *http.Request) {
4099
log.Info("Request to root endpoint ('/')")
100+
41101
if !s.config.rootEnabled {
42102
w.WriteHeader(http.StatusServiceUnavailable)
43103
log.Info("Root endpoint ('/') responded with Status Code 503 Service Unavailable due to root endpoint is disabled")
44-
} else {
104+
return
105+
}
106+
107+
// Handle delay if configured
45108
if s.config.rootDelaySeconds > 0 {
46109
for i := 0; i < s.config.rootDelaySeconds; i++ {
47110
log.Infof("Delayed Response for %d of %d seconds", i+1, s.config.rootDelaySeconds)
48111
time.Sleep(1 * time.Second)
49112
}
50113
log.Info("Finished delaying Response")
51114
}
52-
w.Header().Set("Content-Type", "text/html")
53-
fmt.Fprint(w, "<!DOCTYPE html><htlml>")
54-
fmt.Fprintf(w, "<head><title>%s %s</title></head>", s.config.applicationName, s.config.applicationVersion)
55-
fmt.Fprintf(w, "<body style='background-color:%s;'>", s.config.color)
56-
fmt.Fprintf(w, "<h1>%s</h1>", s.config.applicationName)
57-
fmt.Fprint(w, "<h2>Configuration</h2>")
58-
fmt.Fprintf(w, "Application Version: %s<br>", s.config.applicationVersion)
59-
fmt.Fprintf(w, "Application Message: %s<br>", s.config.applicationMessage)
60-
fmt.Fprintf(w, "Application Liveness: %t<br>", s.config.alive)
61-
fmt.Fprintf(w, "Application Readiness: %t<br>", s.config.ready)
62-
fmt.Fprintf(w, "Delay seconds of root endpoint ('/'): %d<br>", s.config.rootDelaySeconds)
63-
fmt.Fprintf(w, "Seconds the application needs to start up: %d<br>", s.config.startUpDelaySeconds)
64-
fmt.Fprintf(w, "Seconds the application needs to shut down gracefuly: %d<br>", s.config.tearDownDelaySeconds)
65-
fmt.Fprintf(w, "Only log to file: %v<br>", s.config.logToFileOnly)
66-
67-
fmt.Fprint(w, "<h2>Tech Details</h2>")
68-
fmt.Fprintf(w, "Process Id of the application: %d<br>", os.Getpid())
69-
fmt.Fprintf(w, "User Id the application is using: %d<br>", os.Getuid())
70-
hostName, _ := os.Hostname()
71-
fmt.Fprintf(w, "Hostname: %s<br>", hostName)
72-
73-
if s.config.catImageUrl != "" {
74-
fmt.Fprint(w, "<h2>The cute cat</h2>")
75-
fmt.Fprintf(w, "<img src='%s' width='500px'></img>", s.config.catImageUrl)
115+
116+
// Get hostname
117+
hostname, _ := os.Hostname()
118+
119+
// Prepare template data
120+
data := TemplateData{
121+
ApplicationName: s.config.applicationName,
122+
ApplicationVersion: s.config.applicationVersion,
123+
ApplicationMessage: s.config.applicationMessage,
124+
Color: s.config.color,
125+
Alive: s.config.alive,
126+
Ready: s.config.ready,
127+
RootDelaySeconds: s.config.rootDelaySeconds,
128+
StartUpDelaySeconds: s.config.startUpDelaySeconds,
129+
TearDownDelaySeconds: s.config.tearDownDelaySeconds,
130+
LogToFileOnly: s.config.logToFileOnly,
131+
ProcessID: os.Getpid(),
132+
UserID: os.Getuid(),
133+
Hostname: hostname,
134+
CatImageURL: s.config.catImageUrl,
76135
}
77136

78-
fmt.Fprint(w, "</body></htlml>")
137+
// Set content type and execute template
138+
w.Header().Set("Content-Type", "text/html")
139+
if err := s.tmpl.Execute(w, data); err != nil {
140+
log.Errorf("Error executing template: %v", err)
141+
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
142+
return
143+
}
79144
}
145+
146+
func (s *server) handleFavicon(w http.ResponseWriter, r *http.Request) {
147+
http.NotFound(w, r)
80148
}
81149

82150
func (s *server) handleLiveness(w http.ResponseWriter, r *http.Request) {
83151
log.Info("Request to liveness endpoint ('/liveness')")
152+
84153
if s.config.alive {
85154
w.WriteHeader(http.StatusOK)
86155
log.Info("Liveness endpoint ('/liveness') responded with Status Code 200 OK")
87156
} else {
88157
w.WriteHeader(http.StatusInternalServerError)
89-
log.Info("Liveness endpoint ('/liveness') responded with Status Code 503 Service Unavailable")
158+
log.Info("Liveness endpoint ('/liveness') responded with Status Code 500 Internal Server Error")
90159
}
91160
}
92161

93162
func (s *server) handleReadiness(w http.ResponseWriter, r *http.Request) {
94163
log.Info("Request to readiness endpoint ('/readiness')")
164+
95165
if s.config.ready {
96166
w.WriteHeader(http.StatusOK)
97167
log.Info("Readiness endpoint ('/readiness') responded with Status Code 200 OK")

0 commit comments

Comments
 (0)