#!/bin/bash set -euo pipefail # ============================================================ # DSH 双摄安全检测系统 — 一键安装脚本 # 支持:RK3588 (aarch64) / x86_64 Linux / macOS # ============================================================ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" # ---------- 颜色输出 ---------- RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' NC='\033[0m' log_info() { echo -e "${GREEN}[INFO]${NC} $*"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } log_error() { echo -e "${RED}[ERROR]${NC} $*"; } log_step() { echo -e "\n${CYAN}═══════════════════════════════════════════${NC}"; echo -e "${CYAN} $*${NC}"; echo -e "${CYAN}═══════════════════════════════════════════${NC}\n"; } # ---------- 检测平台 ---------- detect_platform() { local arch arch="$(uname -m)" local os os="$(uname -s)" if [ "$os" = "Darwin" ]; then echo "macos" elif [ "$os" = "Linux" ] && [ "$arch" = "aarch64" ]; then echo "rk3588" elif [ "$os" = "Linux" ] && { [ "$arch" = "x86_64" ] || [ "$arch" = "amd64" ]; }; then echo "linux_x86" else echo "unknown" fi } # ---------- 默认路径 ---------- setup_paths() { local platform="$1" case "$platform" in rk3588) INSTALL_DIR="/home/admin/dsh" SERVICE_USER="admin" SERVICE_GROUP="admin" CONDA_PATH="/home/admin/miniconda3" CONDA_ENV="rknn" ;; linux_x86) INSTALL_DIR="/home/wen/dsh" SERVICE_USER="$USER" SERVICE_GROUP="$(id -gn)" CONDA_PATH="${CONDA_PATH:-$HOME/miniconda3}" CONDA_ENV="dsh" ;; macos) INSTALL_DIR="$HOME/dsh" SERVICE_USER="$USER" SERVICE_GROUP="$(id -gn)" CONDA_PATH="${CONDA_PATH:-$HOME/miniconda3}" CONDA_ENV="dsh" ;; esac SYSTEM_DIR="${INSTALL_DIR}/dual_camera_system" LOG_DIR="${SYSTEM_DIR}/logs" } # ============================================================ # 安装步骤 # ============================================================ install_system_deps() { local platform="$1" log_step "1/6 安装系统依赖" case "$platform" in rk3588|linux_x86) if command -v apt-get &>/dev/null; then sudo apt-get update -y sudo apt-get install -y \ python3-pip python3-dev \ libgl1-mesa-glx libglib2.0-0 \ libsm6 libxext6 libxrender-dev \ libgomp1 cmake build-essential \ ffmpeg elif command -v yum &>/dev/null; then sudo yum install -y epel-release sudo yum install -y python3-pip python3-devel \ mesa-libGL glib2-devel \ libSM libXext libXrender \ libgomp cmake gcc-c++ make \ ffmpeg ffmpeg-devel fi ;; macos) if command -v brew &>/dev/null; then brew install ffmpeg fi ;; esac log_info "系统依赖安装完成" } setup_conda_env() { local platform="$1" log_step "2/6 配置 Conda 环境" # 检查 conda if [ ! -f "${CONDA_PATH}/etc/profile.d/conda.sh" ]; then log_warn "未找到 Miniconda3 在 ${CONDA_PATH}" log_info "请手动安装 Miniconda3:" log_info " wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-aarch64.sh" log_info " bash Miniconda3-latest-Linux-aarch64.sh -b -p ${CONDA_PATH}" log_info "按回车键继续,或 Ctrl+C 退出..." read -r fi # 创建 conda 环境(如果不存在) if [ -f "${CONDA_PATH}/etc/profile.d/conda.sh" ]; then # shellcheck disable=SC1091 source "${CONDA_PATH}/etc/profile.d/conda.sh" if ! conda env list | grep -q "^${CONDA_ENV}\s"; then log_info "创建 Conda 环境: ${CONDA_ENV} (Python 3.10)" conda create -y -n "${CONDA_ENV}" python=3.10 else log_info "Conda 环境 '${CONDA_ENV}' 已存在,跳过创建" fi fi log_info "Conda 环境就绪" } install_python_deps() { local platform="$1" log_step "3/6 安装 Python 依赖" local pip_cmd="pip3" if [ -f "${CONDA_PATH}/etc/profile.d/conda.sh" ]; then # shellcheck disable=SC1091 source "${CONDA_PATH}/etc/profile.d/conda.sh" pip_cmd="${CONDA_PATH}/envs/${CONDA_ENV}/bin/pip" fi # 升级 pip $pip_cmd install --upgrade pip setuptools wheel # 平台特定依赖 if [ "$platform" = "rk3588" ]; then # RK3588 使用 ONNX Runtime 而非 ultralytics $pip_cmd install onnxruntime~=1.17.0 fi # 安装主要依赖 $pip_cmd install -r "${SCRIPT_DIR}/requirements.txt" # macOS arm64 需要单独安装 tensorflow-metal 等 if [ "$platform" = "macos" ] && [ "$(uname -m)" = "arm64" ]; then $pip_cmd install --upgrade torch torchvision fi log_info "Python 依赖安装完成" } deploy_project_files() { local platform="$1" log_step "4/6 部署项目文件" # 创建目录结构 sudo mkdir -p "${SYSTEM_DIR}" sudo mkdir -p "${SYSTEM_DIR}/config" sudo mkdir -p "${SYSTEM_DIR}/core" sudo mkdir -p "${SYSTEM_DIR}/data/captures" sudo mkdir -p "${SYSTEM_DIR}/data/previews" sudo mkdir -p "${LOG_DIR}" # 复制源码 — 从 deploy/src/dual_camera_system/ 复制 local SRC="${SCRIPT_DIR}/src/dual_camera_system" if [ ! -d "$SRC" ]; then log_error "未找到源码目录: $SRC" log_error "请确保 deploy/src/dual_camera_system/ 目录存在" exit 1 fi # 复制所有 .py 文件 log_info "复制 Python 模块..." find "${SRC}" -maxdepth 1 -name '*.py' -exec sudo cp -v {} "${SYSTEM_DIR}/" \; find "${SRC}/config" -name '*.py' -exec sudo cp -v {} "${SYSTEM_DIR}/config/" \; find "${SRC}/core" -name '*.py' -exec sudo cp -v {} "${SYSTEM_DIR}/core/" \; # 复制 requirements.txt 和 service.sh sudo cp "${SRC}/requirements.txt" "${SYSTEM_DIR}/" 2>/dev/null || true sudo cp "${SRC}/service.sh" "${SYSTEM_DIR}/" 2>/dev/null || true # 设置权限 sudo chown -R "${SERVICE_USER}:${SERVICE_GROUP}" "${INSTALL_DIR}" log_info "项目文件部署完成" } install_systemd_service() { local platform="$1" log_step "5/7 安装 Systemd 服务" if [ "$platform" = "macos" ]; then log_warn "macOS 不支持 systemd,跳过服务安装" log_info "可手动启动: cd ${SYSTEM_DIR} && python main.py --port 8000" return fi # 复制 service 文件 sudo cp "${SCRIPT_DIR}/dsh-dual-camera.service" /etc/systemd/system/dsh-dual-camera.service sudo chmod 644 /etc/systemd/system/dsh-dual-camera.service # 重载、启用、启动 sudo systemctl daemon-reload sudo systemctl enable dsh-dual-camera.service sudo systemctl restart dsh-dual-camera.service # 检查状态 sleep 2 if systemctl is-active --quiet dsh-dual-camera.service; then log_info "服务已启动并设置为开机自启" else log_warn "服务启动异常,请检查: sudo journalctl -u dsh-dual-camera.service -n 50 --no-pager" fi } install_easytier() { local platform="$1" log_step "6/7 部署 EasyTier VPN" if [ "$platform" != "rk3588" ]; then log_warn "仅 RK3588 需要 easytier,跳过" return fi # 部署 easytier-core if [ -f "${SCRIPT_DIR}/easytier-core" ]; then sudo cp "${SCRIPT_DIR}/easytier-core" /opt/easytier-core sudo chmod 755 /opt/easytier-core sudo chown root:root /opt/easytier-core log_info "easytier-core 已部署到 /opt/easytier-core" else log_warn "未找到 ${SCRIPT_DIR}/easytier-core,跳过 core 部署" fi # 部署 easytier-cli if [ -f "${SCRIPT_DIR}/easytier-cli" ]; then sudo cp "${SCRIPT_DIR}/easytier-cli" /home/admin/easytier-cli sudo chmod 755 /home/admin/easytier-cli sudo chown admin:admin /home/admin/easytier-cli log_info "easytier-cli 已部署到 /home/admin/easytier-cli" else log_warn "未找到 ${SCRIPT_DIR}/easytier-cli,跳过 CLI 部署" fi # 安装 easytier 系统服务 if [ -f "${SCRIPT_DIR}/easytier.service" ]; then sudo cp "${SCRIPT_DIR}/easytier.service" /etc/systemd/system/easytier.service sudo chmod 644 /etc/systemd/system/easytier.service sudo systemctl daemon-reload sudo systemctl enable easytier.service sudo systemctl restart easytier.service sleep 2 if systemctl is-active --quiet easytier.service; then log_info "easytier 服务已启动并设置为开机自启" else log_warn "easytier 服务启动异常,请检查: sudo journalctl -u easytier.service -n 50 --no-pager" fi else log_warn "未找到 ${SCRIPT_DIR}/easytier.service,跳过服务安装" fi } verify_installation() { local platform="$1" log_step "7/7 验证安装" echo "" echo " ┌─────────────────────────────────────────────┐" echo " │ DSH 双摄安全检测系统 │" echo " │ │" echo " │ 安装目录: ${INSTALL_DIR}" if [ "$platform" != "macos" ]; then if systemctl is-active --quiet dsh-dual-camera.service; then echo " │ 主服务: ✅ dsh-dual-camera │" else echo " │ 主服务: ❌ dsh-dual-camera │" fi if systemctl is-active --quiet easytier.service 2>/dev/null; then echo " │ VPN 服务: ✅ easytier │" fi echo " │ 管理命令: │" echo " │ sudo systemctl start dsh-dual-camera │" echo " │ sudo systemctl stop dsh-dual-camera │" echo " │ sudo systemctl restart dsh-dual-camera │" echo " │ sudo journalctl -u dsh-dual-camera -f │" else echo " │ 服务状态: ⚡ 手动启动 │" echo " │ 启动命令: │" echo " │ cd ${SYSTEM_DIR} │" echo " │ python main.py --port 8000 │" fi echo " │ │" echo " │ API 文档: http://localhost:8000/docs │" echo " │ 健康检查: http://localhost:8000/ │" echo " │ │" echo " └─────────────────────────────────────────────┘" echo "" } # ============================================================ # 主流程 # ============================================================ main() { echo "" echo " ╔══════════════════════════════════════════╗" echo " ║ DSH 双摄安全检测系统 — 一键部署 ║" echo " ║ Dual-camera Safety Detection System ║" echo " ╚══════════════════════════════════════════╝" echo "" # 检测平台 local PLATFORM PLATFORM="$(detect_platform)" log_info "检测到平台: ${PLATFORM} ($(uname -m))" if [ "$PLATFORM" = "unknown" ]; then log_error "不支持的平台: $(uname -s) / $(uname -m)" log_error "仅支持 RK3588 (aarch64 Linux)、x86_64 Linux 和 macOS" exit 1 fi # 设置路径 setup_paths "$PLATFORM" # 检查 root 权限 if [ "$PLATFORM" != "macos" ]; then if [ "$EUID" -ne 0 ]; then log_info "部分操作需要 sudo 权限(安装依赖、部署文件、注册服务)" fi fi # 执行安装步骤 install_system_deps "$PLATFORM" setup_conda_env "$PLATFORM" install_python_deps "$PLATFORM" deploy_project_files "$PLATFORM" install_systemd_service "$PLATFORM" install_easytier "$PLATFORM" verify_installation "$PLATFORM" log_info "安装完成!" } main "$@"