#!/bin/sh
# ---------------------------------------------------------------------------
#  supervise.sh <name> <logfile> <command...>
#
#  Keeps one process alive. There is no systemd in this container, so this is
#  what restarts FXServer if it crashes.
#
#  Two details that matter for FXServer specifically:
#
#   * It reads its console from stdin and quits the moment stdin reaches EOF,
#     so it is given a FIFO whose write end this script holds open forever.
#     That doubles as a command channel - see /opt/fivem/bin/rcon.
#
#   * A server that dies immediately is usually failing for a reason that will
#     not fix itself (bad licence key, database down, Cfx rate limiting). The
#     restart delay backs off so a broken server does not hammer an upstream
#     service, and resets once it has stayed up for a while.
# ---------------------------------------------------------------------------
NAME="$1"; LOG="$2"; shift 2

FIFO="${FIFO:-/run/$NAME.stdin}"
MIN_DELAY=5
MAX_DELAY=300
HEALTHY_AFTER=120        # seconds of uptime that count as "it actually started"

mkdir -p "$(dirname "$LOG")"
echo $$ > "/run/$NAME.sup.pid"

[ -p "$FIFO" ] || { rm -f "$FIFO"; mkfifo "$FIFO"; }
# read-write open: holds the pipe open without blocking and without a helper process
exec 9<> "$FIFO"

cleanup() {
  kill "$CHILD" 2>/dev/null
  rm -f "/run/$NAME.sup.pid" "/run/$NAME.child.pid"
  exit 0
}
trap cleanup TERM INT

delay=$MIN_DELAY

while true; do
  if [ -f "$LOG" ] && [ "$(stat -c %s "$LOG")" -gt 209715200 ]; then
    mv "$LOG" "$LOG.1"
  fi

  echo "=== $(date -Is) starting $NAME ===" >> "$LOG"
  started=$(date +%s)

  "$@" >> "$LOG" 2>&1 <&9 &
  CHILD=$!
  echo $CHILD > "/run/$NAME.child.pid"
  wait $CHILD
  RC=$?

  ran=$(( $(date +%s) - started ))
  if [ "$ran" -ge "$HEALTHY_AFTER" ]; then
    delay=$MIN_DELAY
  else
    delay=$(( delay * 2 ))
    [ "$delay" -gt "$MAX_DELAY" ] && delay=$MAX_DELAY
  fi

  echo "=== $(date -Is) $NAME exited (rc=$RC) after ${ran}s, restarting in ${delay}s ===" >> "$LOG"
  sleep "$delay"
done
