feat: harden recording lifecycle and refresh fnOS UI
This commit is contained in:
+9
-176
@@ -8,29 +8,22 @@ VOLUME_ROOT="${TRIM_APPDEST_VOL:-$DATA_ROOT/volume}"
|
||||
RECORD_ROOT="${LIVE_RECORDER_RECORD_ROOT:-$VOLUME_ROOT/@appshare/liverecorder/records}"
|
||||
RUNTIME_ROOT="$APP_ROOT/runtime"
|
||||
SERVER="$APP_ROOT/server/LiveRecorder.WebApi"
|
||||
PG_BIN="$RUNTIME_ROOT/usr/lib/postgresql/15/bin"
|
||||
PG_SHARE="$RUNTIME_ROOT/usr/share/postgresql/15"
|
||||
PG_LIB="$RUNTIME_ROOT/usr/lib/postgresql/15/lib"
|
||||
NODE_BIN="$RUNTIME_ROOT/bin/node"
|
||||
NODEJS_ROOT="${NODEJS_ROOT:-/var/apps/nodejs_v22/target}"
|
||||
NODE_BIN="$NODEJS_ROOT/bin/node"
|
||||
CURL_BIN="$RUNTIME_ROOT/bin/curl"
|
||||
CA_BUNDLE="$RUNTIME_ROOT/etc/ssl/certs/ca-certificates.crt"
|
||||
PG_DATA="$DATA_ROOT/postgres"
|
||||
RUN_ROOT="$DATA_ROOT/run"
|
||||
LOG_ROOT="$DATA_ROOT/log"
|
||||
APP_PID_FILE="$RUN_ROOT/liverecorder.pid"
|
||||
APP_LOG="$LOG_ROOT/liverecorder.log"
|
||||
PG_LOG="$LOG_ROOT/postgresql.log"
|
||||
ADMIN_PASSWORD_FILE="$DATA_ROOT/admin-password.seed"
|
||||
POSTGRES_ENROLLMENT_TOKEN_FILE="$DATA_ROOT/postgres-enrollment-token.seed"
|
||||
POSTGRES_CREDENTIALS_FILE="$DATA_ROOT/postgres-client.conf"
|
||||
POSTGRES_MIGRATION_ROOT="$DATA_ROOT/postgres-migration"
|
||||
POSTGRES_MIGRATION_MARKER="$POSTGRES_MIGRATION_ROOT/shared-database.active"
|
||||
PG_PORT="${LIVE_RECORDER_POSTGRES_PORT:-54329}"
|
||||
SERVICE_PORT="${TRIM_SERVICE_PORT:-18080}"
|
||||
POSTGRES_SERVICE_API="${POSTGRES_SERVICE_API:-http://127.0.0.1:15433}"
|
||||
SYSTEM_PATH="${PATH:-/usr/local/bin:/usr/bin:/bin}"
|
||||
RUNTIME_PATH="$RUNTIME_ROOT/bin:$SYSTEM_PATH"
|
||||
RUNTIME_LIBRARY_PATH="$RUNTIME_ROOT/lib:$PG_LIB"
|
||||
RUNTIME_PATH="$RUNTIME_ROOT/bin:$NODEJS_ROOT/bin:$SYSTEM_PATH"
|
||||
RUNTIME_LIBRARY_PATH="$RUNTIME_ROOT/lib"
|
||||
DATABASE_CONNECTION_STRING=""
|
||||
SHARED_DB_HOST=""
|
||||
SHARED_DB_PORT=""
|
||||
@@ -54,10 +47,6 @@ app_pid() {
|
||||
return 1
|
||||
}
|
||||
|
||||
run_pg() {
|
||||
env LD_LIBRARY_PATH="$RUNTIME_LIBRARY_PATH" PATH="$PG_BIN:$RUNTIME_PATH" "$@"
|
||||
}
|
||||
|
||||
run_native() {
|
||||
env LD_LIBRARY_PATH="$RUNTIME_LIBRARY_PATH" PATH="$RUNTIME_PATH" \
|
||||
SSL_CERT_FILE="$CA_BUNDLE" CURL_CA_BUNDLE="$CA_BUNDLE" "$@"
|
||||
@@ -144,94 +133,11 @@ ensure_shared_credentials() {
|
||||
enroll_shared_database
|
||||
}
|
||||
|
||||
run_shared_pg() {
|
||||
env LD_LIBRARY_PATH="$RUNTIME_LIBRARY_PATH" PATH="$PG_BIN:$RUNTIME_PATH" \
|
||||
PGPASSWORD="$SHARED_DB_PASSWORD" "$@"
|
||||
}
|
||||
|
||||
collect_database_counts() {
|
||||
mode=$1
|
||||
destination=$2
|
||||
: >"$destination"
|
||||
for table_name in AppSettings CleanupOperations LiveRooms RecordResults RecordSessions RecordTasks RecordUploadJobs SystemLogEntries UserAccounts UserSessions; do
|
||||
if [ "$mode" = "private" ]; then
|
||||
count=$(run_pg "$PG_BIN/psql" -h "$RUN_ROOT" -p "$PG_PORT" -U liverecorder -d live_recorder -Atqc \
|
||||
"SELECT count(*) FROM \"$table_name\"" 2>/dev/null) || return 1
|
||||
else
|
||||
count=$(run_shared_pg "$PG_BIN/psql" -h "$SHARED_DB_HOST" -p "$SHARED_DB_PORT" -U "$SHARED_DB_USER" -d "$SHARED_DB_NAME" -Atqc \
|
||||
"SELECT count(*) FROM \"$table_name\"" 2>/dev/null) || return 1
|
||||
fi
|
||||
printf '%s=%s\n' "$table_name" "$count" >>"$destination"
|
||||
done
|
||||
}
|
||||
|
||||
migrate_private_postgres() {
|
||||
mkdir -p "$POSTGRES_MIGRATION_ROOT"
|
||||
chmod 0700 "$POSTGRES_MIGRATION_ROOT"
|
||||
dump_file="$POSTGRES_MIGRATION_ROOT/private-postgres-15.dump"
|
||||
source_counts="$POSTGRES_MIGRATION_ROOT/source-counts.txt"
|
||||
target_counts="$POSTGRES_MIGRATION_ROOT/target-counts.txt"
|
||||
start_postgres || return 1
|
||||
|
||||
log_message "开始导出原内置 PostgreSQL 数据库。"
|
||||
run_pg "$PG_BIN/pg_dump" \
|
||||
-h "$RUN_ROOT" -p "$PG_PORT" -U liverecorder -d live_recorder \
|
||||
--format=custom --no-owner --no-acl --file "$dump_file.tmp" >>"$PG_LOG" 2>&1 || return 1
|
||||
mv "$dump_file.tmp" "$dump_file"
|
||||
sha256sum "$dump_file" >"$dump_file.sha256"
|
||||
collect_database_counts private "$source_counts" || return 1
|
||||
|
||||
log_message "开始恢复数据到 PostgreSQL 共享服务。"
|
||||
run_shared_pg "$PG_BIN/psql" \
|
||||
-h "$SHARED_DB_HOST" -p "$SHARED_DB_PORT" -U "$SHARED_DB_USER" -d "$SHARED_DB_NAME" \
|
||||
-v ON_ERROR_STOP=1 -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public AUTHORIZATION \"$SHARED_DB_USER\"" >>"$PG_LOG" 2>&1 || return 1
|
||||
run_shared_pg "$PG_BIN/pg_restore" \
|
||||
-h "$SHARED_DB_HOST" -p "$SHARED_DB_PORT" -U "$SHARED_DB_USER" -d "$SHARED_DB_NAME" \
|
||||
--no-owner --no-acl --exit-on-error "$dump_file" >>"$PG_LOG" 2>&1 || return 1
|
||||
collect_database_counts shared "$target_counts" || return 1
|
||||
if ! cmp -s "$source_counts" "$target_counts"; then
|
||||
log_message "共享数据库行数校验失败,继续使用原数据库。"
|
||||
return 1
|
||||
fi
|
||||
|
||||
umask 077
|
||||
{
|
||||
printf 'migrated_at=%s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
|
||||
printf 'database=%s\n' "$SHARED_DB_NAME"
|
||||
printf 'dump=%s\n' "$dump_file"
|
||||
} >"$POSTGRES_MIGRATION_MARKER"
|
||||
stop_postgres || return 1
|
||||
log_message "内置 PostgreSQL 已迁移到共享服务,旧数据和迁移转储已保留。"
|
||||
}
|
||||
|
||||
select_database_connection() {
|
||||
if ! ensure_shared_credentials; then
|
||||
if [ -f "$POSTGRES_MIGRATION_MARKER" ]; then
|
||||
log_message "已完成共享数据库迁移,但当前凭据不可用;为避免使用过期旧库,应用不会启动。"
|
||||
return 1
|
||||
fi
|
||||
if [ -f "$PG_DATA/PG_VERSION" ]; then
|
||||
log_message "共享服务暂不可用,本次启动继续使用原内置 PostgreSQL。"
|
||||
start_postgres || return 1
|
||||
DATABASE_CONNECTION_STRING="Host=$RUN_ROOT;Port=$PG_PORT;Database=live_recorder;Username=liverecorder;Timeout=15;Command Timeout=120;Keepalive=30"
|
||||
return 0
|
||||
fi
|
||||
ensure_shared_credentials || {
|
||||
log_message "无法连接 PostgreSQL 共享服务或取得数据库凭据,应用不会启动。"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -f "$PG_DATA/PG_VERSION" ] && [ ! -f "$POSTGRES_MIGRATION_MARKER" ]; then
|
||||
if ! migrate_private_postgres; then
|
||||
log_message "共享数据库迁移失败,本次启动继续使用原内置 PostgreSQL;下次启动会重试迁移。"
|
||||
start_postgres || return 1
|
||||
DATABASE_CONNECTION_STRING="Host=$RUN_ROOT;Port=$PG_PORT;Database=live_recorder;Username=liverecorder;Timeout=15;Command Timeout=120;Keepalive=30"
|
||||
return 0
|
||||
fi
|
||||
elif [ ! -f "$PG_DATA/PG_VERSION" ] && [ ! -f "$POSTGRES_MIGRATION_MARKER" ]; then
|
||||
mkdir -p "$POSTGRES_MIGRATION_ROOT"
|
||||
umask 077
|
||||
printf 'fresh_install_at=%s\ndatabase=%s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$SHARED_DB_NAME" >"$POSTGRES_MIGRATION_MARKER"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
system_media_tools_available() {
|
||||
@@ -248,78 +154,6 @@ system_media_tools_available() {
|
||||
return 0
|
||||
}
|
||||
|
||||
postgres_running() {
|
||||
[ -x "$PG_BIN/pg_ctl" ] || return 1
|
||||
[ -f "$PG_DATA/PG_VERSION" ] || return 1
|
||||
run_pg "$PG_BIN/pg_ctl" -D "$PG_DATA" status >/dev/null 2>&1
|
||||
}
|
||||
|
||||
initialize_postgres() {
|
||||
if [ -f "$PG_DATA/PG_VERSION" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
mkdir -p "$PG_DATA" "$RUN_ROOT"
|
||||
chmod 0700 "$PG_DATA" "$RUN_ROOT"
|
||||
if ! run_pg "$PG_BIN/initdb" \
|
||||
-D "$PG_DATA" \
|
||||
-L "$PG_SHARE" \
|
||||
--username=liverecorder \
|
||||
--auth-local=trust \
|
||||
--auth-host=reject \
|
||||
--encoding=UTF8 \
|
||||
--no-locale >>"$PG_LOG" 2>&1; then
|
||||
log_message "PostgreSQL 初始化失败。"
|
||||
return 1
|
||||
fi
|
||||
|
||||
{
|
||||
printf "listen_addresses = ''\n"
|
||||
printf "port = %s\n" "$PG_PORT"
|
||||
printf "unix_socket_directories = '%s'\n" "$RUN_ROOT"
|
||||
printf "max_connections = 40\n"
|
||||
printf "shared_buffers = '64MB'\n"
|
||||
printf "timezone = 'UTC'\n"
|
||||
printf "log_timezone = 'UTC'\n"
|
||||
} >>"$PG_DATA/postgresql.conf"
|
||||
return 0
|
||||
}
|
||||
|
||||
start_postgres() {
|
||||
if postgres_running; then
|
||||
return 0
|
||||
fi
|
||||
initialize_postgres || return 1
|
||||
if ! run_pg "$PG_BIN/pg_ctl" -D "$PG_DATA" -l "$PG_LOG" -w start; then
|
||||
log_message "PostgreSQL 启动失败。"
|
||||
return 1
|
||||
fi
|
||||
|
||||
database_exists=$(run_pg "$PG_BIN/psql" \
|
||||
-h "$RUN_ROOT" -p "$PG_PORT" -U liverecorder -d postgres -Atqc \
|
||||
"SELECT 1 FROM pg_database WHERE datname = 'live_recorder'" 2>/dev/null || true)
|
||||
if [ "$database_exists" != "1" ]; then
|
||||
if ! run_pg "$PG_BIN/createdb" \
|
||||
-h "$RUN_ROOT" -p "$PG_PORT" -U liverecorder live_recorder >>"$PG_LOG" 2>&1; then
|
||||
log_message "Live Recorder 数据库创建失败。"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
stop_postgres() {
|
||||
if postgres_running; then
|
||||
# A first-run migration can dirty enough pages that a NAS needs more
|
||||
# than pg_ctl's 60-second default to finish the shutdown checkpoint.
|
||||
# Do not let restart race a database that is still shutting down.
|
||||
if ! run_pg "$PG_BIN/pg_ctl" -D "$PG_DATA" -m fast -t 180 -w stop >>"$PG_LOG" 2>&1; then
|
||||
log_message "PostgreSQL 未能在 180 秒内安全停止,已取消后续重启。"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
launch_app_process() {
|
||||
(
|
||||
export ASPNETCORE_ENVIRONMENT=Production
|
||||
@@ -354,7 +188,7 @@ start_app() {
|
||||
log_message "应用程序不存在或不可执行:$SERVER"
|
||||
return 1
|
||||
fi
|
||||
if [ ! -x "$PG_BIN/postgres" ] || [ ! -x "$NODE_BIN" ] || [ ! -x "$CURL_BIN" ] || [ ! -s "$CA_BUNDLE" ]; then
|
||||
if [ ! -x "$NODE_BIN" ] || [ ! -x "$CURL_BIN" ] || [ ! -s "$CA_BUNDLE" ]; then
|
||||
log_message "FPK 原生运行环境不完整。"
|
||||
return 1
|
||||
fi
|
||||
@@ -400,7 +234,7 @@ stop_app() {
|
||||
if pid=$(app_pid); then
|
||||
kill "$pid" 2>/dev/null || true
|
||||
attempt=0
|
||||
while kill -0 "$pid" 2>/dev/null && [ "$attempt" -lt 30 ]; do
|
||||
while kill -0 "$pid" 2>/dev/null && [ "$attempt" -lt 50 ]; do
|
||||
sleep 1
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
@@ -409,7 +243,6 @@ stop_app() {
|
||||
fi
|
||||
fi
|
||||
rm -f "$APP_PID_FILE"
|
||||
stop_postgres
|
||||
}
|
||||
|
||||
case "${1:-status}" in
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
# Persistent PostgreSQL data and recordings are preserved by default.
|
||||
# Persistent application data and recordings are preserved by default.
|
||||
exit 0
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
appname=liverecorder
|
||||
version=1.1.0
|
||||
version=1.2.13
|
||||
display_name=Live Recorder
|
||||
desc=原生直播录制系统,使用独立 PostgreSQL 共享服务,支持分片录制、弹幕采集与 OpenList 自动上传
|
||||
platform=x86
|
||||
@@ -10,4 +10,4 @@ desktop_uidir=ui
|
||||
desktop_applaunchname=liverecorder.Application
|
||||
checkport=true
|
||||
ctl_stop=true
|
||||
install_dep_apps=nxsir.postgresql
|
||||
install_dep_apps=nxsir.postgresql:nodejs_v22
|
||||
|
||||
+2
-2
@@ -4,13 +4,13 @@
|
||||
"items": [
|
||||
{
|
||||
"type": "tips",
|
||||
"helpText": "本次升级会自动把原内置 PostgreSQL 数据迁移到共享服务。迁移成功前仍可回退到原数据库,旧数据不会自动删除。"
|
||||
"helpText": "本版本仅使用独立 PostgreSQL 共享服务,不再包含或启动内置数据库。已有共享数据库凭据可继续使用。"
|
||||
},
|
||||
{
|
||||
"type": "password",
|
||||
"field": "wizard_postgres_enrollment_token",
|
||||
"label": "PostgreSQL 应用接入令牌",
|
||||
"helpText": "首次迁移需要填写共享服务的应用接入令牌;已经完成迁移的后续升级可以留空。",
|
||||
"helpText": "尚未取得共享数据库凭据时需要填写应用接入令牌;已有有效凭据的后续升级可以留空。",
|
||||
"rules": [
|
||||
{
|
||||
"max": 256,
|
||||
|
||||
Reference in New Issue
Block a user