diff --git a/deploy/lib/common.sh b/deploy/lib/common.sh index 1e7ef08..0a87cd5 100755 --- a/deploy/lib/common.sh +++ b/deploy/lib/common.sh @@ -1,156 +1,156 @@ -#!/usr/bin/env bash -# deploy/lib/common.sh — 比特骆驼自动化对冲系统 部署公共函数 -# 目标系统: Ubuntu 22.04 LTS -set -e -set -u -if [ -n "${BASH_VERSION:-}" ]; then - set -o pipefail -fi - -INSTALL_ROOT="${INSTALL_ROOT:-/opt/eth_hedge_sim}" -GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/eth_hedge_sim.git}" -GIT_BRANCH="${GIT_BRANCH:-main}" -BACKUP_ROOT="${BACKUP_ROOT:-/root/backups/eth_hedge_sim}" -TZ_NAME="${EHS_TZ:-Asia/Shanghai}" -NODE_MAJOR="${NODE_MAJOR:-20}" -PM2_APP_NAME="${PM2_APP_NAME:-eth-hedge-api}" -API_PORT="${API_PORT:-5155}" - -LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -DEPLOY_DIR="$(cd "${LIB_DIR}/.." && pwd)" -REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)" - -log() { printf '[%s] %s\n' "$(TZ="${TZ_NAME}" date '+%Y-%m-%d %H:%M:%S')" "$*"; } -step() { echo ""; log "==> $*"; } - -die() { - echo "错误: $*" >&2 - exit 1 -} - -require_root() { - if [[ "$(id -u)" -ne 0 ]]; then - die "请使用 root 执行(推荐: sudo -i 后运行)" - fi -} - -detect_server_ip() { - local ip="" - if command -v hostname >/dev/null 2>&1; then - ip="$(hostname -I 2>/dev/null | awk '{print $1}')" - fi - if [[ -z "${ip}" ]]; then - ip="127.0.0.1" - fi - echo "${ip}" -} - -# curl|bash 时 stdin 可能是管道,交互从 /dev/tty 读 -cm_read() { - local __var="$1" - local __prompt="${2:-}" - local __line="" - if [[ -n "${__prompt}" ]]; then - printf '%s' "${__prompt}" >/dev/tty 2>/dev/null || printf '%s' "${__prompt}" - fi - if [[ -r /dev/tty ]]; then - IFS= read -r __line /dev/null 2>&1; then - apt-get update -qq - apt-get install -y git ca-certificates curl python3 python3-venv python3-pip - fi - if ! command -v node >/dev/null 2>&1; then - step "安装 Node.js ${NODE_MAJOR}" - curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | bash - - apt-get install -y nodejs - fi - if ! command -v pm2 >/dev/null 2>&1; then - step "安装 PM2" - npm install -g pm2 - fi -} - -pm2_stop_project() { - if command -v pm2 >/dev/null 2>&1; then - pm2 stop "${PM2_APP_NAME}" 2>/dev/null || true - fi -} - -pm2_delete_project() { - if command -v pm2 >/dev/null 2>&1; then - pm2 delete "${PM2_APP_NAME}" 2>/dev/null || true - pm2 save 2>/dev/null || true - fi -} - -pm2_save_startup() { - if command -v pm2 >/dev/null 2>&1; then - pm2 save 2>/dev/null || true - pm2 startup systemd -u root --hp /root 2>/dev/null || true - fi -} - -verify_health() { - local port="${1:-${API_PORT}}" - local url="http://127.0.0.1:${port}/health" - step "健康检查 ${url}" - local i - for i in 1 2 3 4 5 6 7 8 9 10; do - if curl -fsS "${url}" >/dev/null 2>&1; then - log "health OK" - curl -fsS "${url}" || true - echo "" - return 0 - fi - sleep 1 - done - log "警告: health 暂未就绪,请稍后检查 pm2 logs ${PM2_APP_NAME}" - return 1 -} - -print_post_install_guide() { - local ip - ip="$(detect_server_ip)" - echo "" - echo "══════════════════════════════════════" - echo " 比特骆驼自动化对冲系统 部署完成" - echo " 目录: ${INSTALL_ROOT}" - echo " 本机: http://${ip}:${API_PORT}/health" - echo " 进程: pm2 status → ${PM2_APP_NAME}" - echo " 管理: bash ${INSTALL_ROOT}/deploy/manage.sh" - echo " 配置: ${INSTALL_ROOT}/.env" - echo "══════════════════════════════════════" - echo "" -} +#!/usr/bin/env bash +# deploy/lib/common.sh — 比特骆驼自动化对冲系统 部署公共函数 +# 目标系统: Ubuntu 22.04 LTS +set -e +set -u +if [ -n "${BASH_VERSION:-}" ]; then + set -o pipefail +fi + +INSTALL_ROOT="${INSTALL_ROOT:-/opt/eth_hedge_sim}" +GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/eth_hedge_sim.git}" +GIT_BRANCH="${GIT_BRANCH:-main}" +BACKUP_ROOT="${BACKUP_ROOT:-/root/backups/eth_hedge_sim}" +TZ_NAME="${EHS_TZ:-Asia/Shanghai}" +NODE_MAJOR="${NODE_MAJOR:-20}" +PM2_APP_NAME="${PM2_APP_NAME:-eth-hedge-api}" +API_PORT="${API_PORT:-5155}" + +LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DEPLOY_DIR="$(cd "${LIB_DIR}/.." && pwd)" +REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)" + +log() { printf '[%s] %s\n' "$(TZ="${TZ_NAME}" date '+%Y-%m-%d %H:%M:%S')" "$*"; } +step() { echo ""; log "==> $*"; } + +die() { + echo "错误: $*" >&2 + exit 1 +} + +require_root() { + if [[ "$(id -u)" -ne 0 ]]; then + die "请使用 root 执行(推荐: sudo -i 后运行)" + fi +} + +detect_server_ip() { + local ip="" + if command -v hostname >/dev/null 2>&1; then + ip="$(hostname -I 2>/dev/null | awk '{print $1}')" + fi + if [[ -z "${ip}" ]]; then + ip="127.0.0.1" + fi + echo "${ip}" +} + +# curl|bash 时 stdin 可能是管道,交互从 /dev/tty 读 +cm_read() { + local __var="$1" + local __prompt="${2:-}" + local __line="" + if [[ -n "${__prompt}" ]]; then + printf '%s' "${__prompt}" >/dev/tty 2>/dev/null || printf '%s' "${__prompt}" + fi + if [[ -r /dev/tty ]]; then + IFS= read -r __line /dev/null 2>&1; then + apt-get update -qq + apt-get install -y git ca-certificates curl python3 python3-venv python3-pip + fi + if ! command -v node >/dev/null 2>&1; then + step "安装 Node.js ${NODE_MAJOR}" + curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | bash - + apt-get install -y nodejs + fi + if ! command -v pm2 >/dev/null 2>&1; then + step "安装 PM2" + npm install -g pm2 + fi +} + +pm2_stop_project() { + if command -v pm2 >/dev/null 2>&1; then + pm2 stop "${PM2_APP_NAME}" 2>/dev/null || true + fi +} + +pm2_delete_project() { + if command -v pm2 >/dev/null 2>&1; then + pm2 delete "${PM2_APP_NAME}" 2>/dev/null || true + pm2 save 2>/dev/null || true + fi +} + +pm2_save_startup() { + if command -v pm2 >/dev/null 2>&1; then + pm2 save 2>/dev/null || true + pm2 startup systemd -u root --hp /root 2>/dev/null || true + fi +} + +verify_health() { + local port="${1:-${API_PORT}}" + local url="http://127.0.0.1:${port}/health" + step "健康检查 ${url}" + local i + for i in 1 2 3 4 5 6 7 8 9 10; do + if curl -fsS "${url}" >/dev/null 2>&1; then + log "health OK" + curl -fsS "${url}" || true + echo "" + return 0 + fi + sleep 1 + done + log "警告: health 暂未就绪,请稍后检查 pm2 logs ${PM2_APP_NAME}" + return 1 +} + +print_post_install_guide() { + local ip + ip="$(detect_server_ip)" + echo "" + echo "══════════════════════════════════════" + echo " 比特骆驼自动化对冲系统 部署完成" + echo " 目录: ${INSTALL_ROOT}" + echo " 本机: http://${ip}:${API_PORT}/health" + echo " 进程: pm2 status → ${PM2_APP_NAME}" + echo " 管理: bash ${INSTALL_ROOT}/deploy/manage.sh" + echo " 配置: ${INSTALL_ROOT}/.env" + echo "══════════════════════════════════════" + echo "" +} diff --git a/deploy/lib/uninstall.sh b/deploy/lib/uninstall.sh index 4603577..0790a19 100755 --- a/deploy/lib/uninstall.sh +++ b/deploy/lib/uninstall.sh @@ -1,80 +1,80 @@ -#!/usr/bin/env bash -# deploy/lib/uninstall.sh — 一键卸载(仅本项目 PM2,不动其它进程) -set -e -set -u -if [ -n "${BASH_VERSION:-}" ]; then - set -o pipefail -fi - -LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=common.sh -source "${LIB_DIR}/common.sh" - -main_uninstall() { - require_root - - local root="" - if ! root="$(resolve_repo_root)"; then - if [[ -d "${INSTALL_ROOT}" ]]; then - root="${INSTALL_ROOT}" - else - die "未找到安装目录 ${INSTALL_ROOT}" - fi - fi - REPO_ROOT="${root}" - - echo "" - echo "将卸载 比特骆驼自动化对冲系统 (eth_hedge_sim):" - echo " - 停止并删除 PM2 进程: ${PM2_APP_NAME}" - echo " - 移走目录: ${INSTALL_ROOT}" - echo " - 备份 .env 到 ${BACKUP_ROOT}" - echo " - 不影响其它 PM2 应用" - echo "" - if ! confirm_yes "确认卸载?"; then - log "已取消卸载" - return 0 - fi - - local stamp backup_dir removed_dir - stamp="$(TZ="${TZ_NAME}" date +%Y%m%d-%H%M%S)" - backup_dir="${BACKUP_ROOT}/pre-uninstall-${stamp}" - removed_dir="${INSTALL_ROOT}.removed.${stamp}" - mkdir -p "${backup_dir}" - - step "备份配置" - if [[ -f "${REPO_ROOT}/.env" ]]; then - cp -a "${REPO_ROOT}/.env" "${backup_dir}/.env" - fi - if [[ -d "${REPO_ROOT}/backend/data" ]]; then - cp -a "${REPO_ROOT}/backend/data" "${backup_dir}/data" 2>/dev/null || true - fi - { - echo "created_at=${stamp}" - echo "install_root=${INSTALL_ROOT}" - echo "removed_dir=${removed_dir}" - echo "pm2_app=${PM2_APP_NAME}" - } >"${backup_dir}/uninstall.manifest" - - step "停止并移除 PM2 进程 ${PM2_APP_NAME}" - pm2_stop_project - pm2_delete_project - - step "移走安装目录" - if [[ -d "${INSTALL_ROOT}" ]]; then - mv "${INSTALL_ROOT}" "${removed_dir}" - log "已移动: ${INSTALL_ROOT} -> ${removed_dir}" - else - log "安装目录不存在,跳过" - fi - - echo "" - echo "卸载完成." - echo " 配置备份: ${backup_dir}" - echo " 旧目录: ${removed_dir} (确认无误后可手动 rm -rf)" - echo "" - echo "回滚示例:" - echo " mv ${removed_dir} ${INSTALL_ROOT}" - echo " bash ${INSTALL_ROOT}/deploy/manage.sh # 选 1 修复环境" -} - -main_uninstall "$@" +#!/usr/bin/env bash +# deploy/lib/uninstall.sh — 一键卸载(仅本项目 PM2,不动其它进程) +set -e +set -u +if [ -n "${BASH_VERSION:-}" ]; then + set -o pipefail +fi + +LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=common.sh +source "${LIB_DIR}/common.sh" + +main_uninstall() { + require_root + + local root="" + if ! root="$(resolve_repo_root)"; then + if [[ -d "${INSTALL_ROOT}" ]]; then + root="${INSTALL_ROOT}" + else + die "未找到安装目录 ${INSTALL_ROOT}" + fi + fi + REPO_ROOT="${root}" + + echo "" + echo "将卸载 比特骆驼自动化对冲系统 (eth_hedge_sim):" + echo " - 停止并删除 PM2 进程: ${PM2_APP_NAME}" + echo " - 移走目录: ${INSTALL_ROOT}" + echo " - 备份 .env 到 ${BACKUP_ROOT}" + echo " - 不影响其它 PM2 应用" + echo "" + if ! confirm_yes "确认卸载?"; then + log "已取消卸载" + return 0 + fi + + local stamp backup_dir removed_dir + stamp="$(TZ="${TZ_NAME}" date +%Y%m%d-%H%M%S)" + backup_dir="${BACKUP_ROOT}/pre-uninstall-${stamp}" + removed_dir="${INSTALL_ROOT}.removed.${stamp}" + mkdir -p "${backup_dir}" + + step "备份配置" + if [[ -f "${REPO_ROOT}/.env" ]]; then + cp -a "${REPO_ROOT}/.env" "${backup_dir}/.env" + fi + if [[ -d "${REPO_ROOT}/backend/data" ]]; then + cp -a "${REPO_ROOT}/backend/data" "${backup_dir}/data" 2>/dev/null || true + fi + { + echo "created_at=${stamp}" + echo "install_root=${INSTALL_ROOT}" + echo "removed_dir=${removed_dir}" + echo "pm2_app=${PM2_APP_NAME}" + } >"${backup_dir}/uninstall.manifest" + + step "停止并移除 PM2 进程 ${PM2_APP_NAME}" + pm2_stop_project + pm2_delete_project + + step "移走安装目录" + if [[ -d "${INSTALL_ROOT}" ]]; then + mv "${INSTALL_ROOT}" "${removed_dir}" + log "已移动: ${INSTALL_ROOT} -> ${removed_dir}" + else + log "安装目录不存在,跳过" + fi + + echo "" + echo "卸载完成." + echo " 配置备份: ${backup_dir}" + echo " 旧目录: ${removed_dir} (确认无误后可手动 rm -rf)" + echo "" + echo "回滚示例:" + echo " mv ${removed_dir} ${INSTALL_ROOT}" + echo " bash ${INSTALL_ROOT}/deploy/manage.sh # 选 1 修复环境" +} + +main_uninstall "$@" diff --git a/deploy/lib/update.sh b/deploy/lib/update.sh index 92c95c5..1c43aa3 100755 --- a/deploy/lib/update.sh +++ b/deploy/lib/update.sh @@ -1,29 +1,29 @@ -#!/usr/bin/env bash -# deploy/lib/update.sh — 更新(仅 git pull,禁止 scp) -set -e -set -u -if [ -n "${BASH_VERSION:-}" ]; then - set -o pipefail -fi - -LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=common.sh -source "${LIB_DIR}/common.sh" - -main_update() { - require_root - if ! REPO_ROOT="$(resolve_repo_root)"; then - die "未找到安装目录 ${INSTALL_ROOT},请先执行「1) 一键部署」" - fi - if ! repo_ready "${REPO_ROOT}"; then - die "安装不完整,请先执行「1) 一键部署」" - fi - - step "更新 比特骆驼自动化对冲系统 (git pull + 构建 + pm2 reload)" - bash "${REPO_ROOT}/deploy/pull_and_restart.sh" - verify_health || true - echo "" - log "更新完成" -} - -main_update "$@" +#!/usr/bin/env bash +# deploy/lib/update.sh — 更新(仅 git pull,禁止 scp) +set -e +set -u +if [ -n "${BASH_VERSION:-}" ]; then + set -o pipefail +fi + +LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=common.sh +source "${LIB_DIR}/common.sh" + +main_update() { + require_root + if ! REPO_ROOT="$(resolve_repo_root)"; then + die "未找到安装目录 ${INSTALL_ROOT},请先执行「1) 一键部署」" + fi + if ! repo_ready "${REPO_ROOT}"; then + die "安装不完整,请先执行「1) 一键部署」" + fi + + step "更新 比特骆驼自动化对冲系统 (git pull + 构建 + pm2 reload)" + bash "${REPO_ROOT}/deploy/pull_and_restart.sh" + verify_health || true + echo "" + log "更新完成" +} + +main_update "$@" diff --git a/deploy/manage.sh b/deploy/manage.sh index d895333..0c89f1b 100755 --- a/deploy/manage.sh +++ b/deploy/manage.sh @@ -1,225 +1,225 @@ -#!/usr/bin/env bash -# 比特骆驼自动化对冲系统 部署管理器(工程 eth_hedge_sim) -# 部署环境: Ubuntu 22.04 LTS -# -# 新服务器(免克隆): -# curl -fsSL https://git.bz121.com/dekun/eth_hedge_sim/raw/branch/main/deploy/manage.sh | bash -# -# 已安装: -# bash /opt/eth_hedge_sim/deploy/manage.sh -# -set -e -if [ -n "${BASH_VERSION:-}" ]; then - set -o pipefail -fi - -INSTALL_ROOT="${INSTALL_ROOT:-/opt/eth_hedge_sim}" -GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/eth_hedge_sim.git}" -GIT_BRANCH="${GIT_BRANCH:-main}" - -# curl | bash 时脚本从 stdin 执行,BASH_SOURCE[0] 为空;须先安全探测再 set -u -_script_src="${BASH_SOURCE[0]:-}" -if [[ -n "${_script_src}" && -f "${_script_src}" ]]; then - DEPLOY_DIR="$(cd "$(dirname "${_script_src}")" && pwd)" - REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)" - LIB_DIR="${DEPLOY_DIR}/lib" -else - DEPLOY_DIR="" - REPO_ROOT="" - LIB_DIR="" -fi -unset _script_src - -set -u - -repo_ready() { - [[ -f "${1}/deploy/manage.sh" && -f "${1}/deploy/pull_and_restart.sh" && -d "${1}/deploy/lib" ]] -} - -ensure_git_cli() { - if command -v git >/dev/null 2>&1; then - return 0 - fi - if command -v apt-get >/dev/null 2>&1; then - export DEBIAN_FRONTEND=noninteractive - apt-get update -qq - apt-get install -y git ca-certificates curl - else - echo "错误: 未找到 git" >&2 - exit 1 - fi -} - -sync_repo_if_present() { - local root="$1" - if [[ -d "${root}/.git" ]] && command -v git >/dev/null 2>&1; then - git -C "${root}" fetch --all --prune 2>/dev/null || true - git -C "${root}" checkout "${GIT_BRANCH}" 2>/dev/null || true - git -C "${root}" pull --ff-only origin "${GIT_BRANCH}" 2>/dev/null \ - || git -C "${root}" pull --ff-only 2>/dev/null \ - || true - fi -} - -# 旧目录已存在但缺 manage.sh:尽量 git pull / 修复后切到仓库内脚本 -heal_existing_install() { - local root="$1" - echo "检测到已有目录但缺少管理脚本: ${root}" - echo "尝试同步最新代码…" - ensure_git_cli - - if [[ -d "${root}/.git" ]]; then - sync_repo_if_present "${root}" - if repo_ready "${root}"; then - echo "同步成功,切换到仓库内 manage.sh" - exec bash "${root}/deploy/manage.sh" "$@" &2 - exit 1 - fi - heal_existing_install "${INSTALL_ROOT}" "$@" - fi - - echo "比特骆驼自动化对冲系统 部署管理器 — 首次自举" - echo "将克隆到: ${INSTALL_ROOT}" - if [[ "$(id -u)" -ne 0 ]]; then - echo "错误: 请使用 root 执行" >&2 - exit 1 - fi - ensure_git_cli - mkdir -p "$(dirname "${INSTALL_ROOT}")" - git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${INSTALL_ROOT}" - # clone 后用仓库内脚本 + 终端 stdin(管道已 EOF) - exec bash "${INSTALL_ROOT}/deploy/manage.sh" "$@" /dev/tty 2>/dev/null || printf '%s' "${__prompt}" - fi - if [[ -r /dev/tty ]]; then - IFS= read -r __line /dev/null 2>&1; then + return 0 + fi + if command -v apt-get >/dev/null 2>&1; then + export DEBIAN_FRONTEND=noninteractive + apt-get update -qq + apt-get install -y git ca-certificates curl + else + echo "错误: 未找到 git" >&2 + exit 1 + fi +} + +sync_repo_if_present() { + local root="$1" + if [[ -d "${root}/.git" ]] && command -v git >/dev/null 2>&1; then + git -C "${root}" fetch --all --prune 2>/dev/null || true + git -C "${root}" checkout "${GIT_BRANCH}" 2>/dev/null || true + git -C "${root}" pull --ff-only origin "${GIT_BRANCH}" 2>/dev/null \ + || git -C "${root}" pull --ff-only 2>/dev/null \ + || true + fi +} + +# 旧目录已存在但缺 manage.sh:尽量 git pull / 修复后切到仓库内脚本 +heal_existing_install() { + local root="$1" + echo "检测到已有目录但缺少管理脚本: ${root}" + echo "尝试同步最新代码…" + ensure_git_cli + + if [[ -d "${root}/.git" ]]; then + sync_repo_if_present "${root}" + if repo_ready "${root}"; then + echo "同步成功,切换到仓库内 manage.sh" + exec bash "${root}/deploy/manage.sh" "$@" &2 + exit 1 + fi + heal_existing_install "${INSTALL_ROOT}" "$@" + fi + + echo "比特骆驼自动化对冲系统 部署管理器 — 首次自举" + echo "将克隆到: ${INSTALL_ROOT}" + if [[ "$(id -u)" -ne 0 ]]; then + echo "错误: 请使用 root 执行" >&2 + exit 1 + fi + ensure_git_cli + mkdir -p "$(dirname "${INSTALL_ROOT}")" + git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${INSTALL_ROOT}" + # clone 后用仓库内脚本 + 终端 stdin(管道已 EOF) + exec bash "${INSTALL_ROOT}/deploy/manage.sh" "$@" /dev/tty 2>/dev/null || printf '%s' "${__prompt}" + fi + if [[ -r /dev/tty ]]; then + IFS= read -r __line /dev/null 2>&1; then - echo "ERROR: npm not found. Install Node.js 18+ first (manage.sh 一键部署会自动装)." - exit 1 -fi - -( - cd "$ROOT/frontend" - if [[ -f package-lock.json ]]; then npm ci; else npm install; fi - npm run build -) - -if ! command -v pm2 >/dev/null 2>&1; then - npm install -g pm2 -fi - -# 仅 reload 本项目进程,禁止 pm2 restart all -pm2 startOrReload "$ROOT/deploy/ecosystem.config.cjs" --update-env -pm2 save - -echo "[比特骆驼] done. health: http://127.0.0.1:5155/health" +#!/usr/bin/env bash +# 一键更新/部署:仅 git pull,禁止 scp 传代码。 +# 用法: +# bash /opt/eth_hedge_sim/deploy/pull_and_restart.sh +# 或通过 manage.sh 选 1/3 +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +echo "[比特骆驼] pull @ $ROOT" +if [[ -d "$ROOT/.git" ]]; then + git fetch --all --prune + git pull --ff-only +fi + +if [[ ! -f "$ROOT/.env" ]]; then + echo "[比特骆驼] missing .env — copy from example" + cp "$ROOT/.env.example" "$ROOT/.env" + # 云上测试机默认直连 OKX + sed -i 's/^OKX_HTTP_PROXY=.*/OKX_HTTP_PROXY=/' "$ROOT/.env" || true + sed -i 's/^API_PORT=.*/API_PORT=5155/' "$ROOT/.env" || true + sed -i 's/^ENV_NAME=.*/ENV_NAME=test/' "$ROOT/.env" || true + sed -i 's/^EXCHANGE=.*/EXCHANGE=okx/' "$ROOT/.env" || true + echo "[比特骆驼] wrote .env — please review AUTH_* secrets" +fi + +if [[ ! -d "$ROOT/.venv" ]]; then + python3 -m venv "$ROOT/.venv" +fi +# shellcheck disable=SC1091 +source "$ROOT/.venv/bin/activate" +pip install -U pip +pip install -r "$ROOT/requirements.txt" + +if ! command -v npm >/dev/null 2>&1; then + echo "ERROR: npm not found. Install Node.js 18+ first (manage.sh 一键部署会自动装)." + exit 1 +fi + +( + cd "$ROOT/frontend" + if [[ -f package-lock.json ]]; then npm ci; else npm install; fi + npm run build +) + +if ! command -v pm2 >/dev/null 2>&1; then + npm install -g pm2 +fi + +# 仅 reload 本项目进程,禁止 pm2 restart all +pm2 startOrReload "$ROOT/deploy/ecosystem.config.cjs" --update-env +pm2 save + +echo "[比特骆驼] done. health: http://127.0.0.1:5155/health"