feat: add spacetimedb json migration tooling
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-27 14:54:26 +08:00
parent ded6f6ee2a
commit 9a79494c68
13 changed files with 1532 additions and 2 deletions

View File

@@ -27,7 +27,8 @@ usage() {
--skip-upload 只生成本地发布包,不上传服务器
--skip-web-build 跳过 Vite 构建,仅用于调试
--skip-api-build 跳过 api-server 构建,仅用于调试
--skip-spacetime-build 跳过 wasm 构建,仅用于调试
--skip-spacetime-build 跳过 wasm 构建,仅用于调试;此时必须同时传 --no-migration-bootstrap-secret
--no-migration-bootstrap-secret 构建不带迁移引导密钥的 spacetime-module wasm
目标服务器要求:
Ubuntu x86_64已安装 node、spacetime CLI并允许执行目标目录内的 start.sh / stop.sh。
@@ -127,6 +128,36 @@ replace_placeholder_in_file() {
sed -i "s|${placeholder}|${escaped_value}|g" "${file_path}"
}
generate_migration_bootstrap_secret() {
node -e 'const crypto = require("crypto"); process.stdout.write(crypto.randomBytes(32).toString("hex"));'
}
prepare_migration_bootstrap_secret() {
case "${MIGRATION_BOOTSTRAP_SECRET_MODE}" in
auto)
MIGRATION_BOOTSTRAP_SECRET="$(generate_migration_bootstrap_secret)"
;;
manual)
if [[ "${#MIGRATION_BOOTSTRAP_SECRET}" -lt 16 ]]; then
echo "[deploy:rust] 迁移引导密钥至少需要 16 个字符。" >&2
exit 1
fi
;;
disabled)
unset GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET
echo "[deploy:rust] 未启用迁移引导密钥。"
return
;;
*)
echo "[deploy:rust] 未知迁移引导密钥模式: ${MIGRATION_BOOTSTRAP_SECRET_MODE}" >&2
exit 1
;;
esac
export GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET="${MIGRATION_BOOTSTRAP_SECRET}"
echo "[deploy:rust] 迁移引导密钥: ${MIGRATION_BOOTSTRAP_SECRET}"
}
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
SERVER_RS_DIR="${REPO_ROOT}/server-rs"
@@ -147,6 +178,8 @@ SKIP_WEB_BUILD=0
SKIP_API_BUILD=0
SKIP_SPACETIME_BUILD=0
BUILD_COMPLETED=0
MIGRATION_BOOTSTRAP_SECRET=""
MIGRATION_BOOTSTRAP_SECRET_MODE="auto"
while [[ $# -gt 0 ]]; do
case "$1" in
@@ -214,6 +247,16 @@ while [[ $# -gt 0 ]]; do
SKIP_SPACETIME_BUILD=1
shift
;;
--migration-bootstrap-secret)
MIGRATION_BOOTSTRAP_SECRET="${2:?缺少 --migration-bootstrap-secret 的值}"
MIGRATION_BOOTSTRAP_SECRET_MODE="manual"
shift 2
;;
--no-migration-bootstrap-secret)
MIGRATION_BOOTSTRAP_SECRET=""
MIGRATION_BOOTSTRAP_SECRET_MODE="disabled"
shift
;;
*)
echo "[deploy:rust] 未知参数: $1" >&2
usage >&2
@@ -227,6 +270,12 @@ if [[ ! "${BUILD_NAME}" =~ ^[0-9A-Za-z._-]+$ ]]; then
exit 1
fi
if [[ "${SKIP_SPACETIME_BUILD}" -eq 1 && "${MIGRATION_BOOTSTRAP_SECRET_MODE}" != "disabled" ]]; then
echo "[deploy:rust] --skip-spacetime-build 无法把迁移引导密钥注入 wasm。" >&2
echo "[deploy:rust] 请移除 --skip-spacetime-build或同时传 --no-migration-bootstrap-secret。" >&2
exit 1
fi
TARGET_DIR="${BUILD_ROOT}/${BUILD_NAME}"
WEB_DIR="${TARGET_DIR}/web"
API_BINARY_SOURCE="${SERVER_RS_DIR}/target/x86_64-unknown-linux-gnu/release/api-server"
@@ -249,6 +298,8 @@ fi
require_command node
require_command cargo
prepare_migration_bootstrap_secret
if [[ "${SKIP_WEB_BUILD}" -ne 1 ]]; then
require_command npm
fi
@@ -310,6 +361,11 @@ fi
copy_required_file "${WASM_SOURCE}" "${TARGET_DIR}/spacetime_module.wasm" "spacetime-module wasm"
if [[ "${MIGRATION_BOOTSTRAP_SECRET_MODE}" != "disabled" ]]; then
printf "%s\n" "${MIGRATION_BOOTSTRAP_SECRET}" >"${TARGET_DIR}/migration-bootstrap-secret.txt"
chmod 600 "${TARGET_DIR}/migration-bootstrap-secret.txt"
fi
cat >"${TARGET_DIR}/web-server.mjs" <<'WEB_SERVER'
import http from 'node:http';
import fs from 'node:fs';
@@ -529,6 +585,7 @@ API_PORT="${GENARRATIVE_API_PORT:-__GENARRATIVE_DEFAULT_API_PORT__}"
API_LOG="${GENARRATIVE_API_LOG:-info,tower_http=info}"
WEB_HOST="${GENARRATIVE_WEB_HOST:-__GENARRATIVE_DEFAULT_WEB_HOST__}"
WEB_PORT="${GENARRATIVE_WEB_PORT:-__GENARRATIVE_DEFAULT_WEB_PORT__}"
MIGRATION_BOOTSTRAP_SECRET_FILE="${SCRIPT_DIR}/migration-bootstrap-secret.txt"
# 日志默认落文件,显式关闭 ANSI 颜色码,避免控制字符写入 *.log。
export NO_COLOR="${NO_COLOR:-1}"
@@ -778,6 +835,11 @@ if [[ "${CLEAR_DATABASE}" -eq 1 ]]; then
fi
echo "[start] 发布 SpacetimeDB wasm: ${SPACETIME_DATABASE}"
if [[ -f "${MIGRATION_BOOTSTRAP_SECRET_FILE}" ]]; then
echo "[start] 迁移引导密钥: $(cat "${MIGRATION_BOOTSTRAP_SECRET_FILE}")"
else
echo "[start] 未启用迁移引导密钥。"
fi
if ! spacetime --root-dir="${SPACETIME_ROOT_DIR}" "${PUBLISH_ARGS[@]}"; then
echo "[start] SpacetimeDB 发布失败。" >&2
echo "[start] 如果错误包含 403 Forbidden 或 is not authorized通常是当前 CLI 身份无权更新目标数据库。" >&2
@@ -868,6 +930,7 @@ cat >"${TARGET_DIR}/README.md" <<EOF
- \`web/\`Vite release 静态资源
- \`api-server\`x86_64-unknown-linux-gnu release 可执行文件
- \`spacetime_module.wasm\`wasm32-unknown-unknown release 模块
- \`migration-bootstrap-secret.txt\`:本发布包 wasm 编译时注入的迁移引导密钥;服务器 \`start.sh\` 发布时会显示,迁移授权完成后可删除
- \`web-server.mjs\`:静态网站与 API 反代入口
- \`start.sh\` / \`stop.sh\`:目标服务器启动与停止脚本
@@ -896,6 +959,7 @@ cat >"${TARGET_DIR}/README.md" <<EOF
- \`GENARRATIVE_SPACETIME_ROOT_DIR\`:默认使用发布目录下的 \`.spacetimedb/\`,同时承载本地 SpacetimeDB 运行数据与 CLI 身份。
- \`GENARRATIVE_SPACETIME_TIMEOUT_SECONDS\`:等待 SpacetimeDB 就绪的秒数,默认 \`60\`。
- OSS、LLM、短信、微信等业务密钥仍通过目标服务器环境变量或同目录 \`.env.local\` 管理。
- 迁移引导密钥由构建发布包时随机生成,构建日志和服务器 \`start.sh\` 发布日志都会显示同一份密钥。
EOF
BUILD_COMPLETED=1