#!/usr/bin/env bash
#
# serve.sh — bring the RPM repo and the OCI registry up, or take them down.
#
# Both have to be reachable from inside the guest, which means bound on the
# host rather than on loopback only: qemu user networking reaches the host as
# 10.0.2.2, and a server bound to 127.0.0.1 is not there.
#
#   serve.sh up      start both, idempotent
#   serve.sh down    stop both
#   serve.sh status  say what is listening
set -euo pipefail

# shellcheck source=build/layertest/common.sh
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh"

# shellcheck source=build/privilege.sh
. "$HERE/../privilege.sh"

PIDFILE="$STATE/repo-server.pid"

repo_up() {
  [ -d "$STATE/repo" ] || die "no state/repo; run build.sh first"
  if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then
    say "repo already serving on $REPO_PORT"; return
  fi
  # `setsid --fork`, and no `&` anywhere. The server has to stop being this
  # script's descendant, and it has to stop holding this script's stdout.
  #
  # Both of those bite. A plain `cmd &` leaves the server a child that bash
  # waits for at exit, and wrapping it in `( ... & )` only moves the problem to
  # the subshell, which then holds the write end of any pipe `serve.sh up` was
  # called through. Either way `./serve.sh up | tail` never returns and an &&
  # chain after it never runs. nohup does not help: it redirects, it does not
  # detach.
  setsid --fork python3 -m http.server "$REPO_PORT" \
    --bind 0.0.0.0 --directory "$STATE/repo" \
    < /dev/null > "$STATE/repo-server.log" 2>&1
  pgrep -f "http.server $REPO_PORT" > "$PIDFILE" || true
  say "repo serving on $REPO_PORT"
}

repo_down() {
  if [ -f "$PIDFILE" ]; then
    kill "$(cat "$PIDFILE")" 2>/dev/null || true
    rm -f "$PIDFILE"
  fi
  # The pidfile is not the whole story: a run killed part-way leaves a server
  # with no pidfile, and the next `up` would then bind-fail for a reason that
  # reads as unrelated.
  pkill -f "http.server $REPO_PORT" 2>/dev/null || true
  say "repo stopped"
}

registry_up() {
  if privc podman container exists alloy-layertest-registry 2>/dev/null; then
    privc podman start alloy-layertest-registry >/dev/null 2>&1 || true
  else
    privc podman run -d --name alloy-layertest-registry \
      -p "$REGISTRY_PORT:5000" docker.io/library/registry:2 >/dev/null
  fi
  say "registry serving on $REGISTRY_PORT"
}

registry_down() {
  privc podman rm -f alloy-layertest-registry >/dev/null 2>&1 || true
  say "registry stopped"
}

case "${1:-up}" in
  up)   repo_up; registry_up ;;
  down) repo_down; registry_down ;;
  status)
    ss -ltn 2>/dev/null | grep -E ":$REPO_PORT|:$REGISTRY_PORT" || say "neither port is listening"
    ;;
  *) die "usage: serve.sh [up|down|status]" ;;
esac
