Commit d6a1b00ffaccf48b2dadec0ec39ea4ecec68c561

Parents: f2c095dba7872cf11e807d21ccf6b1e3f01ebe10

From: Moritz Poldrack <git@moritz.sh>
Date: Sat Jan 27 00:06:56 2024 +0700

http: add basic HTTP server
This makes the UI significantly easier to see.

Stats

internal/config/config.go +1/-0
internal/server/serve.go +15/-0
internal/server/type.go +26/-0
main.go +20/-1
ui/embed.go +6/-0

Changeset

  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
diff --git a/internal/config/config.go b/internal/config/config.go
index e9048b0b08c811b54a76ec89ee101e5ea6df3792..916b3ea411248939e8aad30990a58cc786dc8bfc 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -7,6 +7,7 @@ import "github.com/caarlos0/env/v10"
 
 type Cfg struct {
 	Database string `env:"DATABASE"`
+	Port     int    `env:"PORT" envDefault:"80"`
 }
 
 func init() {
diff --git a/internal/server/serve.go b/internal/server/serve.go
new file mode 100644
index 0000000000000000000000000000000000000000..fbfab30673202bae7db957359f4856d4bf22822c
--- /dev/null
+++ b/internal/server/serve.go
@@ -0,0 +1,15 @@
+package server
+
+import (
+	"net/http"
+	"strings"
+)
+
+func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	path := strings.TrimPrefix(r.URL.Path, "/")
+	if path == "" {
+		path = "index.html"
+	}
+
+	http.FileServer(s.ui).ServeHTTP(w, r)
+}
diff --git a/internal/server/type.go b/internal/server/type.go
new file mode 100644
index 0000000000000000000000000000000000000000..d31fb0918bf3150ce3f38a3d95f55740c426a28f
--- /dev/null
+++ b/internal/server/type.go
@@ -0,0 +1,26 @@
+package server
+
+import (
+	"fmt"
+	"io/fs"
+	"net/http"
+
+	"mpldr.codes/4wd/internal/datastore"
+	"mpldr.codes/4wd/ui"
+)
+
+type Server struct {
+	data datastore.Interface
+	ui   http.FileSystem
+}
+
+func New(data datastore.Interface) *Server {
+	uifs, err := fs.Sub(ui.FS, "dist")
+	if err != nil {
+		panic(fmt.Sprintf("failed to get subdirectory: %v", err))
+	}
+	return &Server{
+		data: data,
+		ui:   http.FS(uifs),
+	}
+}
diff --git a/main.go b/main.go
index 2c5cbfe33362120a3392c4c63f465d4ecd9238fc..999fcab21ba22cc418ca0708e6223c11f7c07dc0 100644
--- a/main.go
+++ b/main.go
@@ -4,14 +4,19 @@ // SPDX-FileCopyrightText: © Moritz Poldrack & AUTHORS
 // SPDX-License-Identifier: EUPL-1.2
 
 import (
+	"errors"
 	"fmt"
+	"net/http"
 	"net/url"
 	"os"
 
 	"mpldr.codes/4wd/internal/config"
 	"mpldr.codes/4wd/internal/datastore"
 	"mpldr.codes/4wd/internal/datastore/sqlite"
+	"mpldr.codes/4wd/internal/server"
 )
+
+var exitCode int
 
 func main() {
 	var db datastore.Interface
@@ -32,6 +37,20 @@ 		fmt.Printf("failed to open database: %v\n", err)
 		os.Exit(1)
 	}
 
-	for {
+	srv := http.Server{
+		Addr:    fmt.Sprintf(":%d", config.Config.Port),
+		Handler: server.New(db),
+	}
+	err = srv.ListenAndServe()
+
+	if err != nil && !errors.Is(err, http.ErrServerClosed) {
+		exitCode = 1
+		fmt.Printf("failed to start server: %v\n", err)
 	}
+	err = db.Close()
+	if err != nil {
+		exitCode = 1
+		fmt.Printf("failed to close database: %v\n", err)
+	}
+	os.Exit(exitCode)
 }
diff --git a/ui/embed.go b/ui/embed.go
new file mode 100644
index 0000000000000000000000000000000000000000..b07fcf89c5fe8ccf88e6e5017aba4a33c519d284
--- /dev/null
+++ b/ui/embed.go
@@ -0,0 +1,6 @@
+package ui
+
+import "embed"
+
+//go:embed dist
+var FS embed.FS