diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh index 18a37c2..de01e6b 100755 --- a/scripts/bootstrap.sh +++ b/scripts/bootstrap.sh @@ -1,7 +1,6 @@ #!/bin/sh set -eu -cd /Users/kris/code/StoryForge/collector-service -python3 -m venv .venv -. .venv/bin/activate -pip install -r requirements.txt -uvicorn app.main:app --host 0.0.0.0 --port 8081 --reload + +ROOT="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)" + +"$ROOT/scripts/start_business.sh" diff --git a/scripts/cleanup_debug_ui.sh b/scripts/cleanup_debug_ui.sh new file mode 100755 index 0000000..048bbde --- /dev/null +++ b/scripts/cleanup_debug_ui.sh @@ -0,0 +1,39 @@ +#!/bin/sh +set -eu + +PORT="${1:-3618}" +SCRIPT_PATH="/Users/kris/code/StoryForge-gitea/scripts/douyin-browser-capture/control_panel.mjs" + +lsof -tiTCP:"$PORT" -sTCP:LISTEN | xargs -r kill || true + +osascript -e 'tell application "Terminal"' \ + -e 'if it is running then' \ + -e 'repeat with w in windows' \ + -e 'set shouldClose to false' \ + -e 'repeat with t in tabs of w' \ + -e 'try' \ + -e 'set tabText to contents of t' \ + -e 'if tabText contains "'"$SCRIPT_PATH"'" then set shouldClose to true' \ + -e 'end try' \ + -e 'end repeat' \ + -e 'if shouldClose then close w saving no' \ + -e 'end repeat' \ + -e 'end if' \ + -e 'end tell' >/dev/null 2>&1 || true + +for app in "Google Chrome" "Brave Browser" "Arc" "Safari"; do + osascript -e 'try' \ + -e 'tell application "'"$app"'"' \ + -e 'repeat with w in windows' \ + -e 'repeat with i from (count of tabs of w) to 1 by -1' \ + -e 'try' \ + -e 'set tabUrl to URL of tab i of w' \ + -e 'if tabUrl contains "127.0.0.1:'"$PORT"'" then close tab i of w' \ + -e 'end try' \ + -e 'end repeat' \ + -e 'end repeat' \ + -e 'end tell' \ + -e 'end try' >/dev/null 2>&1 || true +done + +echo "debug ui cleaned: port $PORT" diff --git a/scripts/start_business.sh b/scripts/start_business.sh new file mode 100755 index 0000000..6aa53d7 --- /dev/null +++ b/scripts/start_business.sh @@ -0,0 +1,39 @@ +#!/bin/sh +set -eu + +ROOT="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)" +COMPOSE_FILE="$ROOT/docker-compose.yml" + +cd "$ROOT" +docker compose -f "$COMPOSE_FILE" up -d --build collector n8n + +python3 - <<'PY' +import time +import urllib.request + +checks = [ + ("collector", "http://127.0.0.1:8081/healthz"), + ("n8n", "http://127.0.0.1:5670/healthz"), +] + +deadline = time.time() + 45 +pending = dict(checks) +while pending and time.time() < deadline: + for name, url in list(pending.items()): + try: + with urllib.request.urlopen(url, timeout=5) as resp: + print(f"{name} ready: {resp.status}") + pending.pop(name, None) + except Exception: + pass + if pending: + time.sleep(1) + +if pending: + print("startup timeout:", ", ".join(pending)) + raise SystemExit(1) +PY + +echo "business started" +echo "collector: http://127.0.0.1:8081/healthz" +echo "n8n: http://127.0.0.1:5670/healthz" diff --git a/scripts/start_collector.sh b/scripts/start_collector.sh index dc82da5..d806637 100755 --- a/scripts/start_collector.sh +++ b/scripts/start_collector.sh @@ -1,25 +1,28 @@ #!/bin/sh set -eu -ROOT="/Users/kris/code/StoryForge" -PID_FILE="$ROOT/data/collector/collector.pid" -LOG_FILE="$ROOT/data/collector/collector.log" -VENV="$ROOT/collector-service/.venv311" -mkdir -p "$ROOT/data/collector" -if [ ! -x "$VENV/bin/python" ]; then - /opt/homebrew/bin/python3.11 -m venv "$VENV" - . "$VENV/bin/activate" - pip install -q -r "$ROOT/collector-service/requirements.txt" -else - . "$VENV/bin/activate" -fi -if [ -f "$PID_FILE" ]; then - PID="$(cat "$PID_FILE" || true)" - if [ -n "$PID" ] && kill -0 "$PID" 2>/dev/null; then - echo "collector already running: $PID" - exit 0 - fi -fi -cd "$ROOT/collector-service" -nohup "$VENV/bin/python" -m uvicorn app.main:app --host 0.0.0.0 --port 8081 >"$LOG_FILE" 2>&1 & -echo $! > "$PID_FILE" -echo "collector started: $(cat "$PID_FILE")" + +ROOT="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)" +COMPOSE_FILE="$ROOT/docker-compose.yml" + +cd "$ROOT" +docker compose -f "$COMPOSE_FILE" up -d --build collector + +python3 - <<'PY' +import time +import urllib.request + +url = "http://127.0.0.1:8081/healthz" +deadline = time.time() + 30 +last_error = "" +while time.time() < deadline: + try: + with urllib.request.urlopen(url, timeout=5) as resp: + print(f"collector ready: {resp.status} {resp.read().decode('utf-8', 'ignore')[:160]}") + raise SystemExit(0) + except Exception as exc: + last_error = str(exc) + time.sleep(1) + +print(f"collector start timeout: {last_error}") +raise SystemExit(1) +PY diff --git a/scripts/status_business.sh b/scripts/status_business.sh new file mode 100755 index 0000000..137a3e6 --- /dev/null +++ b/scripts/status_business.sh @@ -0,0 +1,22 @@ +#!/bin/sh +set -eu + +ROOT="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)" +COMPOSE_FILE="$ROOT/docker-compose.yml" + +cd "$ROOT" +docker compose -f "$COMPOSE_FILE" ps +echo "---" +python3 - <<'PY' +import urllib.request + +for name, url in [ + ("collector", "http://127.0.0.1:8081/healthz"), + ("n8n", "http://127.0.0.1:5670/healthz"), +]: + try: + with urllib.request.urlopen(url, timeout=5) as resp: + print(f"{name}: {resp.status} {resp.read().decode('utf-8', 'ignore')[:200]}") + except Exception as exc: + print(f"{name}: ERROR {exc}") +PY diff --git a/scripts/status_collector.sh b/scripts/status_collector.sh index 6c6c170..616716f 100755 --- a/scripts/status_collector.sh +++ b/scripts/status_collector.sh @@ -1,15 +1,21 @@ #!/bin/sh set -eu -PID_FILE="/Users/kris/code/StoryForge/data/collector/collector.pid" -if [ -f "$PID_FILE" ]; then - PID="$(cat "$PID_FILE" || true)" - if [ -n "$PID" ] && kill -0 "$PID" 2>/dev/null; then - echo "running:$PID" - exit 0 - fi -fi -if lsof -nP -iTCP:8081 -sTCP:LISTEN >/dev/null 2>&1; then - echo "running:port" -else - echo "stopped" -fi + +ROOT="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)" +COMPOSE_FILE="$ROOT/docker-compose.yml" + +cd "$ROOT" +docker compose -f "$COMPOSE_FILE" ps collector +echo "---" +python3 - <<'PY' +import urllib.request + +url = "http://127.0.0.1:8081/healthz" +try: + with urllib.request.urlopen(url, timeout=5) as resp: + print(f"collector health: {resp.status}") + print(resp.read().decode("utf-8", "ignore")[:400]) +except Exception as exc: + print(f"collector health error: {exc}") + raise SystemExit(1) +PY diff --git a/scripts/stop_collector.sh b/scripts/stop_collector.sh index 7ec50be..d681e08 100755 --- a/scripts/stop_collector.sh +++ b/scripts/stop_collector.sh @@ -1,15 +1,9 @@ #!/bin/sh set -eu -PID_FILE="/Users/kris/code/StoryForge/data/collector/collector.pid" -if [ ! -f "$PID_FILE" ]; then - echo "collector not running" - exit 0 -fi -PID="$(cat "$PID_FILE" || true)" -if [ -n "$PID" ] && kill -0 "$PID" 2>/dev/null; then - kill "$PID" - echo "collector stopped: $PID" -else - echo "collector pid stale: $PID" -fi -rm -f "$PID_FILE" + +ROOT="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)" +COMPOSE_FILE="$ROOT/docker-compose.yml" + +cd "$ROOT" +docker compose -f "$COMPOSE_FILE" stop collector +echo "collector stopped"