refactor: extract shared player, session, and chat packages #5

Merged
ryan merged 14 commits from refactor/shared-player-session-chat into main 2026-03-03 08:50:13 +00:00
14 changed files with 64 additions and 109 deletions
Showing only changes of commit 6d43bdea16 - Show all commits

View File

@@ -1,45 +0,0 @@
Create a new Gitea release for this project using semantic versioning.
## Current state
Fetch tags and find the latest version:
```
!git fetch --tags && git tag --sort=-v:refname | head -5
```
Commits since the last release (if no tags exist, this shows all commits):
```
!git log $(git describe --tags --abbrev=0 2>/dev/null && echo "$(git describe --tags --abbrev=0)..HEAD" || echo "") --oneline
```
## Instructions
1. **Determine current version** from the tag output above. If no `vX.Y.Z` tags exist, treat current version as `v0.0.0`.
2. **Analyze commits** using conventional commit prefixes to pick the semver bump:
- Breaking changes (`!` after type, or `BREAKING CHANGE` in body) → **major** bump
- `feat:`**minor** bump
- `fix:`, `chore:`, `deps:`, `revert:`, and everything else → **patch** bump
- Use the **highest** applicable bump level across all commits
3. **Generate release notes** — group commits into sections:
- **Features** — `feat:` commits
- **Fixes** — `fix:` commits
- **Other** — everything else (`chore:`, `deps:`, `revert:`, etc.)
- Omit empty sections. Each commit is a bullet point with its short description (strip the prefix).
4. **Present for approval** — show the user:
- Current version → proposed new version
- The full release notes
- The exact `tea` command that will run
- Ask the user to confirm before proceeding
5. **Create the release** — on user approval, run:
```
tea releases create --login gitea --repo ryan/c4 --tag <version> --target main -t "<version>" -n "<release notes>"
```
Do NOT create a local git tag — Gitea creates it server-side.
6. **Verify** — run `tea releases ls --login gitea --repo ryan/c4` to confirm the release was created.

View File

@@ -1,10 +1,10 @@
c4
c4.db
games
games.db
data/
deploy/
.env
.git
.gitignore
assets/css/output.css
c4-deploy-*.tar.gz
c4-deploy-*_b64*.txt
games-deploy-*.tar.gz
games-deploy-*_b64*.txt

View File

@@ -1,8 +1,8 @@
# Log level (TRACE, DEBUG, INFO, WARN, ERROR). Defaults to INFO.
# LOG_LEVEL=DEBUG
# SQLite database path. Defaults to data/c4.db.
# DB_PATH=data/c4.db
# SQLite database path. Defaults to data/games.db.
# DB_PATH=data/games.db
# Application URL for invite links. Defaults to https://games.adriatica.io.
# APP_URL=http://localhost:7331
@@ -12,5 +12,5 @@
# Goose CLI migration config (only needed for running goose manually)
GOOSE_DRIVER=sqlite3
GOOSE_DBSTRING=data/c4.db?_pragma=foreign_keys(1)&_pragma=journal_mode(WAL)
GOOSE_DBSTRING=data/games.db?_pragma=foreign_keys(1)&_pragma=journal_mode(WAL)
GOOSE_MIGRATION_DIR=db/migrations

View File

@@ -6,7 +6,7 @@ on:
pull_request:
env:
DEPLOY_DIR: /home/ryan/c4
DEPLOY_DIR: /home/ryan/games
jobs:
test:

View File

@@ -9,10 +9,10 @@ RUN go mod download
COPY . .
RUN go tool gotailwind -i assets/css/input.css -o assets/css/output.css --minify
RUN --mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 go build -ldflags="-s" -o /bin/c4 .
RUN upx -9 -k /bin/c4
CGO_ENABLED=0 go build -ldflags="-s" -o /bin/games .
RUN upx -9 -k /bin/games
FROM scratch
ENV PORT=8080
COPY --from=build /bin/c4 /
ENTRYPOINT ["/c4"]
COPY --from=build /bin/games /
ENTRYPOINT ["/games"]

View File

@@ -27,9 +27,9 @@ tasks:
- "assets/css/output.css"
build:
desc: Production build to bin/c4
desc: Production build to bin/games
cmds:
- go build -o bin/c4 .
- go build -o bin/games .
deps:
- build:templ
- build:styles
@@ -49,8 +49,8 @@ tasks:
cmds:
- |
go tool air \
-build.cmd "go build -tags=dev -o tmp/bin/c4 ." \
-build.bin "tmp/bin/c4" \
-build.cmd "go build -tags=dev -o tmp/bin/games ." \
-build.bin "tmp/bin/games" \
-build.exclude_dir "data,bin,tmp,deploy" \
-build.include_ext "go,templ" \
-misc.clean_on_exit "true"
@@ -75,7 +75,7 @@ tasks:
run:
desc: Build and run the server
cmds:
- ./bin/c4
- ./bin/games
deps:
- build

View File

@@ -71,6 +71,6 @@ func loadBase() *Config {
}
}(),
AppURL: getEnv("APP_URL", "https://games.adriatica.io"),
DBPath: getEnv("DB_PATH", "data/c4.db"),
DBPath: getEnv("DB_PATH", "data/games.db"),
}
}

