#!/bin/bash set -euo pipefail RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' VERSION=${VERSION:-"v0.1.0"} DOWNLOAD_URL="https://git.littlediary.cn/CN-JS-HuiBai/PromdataPanel/archive/${VERSION}.zip" MIN_NODE_VERSION=18 SERVICE_NAME="promdatapanel" SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service" OS_ID="" OS_VER="" PROJECT_DIR="" REAL_USER="" echo -e "${BLUE}================================================${NC}" echo -e "${BLUE} PromdataPanel Auto-Installer ${NC}" echo -e "${BLUE} Version: ${VERSION} ${NC}" echo -e "${BLUE}================================================${NC}" detect_os() { if [ -f /etc/os-release ]; then # shellcheck disable=SC1091 . /etc/os-release OS_ID="${ID:-}" OS_VER="${VERSION_ID:-}" else echo -e "${RED}Error: Cannot detect operating system type (/etc/os-release missing).${NC}" exit 1 fi if [ -z "$OS_ID" ]; then echo -e "${RED}Error: Unable to determine operating system ID.${NC}" exit 1 fi echo -e "Detected OS: ${GREEN}${OS_ID} ${OS_VER}${NC}" } require_cmd() { local cmd="$1" local hint="${2:-}" if ! command -v "$cmd" >/dev/null 2>&1; then echo -e "${RED}Missing required command: ${cmd}.${NC}" if [ -n "$hint" ]; then echo -e "${YELLOW}${hint}${NC}" fi exit 1 fi } install_packages() { case "$OS_ID" in ubuntu|debian|raspbian) sudo apt-get update sudo apt-get install -y "$@" ;; centos|rhel|almalinux|rocky) sudo yum install -y "$@" ;; fedora) sudo dnf install -y "$@" ;; *) echo -e "${RED}Unsupported OS for automatic package installation: ${OS_ID}${NC}" echo -e "${YELLOW}Please install the following packages manually: $*${NC}" exit 1 ;; esac } ensure_tooling() { if ! command -v curl >/dev/null 2>&1; then echo -e "${BLUE}Installing curl...${NC}" install_packages curl fi if ! command -v unzip >/dev/null 2>&1; then echo -e "${BLUE}Installing unzip...${NC}" install_packages unzip fi } configure_nodesource_apt_repo() { sudo install -d -m 0755 /etc/apt/keyrings curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list >/dev/null } install_node() { echo -e "${BLUE}Verifying Node.js environment...${NC}" local node_installed=false if command -v node >/dev/null 2>&1; then local current_node_ver current_node_ver=$(node -v | cut -d'v' -f2 | cut -d'.' -f1) if [ "$current_node_ver" -ge "$MIN_NODE_VERSION" ]; then echo -e "${GREEN}Node.js $(node -v) is already installed.${NC}" node_installed=true else echo -e "${YELLOW}Existing Node.js $(node -v) is too old (requires >= ${MIN_NODE_VERSION}).${NC}" fi fi if [ "$node_installed" = true ]; then return fi echo -e "${BLUE}Installing Node.js 20.x...${NC}" case "$OS_ID" in ubuntu|debian|raspbian) install_packages ca-certificates curl gnupg configure_nodesource_apt_repo sudo apt-get update sudo apt-get install -y nodejs ;; centos|rhel|almalinux|rocky) install_packages nodejs ;; fedora) install_packages nodejs ;; *) echo -e "${RED}Unsupported OS for automatic Node.js installation: ${OS_ID}${NC}" echo -e "${YELLOW}Please install Node.js >= ${MIN_NODE_VERSION} manually.${NC}" exit 1 ;; esac require_cmd node "Please install Node.js >= ${MIN_NODE_VERSION} manually and rerun the installer." local installed_major installed_major=$(node -v | cut -d'v' -f2 | cut -d'.' -f1) if [ "$installed_major" -lt "$MIN_NODE_VERSION" ]; then echo -e "${RED}Installed Node.js $(node -v) is still below the required version.${NC}" echo -e "${YELLOW}Please upgrade Node.js manually to >= ${MIN_NODE_VERSION}.${NC}" exit 1 fi } download_project_if_needed() { if [ -f "server/index.js" ]; then return fi echo -e "${YELLOW}Project files not found. Starting download...${NC}" ensure_tooling local temp_dir temp_dir=$(mktemp -d "${TMPDIR:-/tmp}/promdatapanel-install-XXXXXX") local temp_zip="${temp_dir}/promdatapanel_${VERSION}.zip" echo -e "${BLUE}Downloading ${DOWNLOAD_URL}...${NC}" curl -fL "$DOWNLOAD_URL" -o "$temp_zip" echo -e "${BLUE}Extracting files...${NC}" unzip -q "$temp_zip" -d "$temp_dir" local extracted_dir extracted_dir=$(find "$temp_dir" -mindepth 1 -maxdepth 1 -type d | head -n 1) if [ -z "$extracted_dir" ] || [ ! -f "$extracted_dir/server/index.js" ]; then echo -e "${RED}Download succeeded, but archive structure is invalid.${NC}" exit 1 fi cd "$extracted_dir" } detect_runtime_user() { if [ "$EUID" -eq 0 ]; then REAL_USER="${SUDO_USER:-${USER:-root}}" else REAL_USER="${USER}" fi } write_service_file() { local node_path node_path=$(command -v node) if [ -z "$node_path" ]; then echo -e "${RED}Unable to locate node executable after installation.${NC}" exit 1 fi local tmp_service tmp_service=$(mktemp "${TMPDIR:-/tmp}/${SERVICE_NAME}.service.XXXXXX") cat > "$tmp_service" <