#!/usr/bin/env bash # Reports how many people are currently in a call on this instance. # # Asks LiveKit directly (ListRooms over its twirp API) rather than inferring # from the app: LiveKit is the authority on who is actually connected to media. # Prints the participant count and exits 0 when the instance is idle, 1 when # someone is in a call — so it can gate a deploy. set -euo pipefail ENV_FILE=${ENV_FILE:-/opt/backspace/.env} # `|| true`: under `set -o pipefail` a grep with no match aborts the script # before the check below, exiting 1 — which in this script's contract means # "someone is in a call" rather than "I could not tell". KEY=$(grep -E '^LIVEKIT_API_KEY=' "$ENV_FILE" 2>/dev/null | cut -d= -f2- || true) SECRET=$(grep -E '^LIVEKIT_API_SECRET=' "$ENV_FILE" 2>/dev/null | cut -d= -f2- || true) [ -n "$KEY" ] && [ -n "$SECRET" ] || { echo "LiveKit credentials not found in $ENV_FILE" >&2; exit 2; } b64url() { openssl base64 -A | tr '+/' '-_' | tr -d '='; } now=$(date +%s) header=$(printf '%s' '{"alg":"HS256","typ":"JWT"}' | b64url) payload=$(printf '{"iss":"%s","sub":"%s","nbf":%d,"exp":%d,"video":{"roomList":true}}' \ "$KEY" "$KEY" "$now" "$((now + 60))" | b64url) sig=$(printf '%s.%s' "$header" "$payload" \ | openssl dgst -sha256 -hmac "$SECRET" -binary | b64url) jwt="$header.$payload.$sig" resp=$(curl -sS --max-time 10 -w '\n%{http_code}' -X POST http://127.0.0.1:7880/twirp/livekit.RoomService/ListRooms \ -H "Authorization: Bearer $jwt" -H 'Content-Type: application/json' -d '{}') || { echo "LiveKit unreachable — refusing to report idle" >&2; exit 2; } code=$(printf '%s' "$resp" | tail -n1) resp=$(printf '%s' "$resp" | sed '$d') # A failed query returns no participant counts, which would read as "idle" and # green-light a deploy on top of a live call. Anything but a well-formed 200 is # treated as unknown, not as empty. if [ "$code" != "200" ] || ! printf '%s' "$resp" | grep -q '"rooms"'; then echo "LiveKit answered HTTP $code without a room list — status unknown, not deploying" >&2 exit 2 fi # numParticipants is omitted by protobuf JSON when zero, so absence means empty. total=$(printf '%s' "$resp" | grep -oE '"numParticipants":[0-9]+' | cut -d: -f2 | paste -sd+ - | bc 2>/dev/null || true) total=${total:-0} if [ "$total" -gt 0 ]; then echo "EM CALL: $total participante(s) — nao deployar" exit 1 fi echo "OCIOSO: ninguem em call" exit 0