Files
opendance-web/deploy/check-access.sh
T
opendance da03777995 fix(models): Assimp 缺失时给出可操作报错,部署脚本自动安装
现象:服务器未安装 Assimp,上传 PMX 压缩包只得到
  GLB 直出:导出失败(ENOENT):spawn assimp ENOENT
  glTF 直出:导出失败(ENOENT):spawn assimp ENOENT
用户看不出缺什么、怎么装,也不知道只传 glb/vrm 其实不需要它。

修复:
1. 新增 src/common/assimp.ts:按 ASSIMP_BIN -> PATH -> /usr/bin、/usr/local/bin
   等常见目录定位可执行文件(只认文件,不认同名目录),转换前先预检;
   找不到就一次性给出各发行版安装命令、查过的路径与替代办法,
   不再打两条 ENOENT。动作预处理(FBX/glTF -> BVH)复用同一文案。
2. 新增 deploy/assimp-lib.sh:install.sh 按发行版自动安装
   (apt-get / dnf / yum / zypper / apk / pacman),装在非常规目录时把绝对
   路径写入 deploy/.env 的 ASSIMP_BIN;装不上只告警不中止,可用
   SKIP_ASSIMP_INSTALL=1 跳过。check-access.sh 自检增加 Assimp 一行。
3. /health 增加 assimp.path;管理端「概览 -> 服务健康」显示 Assimp 状态,
   不可用时给出安装提示。
4. 新增 test/assimp-locate.spec.ts 13 项;强化「assimp 不存在」用例断言安装命令。
   测试规模 12 文件 / 193 项。
5. 版本 0.2.2,README(.md/.txt)/DSH.md 同步(前置要求、FAQ、环境变量说明)。
2026-09-16 02:55:32 +08:00

