feat: organize scripts and add portal validation assets

This commit is contained in:
phamnazage-jpg
2026-05-27 09:39:05 +08:00
parent c1172d7714
commit 02580cda0b
180 changed files with 3392 additions and 76 deletions

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
IMAGE_TAG="${IMAGE_TAG:-sub2api-cn-relay-manager:local}"
BINARY_PATH="${BINARY_PATH:-$ROOT_DIR/bin/sub2api-cn-relay-manager}"
mkdir -p "$(dirname "$BINARY_PATH")"
echo "[1/2] building linux binary -> $BINARY_PATH"
(
cd "$ROOT_DIR"
GOTOOLCHAIN=local CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -trimpath -ldflags='-s -w' -o "$BINARY_PATH" ./cmd/server
)
echo "[2/2] building OCI image -> $IMAGE_TAG"
(
cd "$ROOT_DIR"
docker build -f Dockerfile.local -t "$IMAGE_TAG" .
)
echo "done: $IMAGE_TAG"

View File

@@ -0,0 +1,161 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
KEY="${KEY:-/home/long/下载/zjsea.pem}"
REMOTE="${REMOTE:-ubuntu@43.155.133.187}"
REMOTE_PORTAL_DIR="${REMOTE_PORTAL_DIR:-/var/www/sub2api-portal}"
REMOTE_NGINX_SITE="${REMOTE_NGINX_SITE:-/etc/nginx/sites-available/tksea}"
REMOTE_HOST_PORT="${REMOTE_HOST_PORT:-18169}"
LOCAL_PORTAL_INDEX="${LOCAL_PORTAL_INDEX:-$ROOT_DIR/deploy/tksea-portal/index.html}"
REMOTE_STAGE_DIR="${REMOTE_STAGE_DIR:-/tmp/sub2api-portal-deploy}"
DRY_RUN="${DRY_RUN:-0}"
die() {
echo "$*" >&2
exit 1
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || die "missing command: $1"
}
run_cmd() {
if [[ "$DRY_RUN" == "1" ]]; then
printf 'DRY_RUN:'
printf ' %q' "$@"
printf '\n'
return 0
fi
"$@"
}
ssh_remote() {
run_cmd ssh -i "$KEY" -o StrictHostKeyChecking=no "$REMOTE" "$@"
}
scp_remote() {
run_cmd scp -i "$KEY" -o StrictHostKeyChecking=no "$@"
}
main() {
require_cmd python3
require_cmd ssh
require_cmd scp
[[ -f "$LOCAL_PORTAL_INDEX" ]] || die "missing portal index: $LOCAL_PORTAL_INDEX"
if [[ "$DRY_RUN" != "1" ]]; then
[[ -f "$KEY" ]] || die "missing ssh key: $KEY"
fi
local tmpdir patch_file index_copy
tmpdir="$(mktemp -d)"
trap "rm -rf $(printf '%q' "$tmpdir")" EXIT
patch_file="$tmpdir/patch_tksea_portal_nginx.py"
index_copy="$tmpdir/index.html"
cp "$LOCAL_PORTAL_INDEX" "$index_copy"
cat > "$patch_file" <<EOF
from pathlib import Path
import re
import textwrap
path = Path(${REMOTE_NGINX_SITE@Q})
text = path.read_text()
block = textwrap.dedent("""\
location = /portal {
return 302 /portal/;
}
location = /kimi-portal {
return 302 /portal/;
}
# BEGIN sub2api-portal
location /portal/ {
alias ${REMOTE_PORTAL_DIR}/;
index index.html;
try_files \$uri \$uri/ /portal/index.html;
}
location /portal-proxy/ {
proxy_pass http://127.0.0.1:${REMOTE_HOST_PORT}/;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_http_version 1.1;
}
location /kimi-portal/ {
return 302 /portal/;
}
location /kimi-portal-proxy/ {
proxy_pass http://127.0.0.1:${REMOTE_HOST_PORT}/;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_http_version 1.1;
}
location /kimi/ {
proxy_pass http://127.0.0.1:${REMOTE_HOST_PORT}/;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_http_version 1.1;
}
location /kimi-v1/ {
proxy_pass http://127.0.0.1:${REMOTE_HOST_PORT}/v1/;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_http_version 1.1;
}
# END sub2api-portal
""")
patterns = [
re.compile(r"\\n\\s*location = /portal \\{.*?# END sub2api-portal\\n\\n", re.S),
re.compile(r"\\n\\s*location = /kimi-portal \\{.*?# END kimi-portal\\n\\n", re.S),
]
for pattern in patterns:
if pattern.search(text):
text = pattern.sub("\\n" + block + "\\n", text, count=1)
path.write_text(text)
raise SystemExit(0)
needle = "\\n location / {\\n proxy_pass http://127.0.0.1:"
index = text.rfind(needle)
if index == -1:
raise SystemExit("failed to locate sub.tksea.top root location block")
text = text[:index] + "\\n" + block + text[index:]
path.write_text(text)
EOF
ssh_remote "mkdir -p $(printf '%q' "$REMOTE_STAGE_DIR")"
scp_remote "$index_copy" "$REMOTE:$REMOTE_STAGE_DIR/index.html"
scp_remote "$patch_file" "$REMOTE:$REMOTE_STAGE_DIR/patch_tksea_portal_nginx.py"
ssh_remote "sudo install -d -m 755 $(printf '%q' "$REMOTE_PORTAL_DIR") && sudo cp $(printf '%q' "$REMOTE_STAGE_DIR/index.html") $(printf '%q' "$REMOTE_PORTAL_DIR/index.html") && sudo python3 $(printf '%q' "$REMOTE_STAGE_DIR/patch_tksea_portal_nginx.py") && sudo nginx -t && sudo systemctl reload nginx"
cat <<EOF
tksea portal deployed
remote: ${REMOTE}
portal url: https://sub.tksea.top/portal/
legacy url: https://sub.tksea.top/kimi-portal/
portal dir: ${REMOTE_PORTAL_DIR}
nginx site: ${REMOTE_NGINX_SITE}
EOF
}
main "$@"

