#!/bin/bash # Auto-rebuild timer and unit installation for the dice solver site. # # Sourced by setup_kcd2_dice_solver.sh; split out to keep kcd2_expose.sh # under the 250-line cap. Sourced rather than run, so it inherits the # caller's strict mode and the variables above the source line. # --- Phase 7: auto-rebuild on commit ---------------------------------------- # The build runs in a memory-capped systemd user unit rather than inside the # git hook. MemorySwapMax=0 is required, not cosmetic: this box has ~4 GB of # zram (swap held IN ram), so a memory-limited cgroup without it thrashes zram # instead of dying cleanly, and freezes the machine. A git hook running tsc and # vite is precisely the scenario that costs. install_autorebuild() { ensure_dir "$UNIT_DIR" cat >"$UNIT_FILE" <"$HOOK_FILE" </dev/null | grep -oE 'tcp dport \{[^}]*\}') return 1 } ensure_firewall() { if web_ports_open; then log_ok "Ports 80/443 already accepted — leaving the ruleset untouched." return 0 fi log_info "Opening ports 80/443 via setup_wireguard_ssh.sh…" sudo bash "$WG_SCRIPT" allow-web } # --- Phase 9: report -------------------------------------------------------- print_report() { cat </dev/null || echo "000 0")" read -r code size <<<"$out" [[ $code == "200" && ${size:-0} -gt 0 ]] && echo 0 || echo 1 } status_cmd() { print_setup_header "KCD2 dice solver status" if has_cmd node; then status_line 0 "node present" else status_line 1 "node missing" fi if has_cmd pnpm; then status_line 0 "pnpm present" else status_line 1 "pnpm missing" fi if [[ -f "${DICE_SRC}/dist/index.html" ]]; then status_line 0 "build present (dist/index.html)" else status_line 1 "build missing — run setup" fi if docker ps --format '{{.Names}}' | grep -qx "$DICE_CONTAINER"; then status_line 0 "${DICE_CONTAINER} container running" local pid listeners pid="$(docker inspect -f '{{.State.Pid}}' "$DICE_CONTAINER" 2>/dev/null || echo "")" listeners="$(sudo -n ss -ltnp 2>/dev/null | grep "pid=${pid}," || true)" if grep -qE ':(80|443)\b' <<<"$listeners"; then status_line 1 "${DICE_CONTAINER} is CONTENDING for :80/:443 with ${CADDY_CONTAINER}" else status_line 0 "${DICE_CONTAINER} listens only on ${DICE_PORT}" fi else status_line 1 "${DICE_CONTAINER} container not running" fi status_line "$(check_http "http://127.0.0.1:${DICE_PORT}/" "$DICE_DOMAIN")" \ "local static server (127.0.0.1:${DICE_PORT}, Host: ${DICE_DOMAIN})" if [[ -f $DICE_SNIPPET ]]; then status_line 0 "Caddy snippet present" else status_line 1 "Caddy snippet missing" fi if getent hosts "$DICE_DOMAIN" >/dev/null; then status_line 0 "${DICE_DOMAIN} resolves" else status_line 1 "${DICE_DOMAIN} does not resolve" fi status_line "$(check_http "https://${DICE_DOMAIN}/")" \ "external https://${DICE_DOMAIN}/" # The hook lives in .git/hooks, which is not version-controlled, so it is # lost on a fresh clone and must be checked rather than assumed. Spelled as # an explicit if: with two conditions, A && B || C really would misfire. if [[ -x $HOOK_FILE ]] && grep -q "$UNIT_NAME" "$HOOK_FILE" 2>/dev/null; then status_line 0 "post-commit auto-rebuild hook installed" else status_line 1 "post-commit hook missing — re-run setup" fi if [[ -f $UNIT_FILE ]]; then status_line 0 "${UNIT_NAME} installed" else status_line 1 "${UNIT_NAME} missing — re-run setup" fi if systemctl --user is-failed --quiet "$UNIT_NAME"; then status_line 1 "last auto-rebuild FAILED — journalctl --user -u ${UNIT_NAME}" else status_line 0 "no failed auto-rebuild recorded" fi # "not failed" also covers "never ran", so check the artefact rather than the # unit: if any source file is newer than the published bundle, the hook is # not firing and the site is quietly serving an old build. local newest_src newest_src="$(find "${DICE_SRC}/src" "${DICE_SRC}/index.html" -type f -newer \ "${DICE_SRC}/dist/index.html" -print -quit 2>/dev/null || true)" if [[ -n $newest_src ]]; then status_line 1 "published bundle is STALE (e.g. ${newest_src#"${DICE_SRC}/"}) — run: systemctl --user start ${UNIT_NAME}" else status_line 0 "published bundle is up to date with src/" fi }