#!/usr/bin/env bash set -Eeuo pipefail ROOT=$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd) PREFIX=${PLUGIN_INSTALL_PREFIX:-/opt/sub2api-add} ETC_DIR=${PLUGIN_ETC_DIR:-/etc/sub2api-add} VAR_DIR=${PLUGIN_VAR_DIR:-/var/lib/sub2api-add} RUN_USER=${PLUGIN_SYSTEM_USER:-sub2api-plugin} SELECTION=all usage() { cat <<'EOF' 用法:scripts/install-local.sh [--plugin all|plugin-admin|subscription-admin] 环境变量: PLUGIN_INSTALL_PREFIX 二进制目录,默认 /opt/sub2api-add PLUGIN_ETC_DIR 环境文件目录,默认 /etc/sub2api-add PLUGIN_VAR_DIR 插件数据目录,默认 /var/lib/sub2api-add PLUGIN_SYSTEM_USER systemd 用户,默认 sub2api-plugin PLUGIN_MARKETPLACE_INDEX plugin-admin 市场索引(默认数据目录下的 marketplace/index.json) PLUGIN_MARKETPLACE_ALLOWED_HOSTS 远程市场索引/插件包允许的精确主机列表 EOF } die() { printf '错误:%s\n' "$*" >&2; exit 1; } info() { printf '[sub2api-add] %s\n' "$*"; } while (($#)); do case "$1" in --plugin) (($# >= 2)) || die "--plugin 需要参数" SELECTION=$2 shift 2 ;; -h|--help) usage exit 0 ;; *) die "未知参数:$1" ;; esac done [[ $EUID -eq 0 ]] || die "请使用 root 或 sudo 运行" command -v go >/dev/null 2>&1 || die "缺少 Go;请安装 Go 1.23 或更高版本" command -v systemctl >/dev/null 2>&1 || die "缺少 systemd/systemctl" command -v install >/dev/null 2>&1 || die "缺少 install 命令" case "$SELECTION" in all) PLUGINS=(plugin-admin subscription-admin) ;; plugin-admin|subscription-admin) PLUGINS=("$SELECTION") ;; *) die "插件必须是 all、plugin-admin 或 subscription-admin" ;; esac if ! id -u "$RUN_USER" >/dev/null 2>&1; then useradd --system --user-group --home-dir "$VAR_DIR" --create-home --shell /usr/sbin/nologin "$RUN_USER" fi ensure_env_value() { local file=$1 key=$2 value=$3 if grep -q "^${key}=" "$file"; then if command sed --version >/dev/null 2>&1; then sed -i "s#^${key}=.*#${key}=${value}#" "$file" else sed -i '' "s#^${key}=.*#${key}=${value}#" "$file" fi else printf '%s=%s\n' "$key" "$value" >> "$file" fi } random_secret() { if command -v openssl >/dev/null 2>&1; then openssl rand -hex 32 else od -An -N32 -tx1 /dev/urandom | tr -d ' \n' fi } install_one() { local name=$1 source="$ROOT/plugins/$1" env_file="$ETC_DIR/$1.env" local binary_dir="$PREFIX/$1/bin" data_dir="$VAR_DIR/$1" [[ -d "$source" ]] || die "插件目录不存在:$source" install -d -m 0755 "$binary_dir" "$data_dir" "$ETC_DIR" if [[ ! -f "$env_file" ]]; then install -m 0600 "$source/.env.example" "$env_file" fi if [[ "$name" == plugin-admin ]]; then ensure_env_value "$env_file" PLUGIN_REGISTRY_DIR "$data_dir" install -d -m 0700 "$data_dir/marketplace" if [[ ! -f "$data_dir/marketplace/index.json" && -f "$source/marketplace/index.example.json" ]]; then install -m 0600 "$source/marketplace/index.example.json" "$data_dir/marketplace/index.json" fi if grep -q '^PLUGIN_CONFIG_KEY=generate-and-replace-with-a-random-32-byte-secret$' "$env_file" || ! grep -q '^PLUGIN_CONFIG_KEY=.' "$env_file"; then ensure_env_value "$env_file" PLUGIN_CONFIG_KEY "$(random_secret)" fi fi local tmp="$binary_dir/.${name}.tmp" info "构建 $name" (cd "$source" && CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o "$tmp" .) chmod 0755 "$tmp" mv -f "$tmp" "$binary_dir/$name" chown -R "$RUN_USER:$RUN_USER" "$data_dir" chown "$RUN_USER:$RUN_USER" "$binary_dir/$name" chmod 0600 "$env_file" cat > "/etc/systemd/system/sub2api-$name.service" <