#!/bin/bash # RK3588 Media Server + Agent 统一管理脚本 # Media Server 和 Agent 是独立的 systemd 服务 # 用法: sudo ./manage.sh [install|status|uninstall] set -e RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" BUILD_DIR="$PROJECT_DIR/build" INSTALL_DIR="/opt/rk3588-media-server" AGENT_INSTALL_DIR="/opt/rk3588-agent" SERVICE_DIR="/etc/systemd/system" # ==================== 功能函数 ==================== cmd_install() { echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" echo -e "${BLUE}║ RK3588 Media Server + Agent 安装脚本 ║${NC}" echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}" echo "" if [ "$(id -u)" -ne 0 ]; then echo -e "${RED}错误: 请使用 sudo 运行此脚本${NC}" exit 1 fi echo "项目目录: $PROJECT_DIR" echo "Media Server 安装目录: $INSTALL_DIR" echo "Agent 安装目录: $AGENT_INSTALL_DIR" echo "" # 检查 Media Server 编译产物 if [ ! -f "$BUILD_DIR/media-server" ]; then echo -e "${RED}错误: 未找到编译好的 media-server${NC}" echo "请先编译项目:" echo " cd $PROJECT_DIR" echo " cmake -S . -B build -DCMAKE_BUILD_TYPE=Release" echo " cmake --build build -j\$(nproc)" exit 1 fi # 检查插件 if [ ! -d "$BUILD_DIR/plugins" ] || [ -z "$(ls -A $BUILD_DIR/plugins/*.so 2>/dev/null)" ]; then echo -e "${YELLOW}警告: 未找到插件目录或插件为空${NC}" read -p "是否继续? (y/N): " -r [ "$REPLY" != "y" ] && [ "$REPLY" != "Y" ] && exit 1 fi # 检查 Agent 编译产物(强制要求) AGENT_SOURCE="" if [ -f "$PROJECT_DIR/agent/rk3588-agent_linux_arm64" ]; then AGENT_SOURCE="$PROJECT_DIR/agent/rk3588-agent_linux_arm64" elif [ -f "$PROJECT_DIR/agent/cmd/rk3588-agent/rk3588-agent" ]; then AGENT_SOURCE="$PROJECT_DIR/agent/cmd/rk3588-agent/rk3588-agent" fi if [ -z "$AGENT_SOURCE" ]; then echo -e "${RED}错误: 未找到编译好的 rk3588-agent${NC}" echo "请先编译 Agent:" echo " cd $PROJECT_DIR/agent" echo " go build -o rk3588-agent_linux_arm64 ./cmd/rk3588-agent" exit 1 fi echo -e "${GREEN}✓${NC} 编译产物检查通过" echo "" # 选择配置文件 echo "请选择配置文件:" echo " 1) test_cam1_face_det_rtsp_server.json (人脸检测)" echo " 2) sample_cam1_native_rtsp_face.json (完整功能)" echo " 3) test_cam1_face_det_recog_rtsp_server.json (人脸识别)" echo " 4) sample_cam1.json (完整功能,需手动修复)" echo "" printf "请输入选项 [1-4,默认1]: " read choice choice=${choice:-1} case $choice in 1) CONFIG_FILE="$PROJECT_DIR/configs/test_cam1_face_det_rtsp_server.json" ;; 2) CONFIG_FILE="$PROJECT_DIR/configs/sample_cam1_native_rtsp_face.json" ;; 3) CONFIG_FILE="$PROJECT_DIR/configs/test_cam1_face_det_recog_rtsp_server.json" ;; 4) CONFIG_FILE="$PROJECT_DIR/configs/sample_cam1.json" ;; *) CONFIG_FILE="$PROJECT_DIR/configs/test_cam1_face_det_rtsp_server.json" ;; esac echo "" # 安装 Media Server echo -e "${YELLOW}[1/3] 安装 Media Server...${NC}" rm -rf "$INSTALL_DIR" mkdir -p "$INSTALL_DIR/bin/plugins" mkdir -p "$INSTALL_DIR/lib" mkdir -p "$INSTALL_DIR/etc" mkdir -p "$INSTALL_DIR/logs" mkdir -p "$INSTALL_DIR/models" mkdir -p "$INSTALL_DIR/web/hls" cp "$BUILD_DIR/media-server" "$INSTALL_DIR/bin/" chmod +x "$INSTALL_DIR/bin/media-server" if [ -d "$BUILD_DIR/plugins" ]; then cp "$BUILD_DIR"/plugins/*.so "$INSTALL_DIR/bin/plugins/" 2>/dev/null || true fi if ls "$BUILD_DIR"/*.so 1> /dev/null 2>&1; then cp "$BUILD_DIR"/*.so "$INSTALL_DIR/lib/" 2>/dev/null || true fi # 复制模型 if [ -d "$PROJECT_DIR/third_party/rknpu2/examples/rknn_yolov5_demo/model/RK3588" ]; then cp "$PROJECT_DIR/third_party/rknpu2/examples/rknn_yolov5_demo/model/RK3588"/*.rknn "$INSTALL_DIR/models/" 2>/dev/null || true fi if [ -d "$PROJECT_DIR/models" ]; then cp -r "$PROJECT_DIR/models"/* "$INSTALL_DIR/models/" 2>/dev/null || true fi # 处理配置 cp "$CONFIG_FILE" "$INSTALL_DIR/etc/media-server.json" python3 << 'EOF' import json, os config_file = "/opt/rk3588-media-server/etc/media-server.json" install_dir = "/opt/rk3588-media-server" project_dir = os.path.expanduser("~/apps/OrangePi3588Media") def fix_path(path): if not path or not isinstance(path, str): return path if 'third_party/rknpu2' in path: return os.path.join(install_dir, 'models', os.path.basename(path)) if path.startswith('./'): if path.startswith('./web/'): return os.path.join(install_dir, path[2:]) elif path.startswith('./models/'): return os.path.join(install_dir, path[2:]) else: abs_path = os.path.join(project_dir, path) if os.path.exists(abs_path): return abs_path return os.path.join(install_dir, path[2:]) return path try: with open(config_file, 'r') as f: config = json.load(f) for graph in config.get('graphs', []): nodes = graph.get('nodes', []) edges = graph.get('edges', []) node_ids = {node['id'] for node in nodes} nodes_with_input = set() for edge in edges: if isinstance(edge, list) and len(edge) >= 2: nodes_with_input.add(edge[1]) for node in nodes: if node.get('role') in ['filter', 'sink'] and node['id'] not in nodes_with_input: if node.get('enable', True): node['enable'] = False if 'model_path' in node: node['model_path'] = fix_path(node['model_path']) if 'gallery' in node and 'path' in node['gallery']: node['gallery']['path'] = fix_path(node['gallery']['path']) if 'outputs' in node: for output in node['outputs']: if 'path' in output: output['path'] = fix_path(output['path']) with open(config_file, 'w') as f: json.dump(config, f, indent=2) print("配置处理完成") except Exception as e: print(f"配置处理出错: {e}") EOF echo -e "${GREEN}✓${NC} Media Server 安装完成" # 安装 Agent echo -e "${YELLOW}[2/3] 安装 Agent...${NC}" rm -rf "$AGENT_INSTALL_DIR" mkdir -p "$AGENT_INSTALL_DIR" mkdir -p "/var/lib/rk3588-agent" cp "$AGENT_SOURCE" "$AGENT_INSTALL_DIR/rk3588-agent" chmod +x "$AGENT_INSTALL_DIR/rk3588-agent" # Agent 配置 - 禁用进程管理,改为监控模式 cat > "$AGENT_INSTALL_DIR/agent.config.json" << 'AGENT_CONFIG' { "agent": { "listen": "0.0.0.0:9100", "token": "CHANGE_ME", "require_token_for_read": false, "discovery_enable": true, "discovery_port": 35688, "device_name": "rk3588_cam1", "device_id_path": "/var/lib/rk3588-agent/device_id", "models_dir": "/opt/rk3588-media-server/models", "max_upload_mb": 200, "config_path": "/opt/rk3588-media-server/etc/media-server.json", "media_server_process": { "enable": false, "exec_path": "", "work_dir": "", "configs_dir": "", "pid_file": "", "graceful_timeout_ms": 5000 }, "media_server_base_url": "http://127.0.0.1:9000", "media_server_timeout_ms": 3000, "media_server_retry": { "max_attempts": 3, "backoff_ms": [200, 500] } } } AGENT_CONFIG chown -R orangepi:orangepi "/var/lib/rk3588-agent" chmod 755 "$AGENT_INSTALL_DIR" echo -e "${GREEN}✓${NC} Agent 安装完成" # 安装服务 echo -e "${YELLOW}[3/3] 安装 Systemd 服务...${NC}" # Media Server 独立服务 cat > "$SERVICE_DIR/media-server.service" << 'EOF' [Unit] Description=RK3588 Media Server After=network.target [Service] Type=simple User=root WorkingDirectory=/opt/rk3588-media-server ExecStart=/opt/rk3588-media-server/bin/media-server --config /opt/rk3588-media-server/etc/media-server.json Restart=always RestartSec=5 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target EOF # Agent 独立服务 cat > "$SERVICE_DIR/rk3588-agent.service" << 'EOF' [Unit] Description=RK3588 Agent Service After=network.target media-server.service Wants=media-server.service [Service] Type=simple User=root WorkingDirectory=/opt/rk3588-agent ExecStart=/opt/rk3588-agent/rk3588-agent --config /opt/rk3588-agent/agent.config.json Restart=always RestartSec=5 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target EOF systemctl daemon-reload # 启动服务(独立运行) systemctl enable media-server systemctl start media-server systemctl enable rk3588-agent systemctl start rk3588-agent echo -e "${GREEN}✓${NC} 服务已启动" # 完成 echo "" echo -e "${GREEN}╔════════════════════════════════════════════════════════════╗${NC}" echo -e "${GREEN}║ 安装完成! ║${NC}" echo -e "${GREEN}╚════════════════════════════════════════════════════════════╝${NC}" echo "" echo "架构说明:" echo " Media Server: 独立 systemd 服务(高可用,崩溃自动重启)" echo " Agent: 独立 systemd 服务(监控状态,Web 管理)" echo "" echo "管理命令:" echo " 状态: sudo ./manage.sh status" echo " 日志: sudo journalctl -u media-server -f" echo " 界面: http://<设备IP>:9100" } cmd_status() { echo -e "${BLUE}========== RK3588 Media Server 状态 ==========${NC}" echo "" echo -e "${YELLOW}[系统信息]${NC}" echo " 时间: $(date '+%Y-%m-%d %H:%M:%S')" echo " 运行时间: $(uptime -p 2>/dev/null || uptime | awk -F',' '{print $1}')" echo "" echo -e "${YELLOW}[NPU 负载]${NC}" if [ -f /sys/kernel/debug/rknpu/load ]; then cat /sys/kernel/debug/rknpu/load | sed 's/^/ /' else echo " NPU 信息不可用" fi echo "" echo -e "${YELLOW}[Media Server]${NC}" if systemctl is-active --quiet media-server 2>/dev/null; then echo -e " 状态: ${GREEN}● 运行中${NC}" PID=$(systemctl show --property=MainPID --value media-server 2>/dev/null) echo " PID: $PID" if [ -n "$PID" ] && [ "$PID" != "0" ]; then CPU_MEM=$(ps -p $PID -o %cpu,%mem --no-headers 2>/dev/null || echo "N/A") echo " CPU/MEM: $CPU_MEM" fi echo " 端口:" ss -tlnp 2>/dev/null | grep -E "(9000|8554|8555)" | head -3 | sed 's/^/ /' else echo -e " 状态: ${RED}○ 停止${NC}" echo " 错误日志:" journalctl -u media-server --no-pager -n 3 2>/dev/null | sed 's/^/ /' fi echo "" echo -e "${YELLOW}[RK3588 Agent]${NC}" if systemctl is-active --quiet rk3588-agent 2>/dev/null; then echo -e " 状态: ${GREEN}● 运行中${NC}" PID=$(systemctl show --property=MainPID --value rk3588-agent 2>/dev/null) if [ -n "$PID" ] && [ "$PID" != "0" ]; then CPU_MEM=$(ps -p $PID -o %cpu,%mem --no-headers 2>/dev/null || echo "N/A") echo " CPU/MEM: $CPU_MEM" fi echo " 管理界面: http://$(hostname -I | awk '{print $1}'):9100" else echo -e " 状态: ${RED}○ 停止${NC}" fi echo "" echo -e "${YELLOW}[最近日志 - Media Server]${NC}" journalctl -u media-server --no-pager -n 5 2>/dev/null | tail -5 || echo " 无日志" echo "" echo "常用命令:" echo " 启动: sudo systemctl start media-server" echo " 停止: sudo systemctl stop media-server" echo " 重启: sudo systemctl restart media-server" echo " 配置: sudo nano /opt/rk3588-media-server/etc/media-server.json" } cmd_uninstall() { echo -e "${YELLOW}========== RK3588 Media Server 卸载 ==========${NC}" echo "" if [ "$(id -u)" -ne 0 ]; then echo -e "${RED}错误: 请使用 sudo 运行${NC}" exit 1 fi read -p "确定要卸载并停止所有服务? (y/N): " -r [ "$REPLY" != "y" ] && [ "$REPLY" != "Y" ] && echo "已取消" && exit 0 echo "[1/3] 停止服务..." systemctl stop media-server rk3588-agent 2>/dev/null || true systemctl disable media-server rk3588-agent 2>/dev/null || true echo -e "${GREEN}✓${NC} 服务已停止" echo "[2/3] 删除服务文件..." rm -f "$SERVICE_DIR/media-server.service" rm -f "$SERVICE_DIR/rk3588-agent.service" systemctl daemon-reload echo -e "${GREEN}✓${NC} 服务文件已删除" echo "[3/3] 备份并清理..." BACKUP_DIR="/root/rk3588-backup-$(date +%Y%m%d%H%M%S)" mkdir -p "$BACKUP_DIR" [ -f "$INSTALL_DIR/etc/media-server.json" ] && cp "$INSTALL_DIR/etc/media-server.json" "$BACKUP_DIR/" [ -d "$INSTALL_DIR/models" ] && cp -r "$INSTALL_DIR/models" "$BACKUP_DIR/" 2>/dev/null || true echo -e "${GREEN}✓${NC} 配置已备份到: $BACKUP_DIR" read -p "是否删除安装目录? (y/N): " -r if [ "$REPLY" = "y" ] || [ "$REPLY" = "Y" ]; then rm -rf "$INSTALL_DIR" "$AGENT_INSTALL_DIR" echo -e "${GREEN}✓${NC} 目录已删除" else echo "保留目录,手动删除: sudo rm -rf $INSTALL_DIR $AGENT_INSTALL_DIR" fi echo "" echo -e "${GREEN}卸载完成${NC}" } # ==================== 主入口 ==================== case "${1:-install}" in install) cmd_install ;; status) cmd_status ;; uninstall) cmd_uninstall ;; *) echo "用法: sudo ./manage.sh [install|status|uninstall]" echo "" echo "命令:" echo " install - 安装 Media Server 和 Agent (默认)" echo " status - 查看运行状态" echo " uninstall - 卸载服务" exit 1 ;; esac