#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" RUN_DIR="$ROOT_DIR/.run" PID_FILE="$RUN_DIR/visual-chat-8018.pid" LOG_FILE="$RUN_DIR/visual-chat-8018.log" ENV_FILE="$ROOT_DIR/.env" mkdir -p "$RUN_DIR" if [[ -f "$ENV_FILE" ]]; then set -a # shellcheck disable=SC1090 source "$ENV_FILE" set +a fi normalize_host() { local host="${1:-0.0.0.0}" case "$host" in 127.0.0.1|localhost|::1) echo "0.0.0.0" ;; *) echo "$host" ;; esac } HOST="$(normalize_host "${HTTP_HOST:-0.0.0.0}")" PORT="${HTTP_PORT:-8018}" SSL_CERTFILE="${SSL_CERTFILE:-$ROOT_DIR/certs/dev-cert.pem}" SSL_KEYFILE="${SSL_KEYFILE:-$ROOT_DIR/certs/dev-key.pem}" if [[ -x "$ROOT_DIR/.venv/bin/python" ]]; then PYTHON_BIN="$ROOT_DIR/.venv/bin/python" else PYTHON_BIN="$(command -v python3 || true)" fi if [[ -z "$PYTHON_BIN" ]]; then echo "python3 not found" exit 1 fi port_pids() { ss -ltnp 2>/dev/null \ | sed -n "s/.*:${PORT} .*users:((\"python\",pid=\([0-9]\+\),.*/\1/p" \ | tr '\n' ' ' } is_running() { if [[ ! -f "$PID_FILE" ]]; then return 1 fi local pid pid="$(cat "$PID_FILE")" [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null } start() { if is_running; then echo "already running: pid=$(cat "$PID_FILE")" return 0 fi local stale stale="$(port_pids)" if [[ -n "${stale// /}" ]]; then echo "killing stale python on port ${PORT}: $stale" # shellcheck disable=SC2086 kill $stale || true sleep 1 fi local args args=(main:app --host "$HOST" --port "$PORT") if [[ -n "$SSL_CERTFILE" && -n "$SSL_KEYFILE" ]]; then args+=(--ssl-certfile "$SSL_CERTFILE" --ssl-keyfile "$SSL_KEYFILE") fi nohup "$PYTHON_BIN" -m uvicorn "${args[@]}" >>"$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 "url: https://$HOST:$PORT" echo "log: $LOG_FILE" else echo "failed to start, see 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 } logs() { if [[ -f "$LOG_FILE" ]]; then tail -n 120 "$LOG_FILE" else echo "no log file yet" fi } restart() { stop || true start } case "${1:-}" in start) start ;; stop) stop ;; status) status ;; restart) restart ;; logs) logs ;; *) echo "usage: $0 {start|stop|status|restart|logs}" exit 2 ;; esac