Files
Aether/apps/aether-tunnel/install.sh

242 lines
7.2 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/sh
set -eu
REPO="${AETHER_TUNNEL_RELEASE_REPO:-fawney19/Aether}"
TAG="${AETHER_TUNNEL_RELEASE_TAG:-}"
INSTALL_DIR="${AETHER_TUNNEL_INSTALL_DIR:-}"
CONFIG_PATH="${AETHER_TUNNEL_CONFIG:-}"
TMP_DIR=""
say() { printf '%s\n' "[Aether Tunnel] $1"; }
fail() { printf '%s\n' "[Aether Tunnel] $1" >&2; exit 1; }
cleanup() {
if [ -n "$TMP_DIR" ] && [ -d "$TMP_DIR" ]; then
rm -rf "$TMP_DIR"
fi
}
trap cleanup EXIT INT TERM
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "缺少命令:$1"
}
download() {
url="$1"
out="$2"
if command -v curl >/dev/null 2>&1; then
curl -fL --retry 3 --connect-timeout 10 -o "$out" "$url"
elif command -v wget >/dev/null 2>&1; then
wget -O "$out" "$url"
else
fail "需要 curl 或 wget 下载 release 制品"
fi
}
prompt_if_empty() {
name="$1"
value="$2"
prompt="$3"
if [ -n "$value" ]; then
printf '%s' "$value"
return
fi
printf '%s' "$prompt" >&2
if [ -r /dev/tty ]; then
IFS= read -r value < /dev/tty
else
fail "$name 未通过环境变量提供,且当前环境无法交互输入"
fi
[ -n "$value" ] || fail "$name 不能为空"
printf '%s' "$value"
}
toml_quote() {
value="$1"
if command -v python3 >/dev/null 2>&1; then
python3 -c 'import json,sys; print(json.dumps(sys.argv[1], ensure_ascii=False))' "$value"
else
escaped=$(printf '%s' "$value" | sed 's/\\/\\\\/g; s/"/\\"/g')
printf '"%s"\n' "$escaped"
fi
}
resolve_latest_tunnel_tag() {
[ -n "$TAG" ] && { printf '%s\n' "$TAG"; return; }
api_url="https://api.github.com/repos/${REPO}/releases?per_page=100"
releases="$TMP_DIR/releases.json"
download "$api_url" "$releases" >/dev/null 2>&1 || fail "无法读取 GitHub Releases$api_url"
if command -v python3 >/dev/null 2>&1; then
python3 - "$releases" <<'PY'
import json, sys
releases = json.load(open(sys.argv[1], encoding='utf-8'))
tunnel = [r for r in releases if not r.get('draft') and str(r.get('tag_name', '')).startswith('tunnel-v')]
tunnel.sort(key=lambda r: r.get('published_at') or r.get('created_at') or '', reverse=True)
if tunnel:
print(tunnel[0]['tag_name'])
PY
else
grep -o '"tag_name"[[:space:]]*:[[:space:]]*"tunnel-v[^"]*"' "$releases" | head -n 1 | sed 's/.*"\(tunnel-v[^"]*\)".*/\1/'
fi
}
detect_asset() {
os=$(uname -s 2>/dev/null || printf unknown)
arch=$(uname -m 2>/dev/null || printf unknown)
case "$os" in
Linux) platform=linux ;;
Darwin) platform=macos ;;
MINGW*|MSYS*|CYGWIN*) fail "检测到 Windows shell请使用 PowerShellirm <install.ps1-url> | iex" ;;
*) fail "不支持的系统:$os" ;;
esac
case "$arch" in
x86_64|amd64) cpu=amd64 ;;
aarch64|arm64) cpu=arm64 ;;
*) fail "不支持的 CPU 架构:$arch" ;;
esac
if [ "$platform" = "linux" ] && command -v ldd >/dev/null 2>&1 && ldd --version 2>&1 | grep -qi musl; then
printf 'aether-tunnel-linux-musl-%s.tar.gz\n' "$cpu"
else
printf 'aether-tunnel-%s-%s.tar.gz\n' "$platform" "$cpu"
fi
}
choose_paths() {
if [ -z "$INSTALL_DIR" ]; then
if [ "$(id -u 2>/dev/null || printf 1)" = "0" ]; then
INSTALL_DIR="/usr/local/bin"
else
INSTALL_DIR="$HOME/.local/bin"
fi
fi
if [ -z "$CONFIG_PATH" ]; then
if [ "$(id -u 2>/dev/null || printf 1)" = "0" ]; then
CONFIG_PATH="/etc/aether-tunnel/aether-tunnel.toml"
else
CONFIG_PATH="$HOME/.aether-tunnel/aether-tunnel.toml"
fi
fi
}
verify_checksum() {
archive="$1"
sums="$2"
asset="$3"
[ -f "$sums" ] || return 0
expected=$(awk -v asset="$asset" '$2 == asset { print $1 }' "$sums" | head -n 1)
[ -n "$expected" ] || return 0
if command -v sha256sum >/dev/null 2>&1; then
actual=$(sha256sum "$archive" | awk '{print $1}')
elif command -v shasum >/dev/null 2>&1; then
actual=$(shasum -a 256 "$archive" | awk '{print $1}')
else
say "未找到 sha256sum/shasum跳过校验"
return 0
fi
[ "$actual" = "$expected" ] || fail "SHA256 校验失败:$asset"
}
install_binary() {
tag="$1"
asset="$2"
base="https://github.com/${REPO}/releases/download/${tag}"
archive="$TMP_DIR/$asset"
say "下载 $tag / $asset"
download "$base/$asset" "$archive"
download "$base/SHA256SUMS.txt" "$TMP_DIR/SHA256SUMS.txt" >/dev/null 2>&1 || true
verify_checksum "$archive" "$TMP_DIR/SHA256SUMS.txt" "$asset"
tar -xzf "$archive" -C "$TMP_DIR"
[ -f "$TMP_DIR/aether-tunnel" ] || fail "制品中未找到 aether-tunnel"
mkdir -p "$INSTALL_DIR"
cp "$TMP_DIR/aether-tunnel" "$INSTALL_DIR/aether-tunnel"
chmod +x "$INSTALL_DIR/aether-tunnel"
say "已安装二进制:$INSTALL_DIR/aether-tunnel"
}
has_legacy_single_server_keys() {
[ -f "$CONFIG_PATH" ] || return 1
awk '
/^[[:space:]]*\[/ { exit }
/^[[:space:]]*(aether_url|management_token)[[:space:]]*=/ { found=1; exit }
END { exit found ? 0 : 1 }
' "$CONFIG_PATH"
}
server_exists() {
[ -f "$CONFIG_PATH" ] || return 1
quoted_url="$1"
quoted_name="$2"
awk -v url="aether_url = $quoted_url" -v name="node_name = $quoted_name" '
BEGIN { found_url=0; found_name=0 }
/^\[\[servers\]\]/ {
if (found_url && found_name) { found=1 }
found_url=0; found_name=0
}
$0 == url { found_url=1 }
$0 == name { found_name=1 }
END { if (found_url && found_name) { found=1 }; exit found ? 0 : 1 }
' "$CONFIG_PATH"
}
append_server_config() {
aether_url="$1"
management_token="$2"
node_name="$3"
mkdir -p "$(dirname "$CONFIG_PATH")"
quoted_url=$(toml_quote "$aether_url")
quoted_token=$(toml_quote "$management_token")
quoted_name=$(toml_quote "$node_name")
if has_legacy_single_server_keys; then
fail "现有配置仍使用旧的顶层 aether_url/management_token请先运行 aether-tunnel setup 迁移为 [[servers]] 后重试:$CONFIG_PATH"
fi
if server_exists "$quoted_url" "$quoted_name"; then
say "配置中已存在相同 aether_url + node_name跳过追加$CONFIG_PATH"
return
fi
if [ -f "$CONFIG_PATH" ]; then
cp "$CONFIG_PATH" "$CONFIG_PATH.bak.$(date +%Y%m%d%H%M%S)"
fi
{
if [ -f "$CONFIG_PATH" ] && [ -s "$CONFIG_PATH" ]; then
printf '\n'
fi
printf '# Added by Aether Tunnel one-click installer. Existing config is preserved.\n'
printf '[[servers]]\n'
printf 'aether_url = %s\n' "$quoted_url"
printf 'management_token = %s\n' "$quoted_token"
printf 'node_name = %s\n' "$quoted_name"
} >> "$CONFIG_PATH"
chmod 600 "$CONFIG_PATH" 2>/dev/null || true
say "已追加 [[servers]] 到:$CONFIG_PATH"
}
main() {
TMP_DIR=$(mktemp -d 2>/dev/null || mktemp -d -t aether-tunnel)
need_cmd tar
choose_paths
aether_url=$(prompt_if_empty AETHER_TUNNEL_AETHER_URL "${AETHER_TUNNEL_AETHER_URL:-}" "Aether URL: ")
management_token=$(prompt_if_empty AETHER_TUNNEL_MANAGEMENT_TOKEN "${AETHER_TUNNEL_MANAGEMENT_TOKEN:-}" "Management token (ae_xxx): ")
node_name=$(prompt_if_empty AETHER_TUNNEL_NODE_NAME "${AETHER_TUNNEL_NODE_NAME:-}" "Node name: ")
tag=$(resolve_latest_tunnel_tag)
[ -n "$tag" ] || fail "没有找到可用的 tunnel-v* release"
asset=$(detect_asset)
install_binary "$tag" "$asset"
append_server_config "$aether_url" "$management_token" "$node_name"
say "完成。运行以下命令启动/配置服务:"
say " $INSTALL_DIR/aether-tunnel setup $CONFIG_PATH"
}
main "$@"