| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- #!/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 "$@"
|