Skip to content

Commit 6656eae

Browse files
committed
initial
0 parents  commit 6656eae

317 files changed

Lines changed: 23973 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.dockerignore‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.git
2+
.kamal
3+
.claude
4+
logs
5+
tools
6+
config
7+
init
8+
*.md

‎.gitattributes‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# LF line endings for every text file, in the repo and in checkouts, whatever each
2+
# machine's core.autocrlf says. The gateway converts the game files it serves
3+
# (languagetext.xml, NewConstants.txt) to CRLF itself.
4+
* text=auto eol=lf
5+
6+
*.dat binary
7+
*.msi binary
8+
*.png binary
9+
*.jpg binary
10+
*.wav binary

‎.github/workflows/deploy.yml‎

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
name: Deploy
3+
4+
on:
5+
push:
6+
branches:
7+
- main
8+
workflow_dispatch:
9+
10+
# one deploy at a time; a queued push waits instead of cancelling a deploy halfway
11+
concurrency:
12+
group: deploy
13+
cancel-in-progress: false
14+
15+
jobs:
16+
deploy:
17+
runs-on: ubuntu-24.04
18+
steps:
19+
- name: Cloning repo
20+
uses: actions/checkout@v7
21+
22+
- name: Set up Go
23+
uses: actions/setup-go@v7
24+
with:
25+
go-version-file: gateway/go.mod
26+
cache-dependency-path: gateway/go.sum
27+
- name: Test gateway
28+
run: go vet ./... && go test ./...
29+
working-directory: gateway
30+
31+
- name: Set up Ruby
32+
uses: ruby/setup-ruby@v1
33+
with:
34+
ruby-version: "3.4"
35+
- name: Install Kamal
36+
run: gem install kamal --version 2.12.0 --no-document
37+
38+
- name: Set up SSH
39+
uses: webfactory/ssh-agent@v0.10.0
40+
with:
41+
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
42+
# pinned rather than scanned, so a deploy can't be sent to a server impersonating this one
43+
- name: Trust the server's host key
44+
run: echo "167.235.138.73 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPB7JAJxXl14Emc4ui2B0lMtcJ/v4B/FlT1SaAn3tdr/" >> ~/.ssh/known_hosts
45+
46+
- name: Set up Docker Buildx
47+
uses: docker/setup-buildx-action@v4
48+
49+
# setup rather than deploy: it also boots the database on the first run and skips it after
50+
- name: Deploy
51+
run: kamal setup
52+
env:
53+
MARIADB_ROOT_PASSWORD: ${{ secrets.MARIADB_ROOT_PASSWORD }}
54+
C4GW_DB_PASSWORD: ${{ secrets.C4GW_DB_PASSWORD }}
55+
C4GW_WEB_SECRET: ${{ secrets.C4GW_WEB_SECRET }}

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# gateway capture logs and raw packet dumps (include login exchanges)
2+
logs/
3+
__pycache__/

‎.kamal/hooks/pre-app-boot‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/sh
2+
# The gateway container publishes the game port (config/deploy.yml), and Kamal boots the
3+
# new container before stopping the old one, so the new one couldn't bind it. Stop the
4+
# running gateway on each host first. C4_SSH_USER defaults to root, like Kamal's ssh user.
5+
set -e
6+
for host in $(echo "$KAMAL_HOSTS" | tr ',' ' '); do
7+
echo "Stopping the running $KAMAL_SERVICE gateway on $host to free the game port"
8+
ssh "${C4_SSH_USER:-root}@$host" \
9+
"docker ps --quiet --filter label=service=$KAMAL_SERVICE --filter label=role=web | xargs -r docker stop"
10+
done

‎.kamal/secrets‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Read from your shell environment when Kamal runs; no secret is stored in this file.
2+
# C4GW_DB_PASSWORD goes into a DSN and a SQL string, so use letters and digits only.
3+
MARIADB_ROOT_PASSWORD=$MARIADB_ROOT_PASSWORD
4+
C4GW_DB_PASSWORD=$C4GW_DB_PASSWORD
5+
# signs website sign-in cookies
6+
C4GW_WEB_SECRET=$C4GW_WEB_SECRET
7+
C4GW_DB_DSN="c4gateway:$C4GW_DB_PASSWORD@tcp(caesar4-online-db:3306)/caesar4?charset=latin1&interpolateParams=true"