View File

@@ -0,0 +1,251 @@
#!/usr/bin/env bash
set -euo pipefail
# remote43 patched stack 渲染 helper供部署脚本和测试脚本共享。
remote43_require_file() {
local path="$1"
local label="$2"
[[ -f "$path" ]] || {
echo "missing $label: $path" >&2
return 1
}
}
remote43_random_hex() {
local bytes="${1:?bytes required}"
python3 - "$bytes" <<'PY'
import secrets
import sys
print(secrets.token_hex(int(sys.argv[1])))
PY
}
remote43_write_env_file() {
local path="$1"
shift
: > "$path"
while [[ $# -gt 0 ]]; do
local key="$1"
local value="$2"
shift 2
case "$value" in
*$'\n'*)
echo "env value for $key must not contain newlines" >&2
return 1
;;
esac
printf '%s=%s\n' "$key" "$value" >> "$path"
done
}
render_remote43_host_env() {
local pg_container="$1"
local redis_container="$2"
local db_password="$3"
local db_name="$4"
local admin_email="$5"
local admin_password="$6"
local jwt_secret="$7"
local totp_key="$8"
cat <<EOF
AUTO_SETUP=true
DATABASE_HOST=$pg_container
DATABASE_PORT=5432
DATABASE_USER=sub2api
DATABASE_PASSWORD=$db_password
DATABASE_DBNAME=$db_name
REDIS_HOST=$redis_container
REDIS_PORT=6379
ADMIN_EMAIL=$admin_email
ADMIN_PASSWORD=$admin_password
JWT_SECRET=$jwt_secret
TOTP_ENCRYPTION_KEY=$totp_key
SECURITY_URL_ALLOWLIST_ENABLED=false
SECURITY_URL_ALLOWLIST_MODE=disabled
EOF
}
render_remote43_crm_env() {
local crm_port="$1"
local sqlite_dsn="$2"
local admin_token="$3"
local sqlite_dsn_q admin_token_q
printf -v sqlite_dsn_q '%q' "$sqlite_dsn"
printf -v admin_token_q '%q' "$admin_token"
cat <<EOF
SUB2API_CRM_LISTEN_ADDR=127.0.0.1:$crm_port
SUB2API_CRM_SQLITE_DSN=$sqlite_dsn_q
SUB2API_CRM_ADMIN_TOKEN=$admin_token_q
SUB2API_CRM_RECONCILE_WORKER_ENABLED=false
EOF
}
render_remote43_bootstrap_script() {
local remote_root="$1"
local host_env_file="$2"
local crm_env_file="$3"
local host_binary_name="$4"
local crm_binary_name="$5"
local data_dir="$6"
local crm_db_file="$7"
local crm_pid_file="$8"
local crm_log_file="$9"
local app_container="${10}"
local pg_container="${11}"
local redis_container="${12}"
local network_name="${13}"
local host_image="${14}"
local pg_image="${15}"
local redis_image="${16}"
local db_password="${17}"
local db_name="${18}"
local host_port="${19}"
local crm_port="${20}"
local host_container_port="${21}"
local remote_root_q host_env_q crm_env_q host_binary_q crm_binary_q
local data_dir_q crm_db_q crm_pid_q crm_log_q app_q pg_q redis_q
local network_q host_image_q pg_image_q redis_image_q db_password_q db_name_q
local host_port_q crm_port_q host_container_port_q
remote_root_q="$(printf '%q' "$remote_root")"
host_env_q="$(printf '%q' "$host_env_file")"
crm_env_q="$(printf '%q' "$crm_env_file")"
host_binary_q="$(printf '%q' "$host_binary_name")"
crm_binary_q="$(printf '%q' "$crm_binary_name")"
data_dir_q="$(printf '%q' "$data_dir")"
crm_db_q="$(printf '%q' "$crm_db_file")"
crm_pid_q="$(printf '%q' "$crm_pid_file")"
crm_log_q="$(printf '%q' "$crm_log_file")"
app_q="$(printf '%q' "$app_container")"
pg_q="$(printf '%q' "$pg_container")"
redis_q="$(printf '%q' "$redis_container")"
network_q="$(printf '%q' "$network_name")"
host_image_q="$(printf '%q' "$host_image")"
pg_image_q="$(printf '%q' "$pg_image")"
redis_image_q="$(printf '%q' "$redis_image")"
db_password_q="$(printf '%q' "$db_password")"
db_name_q="$(printf '%q' "$db_name")"
host_port_q="$(printf '%q' "$host_port")"
crm_port_q="$(printf '%q' "$crm_port")"
host_container_port_q="$(printf '%q' "$host_container_port")"
cat <<EOF
#!/usr/bin/env bash
set -euo pipefail
REMOTE_ROOT=$remote_root_q
HOST_ENV_FILE=$host_env_q
CRM_ENV_FILE=$crm_env_q
HOST_BINARY="\$REMOTE_ROOT/$host_binary_q"
CRM_BINARY="\$REMOTE_ROOT/$crm_binary_q"
DATA_DIR=$data_dir_q
CRM_DB_FILE=$crm_db_q
CRM_PID_FILE=$crm_pid_q
CRM_LOG_FILE=$crm_log_q
APP_CONTAINER=$app_q
PG_CONTAINER=$pg_q
REDIS_CONTAINER=$redis_q
NETWORK_NAME=$network_q
HOST_IMAGE=$host_image_q
PG_IMAGE=$pg_image_q
REDIS_IMAGE=$redis_image_q
DB_PASSWORD=$db_password_q
DB_NAME=$db_name_q
HOST_PORT=$host_port_q
CRM_PORT=$crm_port_q
HOST_CONTAINER_PORT=$host_container_port_q
mkdir -p "\$REMOTE_ROOT" "\$DATA_DIR"
chmod 755 "\$HOST_BINARY" "\$CRM_BINARY"
rm -f "\$DATA_DIR/install.lock" "\$DATA_DIR/config.yaml" "\$DATA_DIR/.installed"
rm -f "\$CRM_DB_FILE"
if [[ -f "\$CRM_PID_FILE" ]]; then
kill "\$(cat "\$CRM_PID_FILE")" >/dev/null 2>&1 || true
rm -f "\$CRM_PID_FILE"
fi
rm -f "\$CRM_LOG_FILE"
sudo -n docker rm -f "\$APP_CONTAINER" "\$PG_CONTAINER" "\$REDIS_CONTAINER" >/dev/null 2>&1 || true
sudo -n docker network inspect "\$NETWORK_NAME" >/dev/null 2>&1 || sudo -n docker network create "\$NETWORK_NAME" >/dev/null
sudo -n docker run -d --name "\$PG_CONTAINER" --network "\$NETWORK_NAME" \\
-e POSTGRES_USER=sub2api \\
-e POSTGRES_PASSWORD="\$DB_PASSWORD" \\
-e POSTGRES_DB="\$DB_NAME" \\
"\$PG_IMAGE" >/dev/null
sudo -n docker run -d --name "\$REDIS_CONTAINER" --network "\$NETWORK_NAME" \\
"\$REDIS_IMAGE" >/dev/null
sleep 10
sudo -n docker run -d --name "\$APP_CONTAINER" --network "\$NETWORK_NAME" \\
-p "127.0.0.1:\$HOST_PORT:\$HOST_CONTAINER_PORT" \\
--env-file "\$HOST_ENV_FILE" \\
-v "\$DATA_DIR:/app/data" \\
-v "\$HOST_BINARY:/app/sub2api:ro" \\
"\$HOST_IMAGE" /app/sub2api >/dev/null
python3 - "\$HOST_ENV_FILE" "\$HOST_PORT" <<'PY'
import json
import pathlib
import subprocess
import sys
import time
env_path = pathlib.Path(sys.argv[1])
host_port = sys.argv[2]
values = {}
for line in env_path.read_text(encoding='utf-8').splitlines():
if '=' not in line:
continue
key, value = line.split('=', 1)
values[key] = value
payload = json.dumps({
'email': values['ADMIN_EMAIL'],
'password': values['ADMIN_PASSWORD'],
'turnstile_token': '',
}, ensure_ascii=False)
url = f"http://127.0.0.1:{host_port}/api/v1/auth/login"
for _ in range(60):
result = subprocess.run(
['curl', '-fsS', '-H', 'Content-Type: application/json', '-X', 'POST', url, '-d', payload],
text=True,
capture_output=True,
)
if result.returncode == 0 and 'access_token' in result.stdout:
raise SystemExit(0)
time.sleep(2)
raise SystemExit(f'host login did not become ready on {url}')
PY
nohup bash -lc 'set -a; source "\$1"; set +a; exec "\$2"' _ "\$CRM_ENV_FILE" "\$CRM_BINARY" >"\$CRM_LOG_FILE" 2>&1 &
echo \$! > "\$CRM_PID_FILE"
python3 - "\$CRM_PORT" <<'PY'
import subprocess
import sys
import time
url = f"http://127.0.0.1:{sys.argv[1]}/healthz"
for _ in range(30):
result = subprocess.run(['curl', '-fsS', url], text=True, capture_output=True)
if result.returncode == 0 and result.stdout.strip() == 'ok':
raise SystemExit(0)
time.sleep(1)
raise SystemExit(f'crm healthz did not become ready on {url}')
PY
printf 'host_base=http://127.0.0.1:%s\n' "\$HOST_PORT"
printf 'crm_base=http://127.0.0.1:%s\n' "\$CRM_PORT"
printf 'remote_host_env=%s\n' "\$HOST_ENV_FILE"
printf 'crm_log=%s\n' "\$CRM_LOG_FILE"
EOF
}

View File

@@ -0,0 +1,205 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
# shellcheck disable=SC1091
source "$ROOT_DIR/scripts/deploy/remote43_patched_stack_lib.sh"
KEY="${KEY:-/home/long/下载/zjsea.pem}"
REMOTE="${REMOTE:-ubuntu@43.155.133.187}"
STACK_NAME="${STACK_NAME:-sub2api-patched-$(date +%Y%m%d)}"
HOST_PORT="${HOST_PORT:-18139}"
CRM_PORT="${CRM_PORT:-18143}"
LOCAL_HOST_TUNNEL_PORT="${LOCAL_HOST_TUNNEL_PORT:-$HOST_PORT}"
LOCAL_CRM_TUNNEL_PORT="${LOCAL_CRM_TUNNEL_PORT:-$CRM_PORT}"
HOST_IMAGE="${HOST_IMAGE:-weishaw/sub2api:0.1.129}"
HOST_CONTAINER_PORT="${HOST_CONTAINER_PORT:-8080}"
PG_IMAGE="${PG_IMAGE:-postgres:16-alpine}"
REDIS_IMAGE="${REDIS_IMAGE:-redis:7-alpine}"
DB_NAME="${DB_NAME:-sub2api}"
DB_PASSWORD="${DB_PASSWORD:-$(remote43_random_hex 16)}"
ADMIN_EMAIL="${ADMIN_EMAIL:-admin@sub2api.local}"
ADMIN_PASSWORD="${ADMIN_PASSWORD:-Sub2API-Remote43-Temp-Admin-20260525}"
JWT_SECRET="${JWT_SECRET:-$(remote43_random_hex 24)}"
TOTP_ENCRYPTION_KEY="${TOTP_ENCRYPTION_KEY:-$(remote43_random_hex 32)}"
CRM_ADMIN_TOKEN="${CRM_ADMIN_TOKEN:-$(remote43_random_hex 24)}"
HOST_NAME="${HOST_NAME:-remote43-patched-${HOST_PORT}}"
HOST_BINARY="${HOST_BINARY:-}"
CRM_BINARY="${CRM_BINARY:-$ROOT_DIR/server}"
PACK_DIR="${PACK_DIR:-$ROOT_DIR/packs/openai-cn-pack}"
LOCAL_SHARED_PACK_DIR="${LOCAL_SHARED_PACK_DIR:-/tmp/openai-cn-pack-${STACK_NAME}}"
LOCAL_OPERATOR_ENV_FILE="${LOCAL_OPERATOR_ENV_FILE:-/tmp/remote43-patched-stack-${HOST_PORT}.env}"
LOCAL_TUNNEL_SCRIPT="${LOCAL_TUNNEL_SCRIPT:-/tmp/remote43-patched-stack-${HOST_PORT}.tunnel.sh}"
REMOTE_ROOT="${REMOTE_ROOT:-/home/ubuntu/${STACK_NAME}_${HOST_PORT}}"
REMOTE_PACK_PATH="${REMOTE_PACK_PATH:-$LOCAL_SHARED_PACK_DIR}"
REMOTE_HOST_ENV_FILE="$REMOTE_ROOT/.env.host"
REMOTE_CRM_ENV_FILE="$REMOTE_ROOT/.env.crm"
REMOTE_BOOTSTRAP_FILE="$REMOTE_ROOT/bootstrap.sh"
REMOTE_HOST_BINARY="$REMOTE_ROOT/sub2api-patched"
REMOTE_CRM_BINARY="$REMOTE_ROOT/sub2api-cn-relay-manager-server"
REMOTE_DATA_DIR="$REMOTE_ROOT/data"
REMOTE_CRM_DB_FILE="$REMOTE_ROOT/sub2api-cn-relay-manager.db"
REMOTE_CRM_PID_FILE="$REMOTE_ROOT/crm.pid"
REMOTE_CRM_LOG_FILE="$REMOTE_ROOT/crm.log"
REMOTE_APP_CONTAINER="${REMOTE_APP_CONTAINER:-${STACK_NAME}-app}"
REMOTE_PG_CONTAINER="${REMOTE_PG_CONTAINER:-${STACK_NAME}-pg}"
REMOTE_REDIS_CONTAINER="${REMOTE_REDIS_CONTAINER:-${STACK_NAME}-redis}"
REMOTE_NETWORK="${REMOTE_NETWORK:-${STACK_NAME}-net}"
DRY_RUN="${DRY_RUN:-0}"
die() {
echo "$*" >&2
exit 1
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || die "missing command: $1"
}
run_cmd() {
if [[ "$DRY_RUN" == "1" ]]; then
printf 'DRY_RUN:'
printf ' %q' "$@"
printf '\n'
return 0
fi
"$@"
}
ssh_remote() {
run_cmd ssh -i "$KEY" -o StrictHostKeyChecking=no "$REMOTE" "$@"
}
scp_remote() {
run_cmd scp -i "$KEY" -o StrictHostKeyChecking=no "$@"
}
prepare_local_shared_pack() {
case "$LOCAL_SHARED_PACK_DIR" in
/tmp/*) ;;
*)
die "LOCAL_SHARED_PACK_DIR must stay under /tmp, got: $LOCAL_SHARED_PACK_DIR"
;;
esac
mkdir -p "$(dirname "$LOCAL_SHARED_PACK_DIR")"
rm -rf "$LOCAL_SHARED_PACK_DIR"
cp -R "$PACK_DIR" "$LOCAL_SHARED_PACK_DIR"
}
write_local_tunnel_script() {
cat > "$LOCAL_TUNNEL_SCRIPT" <<EOF
#!/usr/bin/env bash
set -euo pipefail
exec ssh -N \\
-L ${LOCAL_CRM_TUNNEL_PORT}:127.0.0.1:${CRM_PORT} \\
-L ${LOCAL_HOST_TUNNEL_PORT}:127.0.0.1:${HOST_PORT} \\
-i $(printf '%q' "$KEY") \\
-o StrictHostKeyChecking=no \\
$(printf '%q' "$REMOTE")
EOF
chmod +x "$LOCAL_TUNNEL_SCRIPT"
}
write_operator_env() {
remote43_write_env_file "$LOCAL_OPERATOR_ENV_FILE" \
CRM_BASE "http://127.0.0.1:${LOCAL_CRM_TUNNEL_PORT}" \
HOST_BASE "http://127.0.0.1:${LOCAL_HOST_TUNNEL_PORT}" \
CRM_HOST_BASE "http://127.0.0.1:${HOST_PORT}" \
REMOTE_HOST_BASE "http://127.0.0.1:${HOST_PORT}" \
HOST_NAME "$HOST_NAME" \
PACK_PATH "$LOCAL_SHARED_PACK_DIR" \
REMOTE_HOST_ENV_FILE "$REMOTE_HOST_ENV_FILE" \
KEY "$KEY" \
REMOTE "$REMOTE" \
CRM_ADMIN_TOKEN "$CRM_ADMIN_TOKEN"
chmod 600 "$LOCAL_OPERATOR_ENV_FILE"
}
main() {
require_cmd bash
require_cmd curl
require_cmd python3
require_cmd ssh
require_cmd scp
remote43_require_file "$KEY" "ssh key"
[[ -n "${HOST_BINARY// }" ]] || die "HOST_BINARY is required"
remote43_require_file "$HOST_BINARY" "patched host binary"
remote43_require_file "$CRM_BINARY" "crm server binary"
[[ -d "$PACK_DIR" ]] || die "missing pack dir: $PACK_DIR"
[[ "$REMOTE_PACK_PATH" == "$LOCAL_SHARED_PACK_DIR" ]] || die "REMOTE_PACK_PATH must equal LOCAL_SHARED_PACK_DIR so local/remote PACK_PATH stay identical"
prepare_local_shared_pack
write_local_tunnel_script
write_operator_env
local tmpdir host_env_file crm_env_file bootstrap_file
tmpdir="$(mktemp -d)"
trap "rm -rf $(printf '%q' "$tmpdir")" EXIT
host_env_file="$tmpdir/.env.host"
crm_env_file="$tmpdir/.env.crm"
bootstrap_file="$tmpdir/bootstrap.sh"
render_remote43_host_env \
"$REMOTE_PG_CONTAINER" \
"$REMOTE_REDIS_CONTAINER" \
"$DB_PASSWORD" \
"$DB_NAME" \
"$ADMIN_EMAIL" \
"$ADMIN_PASSWORD" \
"$JWT_SECRET" \
"$TOTP_ENCRYPTION_KEY" > "$host_env_file"
render_remote43_crm_env \
"$CRM_PORT" \
"file:${REMOTE_CRM_DB_FILE}?_foreign_keys=on&_busy_timeout=5000" \
"$CRM_ADMIN_TOKEN" > "$crm_env_file"
render_remote43_bootstrap_script \
"$REMOTE_ROOT" \
"$REMOTE_HOST_ENV_FILE" \
"$REMOTE_CRM_ENV_FILE" \
"$(basename "$REMOTE_HOST_BINARY")" \
"$(basename "$REMOTE_CRM_BINARY")" \
"$REMOTE_DATA_DIR" \
"$REMOTE_CRM_DB_FILE" \
"$REMOTE_CRM_PID_FILE" \
"$REMOTE_CRM_LOG_FILE" \
"$REMOTE_APP_CONTAINER" \
"$REMOTE_PG_CONTAINER" \
"$REMOTE_REDIS_CONTAINER" \
"$REMOTE_NETWORK" \
"$HOST_IMAGE" \
"$PG_IMAGE" \
"$REDIS_IMAGE" \
"$DB_PASSWORD" \
"$DB_NAME" \
"$HOST_PORT" \
"$CRM_PORT" \
"$HOST_CONTAINER_PORT" > "$bootstrap_file"
chmod +x "$bootstrap_file"
ssh_remote "mkdir -p $(printf '%q' "$REMOTE_ROOT") $(printf '%q' "$(dirname "$REMOTE_PACK_PATH")") && rm -rf $(printf '%q' "$REMOTE_PACK_PATH")"
scp_remote "$HOST_BINARY" "$REMOTE:$REMOTE_HOST_BINARY"
scp_remote "$CRM_BINARY" "$REMOTE:$REMOTE_CRM_BINARY"
scp_remote "$host_env_file" "$REMOTE:$REMOTE_HOST_ENV_FILE"
scp_remote "$crm_env_file" "$REMOTE:$REMOTE_CRM_ENV_FILE"
scp_remote "$bootstrap_file" "$REMOTE:$REMOTE_BOOTSTRAP_FILE"
scp_remote -r "$LOCAL_SHARED_PACK_DIR" "$REMOTE:$REMOTE_PACK_PATH"
ssh_remote "bash $(printf '%q' "$REMOTE_BOOTSTRAP_FILE")"
cat <<EOF
remote43 patched stack prepared
remote host base: http://127.0.0.1:${HOST_PORT}
remote crm base: http://127.0.0.1:${CRM_PORT}
remote host env file: ${REMOTE_HOST_ENV_FILE}
local operator env file: ${LOCAL_OPERATOR_ENV_FILE}
local tunnel script: ${LOCAL_TUNNEL_SCRIPT}
shared pack path: ${LOCAL_SHARED_PACK_DIR}
next:
1. 在另一终端运行: ${LOCAL_TUNNEL_SCRIPT}
2. 当前终端执行: set -a; source ${LOCAL_OPERATOR_ENV_FILE}; set +a
3. 再运行: bash ${ROOT_DIR}/scripts/acceptance/import_remote43_provider.sh kimi-a7m kimi-k2.6 A7M_KIMI_API_KEY /path/to/keyfile
EOF
}
main "$@"