Files
sub2api-add/scripts/install-local.sh
T
Qiufeng 028b505c36
Business Plugins CI / check (plugin-admin) (push) Successful in 1m35s
Business Plugins CI / check (subscription-admin) (push) Successful in 1m29s
feat: add controlled plugin marketplace lifecycle
2026-08-28 00:51:34 +08:00

149 lines
4.5 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.
#!/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" <<EOF
[Unit]
Description=Sub2API ${name} business plugin
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=${RUN_USER}
Group=${RUN_USER}
WorkingDirectory=${data_dir}
EnvironmentFile=${env_file}
ExecStart=${binary_dir}/${name}
Restart=on-failure
RestartSec=3
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=${data_dir}
[Install]
WantedBy=multi-user.target
EOF
}
for plugin in "${PLUGINS[@]}"; do
install_one "$plugin"
done
systemctl daemon-reload
for plugin in "${PLUGINS[@]}"; do
systemctl enable --now "sub2api-$plugin.service"
info "$plugin 已启动:$(systemctl is-active "sub2api-$plugin.service")"
done
info "安装完成。配置文件位于 $ETC_DIR;数据位于 $VAR_DIR。"
info "查看日志:journalctl -u sub2api-plugin-admin -u sub2api-subscription-admin -f"