aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--backend/config.go3
-rw-r--r--backend/router.go45
-rw-r--r--go.mod4
-rw-r--r--main.go39
5 files changed, 89 insertions, 3 deletions
diff --git a/.gitignore b/.gitignore
index 284ed34..5f15817 100644
--- a/.gitignore
+++ b/.gitignore
@@ -156,3 +156,4 @@ go.work.sum
# env file
.idea
+public
diff --git a/backend/config.go b/backend/config.go
new file mode 100644
index 0000000..b7624fd
--- /dev/null
+++ b/backend/config.go
@@ -0,0 +1,3 @@
+package backend
+
+type Config struct{}
diff --git a/backend/router.go b/backend/router.go
index 6c7f9f8..4c3b2f8 100644
--- a/backend/router.go
+++ b/backend/router.go
@@ -1,7 +1,10 @@
package backend
import (
+ "embed"
+ "io/fs"
"net/http"
+ "strings"
"time"
"github.com/go-chi/chi/v5"
@@ -22,3 +25,45 @@ func NewRouter() *chi.Mux {
})
return r
}
+
+// httpEmbedFS is an implementation of fs.FS, fs.ReadDirFS and fs.ReadFileFS helping to manage embed.FS for http server
+type httpEmbedFS struct {
+ embed.FS
+ prefix string
+}
+
+func (h *httpEmbedFS) Open(name string) (fs.File, error) {
+ return h.FS.Open(h.prefix + "/" + name)
+}
+
+func (h *httpEmbedFS) ReadFile(name string) ([]byte, error) {
+ return h.FS.ReadFile(h.prefix + "/" + name)
+}
+
+func (h *httpEmbedFS) ReadDir(name string) ([]fs.DirEntry, error) {
+ return h.FS.ReadDir(h.prefix + "/" + name)
+}
+
+// UsableEmbedFS converts embed.FS into usable fs.FS by Golatt
+//
+// folder may not finish or start with a slash (/)
+func UsableEmbedFS(folder string, em embed.FS) fs.FS {
+ return &httpEmbedFS{
+ prefix: folder,
+ FS: em,
+ }
+}
+
+func HandleStaticFiles(r *chi.Mux, path string, root fs.FS) {
+ if path != "/" && path[len(path)-1] != '/' {
+ r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP)
+ path += "/"
+ }
+ path += "*"
+
+ r.Get(path, func(w http.ResponseWriter, r *http.Request) {
+ ctx := chi.RouteContext(r.Context())
+ pathPrefix := strings.TrimSuffix(ctx.RoutePattern(), "/*")
+ http.StripPrefix(pathPrefix, http.FileServerFS(root)).ServeHTTP(w, r)
+ })
+}
diff --git a/go.mod b/go.mod
index 38c749b..a5ede82 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,6 @@ module git.anhgelus.world/anhgelus/small-world
go 1.25.1
require (
- github.com/go-chi/chi/v5 v5.2.3 // indirect
- github.com/joho/godotenv v1.5.1 // indirect
+ github.com/go-chi/chi/v5 v5.2.3
+ github.com/joho/godotenv v1.5.1
)
diff --git a/main.go b/main.go
index a277761..2d943cd 100644
--- a/main.go
+++ b/main.go
@@ -2,28 +2,65 @@ package main
import (
"context"
+ "embed"
"errors"
+ "flag"
+ "fmt"
"log/slog"
"net/http"
"os"
"os/signal"
+ "strconv"
"syscall"
"git.anhgelus.world/anhgelus/small-world/backend"
"github.com/joho/godotenv"
)
+//go:embed dist
+var embeds embed.FS
+
+var (
+ configFile = "config.toml"
+ port = 8000
+ publicDir = "public"
+)
+
func init() {
err := godotenv.Load(".env")
if err != nil && !errors.Is(err, os.ErrNotExist) {
slog.Error("loading .env", "error", err)
}
+
+ if v := os.Getenv("CONFIG_FILE"); v != "" {
+ configFile = v
+ }
+ flag.StringVar(&configFile, "config", configFile, "config file")
+
+ if v := os.Getenv("PORT"); v != "" {
+ port, err = strconv.Atoi(v)
+ if err != nil {
+ panic(err)
+ }
+ }
+ flag.IntVar(&port, "port", port, "server port")
+
+ if v := os.Getenv("PUBLIC_DIR"); v != "" {
+ publicDir = v
+ }
+ flag.StringVar(&publicDir, "public", publicDir, "public directory")
}
+
func main() {
+ flag.Parse()
+
r := backend.NewRouter()
+ backend.HandleStaticFiles(r, "/assets", backend.UsableEmbedFS("dist", embeds))
+ backend.HandleStaticFiles(r, "/static", os.DirFS(publicDir))
+
slog.Info("starting http server")
- server := &http.Server{Addr: ":8000", Handler: r}
+ server := &http.Server{Addr: fmt.Sprintf(":%d", port), Handler: r}
errChan := make(chan error)
go startServer(server, errChan)