Skip to content

Commit c9f9efa

Browse files
hyperpolymathclaude
andcommitted
feat: Steam integration, fire-and-forget wizard, self-healing watchdog
Steam integration (Zig + shell): - src/interface/ffi/src/steam_client.zig: Steam Web API client - resolveVanityUrl() → Steam64 ID via ISteamUser/ResolveVanityURL - getPlayerSummary() → display name, profile URL, visibility - checkOwnership() → verify account owns an AppID - 3 exported C ABI functions + 5 unit tests - Integrated into main.zig (comptime linker hints) + cli.zig subcommand - scripts/steam-stage.sh: SteamCMD authenticated download + volume sync - Installs SteamCMD if absent, auth token persistence (avoids Steam Guard repeats) - Interactive Steam Guard prompt on first login - Rsync to local volume or remote host (Verpex VPS) - AppID 1200170 (CryoFall dedicated server requires owned account) Fire-and-forget wizard: - scripts/wizard.sh: 7-step interactive + --unattended provisioning 1. Game selection 2. Steam ID resolution 3. Settings.xml config 4. Game file staging 5. Provision 6. Probe 7. Report - gsa steam resolve <vanity>: resolve Steam username → Steam64 ID from CLI - gsa steam player <id>: fetch player display name and profile URL Self-healing watchdog: - scripts/self-heal.sh: continuous health monitor with auto-recovery - Container status, UDP port binding, disk space, Settings.xml integrity - Escalating recovery: podman start → systemctl restart → Groove alert - Max restart threshold before DEGRADED + alert - VeriSimDB-backed Settings.xml restore on corruption - Justfile: cryofall-watchdog, cryofall-watchdog-install (systemd user service) Justfile additions: - wizard, wizard-auto, cryofall-stage, cryofall-stage-verpex, steam-resolve - All new scripts marked executable DNS: cryofall.jewell.nexus → 209.42.26.106 grey-cloud (live in Cloudflare) Firewall: UDP 6000+6001 open on Verpex VPS Note: CryoFall server needs authenticated SteamCMD (non-anonymous); run `just cryofall-stage` or `just wizard` to download game files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 54775b3 commit c9f9efa

10 files changed

Lines changed: 1718 additions & 11 deletions

File tree

Justfile

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,48 @@ game-deploy GAME="" DRY="0":
437437
fi
438438
PROVISION_DRY_RUN="{{ DRY }}" bash scripts/provision-server.sh "${GAME}"
439439
440+
# ─── Fire-and-forget wizard ───────────────────────────────────────────────────
441+
# Complete end-to-end server provisioning including Steam auth and game download.
442+
# Set environment variables before running:
443+
# STEAM_USER, STEAM_PASS, GSA_STEAM_API_KEY (optional, for ID resolution)
444+
# WIZARD_TARGET_HOST (optional, for remote Verpex deployment)
445+
446+
# Interactive wizard — prompts for all values
447+
wizard GAME="cryofall":
448+
bash scripts/wizard.sh --game {{ GAME }}
449+
450+
# Unattended wizard — reads all values from environment
451+
wizard-auto GAME="cryofall":
452+
WIZARD_GAME="{{ GAME }}" bash scripts/wizard.sh --game {{ GAME }} --unattended
453+
454+
# Stage game files from Steam onto the deployment host
455+
# Requires: STEAM_USER, STEAM_PASS
456+
cryofall-stage:
457+
bash scripts/steam-stage.sh \
458+
--app-id 1200170 \
459+
--target-volume cryofall-game-data
460+
461+
# Stage game files to Verpex VPS (set WIZARD_TARGET_HOST or uses default)
462+
cryofall-stage-verpex:
463+
bash scripts/steam-stage.sh \
464+
--app-id 1200170 \
465+
--target-volume cryofall-game-data \
466+
--target-host root@209.42.26.106
467+
468+
# Resolve a Steam vanity URL to a Steam64 ID
469+
# Usage: just steam-resolve VANITY=hyperpolymath API_KEY=<your-key>
470+
steam-resolve VANITY="" API_KEY="":
471+
#!/usr/bin/env bash
472+
set -euo pipefail
473+
VANITY="{{ VANITY }}"
474+
KEY="{{ API_KEY }}"
475+
[ -z "${KEY}" ] && KEY="${GSA_STEAM_API_KEY:-}"
476+
if [ -z "${VANITY}" ]; then
477+
echo "Usage: just steam-resolve VANITY=<username>"
478+
exit 1
479+
fi
480+
GSA_STEAM_API_KEY="${KEY}" src/interface/ffi/zig-out/bin/gsa steam resolve "${VANITY}"
481+
440482
# CryoFall shorthand — equivalent to: just game-deploy GAME=cryofall
441483
cryofall-deploy:
442484
just game-deploy GAME=cryofall
@@ -473,6 +515,39 @@ cryofall-status:
473515
echo "Systemd service:"
474516
systemctl --user status gsa-cryofall --no-pager 2>/dev/null | head -8 || echo " Not installed"
475517
518+
# Start self-healing watchdog in the foreground
519+
cryofall-watchdog:
520+
bash scripts/self-heal.sh --container cryofall --port 6000
521+
522+
# Install watchdog as a systemd user service (runs in background on Verpex)
523+
cryofall-watchdog-install:
524+
#!/usr/bin/env bash
525+
set -euo pipefail
526+
UNIT_FILE="${HOME}/.config/systemd/user/gsa-cryofall-watchdog.service"
527+
mkdir -p "$(dirname "${UNIT_FILE}")"
528+
REPO="$(pwd)"
529+
cat > "${UNIT_FILE}" << UNIT
530+
[Unit]
531+
Description=GSA CryoFall self-heal watchdog
532+
After=gsa-cryofall.service
533+
Requires=gsa-cryofall.service
534+
535+
[Service]
536+
Type=simple
537+
ExecStart=/usr/bin/bash ${REPO}/scripts/self-heal.sh --container cryofall --port 6000
538+
Restart=always
539+
RestartSec=10s
540+
StandardOutput=journal
541+
StandardError=journal
542+
543+
[Install]
544+
WantedBy=default.target
545+
UNIT
546+
systemctl --user daemon-reload
547+
systemctl --user enable --now gsa-cryofall-watchdog
548+
echo "Watchdog service installed and started."
549+
systemctl --user status gsa-cryofall-watchdog --no-pager | head -6
550+
476551
# Deploy to Verpex VPS via SSH (run this from local machine)
477552
# Requires SSH key access: root@209.42.26.106
478553
verpex-deploy GAME="cryofall":

