install.sh 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. #!/bin/bash
  2. set -euo pipefail
  3. # ============================================================
  4. # DSH 双摄安全检测系统 — 一键安装脚本
  5. # 支持:RK3588 (aarch64) / x86_64 Linux / macOS
  6. # ============================================================
  7. SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
  8. PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
  9. # ---------- 颜色输出 ----------
  10. RED='\033[0;31m'
  11. GREEN='\033[0;32m'
  12. YELLOW='\033[1;33m'
  13. CYAN='\033[0;36m'
  14. NC='\033[0m'
  15. log_info() { echo -e "${GREEN}[INFO]${NC} $*"; }
  16. log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
  17. log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
  18. log_step() { echo -e "\n${CYAN}═══════════════════════════════════════════${NC}"; echo -e "${CYAN} $*${NC}"; echo -e "${CYAN}═══════════════════════════════════════════${NC}\n"; }
  19. # ---------- 检测平台 ----------
  20. detect_platform() {
  21. local arch
  22. arch="$(uname -m)"
  23. local os
  24. os="$(uname -s)"
  25. if [ "$os" = "Darwin" ]; then
  26. echo "macos"
  27. elif [ "$os" = "Linux" ] && [ "$arch" = "aarch64" ]; then
  28. echo "rk3588"
  29. elif [ "$os" = "Linux" ] && { [ "$arch" = "x86_64" ] || [ "$arch" = "amd64" ]; }; then
  30. echo "linux_x86"
  31. else
  32. echo "unknown"
  33. fi
  34. }
  35. # ---------- 默认路径 ----------
  36. setup_paths() {
  37. local platform="$1"
  38. case "$platform" in
  39. rk3588)
  40. INSTALL_DIR="/home/admin/dsh"
  41. SERVICE_USER="admin"
  42. SERVICE_GROUP="admin"
  43. CONDA_PATH="/home/admin/miniconda3"
  44. CONDA_ENV="rknn"
  45. ;;
  46. linux_x86)
  47. INSTALL_DIR="/home/wen/dsh"
  48. SERVICE_USER="$USER"
  49. SERVICE_GROUP="$(id -gn)"
  50. CONDA_PATH="${CONDA_PATH:-$HOME/miniconda3}"
  51. CONDA_ENV="dsh"
  52. ;;
  53. macos)
  54. INSTALL_DIR="$HOME/dsh"
  55. SERVICE_USER="$USER"
  56. SERVICE_GROUP="$(id -gn)"
  57. CONDA_PATH="${CONDA_PATH:-$HOME/miniconda3}"
  58. CONDA_ENV="dsh"
  59. ;;
  60. esac
  61. SYSTEM_DIR="${INSTALL_DIR}/dual_camera_system"
  62. LOG_DIR="${SYSTEM_DIR}/logs"
  63. }
  64. # ============================================================
  65. # 安装步骤
  66. # ============================================================
  67. install_system_deps() {
  68. local platform="$1"
  69. log_step "1/6 安装系统依赖"
  70. case "$platform" in
  71. rk3588|linux_x86)
  72. if command -v apt-get &>/dev/null; then
  73. sudo apt-get update -y
  74. sudo apt-get install -y \
  75. python3-pip python3-dev \
  76. libgl1-mesa-glx libglib2.0-0 \
  77. libsm6 libxext6 libxrender-dev \
  78. libgomp1 cmake build-essential \
  79. ffmpeg
  80. elif command -v yum &>/dev/null; then
  81. sudo yum install -y epel-release
  82. sudo yum install -y python3-pip python3-devel \
  83. mesa-libGL glib2-devel \
  84. libSM libXext libXrender \
  85. libgomp cmake gcc-c++ make \
  86. ffmpeg ffmpeg-devel
  87. fi
  88. ;;
  89. macos)
  90. if command -v brew &>/dev/null; then
  91. brew install ffmpeg
  92. fi
  93. ;;
  94. esac
  95. log_info "系统依赖安装完成"
  96. }
  97. setup_conda_env() {
  98. local platform="$1"
  99. log_step "2/6 配置 Conda 环境"
  100. # 检查 conda
  101. if [ ! -f "${CONDA_PATH}/etc/profile.d/conda.sh" ]; then
  102. log_warn "未找到 Miniconda3 在 ${CONDA_PATH}"
  103. log_info "请手动安装 Miniconda3:"
  104. log_info " wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-aarch64.sh"
  105. log_info " bash Miniconda3-latest-Linux-aarch64.sh -b -p ${CONDA_PATH}"
  106. log_info "按回车键继续,或 Ctrl+C 退出..."
  107. read -r
  108. fi
  109. # 创建 conda 环境(如果不存在)
  110. if [ -f "${CONDA_PATH}/etc/profile.d/conda.sh" ]; then
  111. # shellcheck disable=SC1091
  112. source "${CONDA_PATH}/etc/profile.d/conda.sh"
  113. if ! conda env list | grep -q "^${CONDA_ENV}\s"; then
  114. log_info "创建 Conda 环境: ${CONDA_ENV} (Python 3.10)"
  115. conda create -y -n "${CONDA_ENV}" python=3.10
  116. else
  117. log_info "Conda 环境 '${CONDA_ENV}' 已存在,跳过创建"
  118. fi
  119. fi
  120. log_info "Conda 环境就绪"
  121. }
  122. install_python_deps() {
  123. local platform="$1"
  124. log_step "3/6 安装 Python 依赖"
  125. local pip_cmd="pip3"
  126. if [ -f "${CONDA_PATH}/etc/profile.d/conda.sh" ]; then
  127. # shellcheck disable=SC1091
  128. source "${CONDA_PATH}/etc/profile.d/conda.sh"
  129. pip_cmd="${CONDA_PATH}/envs/${CONDA_ENV}/bin/pip"
  130. fi
  131. # 升级 pip
  132. $pip_cmd install --upgrade pip setuptools wheel
  133. # 平台特定依赖
  134. if [ "$platform" = "rk3588" ]; then
  135. # RK3588 使用 ONNX Runtime 而非 ultralytics
  136. $pip_cmd install onnxruntime~=1.17.0
  137. fi
  138. # 安装主要依赖
  139. $pip_cmd install -r "${SCRIPT_DIR}/requirements.txt"
  140. # macOS arm64 需要单独安装 tensorflow-metal 等
  141. if [ "$platform" = "macos" ] && [ "$(uname -m)" = "arm64" ]; then
  142. $pip_cmd install --upgrade torch torchvision
  143. fi
  144. log_info "Python 依赖安装完成"
  145. }
  146. deploy_project_files() {
  147. local platform="$1"
  148. log_step "4/6 部署项目文件"
  149. # 创建目录结构
  150. sudo mkdir -p "${SYSTEM_DIR}"
  151. sudo mkdir -p "${SYSTEM_DIR}/config"
  152. sudo mkdir -p "${SYSTEM_DIR}/core"
  153. sudo mkdir -p "${SYSTEM_DIR}/data/captures"
  154. sudo mkdir -p "${SYSTEM_DIR}/data/previews"
  155. sudo mkdir -p "${LOG_DIR}"
  156. # 复制源码 — 从 deploy/src/dual_camera_system/ 复制
  157. local SRC="${SCRIPT_DIR}/src/dual_camera_system"
  158. if [ ! -d "$SRC" ]; then
  159. log_error "未找到源码目录: $SRC"
  160. log_error "请确保 deploy/src/dual_camera_system/ 目录存在"
  161. exit 1
  162. fi
  163. # 复制所有 .py 文件
  164. log_info "复制 Python 模块..."
  165. find "${SRC}" -maxdepth 1 -name '*.py' -exec sudo cp -v {} "${SYSTEM_DIR}/" \;
  166. find "${SRC}/config" -name '*.py' -exec sudo cp -v {} "${SYSTEM_DIR}/config/" \;
  167. find "${SRC}/core" -name '*.py' -exec sudo cp -v {} "${SYSTEM_DIR}/core/" \;
  168. # 复制 requirements.txt 和 service.sh
  169. sudo cp "${SRC}/requirements.txt" "${SYSTEM_DIR}/" 2>/dev/null || true
  170. sudo cp "${SRC}/service.sh" "${SYSTEM_DIR}/" 2>/dev/null || true
  171. # 设置权限
  172. sudo chown -R "${SERVICE_USER}:${SERVICE_GROUP}" "${INSTALL_DIR}"
  173. log_info "项目文件部署完成"
  174. }
  175. install_systemd_service() {
  176. local platform="$1"
  177. log_step "5/7 安装 Systemd 服务"
  178. if [ "$platform" = "macos" ]; then
  179. log_warn "macOS 不支持 systemd,跳过服务安装"
  180. log_info "可手动启动: cd ${SYSTEM_DIR} && python main.py --port 8000"
  181. return
  182. fi
  183. # 复制 service 文件
  184. sudo cp "${SCRIPT_DIR}/dsh-dual-camera.service" /etc/systemd/system/dsh-dual-camera.service
  185. sudo chmod 644 /etc/systemd/system/dsh-dual-camera.service
  186. # 重载、启用、启动
  187. sudo systemctl daemon-reload
  188. sudo systemctl enable dsh-dual-camera.service
  189. sudo systemctl restart dsh-dual-camera.service
  190. # 检查状态
  191. sleep 2
  192. if systemctl is-active --quiet dsh-dual-camera.service; then
  193. log_info "服务已启动并设置为开机自启"
  194. else
  195. log_warn "服务启动异常,请检查: sudo journalctl -u dsh-dual-camera.service -n 50 --no-pager"
  196. fi
  197. }
  198. install_easytier() {
  199. local platform="$1"
  200. log_step "6/7 部署 EasyTier VPN"
  201. if [ "$platform" != "rk3588" ]; then
  202. log_warn "仅 RK3588 需要 easytier,跳过"
  203. return
  204. fi
  205. # 部署 easytier-core
  206. if [ -f "${SCRIPT_DIR}/easytier-core" ]; then
  207. sudo cp "${SCRIPT_DIR}/easytier-core" /opt/easytier-core
  208. sudo chmod 755 /opt/easytier-core
  209. sudo chown root:root /opt/easytier-core
  210. log_info "easytier-core 已部署到 /opt/easytier-core"
  211. else
  212. log_warn "未找到 ${SCRIPT_DIR}/easytier-core,跳过 core 部署"
  213. fi
  214. # 部署 easytier-cli
  215. if [ -f "${SCRIPT_DIR}/easytier-cli" ]; then
  216. sudo cp "${SCRIPT_DIR}/easytier-cli" /home/admin/easytier-cli
  217. sudo chmod 755 /home/admin/easytier-cli
  218. sudo chown admin:admin /home/admin/easytier-cli
  219. log_info "easytier-cli 已部署到 /home/admin/easytier-cli"
  220. else
  221. log_warn "未找到 ${SCRIPT_DIR}/easytier-cli,跳过 CLI 部署"
  222. fi
  223. # 安装 easytier 系统服务
  224. if [ -f "${SCRIPT_DIR}/easytier.service" ]; then
  225. sudo cp "${SCRIPT_DIR}/easytier.service" /etc/systemd/system/easytier.service
  226. sudo chmod 644 /etc/systemd/system/easytier.service
  227. sudo systemctl daemon-reload
  228. sudo systemctl enable easytier.service
  229. sudo systemctl restart easytier.service
  230. sleep 2
  231. if systemctl is-active --quiet easytier.service; then
  232. log_info "easytier 服务已启动并设置为开机自启"
  233. else
  234. log_warn "easytier 服务启动异常,请检查: sudo journalctl -u easytier.service -n 50 --no-pager"
  235. fi
  236. else
  237. log_warn "未找到 ${SCRIPT_DIR}/easytier.service,跳过服务安装"
  238. fi
  239. }
  240. verify_installation() {
  241. local platform="$1"
  242. log_step "7/7 验证安装"
  243. echo ""
  244. echo " ┌─────────────────────────────────────────────┐"
  245. echo " │ DSH 双摄安全检测系统 │"
  246. echo " │ │"
  247. echo " │ 安装目录: ${INSTALL_DIR}"
  248. if [ "$platform" != "macos" ]; then
  249. if systemctl is-active --quiet dsh-dual-camera.service; then
  250. echo " │ 主服务: ✅ dsh-dual-camera │"
  251. else
  252. echo " │ 主服务: ❌ dsh-dual-camera │"
  253. fi
  254. if systemctl is-active --quiet easytier.service 2>/dev/null; then
  255. echo " │ VPN 服务: ✅ easytier │"
  256. fi
  257. echo " │ 管理命令: │"
  258. echo " │ sudo systemctl start dsh-dual-camera │"
  259. echo " │ sudo systemctl stop dsh-dual-camera │"
  260. echo " │ sudo systemctl restart dsh-dual-camera │"
  261. echo " │ sudo journalctl -u dsh-dual-camera -f │"
  262. else
  263. echo " │ 服务状态: ⚡ 手动启动 │"
  264. echo " │ 启动命令: │"
  265. echo " │ cd ${SYSTEM_DIR} │"
  266. echo " │ python main.py --port 8000 │"
  267. fi
  268. echo " │ │"
  269. echo " │ API 文档: http://localhost:8000/docs │"
  270. echo " │ 健康检查: http://localhost:8000/ │"
  271. echo " │ │"
  272. echo " └─────────────────────────────────────────────┘"
  273. echo ""
  274. }
  275. # ============================================================
  276. # 主流程
  277. # ============================================================
  278. main() {
  279. echo ""
  280. echo " ╔══════════════════════════════════════════╗"
  281. echo " ║ DSH 双摄安全检测系统 — 一键部署 ║"
  282. echo " ║ Dual-camera Safety Detection System ║"
  283. echo " ╚══════════════════════════════════════════╝"
  284. echo ""
  285. # 检测平台
  286. local PLATFORM
  287. PLATFORM="$(detect_platform)"
  288. log_info "检测到平台: ${PLATFORM} ($(uname -m))"
  289. if [ "$PLATFORM" = "unknown" ]; then
  290. log_error "不支持的平台: $(uname -s) / $(uname -m)"
  291. log_error "仅支持 RK3588 (aarch64 Linux)、x86_64 Linux 和 macOS"
  292. exit 1
  293. fi
  294. # 设置路径
  295. setup_paths "$PLATFORM"
  296. # 检查 root 权限
  297. if [ "$PLATFORM" != "macos" ]; then
  298. if [ "$EUID" -ne 0 ]; then
  299. log_info "部分操作需要 sudo 权限(安装依赖、部署文件、注册服务)"
  300. fi
  301. fi
  302. # 执行安装步骤
  303. install_system_deps "$PLATFORM"
  304. setup_conda_env "$PLATFORM"
  305. install_python_deps "$PLATFORM"
  306. deploy_project_files "$PLATFORM"
  307. install_systemd_service "$PLATFORM"
  308. install_easytier "$PLATFORM"
  309. verify_installation "$PLATFORM"
  310. log_info "安装完成!"
  311. }
  312. main "$@"