diff --git a/backend/api/api.go b/backend/api/api.go index f273bd0..265c685 100644 --- a/backend/api/api.go +++ b/backend/api/api.go @@ -1,16 +1,12 @@ package api import ( - "fmt" - "log" "log/slog" "net/http" - "strconv" "github.com/HexCardGames/HexDeck/db" "github.com/HexCardGames/HexDeck/game" "github.com/HexCardGames/HexDeck/types" - "github.com/HexCardGames/HexDeck/utils" "github.com/gin-gonic/gin" ) @@ -37,10 +33,7 @@ type LeaveRoomRequest struct { SessionToken string } -func InitApi() { - server := gin.Default() - server.SetTrustedProxies(nil) - +func RegisterApi(server *gin.Engine) { server.GET("/api/stats", func(c *gin.Context) { stats := game.CalculateStats() c.JSON(http.StatusOK, StatsReply{ @@ -142,12 +135,4 @@ func InitApi() { // Handle WebSocket connections using Socket.io wsHandler := initWS() server.Any("/socket.io/", gin.WrapH(wsHandler)) - - listenHost := utils.Getenv("LISTEN_HOST", "0.0.0.0") - listenPort, err := strconv.Atoi(utils.Getenv("LISTEN_PORT", "3000")) - if err != nil { - log.Fatal("Value of variable PORT is not a valid integer!") - } - slog.Info(fmt.Sprintf("HexDeck server listening on http://%s:%d", listenHost, listenPort)) - server.Run(fmt.Sprintf("%s:%d", listenHost, listenPort)) } diff --git a/backend/api/static.go b/backend/api/static.go new file mode 100644 index 0000000..944b634 --- /dev/null +++ b/backend/api/static.go @@ -0,0 +1,26 @@ +package api + +import ( + "embed" + "net/http" + "strings" + + "github.com/gin-gonic/gin" +) + +func SPAMiddleware(fs embed.FS, prefix string, notFoundPath string) gin.HandlerFunc { + fileServer := http.FileServerFS(fs) + + return func(c *gin.Context) { + if strings.HasPrefix(c.Request.URL.Path, "/api/") { + c.Next() + return + } + c.Request.URL.Path = prefix + c.Request.URL.Path + _, err := fs.Open(c.Request.URL.Path) + if err != nil { + c.Request.URL.Path = prefix + notFoundPath + } + fileServer.ServeHTTP(c.Writer, c.Request) + } +} diff --git a/backend/main.go b/backend/main.go index ee2e420..3880635 100644 --- a/backend/main.go +++ b/backend/main.go @@ -1,16 +1,24 @@ package main import ( + "embed" + "fmt" + "log" "log/slog" "os" + "strconv" "time" "github.com/HexCardGames/HexDeck/api" "github.com/HexCardGames/HexDeck/db" "github.com/HexCardGames/HexDeck/game" "github.com/HexCardGames/HexDeck/utils" + "github.com/gin-gonic/gin" ) +//go:embed all:public/* +var public embed.FS + func main() { logHandler := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{ Level: slog.LevelDebug, @@ -39,5 +47,17 @@ func main() { } }() - api.InitApi() + server := gin.Default() + server.SetTrustedProxies(nil) + + api.RegisterApi(server) + server.Use(api.SPAMiddleware(public, "public", "/")) + + listenHost := utils.Getenv("LISTEN_HOST", "0.0.0.0") + listenPort, err := strconv.Atoi(utils.Getenv("LISTEN_PORT", "3000")) + if err != nil { + log.Fatal("Value of variable PORT is not a valid integer!") + } + slog.Info(fmt.Sprintf("HexDeck server listening on http://%s:%d", listenHost, listenPort)) + server.Run(fmt.Sprintf("%s:%d", listenHost, listenPort)) } diff --git a/backend/public/README.md b/backend/public/README.md new file mode 100644 index 0000000..6e6c3b1 --- /dev/null +++ b/backend/public/README.md @@ -0,0 +1,7 @@ +# Static Frontend Hosting + +All files in this directory will be merged into the server binary and served as static assets by the HexDeck server. + +When building with docker, the compiled frontend will be copied here automatically. + +If you are building manually, you can copy the contents of the `dist/client/` folder here after building the frontend.