Files
Genarrative/scripts/dev-rust-stack.sh

281 lines
6.8 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
用法:
npm run dev:rust:sh
./scripts/dev-rust-stack.sh --api-port 8090 --spacetime-port 3110
./scripts/dev-rust-stack.sh --skip-spacetime --skip-publish
./scripts/dev-rust-stack.sh --clear-database
说明:
1. 默认同时启动 SpacetimeDB standalone、Rust api-server 与 Vite 前端。
2. 默认会 publish server-rs/crates/spacetime-module但不会清空数据库。
3. 只有显式传入 --clear-database 时,才会追加 spacetime publish --clear-database。
EOF
}
require_command() {
local command_name="$1"
if ! command -v "${command_name}" >/dev/null 2>&1; then
echo "[dev:rust] 缺少命令: ${command_name}" >&2
exit 1
fi
}
resolve_client_host() {
local host_name="$1"
if [[ "${host_name}" == "0.0.0.0" || "${host_name}" == "::" ]]; then
echo "127.0.0.1"
return
fi
echo "${host_name}"
}
cleanup() {
local index
for ((index = ${#PIDS[@]} - 1; index >= 0; index--)); do
local pid="${PIDS[index]}"
local name="${NAMES[index]}"
if [[ -n "${pid}" ]] && kill -0 "${pid}" 2>/dev/null; then
echo "[dev:rust] 停止 ${name} (pid=${pid})"
if command -v pgrep >/dev/null 2>&1; then
while read -r child_pid; do
if [[ -n "${child_pid}" ]]; then
kill "${child_pid}" 2>/dev/null || true
fi
done < <(pgrep -P "${pid}" 2>/dev/null || true)
fi
kill "${pid}" 2>/dev/null || true
sleep 0.2
if kill -0 "${pid}" 2>/dev/null; then
kill -9 "${pid}" 2>/dev/null || true
fi
fi
done
}
wait_for_spacetime() {
local server="$1"
local timeout_seconds="$2"
local process_pid="${3:-}"
local deadline=$((SECONDS + timeout_seconds))
while ((SECONDS < deadline)); do
if [[ -n "${process_pid}" ]] && ! kill -0 "${process_pid}" 2>/dev/null; then
echo "[dev:rust] SpacetimeDB 进程在就绪前退出。" >&2
exit 1
fi
if spacetime server ping "${server}" >/dev/null 2>&1; then
return
fi
sleep 0.5
done
echo "[dev:rust] 等待 SpacetimeDB 就绪超时: ${server}" >&2
exit 1
}
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
SERVER_RS_DIR="${REPO_ROOT}/server-rs"
MANIFEST_PATH="${SERVER_RS_DIR}/Cargo.toml"
MODULE_PATH="${SERVER_RS_DIR}/crates/spacetime-module"
VITE_CLI_PATH="${REPO_ROOT}/scripts/vite-cli.mjs"
API_HOST="127.0.0.1"
API_PORT="8082"
WEB_HOST="0.0.0.0"
WEB_PORT="3000"
SPACETIME_HOST="127.0.0.1"
SPACETIME_PORT="3101"
SPACETIME_ROOT_DIR="${SERVER_RS_DIR}/.spacetimedb/local"
DATABASE="genarrative-dev"
API_LOG="info,tower_http=info"
SPACETIME_TIMEOUT_SECONDS="60"
SKIP_SPACETIME=0
SKIP_PUBLISH=0
CLEAR_DATABASE=0
PIDS=()
NAMES=()
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--api-host)
API_HOST="${2:?缺少 --api-host 的值}"
shift 2
;;
--api-port)
API_PORT="${2:?缺少 --api-port 的值}"
shift 2
;;
--web-host)
WEB_HOST="${2:?缺少 --web-host 的值}"
shift 2
;;
--web-port)
WEB_PORT="${2:?缺少 --web-port 的值}"
shift 2
;;
--spacetime-host)
SPACETIME_HOST="${2:?缺少 --spacetime-host 的值}"
shift 2
;;
--spacetime-port)
SPACETIME_PORT="${2:?缺少 --spacetime-port 的值}"
shift 2
;;
--spacetime-root-dir)
SPACETIME_ROOT_DIR="${2:?缺少 --spacetime-root-dir 的值}"
shift 2
;;
--database)
DATABASE="${2:?缺少 --database 的值}"
shift 2
;;
--log)
API_LOG="${2:?缺少 --log 的值}"
shift 2
;;
--spacetime-timeout-seconds)
SPACETIME_TIMEOUT_SECONDS="${2:?缺少 --spacetime-timeout-seconds 的值}"
shift 2
;;
--skip-spacetime)
SKIP_SPACETIME=1
shift
;;
--skip-publish)
SKIP_PUBLISH=1
shift
;;
--clear-database)
CLEAR_DATABASE=1
shift
;;
*)
echo "[dev:rust] 未知参数: $1" >&2
usage >&2
exit 1
;;
esac
done
if [[ ! -f "${MANIFEST_PATH}" ]]; then
echo "[dev:rust] 未找到 ${MANIFEST_PATH},无法启动 Rust 本地栈。" >&2
exit 1
fi
if [[ ! -f "${MODULE_PATH}/Cargo.toml" ]]; then
echo "[dev:rust] 未找到 ${MODULE_PATH}/Cargo.toml无法发布 SpacetimeDB 模块。" >&2
exit 1
fi
if [[ ! -f "${VITE_CLI_PATH}" ]]; then
echo "[dev:rust] 未找到 ${VITE_CLI_PATH},无法启动 Web 前端。" >&2
exit 1
fi
require_command cargo
require_command node
if [[ "${SKIP_SPACETIME}" -ne 1 || "${SKIP_PUBLISH}" -ne 1 ]]; then
require_command spacetime
fi
SPACETIME_SERVER="http://${SPACETIME_HOST}:${SPACETIME_PORT}"
API_TARGET_HOST="$(resolve_client_host "${API_HOST}")"
RUST_SERVER_TARGET="http://${API_TARGET_HOST}:${API_PORT}"
trap cleanup EXIT INT TERM
echo "[dev:rust] repo: ${REPO_ROOT}"
echo "[dev:rust] web: http://127.0.0.1:${WEB_PORT}"
echo "[dev:rust] rust api: ${RUST_SERVER_TARGET}"
echo "[dev:rust] spacetime: ${SPACETIME_SERVER}"
echo "[dev:rust] database: ${DATABASE}"
if [[ "${SKIP_SPACETIME}" -ne 1 ]]; then
mkdir -p "${SPACETIME_ROOT_DIR}"
echo "[dev:rust] 启动 spacetimedb"
(
cd "${SERVER_RS_DIR}"
exec spacetime \
--root-dir "${SPACETIME_ROOT_DIR}" \
start \
--edition standalone \
--listen-addr "${SPACETIME_HOST}:${SPACETIME_PORT}"
) &
PIDS+=("$!")
NAMES+=("spacetimedb")
fi
if [[ "${SKIP_PUBLISH}" -ne 1 ]]; then
echo "[dev:rust] 等待 SpacetimeDB 就绪"
wait_for_spacetime "${SPACETIME_SERVER}" "${SPACETIME_TIMEOUT_SECONDS}" "${PIDS[0]:-}"
PUBLISH_ARGS=(
publish
"${DATABASE}"
--server "${SPACETIME_SERVER}"
--module-path "${MODULE_PATH}"
)
if [[ "${CLEAR_DATABASE}" -eq 1 ]]; then
PUBLISH_ARGS+=(--clear-database)
fi
PUBLISH_ARGS+=(--yes)
echo "[dev:rust] 发布 SpacetimeDB 模块: ${DATABASE}"
spacetime "${PUBLISH_ARGS[@]}"
fi
echo "[dev:rust] 启动 api-server"
(
cd "${REPO_ROOT}"
GENARRATIVE_API_HOST="${API_HOST}" \
GENARRATIVE_API_PORT="${API_PORT}" \
GENARRATIVE_API_LOG="${API_LOG}" \
GENARRATIVE_SPACETIME_SERVER_URL="${SPACETIME_SERVER}" \
GENARRATIVE_SPACETIME_DATABASE="${DATABASE}" \
exec cargo run -p api-server --manifest-path "${MANIFEST_PATH}"
) &
PIDS+=("$!")
NAMES+=("api-server")
echo "[dev:rust] 启动 vite"
(
cd "${REPO_ROOT}"
GENARRATIVE_BACKEND_STACK="rust" \
RUST_SERVER_TARGET="${RUST_SERVER_TARGET}" \
GENARRATIVE_RUNTIME_SERVER_TARGET="${RUST_SERVER_TARGET}" \
VITE_DEV_HOST="${WEB_HOST}" \
exec node "${VITE_CLI_PATH}" "--port=${WEB_PORT}" "--host=${WEB_HOST}"
) &
PIDS+=("$!")
NAMES+=("vite")
echo "[dev:rust] 本地 Rust 栈已启动。按 Ctrl+C 停止全部子进程。"
set +e
wait -n "${PIDS[@]}"
EXIT_CODE="$?"
set -e
echo "[dev:rust] 子进程已退出,开始回收本地 Rust 栈,退出码: ${EXIT_CODE}"
exit "${EXIT_CODE}"