#!/usr/bin/env bash set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" PID_FILE="$ROOT/.run/visual-chat.pid" LOG_FILE="$ROOT/.run/visual-chat.log" START_CMD="$ROOT/scripts/start-public.sh" mkdir -p "$ROOT/.run" is_running() { if [[ ! -f "$PID_FILE" ]]; then return 1 fi local pid pid="$(cat "$PID_FILE")" if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then return 0 fi return 1 } start() { if is_running; then echo "already running: pid=$(cat "$PID_FILE")" return 0 fi # If stale process still binds configured port, stop it first. local port port="$(awk -F= '/^WEBRTC_PORT=/{print $2}' "$ROOT/.env" 2>/dev/null || true)" port="${port:-8080}" local pids pids="$(ss -ltnp 2>/dev/null | sed -n "s/.*:${port} .*users:((\"python\",pid=\([0-9]\+\),.*/\1/p" | tr '\n' ' ')" if [[ -n "${pids// /}" ]]; then echo "killing stale python on port $port: $pids" # shellcheck disable=SC2086 kill $pids || true sleep 1 fi nohup bash "$START_CMD" >>"$LOG_FILE" 2>&1 & local pid=$! echo "$pid" >"$PID_FILE" sleep 1 if kill -0 "$pid" 2>/dev/null; then echo "started: pid=$pid" echo "log: $LOG_FILE" else echo "failed to start, check log: $LOG_FILE" rm -f "$PID_FILE" return 1 fi } stop() { if ! is_running; then echo "not running" rm -f "$PID_FILE" return 0 fi local pid pid="$(cat "$PID_FILE")" kill "$pid" || true for _ in {1..20}; do if ! kill -0 "$pid" 2>/dev/null; then break fi sleep 0.2 done if kill -0 "$pid" 2>/dev/null; then kill -9 "$pid" || true fi rm -f "$PID_FILE" echo "stopped" } status() { if is_running; then echo "running: pid=$(cat "$PID_FILE")" return 0 fi echo "not running" return 1 } restart() { stop || true start } logs() { if [[ -f "$LOG_FILE" ]]; then tail -n 80 "$LOG_FILE" else echo "no log file yet" fi } case "${1:-}" in start) start ;; stop) stop ;; restart) restart ;; status) status ;; logs) logs ;; *) echo "usage: $0 {start|stop|restart|status|logs}" exit 2 ;; esac