267 lines
10 KiB
Bash
Executable File
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.
#!/bin/bash
# ============================================================
# OpenDance Studio Web 服务端 —— 外部访问诊断
#
# 用途:服务"本机能 curl 通、外部却访问不了"时,一次性定位原因。
#
# 用法(在装有本服务的服务器上执行,无需 root):
# bash deploy/check-access.sh # 自动寻找 .env
# bash deploy/check-access.sh /opt/opendance
#
# 只读诊断,不修改任何配置、不重启任何服务。
# ============================================================
set -uo pipefail
APP_DIR="${1:-/opt/opendance}"
PORT=""
HOST_CFG=""
PROBLEMS=0
ASSIMP_MISSING=0
c_red() { printf '\033[31m%s\033[0m\n' "$*"; }
c_grn() { printf '\033[32m%s\033[0m\n' "$*"; }
c_yel() { printf '\033[33m%s\033[0m\n' "$*"; }
ok() { c_grn " ✅ $*"; }
bad() { c_red " ❌ $*"; PROBLEMS=$((PROBLEMS + 1)); }
warn() { c_yel " ⚠ $*"; }
info() { printf ' %s\n' "$*"; }
title() { printf '\n\033[1m%s\033[0m\n' "$*"; }
# ---------- 1. 定位并读取 .env ----------
title "1. 定位配置(.env)"
ENV_FILE=""
for cand in "$APP_DIR/deploy/.env" "./deploy/.env" "./.env"; do
if [ -f "$cand" ]; then ENV_FILE="$cand"; break; fi
done
if [ -z "$ENV_FILE" ]; then
warn "未找到 .env(已尝试 $APP_DIR/deploy/.env、./deploy/.env、./.env)"
info "将按默认值 PORT=3000、HOST=0.0.0.0 继续诊断"
else
ok "配置文件:$ENV_FILE"
# 只提取需要的两个键,避免把口令等敏感值读进环境
PORT="$(grep -E '^[[:space:]]*PORT=' "$ENV_FILE" | tail -1 | cut -d= -f2- | tr -d '"'"'"' \r')"
HOST_CFG="$(grep -E '^[[:space:]]*HOST=' "$ENV_FILE" | tail -1 | cut -d= -f2- | tr -d '"'"'"' \r')"
fi
PORT="${PORT:-3000}"
HOST_CFG="${HOST_CFG:-0.0.0.0}"
info "PORT = $PORT"
info "HOST = $HOST_CFG"
case "$HOST_CFG" in
127.0.0.1|localhost|::1)
bad "HOST=$HOST_CFG 表示只监听本机回环,外部一定访问不到"
info "修复:把 $ENV_FILE 里的 HOST 改为 0.0.0.0,然后重启服务"
info " bash deploy/ctl.sh restart (或 systemctl restart opendance-api)"
;;
0.0.0.0|'*'|'')
ok "HOST=$HOST_CFG 允许外部连接(是否真能访问还要看下面的监听与防火墙)"
;;
*)
warn "HOST=$HOST_CFG 只绑定某个具体网卡地址"
info "若客户端不在该网段,请改为 0.0.0.0"
;;
esac
# ---------- 2. 实际监听端口 ----------
title "2. 实际监听状态"
LISTEN_LINE=""
if command -v ss >/dev/null 2>&1; then
LISTEN_LINE="$(ss -tlnH 2>/dev/null | awk -v p=":$PORT" '$4 ~ p"$"')"
elif command -v netstat >/dev/null 2>&1; then
LISTEN_LINE="$(netstat -tln 2>/dev/null | awk -v p=":$PORT" '$4 ~ p"$"')"
fi
if [ -z "$LISTEN_LINE" ]; then
if [ -z "$(command -v ss || command -v netstat)" ]; then
warn "系统里没有 ss / netstat,跳过监听检查"
else
bad "没有任何进程监听 $PORT 端口 —— 服务可能没起来,或 PORT 与 .env 不一致"
info "检查:bash deploy/ctl.sh status / bash deploy/ctl.sh logs"
fi
else
printf '%s\n' "$LISTEN_LINE" | while IFS= read -r l; do info "$l"; done
if printf '%s' "$LISTEN_LINE" | grep -qE '(^|[^0-9])127\.0\.0\.1:'"$PORT"; then
if printf '%s' "$LISTEN_LINE" | grep -qE '(0\.0\.0\.0|\[::\]|\*):'"$PORT"; then
ok "同时监听通配地址,外部可连"
else
bad "只监听 127.0.0.1:$PORT —— 这是「外部访问不到」最常见的原因"
info "修复:$ENV_FILE 中 HOST=0.0.0.0,然后重启服务"
fi
else
ok "监听了通配地址(0.0.0.0 / [::]),绑定层没问题"
fi
fi
# ---------- 3. 本机回环自测 ----------
title "3. 本机自测(回环)"
probe() { # $1=url
if command -v curl >/dev/null 2>&1; then
curl -sS -m 5 -o /dev/null -w '%{http_code}' "$1" 2>/dev/null
elif command -v wget >/dev/null 2>&1; then
wget -q -T 5 -O /dev/null -S "$1" 2>&1 | awk '/HTTP\//{code=$2} END{print code}'
else
printf ''
fi
}
LOOP_CODE="$(probe "http://127.0.0.1:$PORT/health")"
if [ "$LOOP_CODE" = "200" ]; then
ok "http://127.0.0.1:$PORT/health → 200,服务本身正常"
elif [ -z "$LOOP_CODE" ]; then
warn "系统里没有 curl / wget,跳过 HTTP 自测"
else
bad "http://127.0.0.1:$PORT/health → $LOOP_CODE(期望 200)"
info "503 通常表示数据库连不上;000/空表示端口没人应答"
info "看日志:bash deploy/ctl.sh logs"
fi
# ---------- 4. 用对外 IP 自测 ----------
title "4. 本机自测(对外 IP)"
LAN_IP=""
if command -v ip >/dev/null 2>&1; then
LAN_IP="$(ip route get 1.1.1.1 2>/dev/null | awk '/src/{for(i=1;i<=NF;i++) if($i=="src") print $(i+1)}' | head -1)"
fi
[ -z "$LAN_IP" ] && LAN_IP="$(hostname -I 2>/dev/null | awk '{print $1}')"
if [ -z "$LAN_IP" ]; then
warn "拿不到本机对外 IP,跳过"
else
info "本机对外 IP:$LAN_IP"
EXT_CODE="$(probe "http://$LAN_IP:$PORT/health")"
if [ "$EXT_CODE" = "200" ]; then
ok "http://$LAN_IP:$PORT/health → 200,走网卡这一层是通的"
info "那么外部访问不了多半是:防火墙 / 云安全组 / 客户端与服务器不在同一网段,"
info "或者你访问的是 80 / 443 端口(本项目不部署反向代理,见第 5 节)"
elif [ -n "$EXT_CODE" ]; then
bad "http://$LAN_IP:$PORT/health → $EXT_CODE"
else
warn "无法自测(缺 curl / wget)"
fi
fi
# ---------- 5. 是否有 80/443 监听(反代才需要) ----------
title "5. 是否有人在监听 80 / 443(反向代理)"
WEB_LISTEN=""
if command -v ss >/dev/null 2>&1; then
WEB_LISTEN="$(ss -tlnH 2>/dev/null | awk '$4 ~ /:(80|443)$/')"
fi
if [ -z "$WEB_LISTEN" ]; then
warn "本机没有监听 80 / 443 的服务 —— 说明这台机器上没有反向代理"
info "本项目按需求不部署反向代理:直接用 http://<服务器IP>:$PORT 访问后端业务服务"
info "若要通过域名 / 80 / 443 访问,需由运维侧按 deploy/proxy/ 配置 IIS 或 nginx"
else
ok "检测到 80/443 监听(可能是运维侧的反向代理)"
printf '%s\n' "$WEB_LISTEN" | while IFS= read -r l; do info "$l"; done
info "请确认它的转发目标写的是本机 $PORT 端口,见 deploy/proxy/README.md"
fi
# ---------- 6. 防火墙 ----------
title "6. 防火墙"
FW_FOUND=0
if command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2>&1; then
FW_FOUND=1
info "firewalld 运行中"
ZONES="$(firewall-cmd --get-active-zones 2>/dev/null | awk '/^[a-z]/{print $1}')"
for z in $ZONES; do
PORTS="$(firewall-cmd --zone="$z" --list-ports 2>/dev/null)"
SVC="$(firewall-cmd --zone="$z" --list-services 2>/dev/null)"
info " zone=$z ports=[$PORTS] services=[$SVC]"
if printf '%s' "$PORTS" | grep -qE "(^|,| )$PORT/tcp(,| |$)"; then
ok " $PORT/tcp 已在 zone=$z 放行"
else
bad " $PORT/tcp 未在 zone=$z 放行"
info " 修复:firewall-cmd --permanent --add-port=$PORT/tcp && firewall-cmd --reload"
fi
done
fi
if command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -qi '^Status: active'; then
FW_FOUND=1
info "ufw 运行中"
ufw status 2>/dev/null | sed 's/^/ /'
if ufw status 2>/dev/null | grep -qE "(^| )$PORT(/tcp)?( |$)"; then
ok " $PORT 已在 ufw 规则中出现"
else
bad " ufw 中未见 $PORT 放行规则"
info " 修复:ufw allow $PORT/tcp"
fi
fi
if [ "$FW_FOUND" -eq 0 ]; then
if command -v iptables >/dev/null 2>&1; then
if iptables -S 2>/dev/null | grep -qE '(-P INPUT (DROP|REJECT)|--dport '"$PORT"')'; then
info "iptables 规则(节选):"
iptables -S 2>/dev/null | grep -E -- "--dport ($PORT|80|443)|-P INPUT" | sed 's/^/ /'
if iptables -S 2>/dev/null | grep -qE -- "--dport $PORT .*-j ACCEPT"; then
ok " iptables 中有 $PORT 的 ACCEPT 规则"
elif iptables -S 2>/dev/null | grep -qE -- "--dport $PORT .*-j (DROP|REJECT)"; then
bad " iptables 明确拒绝了 $PORT"
else
warn " iptables 中未见 $PORT 的放行规则(默认策略若为 DROP 则外部连不上)"
info " 查询默认策略:iptables -S | grep '^-P INPUT'"
fi
else
info "iptables 无相关丢弃规则(未检测到防火墙拦截迹象)"
fi
else
info "未检测到 firewalld / ufw"
fi
info "注意:云服务器还需检查控制台的「安全组 / 网络 ACL」是否放行 $PORT"
fi
# ---------- 6.5 可选依赖 Assimp ----------
title "可选依赖 Assimp(.pmx/.fbx 模型转换、FBX/glTF 动作预处理)"
if [ -f "$(dirname "$0")/assimp-lib.sh" ]; then
# shellcheck source=deploy/assimp-lib.sh
. "$(dirname "$0")/assimp-lib.sh"
ASSIMP_PATH="$(opendance_assimp_resolve || true)"
if [ -n "$ASSIMP_PATH" ]; then
ok "Assimp 可用:$ASSIMP_PATH($("$ASSIMP_PATH" version 2>/dev/null | head -1))"
else
warn "未安装 Assimp:上传 .pmx / .fbx(或含它们的压缩包)会报转换失败"
info "安装:$(opendance_assimp_install_cmd)"
info "只上传 .glb / .vrm 模型与 .bvh / .vmd 动作则不受影响"
ASSIMP_MISSING=1
fi
else
warn "未找到 deploy/assimp-lib.sh,跳过 Assimp 检查"
fi
# ---------- 7. 结论 ----------
title "结论"
if [ "${ASSIMP_MISSING:-0}" = "1" ]; then
c_yel " 提示:未安装 Assimp,.pmx / .fbx 模型转换与 FBX / glTF 动作预处理不可用(与访问无关)。"
echo " 安装:$(opendance_assimp_install_cmd 2>/dev/null || echo '用发行版包管理器安装 assimp')"
echo
fi
if [ "$PROBLEMS" -eq 0 ]; then
c_grn " 未发现本机侧问题。"
echo " 若仍访问不了,按顺序排查:"
echo " 1) 客户端与服务器是否互通:ping <服务器IP>"
echo " 2) 云控制台安全组 / 公司网络策略是否放行 $PORT"
echo " 3) 你访问的端口是否写错(本项目服务在 $PORT,不在 80/443)"
echo " 4) 若要通过域名访问,需运维侧按 deploy/proxy/ 配置反向代理"
else
c_red " 发现 $PROBLEMS 个问题,按上面的 ❌ 逐条修复后重试。"
echo
echo " 两种修复路径:"
echo " A. 直连后端(本项目开箱即用,无需反代):"
echo " 1) $ENV_FILE 里 HOST=0.0.0.0"
echo " 2) 防火墙放行 $PORT/tcp"
echo " 3) 重启服务后访问 http://<服务器IP>:$PORT"
echo " B. 通过域名 / 80 / 443 访问(需运维侧配合):"
echo " 按 deploy/proxy/README.md 配置 IIS 或 nginx,整体转发到 $PORT"
fi
echo
exit 0