‎Dockerfile‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
FROM golang:1.23-alpine AS build
2+
WORKDIR /src
3+
COPY gateway/go.mod gateway/go.sum ./
4+
RUN go mod download
5+
COPY gateway/ ./
6+
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /c4gateway ./cmd/c4gateway
7+
8+
FROM alpine:3.20
9+
COPY --from=build /c4gateway /usr/local/bin/c4gateway
10+
# Game files players download after registering (-patch-dir).
11+
COPY patched/ /patched/
12+
ENV C4GW_PATCH_DIR=/patched
13+
# for -capture; a volume mounted here starts out owned by nobody
14+
RUN mkdir /logs && chown nobody /logs
15+
USER nobody
16+
ENTRYPOINT ["c4gateway"]
17+
CMD ["serve"]

‎README.md‎

Lines changed: 228 additions & 0 deletions
Large diffs are not rendered by default.

‎config/deploy.yml‎

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Kamal 2: deploys the gateway and its MariaDB to one Docker host. A push to main deploys it
2+
# from GitHub Actions (.github/workflows/deploy.yml). By hand: kamal setup, with the secrets
3+
# .kamal/secrets reads set in your shell.
4+
service: caesar4-online
5+
image: caesar4-online
6+
7+
servers:
8+
web:
9+
hosts:
10+
- 167.235.138.73
11+
options:
12+
# The game speaks raw MySQL, which kamal-proxy can't carry, so the container publishes
13+
# it. Only one container can hold the port: .kamal/hooks/pre-app-boot stops the running
14+
# gateway before each deploy boots the new one, so a deploy has a few seconds of downtime.
15+
publish: "3310:3306"
16+
17+
# The website. c4.xetera.dev is a DNS-only record for this server, so kamal-proxy gets a
18+
# Let's Encrypt certificate for it. Other apps on the server keep their own hosts.
19+
proxy:
20+
host: c4.xetera.dev
21+
ssl: true
22+
app_port: 8080
23+
healthcheck:
24+
path: /
25+
26+
# Kamal runs a registry on your machine for the push and tunnels it to the server over SSH.
27+
registry:
28+
server: localhost:5555
29+
30+
builder:
31+
arch: amd64
32+
# build the working directory (the default is a clean git clone)
33+
context: .
34+
35+
env:
36+
clear:
37+
C4GW_LISTEN: ":3306"
38+
C4GW_WEB: ":8080"
39+
# debug endpoints, reachable only inside the kamal network
40+
C4GW_ADMIN: ":8081"
41+
# Written into players' NewConstants.txt. The game connects here on 3310 directly, so the
42+
# DNS record must stay DNS-only: Cloudflare's proxy only carries HTTP.
43+
C4GW_PUBLIC_SERVER: "c4.xetera.dev"
44+
C4GW_PUBLIC_PORT: "3310"
45+
C4GW_PUBLIC_URL: "https://c4.xetera.dev"
46+
C4GW_CAPTURE: /logs/capture.jsonl
47+
secret:
48+
- C4GW_DB_DSN
49+
- C4GW_WEB_SECRET
50+
51+
volumes:
52+
- caesar4-online-logs:/logs
53+
54+
accessories:
55+
db:
56+
image: mariadb:11.4
57+
host: 167.235.138.73
58+
cmd: --sql-mode=NO_ENGINE_SUBSTITUTION --character-set-server=latin1
59+
env:
60+
clear:
61+
MARIADB_DATABASE: caesar4
62+
secret:
63+
- MARIADB_ROOT_PASSWORD
64+
# read by 99-production.sh
65+
- C4GW_DB_PASSWORD
66+
# Run only when the data directory is empty. 0644 so the entrypoint sources the .sh
67+
# (it needs the entrypoint's docker_process_sql). init/02-leaderboards.sql is test data.
68+
files:
69+
- local: init/01-init.sql
70+
remote: /docker-entrypoint-initdb.d/01-init.sql
71+
mode: "0644"
72+
- local: config/mariadb/99-production.sh
73+
remote: /docker-entrypoint-initdb.d/99-production.sh
74+
mode: "0644"
75+
directories:
76+
- data:/var/lib/mysql

‎config/mariadb/99-production.sh‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Runs last when MariaDB initialises an empty volume (sourced by its entrypoint, so
2+
# docker_process_sql is available). The init SQL is written for local testing: this
3+
# removes the dev account and replaces the gateway's dev password with the real one.
4+
docker_process_sql --database=caesar4 <<-EOSQL
5+
DELETE FROM users WHERE username = 'tester';
6+
ALTER USER 'c4gateway'@'%' IDENTIFIED BY '${C4GW_DB_PASSWORD}';
7+
FLUSH PRIVILEGES;
8+
EOSQL

0 commit comments

Comments
 (0)