#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" STACK_ENV="${STACK_ENV:-$ROOT_DIR/stack.env}" ENSURE_XMPP_SECRET_SCRIPT="$ROOT_DIR/utilities/prosody/ensure_xmpp_secret.sh" podman_cmd() { if [[ "$(id -u)" -eq 0 ]] && id code >/dev/null 2>&1; then local quoted=() local arg for arg in "$@"; do quoted+=("$(printf '%q' "$arg")") done su -s /bin/sh code -c "podman ${quoted[*]}" return fi podman "$@" } if [[ -f "$STACK_ENV" ]]; then set -a . "$STACK_ENV" set +a fi if [[ -x "$ENSURE_XMPP_SECRET_SCRIPT" ]]; then XMPP_SECRET="$("$ENSURE_XMPP_SECRET_SCRIPT" "$STACK_ENV")" export XMPP_SECRET fi STACK_ID="${GIA_STACK_ID:-${STACK_ID:-}}" STACK_ID="$(echo "$STACK_ID" | tr -cs 'a-zA-Z0-9._-' '-' | sed 's/^-*//; s/-*$//')" name_with_stack() { local base="$1" if [[ -n "$STACK_ID" ]]; then echo "${base}_${STACK_ID}" else echo "$base" fi } POD_NAME="$(name_with_stack "gia")" PROSODY_CONTAINER="$(name_with_stack "prosody_gia")" resolve_runtime_names() { local candidates candidates="$( podman_cmd pod ps --format '{{.Name}}' 2>/dev/null \ | grep -E '^((pod_)?gia)($|_[a-zA-Z0-9._-]+$)' || true )" local expected=() if [[ -n "$STACK_ID" ]]; then expected+=("gia_${STACK_ID}" "pod_gia_${STACK_ID}") else expected+=("gia" "pod_gia") fi local name for name in "${expected[@]}"; do if printf '%s\n' "$candidates" | grep -qx "$name"; then POD_NAME="$name" break fi done if [[ "$POD_NAME" != "gia" ]] && [[ "$POD_NAME" != "pod_gia" ]] && ! podman_cmd pod exists "$POD_NAME" >/dev/null 2>&1; then POD_NAME="$(name_with_stack "gia")" fi if podman_cmd pod exists "$POD_NAME" >/dev/null 2>&1; then if [[ "$POD_NAME" == pod_gia* ]]; then local suffix="${POD_NAME#pod_gia}" suffix="${suffix#_}" if [[ -n "$suffix" ]]; then PROSODY_CONTAINER="prosody_gia_${suffix}" else PROSODY_CONTAINER="prosody_gia" fi elif [[ "$POD_NAME" == gia_* ]]; then local suffix="${POD_NAME#gia_}" PROSODY_CONTAINER="prosody_gia_${suffix}" else PROSODY_CONTAINER="prosody_gia" fi return fi # Fallback: if only one gia-like pod exists, use it. local count count="$(printf '%s\n' "$candidates" | sed '/^$/d' | wc -l | tr -d ' ')" if [[ "$count" != "1" ]]; then return fi local detected detected="$(printf '%s\n' "$candidates" | sed '/^$/d' | head -n1)" [[ -z "$detected" ]] && return POD_NAME="$detected" if [[ "$POD_NAME" == pod_gia_* ]]; then local suffix="${POD_NAME#pod_gia_}" PROSODY_CONTAINER="prosody_gia_${suffix}" elif [[ "$POD_NAME" == pod_gia ]]; then PROSODY_CONTAINER="prosody_gia" elif [[ "$POD_NAME" == gia_* ]]; then local suffix="${POD_NAME#gia_}" PROSODY_CONTAINER="prosody_gia_${suffix}" else PROSODY_CONTAINER="prosody_gia" fi echo "Info: auto-detected pod '$POD_NAME' and Prosody container '$PROSODY_CONTAINER'." >&2 } PROSODY_CONFIG_FILE="${QUADLET_PROSODY_CONFIG_FILE:-$ROOT_DIR/utilities/prosody/prosody.cfg.lua}" PROSODY_CERTS_DIR="${QUADLET_PROSODY_CERTS_DIR:-$ROOT_DIR/.podman/gia_prosody_certs}" PROSODY_DATA_DIR="${QUADLET_PROSODY_DATA_DIR:-$ROOT_DIR/.podman/gia_prosody_data}" PROSODY_LOGS_DIR="${QUADLET_PROSODY_LOGS_DIR:-$ROOT_DIR/.podman/gia_prosody_logs}" PROSODY_IMAGE="${PROSODY_IMAGE:-docker.io/prosody/prosody:latest}" if id code >/dev/null 2>&1; then PROSODY_RUN_USER_DEFAULT="$(id -u code):$(id -g code)" else PROSODY_RUN_USER_DEFAULT="$(id -u):$(id -g)" fi PROSODY_RUN_USER="${PROSODY_RUN_USER:-$PROSODY_RUN_USER_DEFAULT}" mkdir -p "$PROSODY_CERTS_DIR" "$PROSODY_DATA_DIR" "$PROSODY_LOGS_DIR" up() { resolve_runtime_names local run_args=() local pod_state="" if podman_cmd pod exists "$POD_NAME"; then pod_state="$(podman_cmd pod inspect "$POD_NAME" --format '{{.State}}' 2>/dev/null || true)" if [[ -z "$pod_state" ]]; then pod_state="$(podman_cmd pod ps --format '{{.Name}} {{.Status}}' 2>/dev/null | awk -v pod="$POD_NAME" '$1==pod {print $2}')" fi if [[ "$pod_state" != "Running" && "$pod_state" != "Degraded" ]]; then podman_cmd pod start "$POD_NAME" >/dev/null 2>&1 || true pod_state="$(podman_cmd pod inspect "$POD_NAME" --format '{{.State}}' 2>/dev/null || true)" if [[ -z "$pod_state" ]]; then pod_state="$(podman_cmd pod ps --format '{{.Name}} {{.Status}}' 2>/dev/null | awk -v pod="$POD_NAME" '$1==pod {print $2}')" fi fi if [[ "$pod_state" == "Running" || "$pod_state" == "Degraded" ]]; then run_args+=(--pod "$POD_NAME") else echo "Warning: pod '$POD_NAME' state is '$pod_state'; starting $PROSODY_CONTAINER standalone with explicit ports." >&2 run_args+=(-p 5222:5222 -p 5269:5269 -p 5280:5280 -p 8888:8888) fi else echo "Warning: pod '$POD_NAME' not found; starting $PROSODY_CONTAINER standalone with explicit ports." >&2 run_args+=(-p 5222:5222 -p 5269:5269 -p 5280:5280 -p 8888:8888) fi podman_cmd run -d \ --replace \ --name "$PROSODY_CONTAINER" \ "${run_args[@]}" \ --env-file "$STACK_ENV" \ --user "$PROSODY_RUN_USER" \ --entrypoint prosody \ -v "$PROSODY_CONFIG_FILE:/etc/prosody/prosody.cfg.lua:ro" \ -v "$PROSODY_CERTS_DIR:/etc/prosody/certs" \ -v "$PROSODY_DATA_DIR:/var/lib/prosody" \ -v "$PROSODY_LOGS_DIR:/var/log/prosody" \ -v "$ROOT_DIR:/code" \ "$PROSODY_IMAGE" \ -F >/dev/null if [[ " ${run_args[*]} " == *" --pod "* ]]; then echo "Started $PROSODY_CONTAINER in pod $POD_NAME" else echo "Started $PROSODY_CONTAINER standalone (not attached to pod $POD_NAME)" fi } down() { resolve_runtime_names podman_cmd rm -f "$PROSODY_CONTAINER" >/dev/null 2>&1 || true echo "Stopped $PROSODY_CONTAINER" } status() { resolve_runtime_names podman_cmd ps --format "table {{.Names}}\t{{.Status}}" | grep -E "^$PROSODY_CONTAINER\b" || true } logs() { resolve_runtime_names podman_cmd logs -f "$PROSODY_CONTAINER" } case "${1:-}" in up) up ;; down) down ;; restart) down up ;; status) status ;; logs) logs ;; *) echo "Usage: $0 {up|down|restart|status|logs}" >&2 exit 2 ;; esac