container/cryofall/Containerfile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,14 @@ RUN groupadd -r -g 1500 cryofall && \
102102
# the linux32/ runtime directory it downloads on first run.
103103

104104
COPY --from=steamcmd-installer /opt/steamcmd /opt/steamcmd
105+
# Create a wrapper script rather than a symlink.
106+
# steamcmd.sh uses dirname/$0 to locate linux32/steamcmd relative to itself,
107+
# so a bare symlink into /usr/local/bin/ breaks the relative path lookup.
108+
# The wrapper cd's into /opt/steamcmd first, keeping all relative paths intact.
105109
RUN chown -R cryofall:cryofall /opt/steamcmd && \
106-
ln -sf /opt/steamcmd/steamcmd.sh /usr/local/bin/steamcmd
110+
printf '#!/bin/sh\ncd /opt/steamcmd && exec ./steamcmd.sh "$@"\n' \
111+
> /usr/local/bin/steamcmd && \
112+
chmod +x /usr/local/bin/steamcmd
107113

108114
# ── Application files ─────────────────────────────────────────────────────
109115
WORKDIR /app

container/cryofall/Settings.xml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,14 @@
9696
Find Steam IDs at: https://steamid.io/
9797
-->
9898
<!--
99+
Joshua's Steam vanity URL "thekumonkid" did not resolve on Steam Community.
100+
Check the correct vanity URL at: https://steamcommunity.com/id/thekumonkid
101+
If that's wrong, find it at: steamcommunity.com → profile → Edit Profile → Custom URL
102+
Replace JOSHUA_STEAM64_ID_HERE with the 17-digit number once confirmed.
103+
-->
99104
<Operators>
100-
<Operator steamId="JOSHUA_STEAM_ID_HERE" name="Joshua Jewell" />
101-
<Operator steamId="JONATHAN_STEAM_ID_HERE" name="Jonathan Jewell" />
105+
<Operator steamId="JOSHUA_STEAM64_ID_HERE" name="thekumonkid" />
106+
<Operator steamId="76561198141836018" name="hyperpolymath" />
102107
</Operators>
103-
-->
104108

105109
</server-settings>

container/cryofall/entrypoint.sh

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,35 @@ trap cleanup TERM INT
5656

5757
if [ ! -f "${SERVER_BINARY}" ]; then
5858
echo "[gsa-cryofall] CryoFall server not found at ${INSTALL_DIR}."
59-
echo "[gsa-cryofall] Installing via SteamCMD (AppID ${APPID}) — this takes a few minutes (~3 GB)..."
60-
"${STEAMCMD}" \
61-
+force_install_dir "${INSTALL_DIR}" \
62-
+login anonymous \
63-
+app_update "${APPID}" validate \
64-
+quit
65-
echo "[gsa-cryofall] Game installation complete."
59+
60+
# CryoFall dedicated server (AppID 1200170) is a DLC of app 552990 and
61+
# requires a Steam account that owns the game — anonymous login fails.
62+
#
63+
# Two routes to stage the server files:
64+
#
65+
# Route A — Steam credentials in environment (set STEAM_USER + STEAM_PASS):
66+
if [ -n "${STEAM_USER:-}" ] && [ -n "${STEAM_PASS:-}" ]; then
67+
echo "[gsa-cryofall] Installing via SteamCMD (authenticated as ${STEAM_USER})..."
68+
"${STEAMCMD}" \
69+
+force_install_dir "${INSTALL_DIR}" \
70+
+login "${STEAM_USER}" "${STEAM_PASS}" \
71+
+app_update "${APPID}" validate \
72+
+quit
73+
echo "[gsa-cryofall] Game installation complete."
74+
75+
# Route B — Files pre-staged into the volume by GSA provisioner:
76+
# Run on the host (or locally) then rsync to the cryofall-game-data volume:
77+
# steamcmd +login <user> +force_install_dir ./cryofall-server \
78+
# +app_update 1200170 validate +quit
79+
# rsync -az ./cryofall-server/ root@209.42.26.106:/path/to/volume/
80+
# Then restart this container — it will skip this block.
81+
else
82+
echo "[gsa-cryofall] ERROR: CryoFall server files not found and no Steam credentials set."
83+
echo "[gsa-cryofall] Stage the server files first — see QUICKSTART-USER.adoc or:"
84+
echo "[gsa-cryofall] GSA GUI → CryoFall → Actions → 'Stage Server Files'"
85+
echo "[gsa-cryofall] Or set STEAM_USER + STEAM_PASS environment variables."
86+
exit 1
87+
fi
6688
fi
6789

6890
# ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)