shadowfh96 commited on
Commit
5fb57b5
·
verified ·
1 Parent(s): 9fdea14

Upload start-space.sh with huggingface_hub

Browse files
Files changed (1) hide show
  1. start-space.sh +356 -0
start-space.sh ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+
4
+ if [ -n "${ADMIN_PASSWORD_V2:-}" ]; then
5
+ ADMIN_PASSWORD="$ADMIN_PASSWORD_V2"
6
+ echo "Admin password secret source: ADMIN_PASSWORD_V2"
7
+ else
8
+ echo "Admin password secret source: ADMIN_PASSWORD"
9
+ fi
10
+
11
+ required_vars="ADMIN_PASSWORD JWT_SECRET TOTP_ENCRYPTION_KEY"
12
+
13
+ for var_name in $required_vars; do
14
+ eval "var_value=\${$var_name:-}"
15
+ if [ -z "$var_value" ]; then
16
+ echo "Missing required secret: $var_name" >&2
17
+ exit 1
18
+ fi
19
+ done
20
+
21
+ ADMIN_EMAIL="${ADMIN_EMAIL:-2691539771@qq.com}"
22
+ SERVER_PORT="${SERVER_PORT:-7860}"
23
+ DATA_DIR="${DATA_DIR:-/tmp/gateway-data}"
24
+
25
+ mkdir -p "$DATA_DIR" /tmp/gateway-redis /tmp/gateway-postgres
26
+ chown -R sub2api:sub2api "$DATA_DIR" /tmp/gateway-redis
27
+ chown -R postgres:postgres /tmp/gateway-postgres
28
+
29
+ redis-server --daemonize yes --bind 127.0.0.1 --port 6379 --dir /tmp/gateway-redis --save "" --appendonly no
30
+
31
+ if [ -z "${DATABASE_HOST:-}" ]; then
32
+ if [ ! -s /tmp/gateway-postgres/PG_VERSION ]; then
33
+ su-exec postgres initdb -D /tmp/gateway-postgres --auth=trust >/tmp/gateway-postgres-init.log
34
+ fi
35
+
36
+ su-exec postgres pg_ctl -D /tmp/gateway-postgres -l /tmp/gateway-postgres.log -o "-c listen_addresses=127.0.0.1 -c port=5432 -c unix_socket_directories=/tmp" start
37
+ createdb -h 127.0.0.1 -U postgres gatewaydb 2>/dev/null || true
38
+
39
+ DATABASE_HOST="127.0.0.1"
40
+ DATABASE_PORT="5432"
41
+ DATABASE_USER="postgres"
42
+ DATABASE_PASSWORD=""
43
+ DATABASE_DBNAME="gatewaydb"
44
+ DATABASE_SSLMODE="disable"
45
+ echo "Using ephemeral local PostgreSQL. Configure Supabase secrets for persistent data."
46
+ else
47
+ DATABASE_PORT="${DATABASE_PORT:-5432}"
48
+ DATABASE_USER="${DATABASE_USER:-postgres}"
49
+ DATABASE_PASSWORD="${DATABASE_PASSWORD:-}"
50
+ DATABASE_DBNAME="${DATABASE_DBNAME:-postgres}"
51
+ DATABASE_SSLMODE="${DATABASE_SSLMODE:-require}"
52
+ fi
53
+
54
+ export AUTO_SETUP="${AUTO_SETUP:-true}"
55
+ export ADMIN_EMAIL
56
+ export ADMIN_PASSWORD
57
+ export JWT_SECRET
58
+ export TOTP_ENCRYPTION_KEY
59
+ export DATA_DIR
60
+ export DATABASE_HOST
61
+ export DATABASE_PORT
62
+ export DATABASE_USER
63
+ export DATABASE_PASSWORD
64
+ export DATABASE_DBNAME
65
+ export DATABASE_SSLMODE
66
+ export REDIS_HOST="${REDIS_HOST:-127.0.0.1}"
67
+ export REDIS_PORT="${REDIS_PORT:-6379}"
68
+ export SERVER_HOST="${SERVER_HOST:-0.0.0.0}"
69
+ export SERVER_PORT
70
+ export SERVER_MODE="${SERVER_MODE:-release}"
71
+ export PORT="${PORT:-$SERVER_PORT}"
72
+ export GIN_MODE="${GIN_MODE:-release}"
73
+
74
+ migration_count() {
75
+ PGPASSWORD="${DATABASE_PASSWORD:-}" psql \
76
+ -h "$DATABASE_HOST" \
77
+ -p "$DATABASE_PORT" \
78
+ -U "$DATABASE_USER" \
79
+ -d "$DATABASE_DBNAME" \
80
+ -tAc "select count(1) from schema_migrations;" 2>/dev/null || printf '0\n'
81
+ }
82
+
83
+ sync_balance_cache_once() {
84
+ if [ "${BALANCE_CACHE_SYNC_ENABLED:-true}" != "true" ]; then
85
+ return 0
86
+ fi
87
+
88
+ rows="$(PGPASSWORD="${DATABASE_PASSWORD:-}" psql \
89
+ -h "$DATABASE_HOST" \
90
+ -p "$DATABASE_PORT" \
91
+ -U "$DATABASE_USER" \
92
+ -d "$DATABASE_DBNAME" \
93
+ -qAt \
94
+ -F '|' \
95
+ -c "select id, balance::double precision from users where deleted_at is null and status = 'active';" 2>/tmp/balance-cache-sync.err || true)"
96
+
97
+ if [ -z "$rows" ]; then
98
+ return 0
99
+ fi
100
+
101
+ ttl="${BALANCE_CACHE_SYNC_TTL_SECONDS:-300}"
102
+ printf '%s\n' "$rows" | while IFS='|' read -r user_id balance; do
103
+ case "$user_id" in
104
+ ''|*[!0-9]*) continue ;;
105
+ esac
106
+ if [ -n "${REDIS_PASSWORD:-}" ]; then
107
+ REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli \
108
+ -h "${REDIS_HOST:-127.0.0.1}" \
109
+ -p "${REDIS_PORT:-6379}" \
110
+ -n "${REDIS_DB:-0}" \
111
+ SETEX "billing:balance:${user_id}" "$ttl" "$balance" >/dev/null 2>&1 || true
112
+ else
113
+ redis-cli \
114
+ -h "${REDIS_HOST:-127.0.0.1}" \
115
+ -p "${REDIS_PORT:-6379}" \
116
+ -n "${REDIS_DB:-0}" \
117
+ SETEX "billing:balance:${user_id}" "$ttl" "$balance" >/dev/null 2>&1 || true
118
+ fi
119
+ done
120
+ }
121
+
122
+ start_balance_cache_sync() {
123
+ if [ "${BALANCE_CACHE_SYNC_ENABLED:-true}" != "true" ]; then
124
+ return 0
125
+ fi
126
+
127
+ (
128
+ interval="${BALANCE_CACHE_SYNC_INTERVAL_SECONDS:-60}"
129
+ while :; do
130
+ sync_balance_cache_once || true
131
+ sleep "$interval"
132
+ done
133
+ ) &
134
+ echo "Balance cache sync loop started."
135
+ }
136
+
137
+ write_runtime_config() {
138
+ cat >"$DATA_DIR/config.yaml" <<EOF
139
+ server:
140
+ host: "${SERVER_HOST}"
141
+ port: ${SERVER_PORT}
142
+ mode: "${SERVER_MODE}"
143
+ database:
144
+ host: "${DATABASE_HOST}"
145
+ port: ${DATABASE_PORT}
146
+ user: "${DATABASE_USER}"
147
+ password: "${DATABASE_PASSWORD}"
148
+ dbname: "${DATABASE_DBNAME}"
149
+ sslmode: "${DATABASE_SSLMODE}"
150
+ max_open_conns: ${DATABASE_MAX_OPEN_CONNS:-10}
151
+ max_idle_conns: ${DATABASE_MAX_IDLE_CONNS:-4}
152
+ conn_max_lifetime_minutes: ${DATABASE_CONN_MAX_LIFETIME_MINUTES:-10}
153
+ conn_max_idle_time_minutes: ${DATABASE_CONN_MAX_IDLE_TIME_MINUTES:-5}
154
+ redis:
155
+ host: "${REDIS_HOST}"
156
+ port: ${REDIS_PORT}
157
+ password: "${REDIS_PASSWORD:-}"
158
+ db: ${REDIS_DB:-0}
159
+ enable_tls: ${REDIS_ENABLE_TLS:-false}
160
+ jwt:
161
+ secret: "${JWT_SECRET}"
162
+ expire_hour: ${JWT_EXPIRE_HOUR:-24}
163
+ totp:
164
+ encryption_key: "${TOTP_ENCRYPTION_KEY}"
165
+ timezone: "${TZ:-Asia/Shanghai}"
166
+ default:
167
+ user_concurrency: 5
168
+ user_balance: 0
169
+ api_key_prefix: "sk-"
170
+ rate_multiplier: 1.0
171
+ rate_limit:
172
+ requests_per_minute: 60
173
+ burst_size: 10
174
+ gateway:
175
+ max_account_switches: ${GATEWAY_MAX_ACCOUNT_SWITCHES:-3}
176
+ max_account_switches_gemini: ${GATEWAY_MAX_ACCOUNT_SWITCHES_GEMINI:-2}
177
+ max_idle_conns: ${GATEWAY_MAX_IDLE_CONNS:-256}
178
+ max_idle_conns_per_host: ${GATEWAY_MAX_IDLE_CONNS_PER_HOST:-32}
179
+ max_conns_per_host: ${GATEWAY_MAX_CONNS_PER_HOST:-128}
180
+ max_upstream_clients: ${GATEWAY_MAX_UPSTREAM_CLIENTS:-256}
181
+ client_idle_ttl_seconds: ${GATEWAY_CLIENT_IDLE_TTL_SECONDS:-300}
182
+ stream_keepalive_interval: ${GATEWAY_STREAM_KEEPALIVE_INTERVAL:-5}
183
+ models_list_cache_ttl_seconds: ${GATEWAY_MODELS_LIST_CACHE_TTL_SECONDS:-30}
184
+ openai_http2:
185
+ enabled: ${OPENAI_HTTP2_ENABLED:-true}
186
+ allow_proxy_fallback_to_http1: ${OPENAI_HTTP2_ALLOW_PROXY_FALLBACK_TO_HTTP1:-true}
187
+ openai_ws:
188
+ max_conns_per_account: ${OPENAI_WS_MAX_CONNS_PER_ACCOUNT:-24}
189
+ min_idle_per_account: ${OPENAI_WS_MIN_IDLE_PER_ACCOUNT:-0}
190
+ max_idle_per_account: ${OPENAI_WS_MAX_IDLE_PER_ACCOUNT:-4}
191
+ event_flush_batch_size: ${OPENAI_WS_EVENT_FLUSH_BATCH_SIZE:-1}
192
+ event_flush_interval_ms: ${OPENAI_WS_EVENT_FLUSH_INTERVAL_MS:-5}
193
+ usage_record:
194
+ worker_count: ${USAGE_RECORD_WORKER_COUNT:-16}
195
+ queue_size: ${USAGE_RECORD_QUEUE_SIZE:-4096}
196
+ task_timeout_seconds: ${USAGE_RECORD_TASK_TIMEOUT_SECONDS:-15}
197
+ overflow_policy: "${USAGE_RECORD_OVERFLOW_POLICY:-sync}"
198
+ auto_scale_enabled: ${USAGE_RECORD_AUTO_SCALE_ENABLED:-false}
199
+ EOF
200
+ printf 'installed_at=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >"$DATA_DIR/.installed"
201
+ chown sub2api:sub2api "$DATA_DIR/config.yaml" "$DATA_DIR/.installed"
202
+ chmod 600 "$DATA_DIR/config.yaml"
203
+ chmod 400 "$DATA_DIR/.installed"
204
+ }
205
+
206
+ maybe_skip_auto_setup() {
207
+ if [ "${FORCE_RUNTIME_CONFIG:-false}" = "true" ]; then
208
+ write_runtime_config
209
+ export AUTO_SETUP=false
210
+ echo "Runtime config forced; skipping auto setup."
211
+ return 0
212
+ fi
213
+
214
+ if [ "${SKIP_AUTO_SETUP_WHEN_MIGRATED:-true}" != "true" ]; then
215
+ return 0
216
+ fi
217
+ if [ "$DATABASE_HOST" = "127.0.0.1" ]; then
218
+ return 0
219
+ fi
220
+
221
+ applied_count="$(migration_count | tr -d '[:space:]')"
222
+ case "$applied_count" in
223
+ ''|*[!0-9]*) applied_count=0 ;;
224
+ esac
225
+ required_count="${MIGRATION_BOOTSTRAP_MIN_COUNT:-178}"
226
+ echo "Detected applied migrations: ${applied_count}/${required_count}"
227
+ if [ "$applied_count" -ge "$required_count" ]; then
228
+ write_runtime_config
229
+ export AUTO_SETUP=false
230
+ echo "External database is already bootstrapped; skipping auto setup."
231
+ fi
232
+ return 0
233
+ }
234
+
235
+ sync_admin_password() {
236
+ if [ "${SYNC_ADMIN_PASSWORD:-true}" != "true" ]; then
237
+ return 0
238
+ fi
239
+
240
+ echo "Admin password sync loop started."
241
+ synced_dbs=""
242
+ candidate_dbs="$DATABASE_DBNAME"
243
+ if [ "$DATABASE_HOST" = "127.0.0.1" ]; then
244
+ candidate_dbs="$DATABASE_DBNAME postgres gatewaydb"
245
+ fi
246
+
247
+ for attempt in $(seq 1 15); do
248
+ password_hash="$(python3 - <<'PY'
249
+ import bcrypt
250
+ import os
251
+
252
+ print(bcrypt.hashpw(os.environ["ADMIN_PASSWORD"].encode("utf-8"), bcrypt.gensalt()).decode("utf-8"))
253
+ PY
254
+ )"
255
+ synced_count=0
256
+ for sync_dbname in $candidate_dbs; do
257
+ case " $synced_dbs " in
258
+ *" $sync_dbname "*) continue ;;
259
+ esac
260
+
261
+ table_exists="$(PGPASSWORD="${DATABASE_PASSWORD:-}" psql \
262
+ -h "$DATABASE_HOST" \
263
+ -p "$DATABASE_PORT" \
264
+ -U "$DATABASE_USER" \
265
+ -d "$sync_dbname" \
266
+ -tAc "select to_regclass('public.users') is not null;" 2>/tmp/admin-user-check.err || true)"
267
+ table_exists="$(printf '%s' "$table_exists" | tr -d '[:space:]')"
268
+ admin_count="$(PGPASSWORD="${DATABASE_PASSWORD:-}" psql \
269
+ -h "$DATABASE_HOST" \
270
+ -p "$DATABASE_PORT" \
271
+ -U "$DATABASE_USER" \
272
+ -d "$sync_dbname" \
273
+ -tAc "select count(1) from users where role = 'admin';" 2>/dev/null || true)"
274
+ admin_count="$(printf '%s' "$admin_count" | tr -d '[:space:]')"
275
+
276
+ if [ "$table_exists" = "t" ]; then
277
+ PGPASSWORD="${DATABASE_PASSWORD:-}" psql \
278
+ -h "$DATABASE_HOST" \
279
+ -p "$DATABASE_PORT" \
280
+ -U "$DATABASE_USER" \
281
+ -d "$sync_dbname" \
282
+ -v ON_ERROR_STOP=1 \
283
+ -c "update users set password_hash = '${password_hash}', role = 'admin', status = 'active', updated_at = now() where email = '${ADMIN_EMAIL}'; insert into users (email, password_hash, role, balance, concurrency, status, created_at, updated_at) select '${ADMIN_EMAIL}', '${password_hash}', 'admin', 0, 5, 'active', now(), now() where not exists (select 1 from users where email = '${ADMIN_EMAIL}');" >/tmp/admin-password-sync.out 2>/tmp/admin-password-sync.err
284
+
285
+ stored_hash="$(PGPASSWORD="${DATABASE_PASSWORD:-}" psql \
286
+ -h "$DATABASE_HOST" \
287
+ -p "$DATABASE_PORT" \
288
+ -U "$DATABASE_USER" \
289
+ -d "$sync_dbname" \
290
+ -tAc "select password_hash from users where role = 'admin' limit 1;" 2>/tmp/admin-password-verify.err || true)"
291
+ export STORED_ADMIN_PASSWORD_HASH="$stored_hash"
292
+ verify_result="$(python3 - <<'PY'
293
+ import bcrypt
294
+ import os
295
+
296
+ stored = os.environ.get("STORED_ADMIN_PASSWORD_HASH", "").strip()
297
+ password = os.environ["ADMIN_PASSWORD"].encode("utf-8")
298
+ print("ok" if stored and bcrypt.checkpw(password, stored.encode("utf-8")) else "failed")
299
+ PY
300
+ )"
301
+ echo "Admin password synchronized from HF secret in db=${sync_dbname}."
302
+ echo "Admin password bcrypt verification: ${verify_result}"
303
+ synced_dbs="$synced_dbs $sync_dbname"
304
+ synced_count=$((synced_count + 1))
305
+ fi
306
+ done
307
+ if [ -n "$(printf '%s' "$synced_dbs" | tr -d '[:space:]')" ] && [ "$attempt" -ge 5 ]; then
308
+ return 0
309
+ fi
310
+ sleep 2
311
+ done
312
+
313
+ echo "Admin password sync skipped: admin user not found before timeout." >&2
314
+ cat /tmp/admin-user-check.err >&2 || true
315
+ }
316
+
317
+ maybe_skip_auto_setup
318
+
319
+ start_balance_cache_sync
320
+
321
+ attempt=1
322
+ max_attempts="${BOOTSTRAP_MAX_ATTEMPTS:-6}"
323
+ while :; do
324
+ echo "Starting gateway on ${SERVER_HOST}:${SERVER_PORT} (attempt ${attempt}/${max_attempts})"
325
+ su-exec sub2api /app/hub-gateway &
326
+ app_pid="$!"
327
+ trap 'kill -TERM "$app_pid" 2>/dev/null || true' INT TERM
328
+ sync_admin_password &
329
+
330
+ set +e
331
+ wait "$app_pid"
332
+ app_status="$?"
333
+ set -e
334
+
335
+ if [ "$app_status" -eq 0 ]; then
336
+ exit 0
337
+ fi
338
+
339
+ if [ "$AUTO_SETUP" != "true" ] || [ "$DATABASE_HOST" = "127.0.0.1" ]; then
340
+ exit "$app_status"
341
+ fi
342
+
343
+ maybe_skip_auto_setup
344
+ if [ "$AUTO_SETUP" != "true" ]; then
345
+ attempt=$((attempt + 1))
346
+ continue
347
+ fi
348
+
349
+ if [ "$attempt" -ge "$max_attempts" ]; then
350
+ exit "$app_status"
351
+ fi
352
+
353
+ attempt=$((attempt + 1))
354
+ echo "Gateway exited during bootstrap; retrying to continue migrations."
355
+ sleep 2
356
+ done