fix: restore fnos live recorder deployment
Some checks failed
StoryForge CI / Baseline checks (push) Has been cancelled
StoryForge CI / Backend tests (push) Has been cancelled
StoryForge CI / Web tests (push) Has been cancelled

This commit is contained in:
kris
2026-04-06 08:55:56 +08:00
parent ec35927fa5
commit 4546c95e8c
5 changed files with 169 additions and 6 deletions

View File

@@ -9,20 +9,23 @@ BACKEND_URL="${STORYFORGE_FNOS_BACKEND_URL:-http://$FNOS_HOST:$COLLECTOR_PORT}"
SKIP_TUNNEL="${SKIP_TUNNEL:-0}"
SKIP_SMOKE="${SKIP_SMOKE:-0}"
echo "[1/4] ensure fnOS cutvideo tunnel"
echo "[1/5] ensure fnOS cutvideo tunnel"
if [ "$SKIP_TUNNEL" = "1" ]; then
echo "skip tunnel deployment because SKIP_TUNNEL=1"
else
STORYFORGE_FNOS_BACKEND_URL="$BACKEND_URL" bash "$ROOT/scripts/deploy_fnos_cutvideo_tunnel.sh"
fi
echo "[2/4] deploy fnOS collector"
echo "[2/5] deploy fnOS live recorder"
bash "$ROOT/scripts/deploy_fnos_storyforge_live_recorder.sh"
echo "[3/5] deploy fnOS collector"
STORYFORGE_FNOS_COLLECTOR_URL="$BACKEND_URL" bash "$ROOT/scripts/deploy_fnos_storyforge_collector.sh"
echo "[3/4] deploy fnOS web"
echo "[4/5] deploy fnOS web"
STORYFORGE_FNOS_BACKEND_URL="$BACKEND_URL" bash "$ROOT/scripts/deploy_fnos_storyforge_web.sh"
echo "[4/4] smoke fnOS lan stack"
echo "[5/5] smoke fnOS lan stack"
if [ "$SKIP_SMOKE" = "1" ]; then
echo "skip smoke because SKIP_SMOKE=1"
else

View File

