脚本是SH后缀,将代码复制后手动创建一个文件名称随意,然后是sh结尾的例如:autman.sh
#!/bin/bash
# 设置颜色变量
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'
# 检查是否为root用户
check_root() {
echo "检查用户权限..."
if [ "$(id -u)" != "0" ]; then
echo "错误: 该脚本需要以root权限运行"
echo "请使用 sudo bash $0 或者使用root用户执行该脚本"
exit 1
fi
echo "确认以root权限运行"
}
# 添加网络连接测试
test_network() {
echo "测试网络连接..."
# 尝试多个网站以提高成功率
if ping -c 1 -W 3 8.8.8.8 &>/dev/null || ping -c 1 -W 3 www.baidu.com &>/dev/null || ping -c 1 -W 3 www.aliyun.com &>/dev/null; then
echo "网络连接正常"
return 0
fi
# 如果所有ping都失败,尝试使用curl或wget
if command -v curl &>/dev/null; then
if curl -s --connect-timeout 3 http://www.baidu.com >/dev/null || curl -s --connect-timeout 3 http://www.aliyun.com >/dev/null; then
echo "网络连接正常 (curl测试)"
return 0
fi
elif command -v wget &>/dev/null; then
if wget -q --timeout=3 --tries=1 http://www.baidu.com -O /dev/null || wget -q --timeout=3 --tries=1 http://www.aliyun.com -O /dev/null; then
echo "网络连接正常 (wget测试)"
return 0
fi
fi
echo "警告: 无法连接到外部网络,这可能会影响下载"
return 1
}
# 添加系统库依赖检查
check_system_libraries() {
echo "检查系统库依赖..."
local missing_libs=()
# 检查常见的关键库
for lib in libc.so.6 libssl.so libcrypto.so; do
if ! ldconfig -p 2>/dev/null | grep -q "$lib"; then
missing_libs+=("$lib")
echo "未找到: $lib"
else
echo "已找到: $lib"
fi
done
if [ ${#missing_libs[@]} -gt 0 ]; then
echo "警告: 系统缺少以下关键库:"
for lib in "${missing_libs[@]}"; do
echo " - $lib"
done
echo "这可能会影响autman的运行,建议安装相应的开发包"
# 尝试安装缺少的库
echo "尝试安装缺少的库..."
case $OS in
ubuntu|debian)
apt-get update -y
apt-get install -y libssl-dev openssl
;;
*)
if [ "$USE_DNF" = "true" ]; then
dnf install -y openssl-devel
else
yum install -y openssl-devel
fi
;;
esac
else
echo "所有必要的系统库都已找到"
fi
}
# 检测系统类型函数
detect_system() {
# 调用已有的check_system函数
check_system
}
# 下载文件函数,带镜像选择
download_with_mirror() {
local original_url=$1
local download_path=$2
local description=$3
local mirrors=("${GITHUB_MIRRORS[@]}")
local download_url=""
local download_success=false
echo "尝试下载${description}..."
# 优先尝试直链下载
echo "尝试直接下载: $original_url"
if curl -f -L -o "$download_path" "$original_url" --connect-timeout 10 --retry 0; then
download_success=true
download_url="$original_url"
echo "${description}下载成功!"
return 0
else
echo "直连下载失败,尝试使用镜像..."
for mirror in "${mirrors[@]}"; do
local mirror_url=""
# 支持完整URL的代理
if [[ "$mirror" =~ ghproxy\.(com|net|org|de|cc|xyz)$ ]] || [[ "$mirror" =~ ghproxy\.liumingye\.cn$ ]]; then
mirror_url="${mirror%/}/$original_url"
else
# 只支持路径的代理
github_path="${original_url#https://github.com/}"
mirror_url="${mirror%/}/$github_path"
fi
echo "尝试从镜像下载: $mirror_url"
if curl -f -L -o "$download_path" "$mirror_url" --connect-timeout 10 --retry 1; then
download_success=true
download_url="$mirror_url"
echo "${description}通过镜像${mirror}下载成功!"
return 0
fi
done
echo "所有下载方式均失败!"
return 1
fi
}
# 测试镜像响应速度并选择最快的镜像
select_fastest_mirror() {
local mirrors=("$@")
local fastest=""
local fastest_time=999
echo "测试镜像速度..."
for mirror in "${mirrors[@]}"; do
# 使用curl的静默模式测试响应时间
curl -s --connect-timeout 3 -o /dev/null -w "%{time_total}" "$mirror" > /tmp/mirror_speed 2>/dev/null
if [ $? -eq 0 ]; then
local time_total=$(cat /tmp/mirror_speed)
# 转换为毫秒以便于比较
local time_ms=$(echo "$time_total * 1000" | bc 2>/dev/null || echo "999")
echo "镜像 $mirror 响应时间: ${time_ms}ms"
# 更新最快镜像
if (( $(echo "$time_ms < $fastest_time" | bc -l) )); then
fastest_time=$time_ms
fastest=$mirror
fi
else
echo "镜像 $mirror 无响应"
fi
done
# 如果所有镜像都无响应,返回第一个
if [ -z "$fastest" ]; then
fastest="${mirrors[0]}"
echo "所有镜像测试失败,使用默认镜像: $fastest"
else
echo "选择最快的镜像: $fastest (${fastest_time}ms)"
fi
# 确保mirror字符串有效
fastest=$(echo "$fastest" | tr -d ' \n\r\t')
# 如果还是空,使用第一个镜像
if [ -z "$fastest" ]; then
fastest="${mirrors[0]}"
echo "镜像选择失败,使用第一个镜像: $fastest"
fi
echo "$fastest"
}
# GitHub镜像代理
GITHUB_MIRRORS=(
"https://gh.llkk.cc"
"https://gitproxy.click"
"https://github.moeyy.xyz"
"https://github.tbedu.top"
"https://github.proxy.class3.fun"
"https://github-proxy.lixxing.top"
"https://ghm.078465.xyz"
"https://gh-proxy.net"
)
# Docker镜像代理
DOCKER_MIRRORS=(
"docker.1ms.run"
"docker.registry.cyou"
"docker-cf.registry.cyou"
"docker.tbedu.top"
"dockerproxy.cn"
"docker.1panel.live"
"hub.rat.dev"
"docker.anyhub.us.kg"
"docker.chenby.cn"
"dockerhub.icu"
"docker.awsl9527.cn"
"dhub.kubesre.xyz"
"docker.hlyun.org"
"docker.m.daocloud.io"
)
# 获取当前IP地址
get_current_ip() {
# 尝试多种方法获取公网IP
local ip=""
# 优先尝试本地网卡获取IP(可能是内网IP)
ip=$(hostname -I | awk '{print $1}')
# 如果为空或以127开头,尝试获取公网IP
if [[ -z "$ip" || "$ip" == 127.* ]]; then
# 尝试通过公共API获取IP
ip=$(curl -s ifconfig.me || curl -s ipinfo.io/ip || curl -s icanhazip.com || curl -s ip.sb)
fi
# 如果所有方法都失败,使用localhost
if [ -z "$ip" ]; then
ip="127.0.0.1"
echo "警告: 无法获取服务器IP地址,将使用localhost" >&2
fi
echo "$ip"
}
# 显示欢迎信息
show_welcome() {
clear
echo "=================================================================="
echo -e "${RED} 感谢您使用AUTMAN一键脚本 ${NC}"
echo "=================================================================="
echo
echo -e "${RED}▶ 如果脚本有bug请加入QQ群:${NC}${GREEN}475866384${NC}"
echo -e "${RED}▶ autman官方QQ群:${NC}${GREEN}735467280${NC}"
echo -e "${RED}▶ 如果懒得手动或者不会可以联系:${NC}${BLUE}偷豆豆的大舅哥${NC}"
echo -e "${RED}▶ QQ:${NC}${GREEN}2182043734${NC}"
echo -e "${RED}▶ 本地服务器用户作者不推荐您关闭防火墙,为了您的安全放行对应端口即可${NC}"
echo -e "${RED}▶ 云服务器用户在安装完成后请手动去服务器提供商放行对应的端口${NC}"
echo "=================================================================="
}
# 检测系统架构和版本
check_system() {
echo "正在检测系统信息..."
# 检测系统架构
ARCH=$(uname -m)
case $ARCH in
x86_64)
ARCH_TYPE="amd64"
;;
aarch64)
ARCH_TYPE="arm64"
;;
armv7l|armv8l)
ARCH_TYPE="arm"
echo "警告: ARM 32位架构可能不完全支持"
;;
i386|i686)
ARCH_TYPE="386"
echo "警告: 32位系统可能不完全支持"
;;
*)
echo "不支持的系统架构: $ARCH"
read -p "是否继续安装? [y/N]: " continue_install
if [[ "$continue_install" != "y" && "$continue_install" != "Y" ]]; then
exit 1
fi
;;
esac
# 检测操作系统类型和版本
if [ -f /etc/os-release ]; then
source /etc/os-release
OS=$ID
VERSION_ID=$VERSION_ID
case $OS in
ubuntu)
OS_TYPE="Ubuntu"
;;
centos)
OS_TYPE="CentOS"
# 检查CentOS 8及以上版本
if [ -n "$VERSION_ID" ] && [ "$(echo "$VERSION_ID" | cut -d. -f1)" -ge "8" ]; then
USE_DNF=true
echo "检测到CentOS 8或更高版本,将使用dnf包管理器"
else
USE_DNF=false
fi
;;
debian)
OS_TYPE="Debian"
;;
fedora)
OS_TYPE="Fedora"
USE_DNF=true
;;
rhel)
OS_TYPE="RHEL"
if [ -n "$VERSION_ID" ] && [ "$(echo "$VERSION_ID" | cut -d. -f1)" -ge "8" ]; then
USE_DNF=true
else
USE_DNF=false
fi
;;
amzn)
OS_TYPE="Amazon Linux"
if [ "$VERSION_ID" == "2" ] || [ "$VERSION_ID" == "2023" ]; then
USE_DNF=false
else
USE_DNF=true
fi
;;
*)
# 检查常见的基于Debian/Ubuntu的衍生发行版
if grep -q "debian" /etc/os-release || grep -q "ubuntu" /etc/os-release; then
OS_TYPE="Debian/Ubuntu 衍生版"
OS="debian"
# 检查常见的基于RHEL的衍生发行版
elif grep -q "rhel" /etc/os-release || grep -q "centos" /etc/os-release || grep -q "fedora" /etc/os-release; then
OS_TYPE="RHEL 衍生版"
OS="centos"
# 检查是否支持dnf
if command -v dnf &>/dev/null; then
USE_DNF=true
else
USE_DNF=false
fi
else
echo "无法确定操作系统类型,将尝试自动检测包管理器"
OS_TYPE="未知"
OS="unknown"
# 自动检测包管理器
if command -v apt-get &>/dev/null; then
OS="debian"
elif command -v dnf &>/dev/null; then
OS="centos"
USE_DNF=true
elif command -v yum &>/dev/null; then
OS="centos"
USE_DNF=false
else
echo "不支持的操作系统,无法确定包管理器"
read -p "是否继续安装? [y/N]: " continue_install
if [[ "$continue_install" != "y" && "$continue_install" != "Y" ]]; then
exit 1
fi
fi
fi
;;
esac
else
echo "无法确定操作系统类型"
read -p "是否继续安装? [y/N]: " continue_install
if [[ "$continue_install" != "y" && "$continue_install" != "Y" ]]; then
exit 1
fi
# 自动检测包管理器
if command -v apt-get &>/dev/null; then
OS="debian"
OS_TYPE="Debian 系"
elif command -v dnf &>/dev/null; then
OS="centos"
OS_TYPE="RHEL 系"
USE_DNF=true
elif command -v yum &>/dev/null; then
OS="centos"
OS_TYPE="RHEL 系"
USE_DNF=false
else
echo "不支持的操作系统,无法确定包管理器"
exit 1
fi
fi
# 检查systemd
if command -v systemctl &>/dev/null; then
USING_SYSTEMD=true
else
USING_SYSTEMD=false
echo "警告: 系统不使用 systemd,将使用传统的服务管理方式"
fi
echo "=================================================================="
echo "系统信息检测完成:"
echo "操作系统: $OS_TYPE $VERSION_ID"
echo "系统架构: $ARCH ($ARCH_TYPE)"
# 修正包管理器输出逻辑
if command -v apt-get &>/dev/null; then
echo "包管理器: apt"
elif command -v dnf &>/dev/null; then
echo "包管理器: dnf"
elif command -v yum &>/dev/null; then
echo "包管理器: yum"
else
echo "包管理器: 未知"
fi
echo "服务管理: $([ "$USING_SYSTEMD" = "true" ] && echo "systemd" || echo "传统方式")"
echo "=================================================================="
}
# 添加选择镜像源的函数
select_mirror_source() {
echo "=================================================================="
echo "请选择要使用的镜像源类型:"
echo "1. 阿里云镜像 (推荐,国内访问速度快)"
echo "2. 清华大学镜像 (备选)"
echo "3. 中科大镜像 (备选)"
echo "4. 原始官方源 (国外源,速度可能较慢)"
echo "=================================================================="
read -p "请选择 [1/2/3/4] (默认: 1): " mirror_choice
mirror_choice=${mirror_choice:-1}
case $mirror_choice in
2)
echo "已选择清华大学镜像源"
MIRROR_SOURCE="tsinghua"
;;
3)
echo "已选择中科大镜像源"
MIRROR_SOURCE="ustc"
;;
4)
echo "已选择原始官方源"
MIRROR_SOURCE="official"
;;
*)
echo "已选择阿里云镜像源"
MIRROR_SOURCE="aliyun"
;;
esac
export MIRROR_SOURCE
}
# 修改配置镜像源函数
configure_mirrors() {
echo "正在配置镜像源..."
# 如果未选择镜像源,默认使用阿里云
if [ -z "$MIRROR_SOURCE" ]; then
MIRROR_SOURCE="aliyun"
fi
case $OS in
ubuntu|debian)
# 备份原始源
cp /etc/apt/sources.list /etc/apt/sources.list.bak
# 根据不同的镜像源选择配置不同的源
case $MIRROR_SOURCE in
aliyun)
# 配置阿里云镜像源
if [ "$OS" = "ubuntu" ]; then
sed -i 's/http:\/\/\(archive\|security\|ports\).ubuntu.com/https:\/\/mirrors.aliyun.com/g' /etc/apt/sources.list
else
sed -i 's/http:\/\/\(deb\|security\).debian.org/https:\/\/mirrors.aliyun.com/g' /etc/apt/sources.list
fi
echo "已配置阿里云镜像源"
;;
tsinghua)
# 配置清华镜像源
if [ "$OS" = "ubuntu" ]; then
sed -i 's/http:\/\/\(archive\|security\|ports\).ubuntu.com/https:\/\/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list
else
sed -i 's/http:\/\/\(deb\|security\).debian.org/https:\/\/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list
fi
echo "已配置清华大学镜像源"
;;
ustc)
# 配置中科大镜像源
if [ "$OS" = "ubuntu" ]; then
sed -i 's/http:\/\/\(archive\|security\|ports\).ubuntu.com/https:\/\/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
else
sed -i 's/http:\/\/\(deb\|security\).debian.org/https:\/\/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
fi
echo "已配置中科大镜像源"
;;
official)
echo "使用官方源,无需修改"
;;
esac
# 更新软件包列表
apt update
;;
*)
# CentOS/RHEL等
if [ "$MIRROR_SOURCE" != "official" ]; then
# 备份原始源
mkdir -p /etc/yum.repos.d/backup
cp /etc/yum.repos.d/CentOS-*.repo /etc/yum.repos.d/backup/ 2>/dev/null || echo "未找到CentOS仓库文件,可能使用其他发行版"
case $MIRROR_SOURCE in
aliyun)
# 下载阿里云镜像源
if [ "$USE_DNF" = "true" ]; then
# CentOS 8及以上,使用dnf
if [ -f /etc/yum.repos.d/CentOS-Base.repo ]; then
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-8.repo
fi
else
# CentOS 7
if [ -f /etc/yum.repos.d/CentOS-Base.repo ]; then
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
fi
fi
echo "已配置阿里云镜像源"
;;
tsinghua)
# 下载清华镜像源
if [ "$USE_DNF" = "true" ]; then
# CentOS 8及以上,使用dnf
if [ -f /etc/yum.repos.d/CentOS-Base.repo ]; then
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.tuna.tsinghua.edu.cn/repo/Centos-8.repo
fi
else
# CentOS 7
if [ -f /etc/yum.repos.d/CentOS-Base.repo ]; then
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.tuna.tsinghua.edu.cn/repo/Centos-7.repo
fi
fi
echo "已配置清华大学镜像源"
;;
ustc)
# 下载中科大镜像源
if [ "$USE_DNF" = "true" ]; then
# CentOS 8及以上,使用dnf
if [ -f /etc/yum.repos.d/CentOS-Base.repo ]; then
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.ustc.edu.cn/repo/Centos-8.repo
fi
else
# CentOS 7
if [ -f /etc/yum.repos.d/CentOS-Base.repo ]; then
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.ustc.edu.cn/repo/Centos-7.repo
fi
fi
echo "已配置中科大镜像源"
;;
official)
echo "使用官方源,无需修改"
;;
esac
# 配置EPEL源
if [ "$MIRROR_SOURCE" != "official" ] && command -v yum &>/dev/null; then
if ! rpm -q epel-release &>/dev/null; then
echo "安装EPEL仓库..."
if [ "$USE_DNF" = "true" ]; then
dnf -y install epel-release
else
yum -y install epel-release
fi
fi
# 配置EPEL镜像
if [ -f /etc/yum.repos.d/epel.repo ]; then
case $MIRROR_SOURCE in
aliyun)
sed -i 's/^#baseurl=http:\/\/download.fedoraproject.org\/pub\/epel/baseurl=https:\/\/mirrors.aliyun.com\/epel/g' /etc/yum.repos.d/epel.repo
sed -i 's/^metalink/#metalink/g' /etc/yum.repos.d/epel.repo
;;
tsinghua)
sed -i 's/^#baseurl=http:\/\/download.fedoraproject.org\/pub\/epel/baseurl=https:\/\/mirrors.tuna.tsinghua.edu.cn\/epel/g' /etc/yum.repos.d/epel.repo
sed -i 's/^metalink/#metalink/g' /etc/yum.repos.d/epel.repo
;;
ustc)
sed -i 's/^#baseurl=http:\/\/download.fedoraproject.org\/pub\/epel/baseurl=https:\/\/mirrors.ustc.edu.cn\/epel/g' /etc/yum.repos.d/epel.repo
sed -i 's/^metalink/#metalink/g' /etc/yum.repos.d/epel.repo
;;
esac
fi
fi
fi
# 清理并重建缓存
if [ "$USE_DNF" = "true" ]; then
dnf clean all
dnf makecache
else
yum clean all
yum makecache
fi
;;
esac
echo "镜像源配置完成"
}
# 检测已安装的软件和环境
check_installed_dependencies() {
echo "检测系统已安装的软件和环境..."
local missing_packages=()
# 检测基础软件包
for pkg in git curl wget vim gcc make jq python3 pip3; do
if ! command -v $pkg &> /dev/null; then
missing_packages+=("$pkg")
echo "未安装: $pkg"
else
echo "已安装: $pkg ($(command -v $pkg))"
fi
done
# 检测Node.js版本
if command -v node &> /dev/null; then
NODE_VERSION=$(node -v)
echo "已安装: Node.js $NODE_VERSION"
# 检查是否为所需版本 16.13.1
if [[ "$NODE_VERSION" != "v16.13.1" ]]; then
echo "Node.js版本不匹配 (需要: v16.13.1, 当前: $NODE_VERSION)"
NODEJS_NEEDS_INSTALL=true
else
NODEJS_NEEDS_INSTALL=false
fi
else
echo "未安装: Node.js"
NODEJS_NEEDS_INSTALL=true
fi
# 检测Go版本
if command -v go &> /dev/null; then
GO_VERSION=$(go version | cut -d' ' -f3 | sed 's/go//')
echo "已安装: Go $GO_VERSION"
# 检查是否为所需版本 1.22.0
if [[ "$GO_VERSION" != "1.22.0" ]]; then
echo "Go版本不匹配 (需要: 1.22.0, 当前: $GO_VERSION)"
GO_NEEDS_INSTALL=true
else
GO_NEEDS_INSTALL=false
fi
else
echo "未安装: Go"
GO_NEEDS_INSTALL=true
fi
# 检测Docker
if command -v docker &> /dev/null; then
DOCKER_VERSION=$(docker --version | cut -d' ' -f3 | sed 's/,//')
echo "已安装: Docker $DOCKER_VERSION"
DOCKER_NEEDS_INSTALL=false
else
echo "未安装: Docker"
DOCKER_NEEDS_INSTALL=true
fi
# 根据OS类型确定缺少的包名
case $OS in
ubuntu|debian)
MISSING_BASE_PACKAGES=()
for pkg in "${missing_packages[@]}"; do
case $pkg in
git|curl|wget|vim|jq)
MISSING_BASE_PACKAGES+=("$pkg")
;;
gcc)
MISSING_BASE_PACKAGES+=("gcc" "g++")
;;
make)
MISSING_BASE_PACKAGES+=("make")
;;
python3)
MISSING_BASE_PACKAGES+=("python3")
;;
pip3)
MISSING_BASE_PACKAGES+=("python3-pip")
;;
esac
done
;;
centos)
MISSING_BASE_PACKAGES=()
for pkg in "${missing_packages[@]}"; do
case $pkg in
git|curl|wget|vim|jq|make)
MISSING_BASE_PACKAGES+=("$pkg")
;;
gcc)
MISSING_BASE_PACKAGES+=("gcc" "gcc-c++")
;;
python3)
MISSING_BASE_PACKAGES+=("python3")
;;
pip3)
MISSING_BASE_PACKAGES+=("python3-pip")
;;
esac
done
if [ ${#MISSING_BASE_PACKAGES[@]} -gt 0 ]; then
MISSING_BASE_PACKAGES+=("epel-release")
fi
;;
esac
echo "检测完成!"
echo "=================================================================="
}
# 重新添加被删除的ask_install_path函数
ask_install_path() {
local default_path="$HOME/autman"
# 如果是root,使用/root/autman,否则使用$HOME/autman
if [ "$(id -u)" -eq 0 ]; then
default_path="/root/autman"
fi
read -p "是否安装到默认路径 ($default_path)?[Y/n]: " custom_path
if [[ "$custom_path" == "n" || "$custom_path" == "N" ]]; then
read -p "请输入安装路径: " install_path
install_path=${install_path:-$default_path}
else
install_path=$default_path
fi
# 确保目录存在
mkdir -p "$install_path"
# 设置全局变量
INSTALL_PATH="$install_path"
# 添加权限检查
if ! touch "$install_path/.write_test" 2>/dev/null; then
echo "警告: 无法写入目录 $install_path,请选择其他目录或使用具有写入权限的用户"
return 1
fi
rm -f "$install_path/.write_test"
return 0
}
# 修改install_base_packages函数以确保安装pip
install_base_packages() {
echo "=================================================================="
echo "安装基础软件包..."
# 根据包管理器安装基础软件包
if [ -x "$(command -v apt-get)" ]; then
echo "使用apt安装基础软件包..."
apt-get update -y || { echo "更新软件源失败"; return 1; }
apt-get install -y \
curl wget git vim gcc g++ jq \
python3 python3-pip \
python3-dev \
libssl-dev \
libffi-dev \
python3-setuptools \
python3-wheel \
python3-cryptography \
python3-cffi || { echo "安装基础软件包失败"; return 1; }
# 创建pip的软链接
if [ ! -e /usr/bin/pip ]; then
ln -s /usr/bin/pip3 /usr/bin/pip
fi
# 升级pip并用pip安装pyOpenSSL
python3 -m pip install --upgrade pip
python3 -m pip install pyOpenSSL
elif [ "$USE_DNF" = "true" ]; then
# CentOS 8+/Fedora等使用dnf的系统
echo "使用dnf安装基础软件包..."
dnf update -y || { echo "更新软件源失败"; return 1; }
dnf install -y epel-release || echo "安装EPEL仓库失败,尝试继续安装其他包"
dnf install -y \
curl wget git vim gcc gcc-c++ make jq \
python3 python3-pip \
python3-devel \
openssl-devel \
libffi-devel \
python3-setuptools \
python3-wheel \
python3-cryptography \
python3-cffi || { echo "安装基础软件包失败"; return 1; }
# 创建pip的软链接
if [ ! -e /usr/bin/pip ]; then
ln -s /usr/bin/pip3 /usr/bin/pip
fi
elif [ -x "$(command -v yum)" ]; then
# CentOS 7等使用yum的系统
echo "使用yum安装基础软件包..."
yum update -y || { echo "更新软件源失败"; return 1; }
yum install -y epel-release || echo "安装EPEL仓库失败,尝试继续安装其他包"
yum install -y \
curl wget git vim gcc gcc-c++ make jq \
python3 python3-pip \
python3-devel \
openssl-devel \
libffi-devel \
python3-setuptools \
python3-wheel \
python3-cffi || { echo "安装基础软件包失败"; return 1; }
# 尝试安装其他可能可用的包
yum install -y python3-cryptography || echo "安装python3-cryptography失败,将使用pip安装"
yum install -y python3-pyOpenSSL || echo "安装python3-pyOpenSSL失败,将使用pip安装"
# 重新安装 Python 的 SSL 支持
yum reinstall -y python3-libs || echo "重新安装python3-libs失败"
# 创建pip的软链接
if [ ! -e /usr/bin/pip ]; then
ln -s /usr/bin/pip3 /usr/bin/pip
fi
# 修复 SSL 问题
if ! python3 -c "import ssl" 2>/dev/null; then
echo "尝试修复 Python SSL 问题..."
# 使用 easy_install 安装 pip(不依赖 SSL)
yum install -y python3-setuptools || echo "安装python3-setuptools失败"
if command -v easy_install-3 >/dev/null 2>&1; then
easy_install-3 pip
else
python3 -m easy_install pip
fi
# 安装 pyOpenSSL
pip3 install --index-url=http://mirrors.aliyun.com/pypi/simple/ --trusted-host=mirrors.aliyun.com pyOpenSSL
fi
else
echo "不支持的系统,无法安装基础软件包"
echo "请手动安装以下软件包: curl wget git vim gcc make python3 python3-pip"
read -p "是否继续安装? [y/N]: " continue_install
if [[ "$continue_install" != "y" && "$continue_install" != "Y" ]]; then
return 1
fi
fi
# 升级 pip 到最新版本,独立于系统类型
echo "升级pip到最新版本..."
python3 -m pip install --index-url=http://mirrors.aliyun.com/pypi/simple/ --trusted-host=mirrors.aliyun.com pip --upgrade || echo "升级pip失败,使用现有版本"
# 安装常见的Python依赖包
echo "安装Python通用依赖..."
python3 -m pip install --index-url=http://mirrors.aliyun.com/pypi/simple/ --trusted-host=mirrors.aliyun.com requests urllib3 pyOpenSSL || echo "安装基础Python依赖失败"
echo "基础软件包安装完成"
echo "=================================================================="
}
# 完全修复Node.js安装问题
install_nodejs() {
echo "=================================================================="
echo "开始安装Node.js v16.13.1..."
# 检测是否已安装 Node.js,如果已安装则跳过
if [ "$NODEJS_NEEDS_INSTALL" = false ]; then
echo "检测到已安装 Node.js,跳过安装"
echo "Node.js 安装路径: $(dirname $(command -v node))" # 显示安装路径
echo "=================================================================="
return 0
fi
# 根据架构选择正确的Node.js版本
local arch_name="x64"
if [ "$ARCH_TYPE" = "arm64" ]; then
arch_name="arm64"
fi
NODE_VERSION_FULL="node-v16.13.1-linux-${arch_name}"
NODE_VERSION="v16.13.1"
cd /tmp
# 下载 Node.js
echo "下载 Node.js v$NODE_VERSION (架构: $arch_name)..."
if ! download_with_mirror "https://nodejs.org/dist/$NODE_VERSION/$NODE_VERSION_FULL.tar.gz" "/tmp/$NODE_VERSION_FULL.tar.gz" "Node.js压缩包"; then
echo "Node.js 下载失败"
echo "下载的压缩包文件位于: /tmp/$NODE_VERSION_FULL.tar.gz" # 显示下载路径 (即使失败也显示)
return 1
fi
# 解压 Node.js
echo "解压 Node.js..."
tar -xzf "$NODE_VERSION_FULL.tar.gz"
# 检查解压是否成功
if [ ! -d "$NODE_VERSION_FULL" ]; then
echo "Node.js解压失败,请检查压缩包是否完整"
return 1
fi
# 移动到 /usr/local
echo "移动 Node.js 到 /usr/local..."
if [ -d "/usr/local/$NODE_VERSION_FULL" ]; then
# 添加安全检查
if [ -n "$NODE_VERSION_FULL" ] && [ "$NODE_VERSION_FULL" != "/" ]; then
rm -rf "/usr/local/$NODE_VERSION_FULL"
fi
fi
mv "$NODE_VERSION_FULL" /usr/local/
echo "Node.js 安装路径: /usr/local/$NODE_VERSION_FULL" # 显示安装路径
# 配置环境变量
echo "配置 Node.js 环境变量..."
NODE_HOME="/usr/local/$NODE_VERSION_FULL"
# 检查用户主目录,使用正确的profile文件
local profile_file="$HOME/.profile"
if [ "$HOME" = "/root" ]; then
profile_file="/root/.profile"
# 如果文件不存在,尝试使用.bash_profile
if [ ! -f "$profile_file" ]; then
profile_file="/root/.bash_profile"
fi
fi
# 检查 profile 文件是否存在,如果不存在则创建
if [ ! -f "$profile_file" ]; then
touch "$profile_file"
fi
# 使用 grep 检查是否已存在 NODE_HOME 环境变量设置
if ! grep -q "export NODE_HOME=" "$profile_file"; then
echo "export NODE_HOME=$NODE_HOME" >> "$profile_file"
fi
# 使用 grep 检查是否已存在 NODE_PATH 环境变量设置
if ! grep -q "export NODE_PATH=" "$profile_file"; then
echo "export NODE_PATH=$NODE_HOME/lib/node_modules" >> "$profile_file"
fi
# 使用 grep 检查是否已存在 NODE 可执行文件路径添加到 PATH
if ! grep -q "export PATH=.*\$NODE_HOME/bin" "$profile_file"; then
echo "export PATH=\$PATH:\$NODE_HOME/bin" >> "$profile_file"
fi
# 创建符号链接到/usr/bin目录,确保系统可以找到node和npm命令
echo "创建Node.js命令符号链接到/usr/bin..."
ln -sf "$NODE_HOME/bin/node" /usr/bin/node
ln -sf "$NODE_HOME/bin/npm" /usr/bin/npm
ln -sf "$NODE_HOME/bin/npx" /usr/bin/npx
# 使环境变量在当前会话中生效
export NODE_HOME="$NODE_HOME"
export PATH="$PATH:$NODE_HOME/bin"
export NODE_PATH="$NODE_HOME/lib/node_modules"
# 检查 Node.js 和 npm 是否安装成功
if node -v && npm -v; then
echo -e "${GREEN}Node.js v$NODE_VERSION 安装成功!${NC}"
else
echo -e "${RED}Node.js v$NODE_VERSION 安装失败,请检查错误信息${NC}"
return 1
fi
# 删除压缩包文件
echo "删除 Node.js 压缩包文件..."
# 检查文件存在性和安全性,确保不会误删文件
if [ -f "/tmp/$NODE_VERSION_FULL.tar.gz" ]; then
rm -f "/tmp/$NODE_VERSION_FULL.tar.gz"
echo "已删除压缩包文件: /tmp/$NODE_VERSION_FULL.tar.gz" # 提示已删除
fi
echo "=================================================================="
return 0
}
# 设置Node.js环境变量并验证 - 增加Ubuntu/Debian兼容性
setup_nodejs_environment() {
echo "配置Node.js环境变量..."
# 注意:使用与install_nodejs中相同的架构名称
local arch_name="x64"
if [ "$ARCH_TYPE" = "arm64" ]; then
arch_name="arm64"
fi
# 根据系统类型选择不同的环境变量配置方式
case $OS in
ubuntu|debian)
# Ubuntu/Debian方式
# 检查是否已配置
if ! grep -q "NODE_HOME=/usr/local/node-v16.13.1-linux-${arch_name}" /etc/environment; then
# 修改/etc/environment文件 - 修复变量引用问题
echo "NODE_HOME=/usr/local/node-v16.13.1-linux-${arch_name}" >> /etc/environment
# 获取当前PATH并附加NODE_HOME/bin,不使用变量引用
local current_path=$(grep "^PATH=" /etc/environment | cut -d= -f2- || echo "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
echo "PATH=${current_path}:/usr/local/node-v16.13.1-linux-${arch_name}/bin" >> /etc/environment
echo "NODE_PATH=/usr/local/node-v16.13.1-linux-${arch_name}/lib/node_modules" >> /etc/environment
fi
# 创建profile.d脚本
cat > /etc/profile.d/nodejs.sh << EOF
export NODE_HOME=/usr/local/node-v16.13.1-linux-${arch_name}
export PATH=\$PATH:\$NODE_HOME/bin
export NODE_PATH=\$NODE_HOME/lib/node_modules
EOF
chmod +x /etc/profile.d/nodejs.sh
;;
centos|rhel)
# CentOS/RHEL方式
if ! grep -q "NODE_HOME=/usr/local/node-v16.13.1-linux-${arch_name}" /etc/profile; then
echo "" >> /etc/profile
echo "# Node.js环境变量" >> /etc/profile
echo "export NODE_HOME=/usr/local/node-v16.13.1-linux-${arch_name}" >> /etc/profile
echo "export PATH=\$PATH:\$NODE_HOME/bin" >> /etc/profile
echo "export NODE_PATH=\$NODE_HOME/lib/node_modules" >> /etc/profile
fi
;;
esac
# 设置当前会话的环境变量(通用方式)
export NODE_HOME=/usr/local/node-v16.13.1-linux-${arch_name}
export PATH=$PATH:$NODE_HOME/bin
export NODE_PATH=$NODE_HOME/lib/node_modules
# 刷新环境变量 - 兼容不同系统
echo "刷新系统环境变量..."
case $OS in
ubuntu|debian)
if [ -f /etc/profile.d/nodejs.sh ]; then
source /etc/profile.d/nodejs.sh
fi
;;
centos|rhel)
source /etc/profile
;;
esac
# 验证Node.js环境变量是否正确设置
echo "验证Node.js环境变量..."
# 尝试多次确认node命令可用
local max_attempts=3
local attempt=1
while [ $attempt -le $max_attempts ]; do
if command -v node &>/dev/null; then
echo "Node.js命令可用,环境变量已生效"
break
else
echo "尝试 $attempt/$max_attempts: Node.js命令尚未可用,等待环境变量生效..."
# 再次导出环境变量并刷新
export PATH=$PATH:$NODE_HOME/bin
sleep 2
fi
attempt=$((attempt+1))
done
# 详细输出环境信息
echo "Node.js版本: $(node -v 2>/dev/null || echo '未找到Node.js命令')"
echo "NPM版本: $(npm -v 2>/dev/null || echo '未找到NPM命令')"
# 返回结果
if command -v node &>/dev/null; then
echo "Node.js环境变量配置成功"
return 0
else
echo "警告: Node.js环境变量可能未正确配置,可能影响后续步骤"
echo "建议: 安装完成后,请手动运行 'source /etc/profile' 并重新开始安装"
sleep 3
return 1
fi
}
# 设置Go环境变量并验证 - 增加Ubuntu/Debian兼容性
setup_go_environment() {
echo "配置Go环境变量..."
# 创建GOPATH目录
mkdir -p /usr/local/go/path
# 根据系统类型选择不同的环境变量配置方式
case $OS in
ubuntu|debian)
# Ubuntu/Debian方式
# 检查是否已配置
if ! grep -q "GOROOT=/usr/local/go" /etc/environment; then
# 修改/etc/environment文件 - 修复变量引用问题
echo "GO111MODULE=on" >> /etc/environment
echo "GOPROXY=https://goproxy.cn" >> /etc/environment
echo "GOROOT=/usr/local/go" >> /etc/environment
echo "GOPATH=/usr/local/go/path" >> /etc/environment
# 获取当前PATH并附加Go路径,不使用变量引用
local current_path=$(grep "^PATH=" /etc/environment | cut -d= -f2- || echo "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
echo "PATH=${current_path}:/usr/local/go/bin:/usr/local/go/path/bin" >> /etc/environment
fi
# 创建profile.d脚本
cat > /etc/profile.d/golang.sh << EOF
export GO111MODULE=on
export GOPROXY=https://goproxy.cn
export GOROOT=/usr/local/go
export GOPATH=/usr/local/go/path
export PATH=\$PATH:\$GOROOT/bin:\$GOPATH/bin
EOF
chmod +x /etc/profile.d/golang.sh
;;
centos|rhel)
# CentOS/RHEL方式 - 保持原有实现
if ! grep -q "GOROOT=/usr/local/go" /etc/profile; then
echo "" >> /etc/profile
echo "# Go环境变量" >> /etc/profile
echo "export GO111MODULE=on" >> /etc/profile
echo "export GOPROXY=https://goproxy.cn" >> /etc/profile
echo "export GOROOT=/usr/local/go" >> /etc/profile
echo "export GOPATH=/usr/local/go/path" >> /etc/profile
echo "export PATH=\$PATH:\$GOROOT/bin:\$GOPATH/bin" >> /etc/profile
fi
;;
esac
# 设置当前会话的环境变量(通用方式)
export GO111MODULE=on
export GOPROXY=https://goproxy.cn
export GOROOT=/usr/local/go
export GOPATH=/usr/local/go/path
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
# 刷新环境变量 - 兼容不同系统
echo "刷新系统环境变量..."
case $OS in
ubuntu|debian)
if [ -f /etc/profile.d/golang.sh ]; then
source /etc/profile.d/golang.sh
fi
;;
centos|rhel)
source /etc/profile
;;
esac
# 加入多次环境检查,确保变量已经生效
echo "验证Go环境变量是否正确设置..."
# 尝试多次确认Go命令可用
local max_attempts=3
local attempt=1
while [ $attempt -le $max_attempts ]; do
if command -v go &>/dev/null; then
echo "Go命令可用,环境变量已生效"
break
else
echo "尝试 $attempt/$max_attempts: Go命令尚未可用,等待环境变量生效..."
# 再次导出环境变量并刷新
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
sleep 2
fi
attempt=$((attempt+1))
done
# 详细输出环境信息
echo "Go版本: $(go version 2>/dev/null || echo '未找到Go命令')"
echo "Go环境: $(go env GOROOT 2>/dev/null || echo 'GOROOT未设置')"
echo "Go路径: $(go env GOPATH 2>/dev/null || echo 'GOPATH未设置')"
# 返回结果
if command -v go &>/dev/null; then
echo "Go环境变量配置成功"
return 0
else
echo "警告: Go环境变量可能未正确配置,可能影响后续步骤"
echo "建议: 安装完成后,请手动运行 'source /etc/profile' 并重新开始安装"
sleep 3 # 给用户时间阅读警告
return 1
fi
}
# 安装Go
install_golang() {
echo "=================================================================="
echo "开始安装Go 1.22.0..."
# 下载Go
GO_URL="https://dl.google.com/go/go1.22.0.linux-${ARCH_TYPE}.tar.gz"
GO_TARBALL="/tmp/go1.22.0.linux-${ARCH_TYPE}.tar.gz"
echo "下载Go安装包..."
curl -L -o "$GO_TARBALL" "$GO_URL"
if [ $? -ne 0 ]; then
echo "Go下载失败,尝试使用镜像..."
for mirror in "${GITHUB_MIRRORS[@]}"; do
echo "尝试从 $mirror 下载Go..."
if curl -L -o "$GO_TARBALL" "$mirror/https://dl.google.com/go/go1.22.0.linux-${ARCH_TYPE}.tar.gz"; then
echo "Go下载成功"
break
fi
done
fi
# 安装Go
echo "安装Go..."
rm -rf /usr/local/go
tar -C /usr/local -xzf "$GO_TARBALL"
# 设置环境变量
setup_go_environment
# 验证安装
if go version | grep -q "go1.22.0"; then
echo "Go 1.22.0 安装成功!"
return 0
else
echo "Go 安装失败,请手动安装"
return 1
fi
}
# 恢复 download_autman 函数,包含下载方式选择菜单
download_autman() {
local install_path=$1
echo "=================================================================="
echo "开始下载autman..."
# 确保安装目录存在
mkdir -p "$install_path"
# 自动获取最新版tag
local DEFAULT_VERSION="3.5.1"
local LATEST_VERSION=""
LATEST_VERSION=$(curl -s https://api.github.com/repos/hdbjlizhe/fanli/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
if [ -z "$LATEST_VERSION" ]; then
LATEST_VERSION="$DEFAULT_VERSION"
echo "未能获取最新版本号,使用默认版本: $DEFAULT_VERSION"
else
echo "检测到最新版本: $LATEST_VERSION"
fi
local VERSION="$LATEST_VERSION"
# 询问用户是否使用最新版
read -p "是否使用最新版 ($LATEST_VERSION)?[Y/n]: " use_latest_version
if [[ "$use_latest_version" == "n" || "$use_latest_version" == "N" ]]; then
read -p "请输入要安装的版本号: " custom_version
if [ -n "$custom_version" ]; then
VERSION="$custom_version"
fi
fi
echo "将安装 autman 版本: $VERSION"
# 设置文件名和下载路径
local FILENAME="autMan_${ARCH_TYPE}.tar.gz"
local DOWNLOAD_PATH="${install_path}/${FILENAME}"
echo "安装目录: $install_path"
echo "下载文件: $DOWNLOAD_PATH"
# 直接使用GitHub URL
local GITHUB_URL="https://github.com/hdbjlizhe/fanli/releases/download/${VERSION}/${FILENAME}"
# 显示下载选项菜单
echo "请选择下载方式:"
echo "1. 直连下载"
echo "2. 通过内置代理下载"
echo "3. 手动输入代理链接下载"
echo "4. 手动上传autman压缩包文件"
echo "5. 通过 socks5 代理下载"
echo "=================================================================="
read -p "请选择 [1/2/3/4/5] 或 'q' 退出: " download_option
while true; do
local download_success=false
case "$download_option" in
"1")
echo "选择直连下载..."
if download_with_mirror "$GITHUB_URL" "$DOWNLOAD_PATH" "autman程序 (直连)"; then
echo "autman程序下载成功 (直连)"
download_success=true
else
echo "直连下载失败,请重新选择下载方式或手动上传/退出"
fi
;;
"2")
echo "选择通过内置代理下载..."
local download_success_mirror=false
if download_with_mirror "$GITHUB_URL" "$DOWNLOAD_PATH" "autman程序 (镜像)"; then
echo "autman程序下载成功 (镜像)"
download_success_mirror=true
download_success=true
else
echo "所有镜像源下载尝试失败,请检查网络或手动下载"
echo "请重新选择下载方式或选择手动上传/退出"
fi
;;
"3")
echo "选择手动输入代理链接下载..."
read -p "请输入GitHub镜像代理链接: " manual_proxy_url
if [ -n "$manual_proxy_url" ]; then
manual_proxy_url="${manual_proxy_url%/}"
echo "尝试从手动代理链接下载: $manual_proxy_url"
if [[ "$manual_proxy_url" =~ github\.com ]]; then
manual_mirror_url="$manual_proxy_url"
else
manual_mirror_url="$manual_proxy_url/$GITHUB_URL"
fi
echo "实际请求URL: $manual_mirror_url"
if curl -f -L -o "$DOWNLOAD_PATH" "$manual_mirror_url" --connect-timeout 10 --retry 0; then
echo "autman程序下载成功 (手动代理链接)"
download_success=true
else
echo "从手动链接下载失败,请检查链接或手动上传文件"
echo "请重新选择下载方式或选择手动上传/退出"
fi
else
echo "您没有输入任何代理链接。"
echo "将返回下载选项菜单,请选择其他下载方式或手动上传文件。"
echo "请重新选择下载方式或选择手动上传/退出"
fi
;;
"4")
echo "选择手动上传autman压缩包文件..."
install_autman_from_archive "$install_path"
return $? # 返回手动上传的结果
download_success=true # 手动上传也视为下载成功
;;
"5")
echo "选择通过 socks5 代理下载..."
echo "请输入 socks5 代理地址:"
echo " - 无账号密码格式:ip:端口 例如 192.168.8.253:1080"
echo " - 有账号密码格式:用户名:密码@ip:端口 例如 user:pass@192.168.8.253:1080"
read -p "请输入 socks5 代理地址: " socks5_addr
if [ -z "$socks5_addr" ]; then
echo "未输入 socks5 代理地址,将返回下载选项菜单。"
else
echo "使用 socks5 代理 $socks5_addr 下载..."
if curl --socks5-hostname "$socks5_addr" -L -o "$DOWNLOAD_PATH" "$GITHUB_URL" --connect-timeout 20 --retry 1; then
echo "autman程序下载成功 (socks5 代理)"
download_success=true
else
echo "通过 socks5 代理下载失败,请检查代理设置或网络。"
fi
fi
;;
"q")
echo "用户取消安装"
return 1 # 用户选择退出,函数返回
;;
*)
echo "无效的选择,请重新运行脚本"
echo "请重新选择下载方式或选择手动上传/退出"
;;
esac
if [ "$download_success" = true ]; then
echo "解压autman..."
cd "$install_path"
rm -rf autman autMan AutoMan AUTMAN 2>/dev/null
tar -xzf "$FILENAME"
if [ $? -ne 0 ]; then
echo "autman解压失败! 请检查下载的文件是否完整或磁盘空间"
return 1
fi
if [ ! -f "autMan" ]; then
echo "错误:解压后未找到 autMan 程序文件"
return 1
fi
echo "autman下载和解压完成!"
return 0 # 下载和解压成功,函数返回
fi
read -p "请选择下载方式 [1/2/3/4/5] 或 'q' 退出 (或按 Enter 重新显示选项): " download_option_loop
if [ -z "$download_option_loop" ]; then
echo "请选择下载方式:"
echo "1. 直连下载"
echo "2. 通过内置代理下载"
echo "3. 手动输入代理链接下载"
echo "4. 手动上传autman压缩包文件"
echo "5. 通过 socks5 代理下载"
echo "=================================================================="
read -p "请选择 [1/2/3/4/5] 或 'q' 退出 (或按 Enter 重新显示选项): " download_option_loop
else
# 用户直接输入数字时也要展示菜单
echo "您选择了: $download_option_loop"
echo "对应选项说明:"
case "$download_option_loop" in
1) echo "1. 直连下载";;
2) echo "2. 通过内置代理下载";;
3) echo "3. 手动输入代理链接下载";;
4) echo "4. 手动上传autman压缩包文件";;
5) echo "5. 通过 socks5 代理下载";;
q) echo "q. 退出安装";;
*) echo "无效选项,请重新选择。";;
esac
fi
download_option="$download_option_loop"
done
}
# 修改download_ip2region函数,确保直接下载到安装目录
download_ip2region() {
echo "进入 download_ip2region 函数,准备弹出菜单..."
sleep 1
local install_path=$1
echo "=================================================================="
echo "下载IP2Region数据库文件..."
# 设置下载URL
local IP2REGION_URL="https://github.com/lionsoul2014/ip2region/raw/master/data/ip2region.xdb"
local IP2REGION_PATH="${install_path}/ip2region.xdb"
local FILENAME="ip2region.xdb"
local download_success=false
while [ "$download_success" = false ]; do
echo "请选择下载方式:"
echo "1. 直连下载"
echo "2. 通过内置镜像源下载"
echo "3. 通过 socks5 代理下载"
echo "4. 手动输入代理链接下载"
echo "5. 手动上传 ip2region.xdb 文件"
echo "6. 跳过 ip2region.xdb 安装"
echo "=================================================================="
read -p "请选择 [1/2/3/4/5/6] 或 'q' 退出: " ip2region_option
case "$ip2region_option" in
1)
echo "尝试直接下载ip2region.xdb..."
if curl -L -o "$IP2REGION_PATH" "$IP2REGION_URL" --connect-timeout 20 --retry 1; then
echo "ip2region.xdb下载成功 (直连)"
download_success=true
else
echo "直连下载失败,请选择其他方式。"
fi
;;
2)
echo "尝试通过内置镜像源下载..."
for mirror in "${GITHUB_MIRRORS[@]}"; do
local mirror_url=$(echo "$IP2REGION_URL" | sed "s#https://github.com#${mirror}#")
echo "尝试镜像: $mirror_url"
if curl -L -o "$IP2REGION_PATH" "$mirror_url" --connect-timeout 20 --retry 1; then
echo "ip2region.xdb下载成功 (镜像: $mirror)"
download_success=true
break
fi
done
if [ "$download_success" = false ]; then
echo "所有镜像源下载失败,请选择其他方式。"
fi
;;
3)
echo "选择通过 socks5 代理下载..."
echo "请输入 socks5 代理地址:"
echo " - 无账号密码格式:ip:端口 例如 192.168.8.253:1080"
echo " - 有账号密码格式:用户名:密码@ip:端口 例如 user:pass@192.168.8.253:1080"
read -p "请输入 socks5 代理地址: " socks5_addr_ip2region
if [ -z "$socks5_addr_ip2region" ]; then
echo "未输入 socks5 代理地址,将返回下载选项菜单。"
else
echo "使用 socks5 代理 $socks5_addr_ip2region 下载..."
if curl --socks5-hostname "$socks5_addr_ip2region" -L -o "$IP2REGION_PATH" "$IP2REGION_URL" --connect-timeout 20 --retry 1; then
echo "ip2region.xdb下载成功 (socks5 代理)"
download_success=true
else
echo "通过 socks5 代理下载失败,请检查代理设置或选择其他方式。"
fi
fi
;;
4)
echo "选择手动输入代理链接下载..."
read -p "请输入ip2region.xdb的下载链接: " manual_proxy_url_ip2region
if [ -n "$manual_proxy_url_ip2region" ]; then
echo "尝试从手动代理链接下载: $manual_proxy_url_ip2region"
if curl -L -o "$IP2REGION_PATH" "$manual_proxy_url_ip2region" --connect-timeout 20 --retry 1; then
echo "ip2region.xdb下载成功 (手动代理链接)"
download_success=true
else
echo "手动代理下载失败,请检查链接或选择其他方式。"
fi
else
echo "未输入任何代理链接,将返回下载选项菜单。"
fi
;;
5)
echo "选择手动上传ip2region.xdb文件..."
read -p "请输入本地ip2region.xdb文件的完整路径或所在文件夹路径: " local_ip2region_path
if [ -f "$local_ip2region_path" ]; then
# 如果目标文件已在安装目录,无需复制
if [ "$local_ip2region_path" = "$IP2REGION_PATH" ]; then
echo "ip2region.xdb 已存在于安装目录,无需复制,安装成功。"
download_success=true
else
cp "$local_ip2region_path" "$IP2REGION_PATH"
if [ $? -eq 0 ]; then
echo "ip2region.xdb已成功复制到安装目录。"
download_success=true
else
echo "文件复制失败,请检查权限或路径。"
fi
fi
elif [ -d "$local_ip2region_path" ]; then
# 自动查找目录下的 ip2region.xdb 文件
found_file=$(find "$local_ip2region_path" -maxdepth 1 -type f -name 'ip2region.xdb' | head -n 1)
if [ -n "$found_file" ]; then
if [ "$found_file" = "$IP2REGION_PATH" ]; then
echo "ip2region.xdb 已存在于安装目录,无需复制,安装成功。"
download_success=true
else
cp "$found_file" "$IP2REGION_PATH"
if [ $? -eq 0 ]; then
echo "ip2region.xdb已成功从目录复制到安装目录。"
download_success=true
else
echo "文件复制失败,请检查权限或路径。"
fi
fi
else
echo "目录中未找到 ip2region.xdb 文件,请检查后重试。"
fi
else
echo "文件或目录不存在,请检查路径。"
fi
;;
6)
echo "用户选择跳过 ip2region.xdb 安装。"
return 0
;;
q|Q)
echo "用户取消ip2region.xdb下载。"
return 1
;;
*)
echo "无效的选择,请重新输入。"
;;
esac
done
echo "ip2region.xdb下载和处理完成!"
echo "=================================================================="
return 0
}
# 修复Go依赖安装函数,确保显示正确的GOPATH
install_go_dependencies() {
local install_path=$1
echo "=================================================================="
echo "开始安装Go依赖..."
# 保存当前目录,以便后续返回
local current_dir=$(pwd)
# 尝试查找plugin/scripts目录,不限制深度
local scripts_dir=$(find "$install_path" -type d -name "scripts" | grep "plugin/scripts" | head -1)
if [ -n "$scripts_dir" ]; then
echo "找到插件目录: $scripts_dir"
cd "$scripts_dir" || {
echo "错误: 无法切换到 $scripts_dir 目录"
cd "$current_dir" 2>/dev/null # 返回原目录
return 1
}
# 初始化Go模块
echo "初始化Go模块..."
if [ ! -f "go.mod" ]; then
go mod init autman/plugins
if [ $? -ne 0 ]; then
echo "警告: Go模块初始化失败,可能影响插件功能"
fi
fi
# 安装Go依赖
echo "安装hdbjlizhe/middleware..."
go get -u github.com/hdbjlizhe/middleware
# 检查安装结果
if [ $? -ne 0 ]; then
echo "错误: Go依赖安装失败,请检查网络连接和Go环境配置"
cd "$current_dir" 2>/dev/null # 返回原目录
return 1
fi
# 返回原目录
cd "$current_dir" || echo "警告: 无法返回原目录 $current_dir"
echo "Go依赖安装完成"
# 获取正确的GOPATH
local actual_gopath=$(go env GOPATH)
if [ -n "$actual_gopath" ]; then
echo "依赖已保存到: ${actual_gopath}/pkg/mod"
else
echo "无法确定Go依赖保存位置,请检查go env GOPATH的输出"
fi
return 0
else
echo "错误: 找不到plugin/scripts目录"
echo "请确认autman安装是否完整,目录结构如下:"
find "$install_path" -type d | sort
cd "$current_dir" 2>/dev/null # 返回原目录
return 1
fi
}
# 修改主安装函数,确保正确安装顺序
install_autman() {
echo "=================================================================="
echo "开始安装autman..."
# 询问安装路径
ask_install_path
# 下载并解压autman
if ! download_autman "$INSTALL_PATH"; then
echo "autman下载或解压失败!"
return 1
fi
echo "autman基础安装完成"
echo "=================================================================="
# 自动下载ip2region.xdb数据库
download_ip2region "$INSTALL_PATH"
return 0
}
# 安装Python依赖
install_python_deps() {
echo "安装Python依赖..."
# 使用 HTTP 而不是 HTTPS,并信任主机
pip3 install --index-url=http://mirrors.aliyun.com/pypi/simple/ \
--trusted-host=mirrors.aliyun.com \
requests \
user_agent \
PyExecJS \
aiohttp \
pyOpenSSL
echo "Python依赖安装完成"
}
# 安装Node.js依赖
install_nodejs_deps() {
echo "安装Node.js依赖..."
# 设置npm使用淘宝镜像
npm config set registry https://registry.npmmirror.com
# 安装依赖
npm install --timeout=60000 --retry=3 axios request require crypto-js
if [ $? -ne 0 ]; then
echo "Node.js依赖安装失败"
return 1
fi
echo "Node.js依赖安装完成"
}
# 安装Go依赖
install_golang_deps() {
local install_path=$1
echo "安装Go依赖..."
# 进入plugin/scripts目录
if [ -d "${install_path}/autman/plugin/scripts" ]; then
cd "${install_path}/autman/plugin/scripts"
# 安装Go依赖
echo "安装hdbjlizhe/middleware..."
go get -u github.com/hdbjlizhe/middleware
cd - >/dev/null
echo "Go依赖安装完成"
else
echo "警告: 找不到plugin/scripts目录,跳过Go依赖安装"
fi
}
# 修复依赖安装顺序问题 - 将Go依赖安装从install_dependencies中分离出来
install_dependencies() {
local install_path=$1
echo "=================================================================="
echo "开始安装依赖..."
# 安装Python依赖
echo "安装Python依赖..."
pip install -U requests user_agent PyExecJS aiohttp
# 安装Node.js依赖
echo "安装Node.js依赖..."
npm install -g axios request require crypto-js
echo "基础依赖安装完成"
echo "=================================================================="
}
# 检测GLIBC版本
check_glibc_version() {
echo "检测系统GLIBC版本..."
# 获取GLIBC版本
GLIBC_VERSION=$(ldd --version | head -n 1 | grep -oE '[0-9]+\.[0-9]+$')
GLIBC_VERSION_MAJOR=$(echo $GLIBC_VERSION | cut -d. -f1)
GLIBC_VERSION_MINOR=$(echo $GLIBC_VERSION | cut -d. -f2)
echo "系统GLIBC版本: $GLIBC_VERSION"
# 检查GLIBC版本是否满足要求
if [ "$GLIBC_VERSION_MAJOR" -lt 2 ] || [ "$GLIBC_VERSION_MAJOR" -eq 2 -a "$GLIBC_VERSION_MINOR" -lt 17 ]; then
echo "警告: 系统GLIBC版本过低,autman可能无法正常运行"
echo "建议通过Docker安装autman"
return 1
fi
return 0
}
# 配置autman
configure_autman() {
local install_path=$1
echo "配置autman在 $install_path..."
# 创建配置文件
local config_file="${install_path}/sets.conf"
echo "创建配置文件..."
touch "$config_file"
# 询问用户是否设置管理员账号
read -p "是否需要设置管理员账号?[Y/n]: " set_admin
if [[ "$set_admin" != "n" && "$set_admin" != "N" ]]; then
read -p "请输入管理员账号 (默认: admin): " admin_username
admin_username=${admin_username:-"admin"}
echo "set autMan adminUsername $admin_username" >> "$config_file"
echo "管理员账号设置为: $admin_username"
fi
# 询问用户是否设置管理员密码
read -p "是否需要设置管理员密码?[Y/n]: " set_password
if [[ "$set_password" != "n" && "$set_password" != "N" ]]; then
read -p "请输入管理员密码 (默认: 123456): " admin_password
admin_password=${admin_password:-"123456"}
echo "set autMan adminPassword $admin_password" >> "$config_file"
echo "管理员密码设置为: $admin_password"
fi
# 询问用户设置端口
read -p "是否需要设置端口?[Y/n]: " set_port
if [[ "$set_port" != "n" && "$set_port" != "N" ]]; then
read -p "请输入端口号 (默认: 9090): " port
port=${port:-9090}
echo "set autMan port $port" >> "$config_file"
echo "端口设置为: $port"
# 保存端口到全局变量
configured_port=$port
export configured_port # 明确导出变量使其对其他函数可见
else
# 使用默认端口
configured_port=9090
export configured_port # 明确导出变量使其对其他函数可见
fi
# 询问用户是否注册云账号
read -p "是否需要注册云账号?[Y/n]: " set_cloud
if [[ "$set_cloud" != "n" && "$set_cloud" != "N" ]]; then
read -p "请输入云账号: " cloud_username
if [ -n "$cloud_username" ]; then
echo "set cloud username $cloud_username" >> "$config_file"
echo "云账号已设置"
read -p "请输入云密码: " cloud_password
if [ -n "$cloud_password" ]; then
echo "set cloud password $cloud_password" >> "$config_file"
echo "云密码已设置"
fi
fi
fi
echo "配置完成"
return 0
}
# 检查Docker是否安装
check_docker() {
if [ "$DOCKER_NEEDS_INSTALL" = false ]; then
echo "Docker已安装"
return 0
else
echo "Docker未安装,开始安装..."
return 1
fi
}
# 安装Docker
install_docker() {
echo "开始安装Docker..."
case $OS in
ubuntu|debian)
# 安装依赖
apt update || { echo "更新软件源失败"; return 1; }
apt install -y apt-transport-https ca-certificates curl gnupg lsb-release || { echo "安装Docker依赖失败"; return 1; }
# 添加Docker官方GPG密钥
curl -fsSL https://download.docker.com/linux/$OS/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 添加Docker源
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/$OS $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装Docker
apt update || { echo "更新Docker源失败"; return 1; }
apt install -y docker-ce docker-ce-cli containerd.io || {
echo "Docker安装失败,尝试使用镜像源安装..."
# 尝试使用阿里云镜像安装
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/$OS/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/$OS $(lsb_release -cs) stable"
apt update
apt install -y docker-ce docker-ce-cli containerd.io || {
echo "Docker安装失败,请手动安装";
return 1;
}
}
;;
*)
# CentOS/RHEL/Fedora等
if [ "$USE_DNF" = "true" ]; then
# 使用DNF安装
dnf -y install dnf-plugins-core || echo "安装dnf-plugins-core失败"
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo || {
echo "添加Docker仓库失败,尝试添加阿里云Docker镜像..."
dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
}
dnf install -y docker-ce docker-ce-cli containerd.io || {
echo "Docker安装失败,请手动安装"
return 1
}
else
# 使用YUM安装
yum install -y yum-utils device-mapper-persistent-data lvm2 || echo "安装Docker依赖失败"
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo || {
echo "添加Docker仓库失败,尝试添加阿里云Docker镜像..."
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
}
yum install -y docker-ce docker-ce-cli containerd.io || {
echo "Docker安装失败,请手动安装"
return 1
}
fi
;;
esac
# 启动Docker
echo "启动Docker服务..."
start_service docker
if [ $? -ne 0 ]; then
echo "启动Docker服务失败,请手动启动"
return 1
fi
# 配置Docker镜像加速
echo "配置Docker镜像加速..."
mkdir -p /etc/docker
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com",
"https://registry.docker-cn.com"
]
}
EOF
# 重启Docker服务使配置生效
echo "重启Docker服务以应用镜像加速配置..."
restart_service docker
if [ $? -ne 0 ]; then
echo "重启Docker服务失败,请手动重启以应用镜像加速配置"
fi
# 验证Docker安装
if docker --version &>/dev/null; then
echo "Docker安装完成,版本: $(docker --version)"
return 0
else
echo "Docker安装可能有问题,请检查"
return 1
fi
}
# 尝试使用Docker镜像代理拉取镜像
try_docker_pull_with_mirrors() {
local image_name=$1
local mirrors=("${DOCKER_MIRRORS[@]}") # 使用 Docker 镜像代理列表
local pull_success=false
local last_error=""
echo "尝试使用Docker镜像代理拉取镜像: $image_name"
# 直接尝试拉取
echo "尝试直接拉取镜像 $image_name..."
if docker pull "$image_name"; then
echo "镜像拉取成功!"
return 0
else
echo "直接拉取失败,将尝试使用代理..."
fi
# 使用预设的Docker镜像代理
for mirror in "${mirrors[@]}"; do
echo "=================================================================="
echo "尝试使用代理 $mirror 拉取镜像..."
local proxy_image="${mirror}/${image_name}"
# 显示Docker原生输出
if docker pull "$proxy_image"; then
echo "镜像拉取成功!"
echo "重新标记镜像..."
docker tag "$proxy_image" "$image_name"
docker rmi "$proxy_image"
return 0
fi
echo "当前代理拉取失败,尝试下一个代理..."
done
return 1
}
# 手动镜像拉取函数
try_manual_mirror() {
echo "所有预设镜像代理均失败"
echo "可用的Docker镜像代理有:"
for i in "${!DOCKER_MIRRORS[@]}"; do
echo "$((i+1)). ${DOCKER_MIRRORS[$i]}"
done
read -p "请选择一个镜像代理编号,或输入'c'自定义代理,或输入'q'退出: " choice
if [[ "$choice" == "q" ]]; then
echo "用户取消安装"
return 1
elif [[ "$choice" == "c" ]]; then
read -p "请输入自定义Docker镜像代理地址 (如 docker.io): " custom_mirror
echo "尝试使用代理 $custom_mirror 拉取镜像..."
if docker pull "${custom_mirror}/hdbjlizhe/autman:latest"; then
echo "镜像拉取成功!"
docker tag "${custom_mirror}/hdbjlizhe/autman:latest" "hdbjlizhe/autman:latest"
docker rmi "${custom_mirror}/hdbjlizhe/autman:latest"
return 0
else
echo "自定义代理拉取失败"
return 1
fi
elif [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#DOCKER_MIRRORS[@]} ]; then
local mirror_index=$((choice-1))
local mirror="${DOCKER_MIRRORS[$mirror_index]}"
echo "尝试使用代理 $mirror 拉取镜像..."
if docker pull "${mirror}/hdbjlizhe/autman:latest"; then
echo "镜像拉取成功!"
docker tag "${mirror}/hdbjlizhe/autman:latest" "hdbjlizhe/autman:latest"
docker rmi "${mirror}/hdbjlizhe/autman:latest"
return 0
else
echo "选择的代理拉取失败"
return 1
fi
else
echo "无效的选择"
return 1
fi
}
# 重启Docker容器的函数
restart_docker_container() {
local container_name="$1"
echo "重启 $container_name 容器..."
# 重启容器
docker restart "$container_name"
if [ $? -eq 0 ]; then
echo "$container_name 容器重启成功"
return 0
else
echo "警告: $container_name 容器重启失败"
return 1
fi
}
# 修改 `install_autman_docker` 函数,明确分离Docker安装流程
install_autman_docker() {
echo "=================================================================="
echo "开始使用Docker安装autman..."
echo "请选择Docker镜像拉取方式:"
echo "1. 直接拉取 (默认 - 适合网络环境较好)"
echo "2. 使用Docker镜像代理拉取 (推荐 - 解决网络问题)"
echo "3. 手动上传Docker镜像压缩包 (离线安装或网络极差)"
echo "=================================================================="
read -p "请选择 [1/2/3]: " docker_pull_method
local docker_pull_option=${docker_pull_method:-1}
# 确认用户是否想指定数据目录路径
read -p "是否使用默认数据目录 (/root/autman)?[Y/n]: " use_default_path
local docker_data_path="/root/autman"
if [[ "$use_default_path" == "n" || "$use_default_path" == "N" ]]; then
read -p "请输入数据目录路径: " custom_path
if [ -n "$custom_path" ]; then
docker_data_path="$custom_path"
fi
fi
# 确保目录存在且为空
mkdir -p "$docker_data_path"
INSTALL_PATH="$docker_data_path" # 设置全局变量以便其他函数使用
echo "将使用目录 $docker_data_path 存储autman数据"
# 拉取Docker镜像
echo "拉取autman Docker镜像..."
# 定义 Docker 镜像名称
local DOCKER_IMAGE="hdbjlizhe/autman:latest"
local pull_success=false
case $docker_pull_option in
"2")
echo "使用Docker镜像代理拉取..."
# 遍历所有 Docker 镜像代理
for mirror in "${DOCKER_MIRRORS[@]}"; do
echo "尝试使用代理: $mirror"
if docker pull ${mirror}/hdbjlizhe/autman:latest; then
# 代理拉取成功后,重新标记镜像
docker tag ${mirror}/hdbjlizhe/autman:latest hdbjlizhe/autman:latest
if [ $? -eq 0 ]; then
docker rmi ${mirror}/hdbjlizhe/autman:latest
pull_success=true
break
else
echo "镜像标记失败,尝试下一个代理..."
fi
else
echo "使用 $mirror 拉取失败,尝试下一个代理..."
fi
done
if [ "$pull_success" = false ]; then
echo "所有代理拉取都失败,请检查网络或尝试其他安装方式"
return 1
fi
;;
"3")
echo "请将Docker镜像压缩包上传到服务器,并输入文件路径"
read -p "输入文件路径: " image_path
if [ -f "$image_path" ]; then
docker load -i "$image_path"
else
echo "文件不存在: $image_path"
return 1
fi
;;
*)
echo "直接拉取Docker镜像..."
docker pull hdbjlizhe/autman:latest
;;
esac
if [ $? -ne 0 ]; then
echo "Docker 镜像拉取失败,安装终止"
return 1
fi
echo "容器下载完成"
# 停止可能存在的旧容器
docker stop autman 2>/dev/null
docker rm autman 2>/dev/null
echo "容器已停止,开始配置autman"
# 清空数据目录中的旧文件
echo "清理数据目录中的旧文件..."
rm -rf "${docker_data_path:?}"/* 2>/dev/null
# 下载autman压缩文件
echo "下载autman压缩文件..."
download_autman "$docker_data_path"
# 配置autman
echo "配置autman..."
configure_autman "$docker_data_path"
# 启动Docker容器
echo "启动autman容器..."
docker run -d --name autman --restart always --network=host -e autPort=${configured_port:-9090} -v "$docker_data_path:/autMan" hdbjlizhe/autman:latest
# 检查容器是否启动成功
if [ $? -ne 0 ]; then
echo "autman Docker容器启动失败,请检查日志"
docker logs autman
return 1
fi
echo "autman容器已启动"
# 在容器内安装Go依赖 - 【错误,应该在宿主机安装】
# 等待容器初始化
echo "等待容器初始化..."
sleep 5
# 重启容器以确保配置生效
echo "重启autman容器以应用配置..."
restart_docker_container "autman"
if [ $? -eq 0 ]; then
echo "=================================================================="
echo "autman Docker容器启动成功!"
# 获取当前IP地址
current_ip=$(get_current_ip)
echo "您可以通过访问 http://${current_ip}:${configured_port:-9090} 使用autman"
echo "=================================================================="
# 在显示完安装结果后,添加网络修复步骤
echo "=================================================================="
echo "注意:部分用户可能会出现容器无法正常访问的情况,脚本将进行简单修复..."
echo "正在重新配置容器网络模式..."
docker stop autman
docker rm autman
docker run -d --name autman --restart always --network=host -e autPort=${configured_port:-9090} -v "$docker_data_path:/autMan" hdbjlizhe/autman:latest
echo "=================================================================="
echo "如果您觉得当前的容器网络结构对您来说并不安全,您可执行以下命令来替换掉当前的容器模式:"
echo
echo "docker stop autman"
echo "docker rm autman"
echo "docker run -d --name autman --restart always -p 9090:8080 -v /root/autman:/autMan --log-opt max-size=10m --log-opt max-file=3 hdbjlizhe/autman:latest"
echo "=================================================================="
return 0
else
echo "autman Docker容器启动失败,请检查日志"
docker logs autman
return 1
fi
}
# 手动安装Docker镜像
install_docker_from_archive() {
echo "=================================================================="
echo "开始手动安装Docker镜像..."
read -p "请输入Docker镜像压缩包文件路径: " archive_path
if [ ! -f "$archive_path" ]; then
echo "错误: 文件 '$archive_path' 不存在"
return 1
fi
echo "加载Docker镜像..."
docker load -i "$archive_path"
if [ $? -ne 0 ]; then
echo "Docker 镜像加载失败,请检查文件是否有效或Docker环境"
return 1
fi
echo "Docker 镜像加载完成"
echo "=================================================================="
return 0
}
# 修复GLIBC版本检测后的Docker切换逻辑,但保留用户选择
setup_and_start_autman() {
local install_path=$1
echo "=================================================================="
echo "准备启动autman服务..."
# 搜索可执行文件,优先查找autman,然后是autMan
echo "查找autman可执行文件..."
local autman_exec=""
for exec_name in "autman" "autMan" "AutoMan" "AUTMAN"; do
local found_exec=$(find "$install_path" -type f -name "$exec_name" 2>/dev/null | head -1)
if [ -n "$found_exec" ]; then
autman_exec="$found_exec"
echo "找到可执行文件: $autman_exec"
break
fi
done
# 如果仍找不到,尝试查找其他可能的可执行文件
if [ -z "$autman_exec" ]; then
autman_exec=$(find "$install_path" -type f -executable -not -path "*/\.*" -not -name "*.sh" 2>/dev/null | head -1)
if [ -n "$autman_exec" ]; then
echo "未找到明确的autman可执行文件,尝试使用: $autman_exec"
else
echo "错误: 找不到可执行文件,安装可能不完整"
echo "建议切换到Docker安装方式"
read -p "是否切换到Docker安装? [Y/n]: " switch_docker
if [[ "$switch_docker" != "n" && "$switch_docker" != "N" ]]; then
USE_DOCKER=true
install_autman_docker
show_installation_result
exit 0
else
echo "用户选择不切换到Docker,退出安装"
return 1
fi
fi
fi
# 确保有执行权限
chmod +x "$autman_exec"
# 检查GLIBC兼容性,使用超时避免卡死
echo "检查系统兼容性..."
local error_output=$(timeout 5 "$autman_exec" --version 2>&1 || echo "执行超时或错误")
# 检查输出是否包含GLIBC错误
if [[ "$error_output" == *"GLIBC"* ]]; then
echo "=================================================================="
echo "错误: 检测到GLIBC版本不兼容"
echo "错误信息: $error_output"
echo "=================================================================="
echo "您的系统GLIBC版本过低,无法直接运行autman"
echo "建议使用Docker安装方式"
echo "=================================================================="
read -p "是否切换到Docker安装? [Y/n]: " switch_to_docker
if [[ "$switch_to_docker" != "n" && "$switch_to_docker" != "N" ]]; then
echo "正在切换到Docker安装..."
USE_DOCKER=true
install_autman_docker
show_installation_result
exit 0 # 在Docker安装完成后直接退出
fi
echo "警告: 继续使用本地安装可能导致服务无法正常运行"
fi
# 配置autman
configure_autman "$install_path"
# 创建启动脚本
local start_script="${install_path}/start_autman.sh"
echo "#!/bin/bash" > "$start_script"
echo "cd \"$(dirname "$autman_exec")\"" >> "$start_script"
echo "nohup \"$autman_exec\" > \"${install_path}/autman.log\" 2>&1 &" >> "$start_script"
chmod +x "$start_script"
# 启动服务
echo "启动autman服务..."
bash "$start_script"
# 检查进程是否启动
sleep 3
local pid=$(pgrep -f "$(basename "$autman_exec")")
if [ -n "$pid" ]; then
echo "服务进程已启动,进程ID: $pid"
echo "服务日志保存在: ${install_path}/autman.log"
# 获取当前IP地址
local ip=$(hostname -I | awk '{print $1}')
echo "=================================================================="
echo "autman已启动,请访问 http://${ip}:${configured_port:-9090}"
echo "=================================================================="
return 0
else
echo "警告: 服务可能未正常启动,检查日志..."
if [ -f "${install_path}/autman.log" ]; then
echo "---------------日志内容---------------"
tail -n 10 "${install_path}/autman.log"
echo "-------------------------------------"
# 再次检查日志中是否有GLIBC错误
if grep -q "GLIBC" "${install_path}/autman.log"; then
echo "=================================================================="
echo "检测到GLIBC版本问题,强烈建议使用Docker安装"
echo "=================================================================="
read -p "是否现在切换到Docker安装? [Y/n]: " switch_now
if [[ "$switch_now" != "n" && "$switch_now" != "N" ]]; then
USE_DOCKER=true
install_autman_docker
return $?
fi
fi
fi
echo "您可以手动启动: cd ${install_path} && ./$(basename "$autman_exec")"
return 1
fi
}
# 显示安装结果
show_installation_result() {
local ip=$(get_current_ip)
local port=${configured_port:-9090}
echo "=================================================================="
echo -e "${GREEN}安装完成!${NC}"
echo -e "${GREEN}感谢您使用AUTMAN一键脚本${NC}"
echo -e "${RED}如果脚本有bug请加入QQ群:${NC}${GREEN}475866384${NC}"
echo -e "${RED}autman官方QQ群:${NC}${GREEN}735467280${NC}"
echo -e "${RED}如果懒得手动或者不会可以联系:${NC}${BLUE}偷豆豆的大舅哥${NC}"
echo -e "${RED}QQ:${NC}${GREEN}2182043734${NC}"
echo -e "${RED}▶ 本地服务器用户作者不推荐您关闭防火墙,为了您的安全放行对应端口即可${NC}"
echo -e "${RED}▶ 云服务器用户在安装完成后请手动去服务器提供商放行对应的端口${NC}"
echo "=================================================================="
}
# 询问安装方式
ask_installation_method() {
echo "=================================================================="
echo "请选择安装方式:"
echo "1. 本地安装 (直接安装在系统中)"
echo "2. Docker安装 (使用Docker容器运行-大舅哥推荐)"
echo "=================================================================="
read -p "请输入选择 [1/2]: " install_method
case $install_method in
2)
USE_DOCKER=true
echo "已选择Docker安装方式"
;;
*)
USE_DOCKER=false
echo "已选择本地安装方式"
;;
esac
}
# 添加缺失的函数 - 从本地压缩包安装autman
install_autman_from_archive() {
local install_path=$1
echo "=================================================================="
echo "开始从本地压缩包安装autman..."
echo "请将 autman 压缩包上传到 ${install_path} 文件夹,然后输入该文件夹路径(无需输入压缩包文件名)"
read -p "请输入 autman 文件夹路径: " archive_dir
# 检查文件夹是否存在
if [ ! -d "$archive_dir" ]; then
echo "错误: 文件夹 '$archive_dir' 不存在"
return 1
fi
# 自动查找文件夹下的 autMan_*.tar.gz 文件
local archive_path=$(find "$archive_dir" -maxdepth 1 -type f -name 'autMan_*.tar.gz' | head -n 1)
if [ -z "$archive_path" ]; then
echo "错误: 在 '$archive_dir' 未找到 autMan_*.tar.gz 压缩包文件"
echo "请确认已上传压缩包,并重试"
return 1
fi
echo "检测到压缩包: $archive_path"
# 确保安装目录存在
mkdir -p "$install_path"
# 解压文件到安装目录
echo "解压 autman 压缩包到 $install_path..."
tar -xzf "$archive_path" -C "$install_path"
if [ $? -ne 0 ]; then
echo "错误: 解压失败,请检查压缩包是否有效"
return 1
fi
# 检查是否成功解压出autMan程序
local autman_exec=""
for exec_name in "autman" "autMan" "AutoMan" "AUTMAN"; do
if [ -f "$install_path/$exec_name" ]; then
autman_exec="$install_path/$exec_name"
chmod +x "$autman_exec"
echo "找到autman可执行文件: $autman_exec"
break
fi
done
if [ -z "$autman_exec" ]; then
echo "警告: 未找到autman可执行文件,解压可能不完整"
echo "解压内容:"
ls -la "$install_path"
return 1
fi
echo "autman从本地压缩包安装完成"
echo "=================================================================="
echo "即将进入ip2region数据库下载菜单..."
sleep 1
return 0
}
# 执行函数
main() {
# 欢迎信息
show_welcome
# 检测系统
check_system
# 检查是否为root用户
check_root
# 测试网络连接
echo "检测网络连接..."
test_network || echo "网络连接测试失败,部分功能可能无法正常工作"
# 添加选择镜像源的步骤
select_mirror_source
# 询问安装方式
ask_installation_method
# 检查必要的系统库
check_system_libraries
# 配置镜像源
configure_mirrors
# 检测已安装的软件
check_installed_dependencies
if [ "$USE_DOCKER" = true ]; then
# Docker安装流程
if ! check_docker; then
if ! install_docker; then
echo "Docker安装失败,请手动安装Docker后重试"
exit 1
fi
fi
if ! install_autman_docker; then
echo "Docker安装autman失败"
exit 1
fi
else
# 本地安装流程
if ! install_base_packages; then
echo "基础软件包安装失败,请检查网络和软件源"
exit 1
fi
# 安装Node.js
if [ "$NODEJS_NEEDS_INSTALL" = true ]; then
if ! install_nodejs; then
echo "Node.js安装失败,请手动安装后重试"
exit 1
fi
else
echo "Node.js已安装,跳过"
fi
# 安装Go
if [ "$GO_NEEDS_INSTALL" = true ]; then
if ! install_golang; then
echo "Go安装失败,请手动安装后重试"
exit 1
fi
else
echo "Go已安装,跳过"
fi
# 安装基础依赖(Python和Node.js)
if ! install_dependencies "$INSTALL_PATH"; then
echo "依赖安装失败,但将继续安装"
fi
# 安装autman
if ! install_autman; then
echo "autman安装失败"
exit 1
fi
# 安装Go依赖(在autman安装完成后)
install_go_dependencies "$INSTALL_PATH"
# 配置和启动
if ! setup_and_start_autman "$INSTALL_PATH"; then
echo "autman启动失败,请检查日志"
exit 1
fi
# 配置防火墙
if [ -n "$configured_port" ]; then
echo "请手动开放服务器防火墙端口 $configured_port(如 9090),以保证 Web 服务可访问。"
fi
fi
show_installation_result
exit 0
}
# 调用主函数
main
喜欢就支持一下吧
暂无评论内容