View File

@@ -1,11 +1,11 @@
#!/usr/bin/env bash
# Deploy the c4 binary to /opt/c4, then restart the service.
# Deploy the games binary to /opt/games, then restart the service.
# Works from the repo (builds first) or from an extracted tarball (pre-built binary).
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
INSTALL_DIR="/opt/c4"
BINARY="$ROOT_DIR/c4"
INSTALL_DIR="/opt/games"
BINARY="$ROOT_DIR/games"
# If Go is available and we have source, build fresh
if [[ -f "$ROOT_DIR/go.mod" ]] && command -v go &>/dev/null; then
@@ -13,7 +13,7 @@ if [[ -f "$ROOT_DIR/go.mod" ]] && command -v go &>/dev/null; then
(cd "$ROOT_DIR" && go tool gotailwind -i assets/css/input.css -o assets/css/output.css --minify)
echo "Building binary..."
(cd "$ROOT_DIR" && CGO_ENABLED=0 go build -o c4 .)
(cd "$ROOT_DIR" && CGO_ENABLED=0 go build -o games .)
fi
if [[ ! -f "$BINARY" ]]; then
@@ -22,10 +22,10 @@ if [[ ! -f "$BINARY" ]]; then
fi
echo "Installing to $INSTALL_DIR..."
install -o games -g games -m 755 "$BINARY" "$INSTALL_DIR/c4"
install -o games -g games -m 755 "$BINARY" "$INSTALL_DIR/games"
echo "Restarting service..."
systemctl restart c4.service
systemctl restart games.service
echo "Done. Status:"
systemctl status c4.service --no-pager
systemctl status games.service --no-pager

View File

@@ -1,13 +1,13 @@
[Unit]
Description=C4 Game Lobby
Description=Games Lobby
After=network.target
[Service]
Type=simple
User=games
Group=games
WorkingDirectory=/opt/c4
ExecStart=/opt/c4/c4
WorkingDirectory=/opt/games
ExecStart=/opt/games/games
Restart=on-failure
RestartSec=5
@@ -17,7 +17,7 @@ Environment=PORT=8080
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/c4
ReadWritePaths=/opt/games
PrivateTmp=true
[Install]

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Build the c4 binary, bundle it with deploy files into a tarball,
# Build the games binary, bundle it with deploy files into a tarball,
# base64-encode it, and split into 25MB chunks for transfer.
set -euo pipefail
@@ -7,14 +7,14 @@ REPO_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$REPO_DIR"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
TARBALL="c4-deploy-${TIMESTAMP}.tar.gz"
BASE64_FILE="c4-deploy-${TIMESTAMP}_b64.txt"
TARBALL="games-deploy-${TIMESTAMP}.tar.gz"
BASE64_FILE="games-deploy-${TIMESTAMP}_b64.txt"
#==============================================================================
# Clean previous artifacts
#==============================================================================
echo "--- Cleaning old artifacts ---"
rm -f ./c4 c4-deploy-*.tar.gz c4-deploy-*_b64*.txt
rm -f ./games games-deploy-*.tar.gz games-deploy-*_b64*.txt
#==============================================================================
# Build
@@ -23,18 +23,18 @@ echo "--- Building CSS ---"
go tool gotailwind -i assets/css/input.css -o assets/css/output.css --minify
echo "--- Building binary (linux/amd64) ---"
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o c4 .
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o games .
#==============================================================================
# Verify required files
#==============================================================================
echo "--- Verifying files ---"
REQUIRED_FILES=(
c4
games
deploy/setup.sh
deploy/deploy.sh
deploy/reassemble.sh
deploy/c4.service
deploy/games.service
)
for f in "${REQUIRED_FILES[@]}"; do
if [[ ! -f "$f" ]]; then
@@ -48,12 +48,12 @@ done
# Create tarball
#==============================================================================
echo "--- Creating tarball ---"
tar -czf "/tmp/${TARBALL}" --transform 's,^,c4/,' \
c4 \
tar -czf "/tmp/${TARBALL}" --transform 's,^,games/,' \
games \
deploy/setup.sh \
deploy/deploy.sh \
deploy/reassemble.sh \
deploy/c4.service
deploy/games.service
mv "/tmp/${TARBALL}" .
echo " -> ${TARBALL} ($(du -h "${TARBALL}" | cut -f1))"
@@ -66,10 +66,10 @@ base64 "${TARBALL}" > "${BASE64_FILE}"
echo " -> ${BASE64_FILE} ($(du -h "${BASE64_FILE}" | cut -f1))"
echo "--- Splitting into 25MB chunks ---"
split -b 25M -d --additional-suffix=.txt "${BASE64_FILE}" "c4-deploy-${TIMESTAMP}_b64_part"
split -b 25M -d --additional-suffix=.txt "${BASE64_FILE}" "games-deploy-${TIMESTAMP}_b64_part"
rm -f "${BASE64_FILE}"
CHUNKS=(c4-deploy-${TIMESTAMP}_b64_part*.txt)
CHUNKS=(games-deploy-${TIMESTAMP}_b64_part*.txt)
echo " -> ${#CHUNKS[@]} chunk(s):"
for chunk in "${CHUNKS[@]}"; do
echo " $chunk ($(du -h "$chunk" | cut -f1))"
@@ -83,5 +83,5 @@ echo "=== Package Complete ==="
echo ""
echo "Transfer the chunk files to the target server, then run:"
echo " ./reassemble.sh"
echo " cd ~/c4 && sudo ./deploy/setup.sh # first time only"
echo " cd ~/c4 && sudo ./deploy/deploy.sh"
echo " cd ~/games && sudo ./deploy/setup.sh # first time only"
echo " cd ~/games && sudo ./deploy/deploy.sh"

