#!/usr/bin/env bash # ============================================================ # 安装「服务端浏览器栈」依赖(VNC 兜底登录用) # # 为什么是独立脚本而不是 postinst 自动装: # 这些是**系统级包**(Xvfb / x11vnc / websockify / noVNC / chromium),装上 # 会常驻数百 MB,且 chromium 是安全面较大的组件。很多部署根本用不到 VNC 兜底 # (大部分平台的登录是 device-poll / callback / paste,纯 HTTP 即可)。默认替 # 运维的机器装一堆浏览器组件不是发行包该做的事 —— 需要的人显式装。 # # 什么时候需要它: # 平台声明 flow="vnc"(登录必须在服务端浏览器里完成:回环回调落不到用户机器、 # 授权页要求浏览器内交互)。插件会在登录时如实报告缺哪个依赖。 # # 用法: # sudo bash packaging/install-browser-stack.sh # 自动识别包管理器 # sudo bash packaging/install-browser-stack.sh --check # 只检查,不安装 # ============================================================ set -euo pipefail CHECK_ONLY=0 for a in "$@"; do case "$a" in --check|-c) CHECK_ONLY=1 ;; -h|--help) sed -n '2,20p' "$0"; exit 0 ;; *) echo "未知参数: $a" >&2; exit 2 ;; esac done # 需要的外部可执行文件(插件 browserDeps 同一份清单) BINS=(Xvfb x11vnc websockify python3) # chromium 的二进制名随发行版变化 CHROMIUM_CANDIDATES=(chromium chromium-browser google-chrome google-chrome-stable) NOVNC_DIRS=(/usr/share/novnc /usr/share/webapps/novnc /opt/novnc) missing=() for b in "${BINS[@]}"; do command -v "$b" >/dev/null 2>&1 || missing+=("$b") done chromium="" for c in "${CHROMIUM_CANDIDATES[@]}"; do if command -v "$c" >/dev/null 2>&1; then chromium="$c"; break; fi done [ -z "$chromium" ] && missing+=("chromium") novnc="" for d in "${NOVNC_DIRS[@]}"; do [ -f "$d/vnc.html" ] && { novnc="$d"; break; } done [ -z "$novnc" ] && missing+=("novnc") # CDP 取凭据需要 python websocket 客户端 if command -v python3 >/dev/null 2>&1; then python3 -c 'import websocket' >/dev/null 2>&1 || missing+=("python3-websocket") fi if [ ${#missing[@]} -eq 0 ]; then echo "OK 浏览器栈依赖齐全" echo " chromium: ${chromium}" echo " noVNC: ${novnc}" exit 0 fi echo "缺少依赖: ${missing[*]}" if [ "$CHECK_ONLY" = 1 ]; then exit 1 fi # ---------- 识别包管理器 ---------- if command -v apt-get >/dev/null 2>&1; then # Debian/Ubuntu:chromium 在部分版本是 snap 包,apt 装不上; # 先试 apt,失败时明确提示替代方案,不静默放弃。 pkgs=(xvfb x11vnc websockify novnc python3-websocket) echo "→ apt-get install ${pkgs[*]} chromium" apt-get update -qq || true apt-get install -y "${pkgs[@]}" || { echo "WARN: 部分包装失败,仍尝试装 chromium" >&2 } apt-get install -y chromium || apt-get install -y chromium-browser || { echo "WARN: apt 装不上 chromium(Ubuntu 新版将其作为 snap 分发)。" >&2 echo " 可选:snap install chromium 或 apt-get install -y chromium-browser" >&2 } elif command -v dnf >/dev/null 2>&1; then echo "→ dnf install xorg-x11-server-Xvfb x11vnc python3-websockify novnc chromium python3-websocket-client" dnf install -y xorg-x11-server-Xvfb x11vnc python3-websockify novnc chromium python3-websocket-client elif command -v yum >/dev/null 2>&1; then echo "→ yum install xorg-x11-server-Xvfb x11vnc python3-websockify novnc chromium python3-websocket-client" yum install -y xorg-x11-server-Xvfb x11vnc python3-websockify novnc chromium python3-websocket-client elif command -v apk >/dev/null 2>&1; then echo "→ apk add xvfb x11vnc websockify novnc chromium py3-websocket-client" apk add --no-cache xvfb x11vnc websockify novnc chromium py3-websocket-client else echo "未识别的包管理器。请手动安装:" >&2 echo " Xvfb, x11vnc, websockify, noVNC, chromium, python3 websocket-client" >&2 exit 1 fi # ---------- 复核 ---------- echo echo "复核安装结果:" ok=1 for b in "${BINS[@]}"; do if command -v "$b" >/dev/null 2>&1; then echo " OK $b" else echo " FAIL $b"; ok=0; fi done chromium="" for c in "${CHROMIUM_CANDIDATES[@]}"; do if command -v "$c" >/dev/null 2>&1; then chromium="$c"; break; fi done [ -n "$chromium" ] && echo " OK $chromium" || { echo " FAIL chromium"; ok=0; } novnc="" for d in "${NOVNC_DIRS[@]}"; do [ -f "$d/vnc.html" ] && { novnc="$d"; break; } done [ -n "$novnc" ] && echo " OK noVNC ($novnc)" || { echo " FAIL noVNC"; ok=0; } python3 -c 'import websocket' >/dev/null 2>&1 && echo " OK python3 websocket-client" || { echo " FAIL python3 websocket-client"; ok=0; } if [ "$ok" = 1 ]; then echo echo "OK 浏览器栈就绪。重启 llmsproxy 后,flow=vnc 的平台即可用 VNC 兜底登录。" else echo echo "WARN: 仍有缺失项,VNC 兜底在该机器上不可用。插件的 deps/status 端点会一样报告。" >&2 exit 1 fi