#!/bin/sh # with-sidecar.sh — start the rust-link sidecar beside a Rust server, then become the server. # # The egg's startup is this script followed by the game's own command line: # # ./rust-link/with-sidecar.sh ./RustDedicated -batchmode … # # It ships in Rust-Link's release rather than inside the egg, so a fix here reaches a server at its # next reinstall without anybody re-importing the egg (docs/modules/rust/PLAN.md §34.2.6, §34.4). # The shape is docs/rust-link/INSTALL_RIG.md's, proven on the rigs; see that file for why each line # that looks optional is not. # # POSIX sh and no jq: the game image (ghcr.io/pterodactyl/games:rust) has grep and sed, not jq. # # Deliberately NOT `set -e`. Every step before the last line is the bridge's, and the last line is # the game's: nothing the bridge gets wrong — an unwritable log, a sidecar that will not start — may # keep the server from booting. Each step reports its own failure and the script goes on to `exec`. RL=/home/container/rust-link mkdir -p "$RL" 2>/dev/null export RUSTLINK_CONFIG="$RL/sidecar.toml" # Fixed, and never a panel variable: the install script moves this directory aside around its own # `rm -rf ${REMOVE_FILES}`, which is what keeps a wipe from reaching the store (§34.1). export RUSTLINK_DB_PATH="$RL/rust-link.db" # An EMPTY panel variable is exported as `VAR=""`. The sidecar treats that as unset, and so does # this script, so a blank field always means "the default" (or, for the token, "the saved one"). for v in RUSTLINK_SERVER_ID RUSTLINK_WEB_TOKEN RUSTLINK_RETAIN_DAYS RUSTLINK_WEB_PORT RUSTLINK_GAME_BIND RUSTLINK_WEB_BIND; do eval "val=\${$v-}" if [ -z "$val" ]; then unset "$v"; fi done # The website-facing bind. Pterodactyl tells a container nothing about its extra allocations, so # the port is typed into the egg, and it must be one of this server's allocations — a port that is # not fails as a bind the website never reaches, which the lines below make visible (§34.1). if [ -n "${RUSTLINK_WEB_PORT-}" ]; then export RUSTLINK_WEB_BIND="0.0.0.0:${RUSTLINK_WEB_PORT}" fi SIDECAR="$RL/rust-link-sidecar" if [ ! -x "$SIDECAR" ]; then echo "[rust-link] $SIDECAR is missing - reinstall the server to fetch the bridge. Starting the game without it." exec "$@" fi # Provision first, so the token can be shown. `--print-config` resolves the configuration exactly as # a start does, writing sidecar.toml with a generated token when there is none; the JSON it prints # says whether it generated one on THIS call, which is what makes "print once" true (D152). # Tracing is off on that path, so stdout is only the document. LD_PRELOAD is dropped for the # sidecar in both calls: Carbon's entrypoint puts its Mono preloader in front of the whole startup. if CFG="$(env -u LD_PRELOAD "$SIDECAR" --print-config 2>&1)"; then # The Nth `"key": "value"` line of the pretty-printed JSON. `bind` appears twice — game, then web. field() { printf '%s\n' "$CFG" | sed -n "s/^ *\"$1\": \"\([^\"]*\)\",\{0,1\}\$/\1/p" | sed -n "${2:-1}p"; } WEB_BIND="$(field bind 2)" SERVER_ID="$(field server_id)" if printf '%s\n' "$CFG" | grep -q '"token_generated": true'; then TOKEN="$(field auth_token)" echo "[rust-link] ================================================================" echo "[rust-link] A new sidecar token was generated. It is shown ONCE, here:" echo "[rust-link] ${TOKEN}" echo "[rust-link] It is kept in rust-link/sidecar.toml; read it there if you lose it." echo "[rust-link] ================================================================" fi PORT="${WEB_BIND##*:}" HOST="${SERVER_IP-}" case "$HOST" in ""|0.0.0.0) HOST="" ;; esac echo "[rust-link] Admin -> Rust -> Servers: server id '${SERVER_ID:-main}', sidecar URL http://${HOST}:${PORT} (listening on ${WEB_BIND})" else echo "[rust-link] the sidecar could not read its configuration:" printf '%s\n' "$CFG" | sed 's/^/[rust-link] /' fi # A background job's redirection fails in the child, invisibly, so writability is asked first. A # directory the log cannot be written to is one the store and the token cannot be written to either. if touch "$RL/sidecar.log" 2>/dev/null; then env -u LD_PRELOAD "$SIDECAR" >> "$RL/sidecar.log" 2>&1 & else echo "[rust-link] $RL is not writable - the game starts without the sidecar." fi # The game BECOMES this process: the panel console keeps its stdin and stdout, and stop still # stops the server, which takes the sidecar down with the container. exec "$@"