View File

@@ -1,11 +1,11 @@
#!/usr/bin/env bash
# Reassembles base64 chunks and extracts the c4 deployment tarball.
# Reassembles base64 chunks and extracts the games deployment tarball.
# Expects chunk files in the current directory.
set -euo pipefail
cd "$HOME"
echo "=== C4 Deployment Reassembler ==="
echo "=== Games Deployment Reassembler ==="
echo "Working directory: $HOME"
echo ""
@@ -14,10 +14,10 @@ echo ""
#==============================================================================
echo "--- Finding chunk files ---"
CHUNKS=($(ls -1 c4-deploy-*_b64_part*.txt 2>/dev/null | sort))
CHUNKS=($(ls -1 games-deploy-*_b64_part*.txt 2>/dev/null | sort))
if [[ ${#CHUNKS[@]} -eq 0 ]]; then
echo "ERROR: No chunk files found matching c4-deploy-*_b64_part*.txt"
echo "ERROR: No chunk files found matching games-deploy-*_b64_part*.txt"
exit 1
fi
@@ -32,8 +32,8 @@ done
echo ""
echo "--- Reassembling chunks ---"
TIMESTAMP=$(echo "${CHUNKS[0]}" | sed -E 's/c4-deploy-([0-9]+-[0-9]+)_b64_part.*/\1/')
TARBALL="c4-deploy-${TIMESTAMP}.tar.gz"
TIMESTAMP=$(echo "${CHUNKS[0]}" | sed -E 's/games-deploy-([0-9]+-[0-9]+)_b64_part.*/\1/')
TARBALL="games-deploy-${TIMESTAMP}.tar.gz"
COMBINED="combined_b64.txt"
echo "Concatenating chunks..."
@@ -58,12 +58,12 @@ fi
echo ""
echo "--- Archiving existing source ---"
if [[ -d c4 ]]; then
rm -rf c4.bak
mv c4 c4.bak
echo " -> Moved c4 -> c4.bak"
if [[ -d games ]]; then
rm -rf games.bak
mv games games.bak
echo " -> Moved games -> games.bak"
else
echo " -> No existing c4 directory"
echo " -> No existing games directory"
fi
#==============================================================================
@@ -73,7 +73,7 @@ echo ""
echo "--- Extracting tarball ---"
tar -xzf "$TARBALL"
echo " -> Extracted to ~/c4"
echo " -> Extracted to ~/games"
#==============================================================================
# Cleanup
@@ -91,6 +91,6 @@ echo ""
echo "=== Reassembly Complete ==="
echo ""
echo "Next steps:"
echo " cd ~/c4"
echo " cd ~/games"
echo " sudo ./deploy/setup.sh # first time only"
echo " sudo ./deploy/deploy.sh"

View File

@@ -10,20 +10,20 @@ fi
# Create system user if it doesn't exist
if ! id -u games &>/dev/null; then
useradd --system --shell /usr/sbin/nologin --home-dir /opt/c4 --create-home games
useradd --system --shell /usr/sbin/nologin --home-dir /opt/games --create-home games
echo "Created system user: games"
else
echo "User 'games' already exists"
fi
# Ensure install directory exists with correct ownership
install -d -o games -g games -m 755 /opt/c4
install -d -o games -g games -m 755 /opt/c4/data
install -d -o games -g games -m 755 /opt/games
install -d -o games -g games -m 755 /opt/games/data
# Install systemd unit
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
cp "$SCRIPT_DIR/c4.service" /etc/systemd/system/c4.service
cp "$SCRIPT_DIR/games.service" /etc/systemd/system/games.service
systemctl daemon-reload
systemctl enable c4.service
systemctl enable games.service
echo "Setup complete. Run deploy.sh to build and start the service."

View File

@@ -1,7 +1,7 @@
services:
c4:
games:
build: .
container_name: c4
container_name: games
restart: unless-stopped
ports:
- "8080:8080"

View File

@@ -23,7 +23,7 @@ func SetupSessionManager(db *sql.DB) (*scs.SessionManager, func()) {
sessionManager := scs.New()
sessionManager.Store = store
sessionManager.Lifetime = 30 * 24 * time.Hour
sessionManager.Cookie.Name = "c4_session"
sessionManager.Cookie.Name = "games_session"
sessionManager.Cookie.Path = "/"
sessionManager.Cookie.HttpOnly = true
sessionManager.Cookie.Secure = true