#!/usr/bin/env bash if [ -z "${BASH_VERSION:-}" ]; then echo "请使用 bash 运行此脚本,例如:curl -fsSL https://tg-ff.com/tg-ff-agent-install.sh | sudo bash" >&2 exit 1 fi # # TG-FF 控制中心 Linux 在线安装 / 升级脚本,发布在 https://tg-ff.com/tg-ff-agent-install.sh。 # # 安装或升级:curl -fsSL https://tg-ff.com/tg-ff-agent-install.sh | sudo bash # 指定运行用户:curl -fsSL https://tg-ff.com/tg-ff-agent-install.sh | sudo bash -s -- --user tgff # 卸载: curl -fsSL https://tg-ff.com/tg-ff-agent-install.sh | sudo bash -s -- uninstall # # 脚本只负责按 CPU 架构下载 GitHub 公开发布里的 tg-ff-agent-linux-<架构>.tar.gz 并解压, # 之后交给安装包里的 install.sh 完成安装:升级时沿用已安装服务的运行用户,账号登录信息和 # 下载记录保留在运行用户的 ~/.local/share/com.tgff.agent,已经下载的文件始终保留。 # 除下面列出的下载选项外,其余参数原样交给 install.sh(例如 --user、--prefix、--yes)。 # # 整个脚本放在 main 函数里,读取完成后才开始执行,避免管道传输中断时只执行了半个脚本。 main() { set -Eeuo pipefail umask 022 local default_repository='271387591/at-bot' local release_tag='v1' local download_base="${TG_FF_DOWNLOAD_BASE:-}" local release_version='' local prefix="${TG_FF_AGENT_PREFIX:-/opt/tg-ff-agent}" local action='install' local -a passthrough=() local c_reset='' c_bold='' c_cyan='' c_red='' if [[ -z "${NO_COLOR:-}" && "${TERM:-dumb}" != 'dumb' && -t 2 ]]; then c_reset=$'\033[0m' c_bold=$'\033[1m' c_cyan=$'\033[36m' c_red=$'\033[31m' fi step() { printf '%s==>%s %s\n' "${c_cyan}${c_bold}" "${c_reset}" "$*" >&2; } fail() { printf '\n%s错误:%s%s\n' "${c_red}${c_bold}" "${c_reset}" "$*" >&2 exit 1 } usage() { cat <<'EOF' TG-FF 控制中心 Linux 在线安装脚本 用法:curl -fsSL https://tg-ff.com/tg-ff-agent-install.sh | sudo bash -s -- [install|uninstall] [选项] 下载选项: --version <版本> 安装指定版本,例如 5.1.0(默认安装最新版) --base-url <地址> 从这个地址下载 tg-ff-agent-linux-<架构>.tar.gz(也可设置 TG_FF_DOWNLOAD_BASE) 安装选项(交给安装包里的 install.sh): --user <用户名> 用这个用户运行服务(默认 root,升级时沿用原来的用户) --prefix <目录> 安装目录,默认 /opt/tg-ff-agent --no-service 只复制程序,不注册 systemd 服务 --purge 卸载时同时删除账号登录信息和下载记录(已下载的文件始终保留) -y, --yes 不再询问确认 -h, --help 显示本帮助 EOF } while [[ $# -gt 0 ]]; do case "$1" in install | uninstall) action="$1" passthrough+=("$1") ;; --version) [[ $# -ge 2 ]] || fail '--version 后面需要填写版本号,例如 5.1.0。' release_version="${2#v}" [[ "${release_version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || fail "版本号格式不正确:$2" shift ;; --base-url) [[ $# -ge 2 ]] || fail '--base-url 后面需要填写下载地址。' download_base="$2" shift ;; --prefix) [[ $# -ge 2 ]] || fail '--prefix 后面需要填写安装目录。' prefix="$2" passthrough+=("$1" "$2") shift ;; --user) [[ $# -ge 2 ]] || fail '--user 后面需要填写用户名。' passthrough+=("$1" "$2") shift ;; --package) fail '在线安装会自动下载安装包。已经有安装包时,请解压后运行包里的 sudo ./install.sh。' ;; -h | --help) usage return 0 ;; *) passthrough+=("$1") ;; esac shift done [[ "$(uname -s)" == 'Linux' ]] || fail '这个脚本只能在 Linux 上运行。' [[ "${EUID}" -eq 0 ]] || fail '请使用 root 权限运行,例如:curl -fsSL https://tg-ff.com/tg-ff-agent-install.sh | sudo bash' # 卸载不需要下载,直接使用已经安装的 install.sh。 if [[ "${action}" == 'uninstall' ]]; then [[ -f "${prefix}/install.sh" ]] || fail "没有在 ${prefix} 找到已经安装的 TG-FF 控制中心。" bash "${prefix}/install.sh" "${passthrough[@]}" return fi local arch case "$(uname -m)" in x86_64 | amd64) arch='amd64' ;; aarch64 | arm64) arch='arm64' ;; *) fail "暂不支持当前 CPU 架构:$(uname -m)。目前只提供 x86_64(amd64)和 ARM64 版本。" ;; esac if [[ -z "${download_base}" ]]; then local tag="${release_tag}" [[ -z "${release_version}" ]] || tag="v${release_version}" download_base="https://github.com/${default_repository}/releases/download/${tag}" fi download_base="${download_base%/}" [[ "${download_base}" == https://* ]] || fail '下载地址必须以 https:// 开头。' local package_name="tg-ff-agent-linux-${arch}.tar.gz" local package_url="${download_base}/${package_name}" command -v tar >/dev/null 2>&1 || fail '系统缺少 tar 命令,请先安装 tar。' local downloader='' if command -v curl >/dev/null 2>&1; then downloader='curl' elif command -v wget >/dev/null 2>&1; then downloader='wget' else fail '系统缺少 curl 或 wget,请先安装其中一个再运行。' fi local work_dir work_dir="$(mktemp -d /var/tmp/tg-ff-agent-install.XXXXXX)" || fail '无法创建临时目录 /var/tmp。' # shellcheck disable=SC2064 trap "rm -rf '${work_dir}'" EXIT chmod 0700 "${work_dir}" local available_kb available_kb="$(df -Pk "${work_dir}" | awk 'NR == 2 { print $4 }')" if [[ -n "${available_kb}" && "${available_kb}" -lt $((1024 * 1024)) ]]; then fail '/var/tmp 可用空间不足 1 GB,无法下载和解压安装包。请清理磁盘后重试。' fi step "正在下载 ${package_name}" local archive="${work_dir}/${package_name}" local progress=(--silent --show-error) [[ -t 2 ]] && progress=(--progress-bar) local downloaded=0 if [[ "${downloader}" == 'curl' ]]; then curl --fail --location --proto '=https' --tlsv1.2 --retry 3 --retry-delay 3 \ --connect-timeout 20 "${progress[@]}" --output "${archive}" "${package_url}" /dev/null 2>&1 \ || fail '下载的安装包不完整或已损坏,请稍后重试。' tar -xzf "${archive}" -C "${work_dir}"