Merge branch 'dev' into feature/game-view

This commit is contained in:
2025-03-11 18:54:03 +01:00
9 changed files with 137 additions and 23 deletions

20
Dockerfile Normal file
View File

@ -0,0 +1,20 @@
FROM node:23-alpine AS frontend
WORKDIR /frontend
COPY frontend/package*.json /frontend
RUN npm ci
RUN npm i @tailwindcss/oxide-linux-x64-musl
COPY frontend/ /frontend
RUN npm run build
FROM golang:1.24-alpine AS backend
WORKDIR /backend
COPY backend/go.* /backend/
RUN go mod download
COPY backend/ /backend
COPY --from=frontend /frontend/dist/client/ /backend/public/
RUN go build -o HexDeck
FROM scratch
WORKDIR /app
COPY --from=backend /backend/HexDeck .
CMD ["/app/HexDeck"]

1
backend/.dockerignore Normal file
View File

@ -0,0 +1 @@
HexDeck

View File

@ -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))
}

26
backend/api/static.go Normal file
View File

@ -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)
}
}

View File

@ -70,13 +70,22 @@ func (conn *DatabaseConnection) QueryGlobalStats() GlobalStatsCollection {
return stats
}
func CreateDBConnection(uri string) DatabaseConnection {
client, _ := mongo.Connect(options.Client().ApplyURI(uri))
return DatabaseConnection{client}
func CreateDBConnection(uri string) *DatabaseConnection {
client, err := mongo.Connect(options.Client().ApplyURI(uri))
if err != nil {
slog.Error("MongoDB connection failed", "error", err)
return nil
}
return &DatabaseConnection{client}
}
var Conn DatabaseConnection
func InitDB(uri string) {
Conn = CreateDBConnection(uri)
func InitDB(uri string) bool {
dbConn := CreateDBConnection(uri)
if dbConn == nil {
return false
}
Conn = *dbConn
return true
}

View File

@ -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,
@ -22,7 +30,11 @@ func main() {
slog.Error("MONGO_URI environment variable not set!")
return
}
db.InitDB(mongoUri)
ok := db.InitDB(mongoUri)
if !ok {
slog.Error("Initializing MongoDB database failed")
return
}
game.LoadRooms()
roomTicker := time.NewTicker(1 * time.Second)
@ -35,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))
}

7
backend/public/README.md Normal file
View File

@ -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.

16
docker-compose.yml Normal file
View File

@ -0,0 +1,16 @@
services:
mongodb:
user: "1000"
volumes:
- ./data/mongodb/:/data/db/
image: mongodb/mongodb-community-server:latest
command: mongod --bind_ip_all
hexdeck:
user: "1000"
ports:
- 3000:3000
environment:
- MONGO_URI=mongodb://mongodb:27017/
depends_on:
- mongodb
build: .

26
frontend/.dockerignore Normal file
View File

@ -0,0 +1,26 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
.routify/*
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?