@@ -0,0 +1,137 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)"
export CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
export FNOS_SKILL="${FNOS_SKILL:-$CODEX_HOME/skills/fnos-hyzq-deploy}"
export FNOS_SSH="${FNOS_SSH:-$FNOS_SKILL/scripts/fnos_ssh.sh}"
export FNOS_SCP="${FNOS_SCP:-$FNOS_SKILL/scripts/fnos_scp.sh}"
FNOS_HOST="${FNOS_HOST:-192.168.31.188}"
FNOS_USER="${FNOS_USER:-krisolo}"
LIVE_RECORDER_SOURCE_DIR="${LIVE_RECORDER_SOURCE_DIR:-/Users/kris/code/DouyinLiveRecorder-main}"
REMOTE_ROOT="${STORYFORGE_FNOS_REMOTE_ROOT:-/vol1/docker/hyzq-stack/current/storyforge}"
REMOTE_SOURCE_PARENT="$REMOTE_ROOT"
REMOTE_SOURCE_DIR="$REMOTE_ROOT/live-recorder-source"
REMOTE_COMPOSE_DIR="${STORYFORGE_FNOS_COMPOSE_DIR:-/vol1/docker/hyzq-stack/current/deploy/fnos}"
REMOTE_COMPOSE_FILE="$REMOTE_COMPOSE_DIR/storyforge-fnos-live-recorder.compose.yaml"
LIVE_RECORDER_PORT="${STORYFORGE_LIVE_RECORDER_PORT:-19106}"
LIVE_RECORDER_IMAGE="${STORYFORGE_LIVE_RECORDER_IMAGE:-storyforge-live-recorder:fnos}"
LIVE_RECORDER_BASE_IMAGE="${STORYFORGE_LIVE_RECORDER_BASE_IMAGE:-docker.m.daocloud.io/library/python:3.11-slim}"
LIVE_RECORDER_STATE_ROOT="${STORYFORGE_LIVE_RECORDER_STATE_ROOT:-/vol1/docker/hyzq-stack/shared/storyforge-live-recorder}"
need_cmd() {
if ! command -v "$1" >/dev/null 2>&1; then
echo "missing required command: $1" >&2
exit 1
fi
}
need_cmd python3
need_cmd security
need_cmd rsync
if [ ! -f "$LIVE_RECORDER_SOURCE_DIR/webui.py" ]; then
echo "live recorder source missing webui.py: $LIVE_RECORDER_SOURCE_DIR" >&2
exit 1
fi
shell_quote() {
python3 - "$1" <<'PY'
import shlex
import sys
print(shlex.quote(sys.argv[1]))
PY
}
resolve_password() {
if [ -n "${FNOS_PASSWORD:-}" ]; then
printf '%s' "$FNOS_PASSWORD"
return 0
fi
security find-internet-password -s "$FNOS_HOST" -a "$FNOS_USER" -w
}
run_remote_sudo() {
local password="$1"
shift
local remote_cmd="$*"
local password_quoted
password_quoted="$(shell_quote "$password")"
"$FNOS_SSH" "$(shell_quote "printf '%s\\n' $password_quoted | sudo -S -p '' sh -lc $(shell_quote "$remote_cmd")")"
}
PASSWORD="$(resolve_password)"
TMPDIR_DEPLOY="$(mktemp -d)"
FILTERED_SOURCE_DIR="$TMPDIR_DEPLOY/live-recorder-source"
trap 'rm -rf "$TMPDIR_DEPLOY"' EXIT
mkdir -p "$FILTERED_SOURCE_DIR"
rsync -a --delete \
--exclude '.git' \
--exclude '.github' \
--exclude '__pycache__' \
--exclude '*.pyc' \
--exclude '.venv' \
--exclude 'downloads' \
--exclude 'logs' \
--exclude 'backup_config' \
"$LIVE_RECORDER_SOURCE_DIR/" "$FILTERED_SOURCE_DIR/"
cat >"$FILTERED_SOURCE_DIR/Dockerfile.storyforge" <<EOF
ARG BASE_IMAGE=$LIVE_RECORDER_BASE_IMAGE
FROM \$BASE_IMAGE
WORKDIR /app
COPY . /app
RUN apt-get update && \\
apt-get install -y curl gnupg && \\
curl -sL https://deb.nodesource.com/setup_20.x | bash - && \\
apt-get install -y nodejs
RUN pip install --no-cache-dir -r requirements.txt
RUN apt-get update && \\
apt-get install -y ffmpeg tzdata && \\
ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \\
dpkg-reconfigure -f noninteractive tzdata
CMD ["python", "main.py"]
EOF
echo "[1/5] prepare remote directories"
"$FNOS_SSH" "$(shell_quote "rm -rf $(shell_quote "$REMOTE_SOURCE_DIR") && mkdir -p $(shell_quote "$REMOTE_SOURCE_PARENT") $(shell_quote "$REMOTE_COMPOSE_DIR") $(shell_quote "$LIVE_RECORDER_STATE_ROOT")")"
run_remote_sudo "$PASSWORD" "mkdir -p \
$(shell_quote "$LIVE_RECORDER_STATE_ROOT/config") \
$(shell_quote "$LIVE_RECORDER_STATE_ROOT/logs") \
$(shell_quote "$LIVE_RECORDER_STATE_ROOT/backup_config") \
$(shell_quote "$LIVE_RECORDER_STATE_ROOT/downloads")"
echo "[2/5] sync live recorder source"
"$FNOS_SCP" "$REMOTE_SOURCE_PARENT" "$FILTERED_SOURCE_DIR"
echo "[3/5] sync compose file"
"$FNOS_SCP" "$REMOTE_COMPOSE_DIR" "$ROOT/deploy/storyforge-fnos-live-recorder.compose.yaml"
echo "[4/5] build and restart live recorder"
run_remote_sudo "$PASSWORD" "cd $(shell_quote "$REMOTE_COMPOSE_DIR") && \
STORYFORGE_LIVE_RECORDER_PORT=$(shell_quote "$LIVE_RECORDER_PORT") \
STORYFORGE_LIVE_RECORDER_IMAGE=$(shell_quote "$LIVE_RECORDER_IMAGE") \
STORYFORGE_LIVE_RECORDER_BASE_IMAGE=$(shell_quote "$LIVE_RECORDER_BASE_IMAGE") \
STORYFORGE_LIVE_RECORDER_STATE_ROOT=$(shell_quote "$LIVE_RECORDER_STATE_ROOT") \
docker compose -f $(shell_quote "$REMOTE_COMPOSE_FILE") up -d --build --force-recreate storyforge-live-recorder && \
STORYFORGE_LIVE_RECORDER_PORT=$(shell_quote "$LIVE_RECORDER_PORT") docker compose -f $(shell_quote "$REMOTE_COMPOSE_FILE") ps"
echo "[5/5] verify live recorder health"
for _attempt in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
if curl -fsS "http://$FNOS_HOST:$LIVE_RECORDER_PORT/api/healthz" >/dev/null; then
break
fi
sleep 2
done
curl -fsS "http://$FNOS_HOST:$LIVE_RECORDER_PORT/api/healthz" >/dev/null
echo "fnOS StoryForge live recorder ready: http://$FNOS_HOST:$LIVE_RECORDER_PORT/"

View File

@@ -10,6 +10,7 @@ WEB_URL="${STORYFORGE_FNOS_WEB_URL:-http://$FNOS_HOST:$WEB_PORT}"
BACKEND_URL="${STORYFORGE_FNOS_COLLECTOR_URL:-http://$FNOS_HOST:$COLLECTOR_PORT}"
CUTVIDEO_URL="${CUTVIDEO_BASE_URL:-http://$FNOS_HOST:$CUTVIDEO_FORWARD_PORT}"
COMPAT_URL="${STORYFORGE_COMPAT_BASE_URL:-http://$FNOS_HOST:$STORYFORGE_COMPAT_FORWARD_PORT}"
LIVE_RECORDER_URL="${LIVE_RECORDER_BASE_URL:-http://$FNOS_HOST:19106}"
CURL_MAX_TIME="${STORYFORGE_FNOS_CURL_MAX_TIME:-60}"
need_cmd() {
@@ -39,6 +40,7 @@ action_registry_file="$tmp_dir/action-registry.json"
integrations_file="$tmp_dir/integrations.json"
bootstrap_file="$tmp_dir/bootstrap.json"
compat_file="$tmp_dir/compat.html"
live_recorder_health_file="$tmp_dir/live-recorder-health.json"
token_file="$tmp_dir/token.txt"
project_id_file="$tmp_dir/project-id.txt"
@@ -138,7 +140,7 @@ if not cutvideo.get("supports_uploads"):
print("integrations ok")
' "$integrations_file" "$CUTVIDEO_URL"
echo "[7/7] check fnOS tunnel endpoints"
echo "[7/8] check fnOS tunnel endpoints"
curl_fetch "$CUTVIDEO_URL/api/bootstrap" >"$bootstrap_file"
curl_fetch "$COMPAT_URL/" >"$compat_file"
python3 -c '
@@ -154,8 +156,19 @@ if ! rg -Fq "数字人网页业务台" "$compat_file" && ! rg -Fq "BUSINESS CONS
fi
echo "compat ok"
echo "[8/8] check live recorder health"
curl_fetch "$LIVE_RECORDER_URL/api/healthz" >"$live_recorder_health_file"
python3 -c '
import json, pathlib, sys
payload = json.loads(pathlib.Path(sys.argv[1]).read_text())
if payload.get("ok") is not True:
raise SystemExit(f"unexpected live recorder health payload: {payload!r}")
print("live recorder ok")
' "$live_recorder_health_file"
echo "fnOS lan smoke passed:"
echo " web: $WEB_URL/"
echo " collector: $BACKEND_URL"
echo " cutvideo: $CUTVIDEO_URL"
echo " compat: $COMPAT_URL"
echo " live_recorder: $LIVE_RECORDER_URL"