Murasame52 commited on
Commit
f5a618e
·
verified ·
1 Parent(s): d7b846b

Update start-space.sh

Browse files
Files changed (1) hide show
  1. start-space.sh +107 -30
start-space.sh CHANGED
@@ -12,11 +12,73 @@ else
12
  fi
13
 
14
  # ============================================================
15
- # 2. 数据库连接解析:优先使用 DATABASE_URL
16
  # ============================================================
17
- if [ -n "${DATABASE_URL:-}" ]; then
18
- echo "DATABASE_URL provided, parsing..."
19
- # 使用 Python 解析标准 PostgreSQL URI
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  eval $(python3 -c "
21
  import os, urllib.parse
22
  url = os.environ['DATABASE_URL']
@@ -35,22 +97,27 @@ print(f'export DATABASE_PASSWORD={password}')
35
  print(f'export DATABASE_DBNAME={dbname}')
36
  print(f'export DATABASE_SSLMODE={sslmode}')
37
  ")
38
- echo "Parsed: DATABASE_HOST=$DATABASE_HOST, DATABASE_DBNAME=$DATABASE_DBNAME"
39
  else
40
- echo "DATABASE_URL not set, expecting individual DATABASE_* variables."
 
41
  fi
42
 
43
- # 检查必需的数据库变量(无论从何处获得)
 
 
44
  required_db_vars="DATABASE_HOST DATABASE_PORT DATABASE_USER DATABASE_DBNAME"
45
  for var in $required_db_vars; do
46
  eval "val=\${$var:-}"
47
  if [ -z "$val" ]; then
48
- echo "Missing required database variable: $var. Please set DATABASE_URL or all individual DATABASE_* vars." >&2
49
  exit 1
50
  fi
51
  done
52
 
53
- # 检查其他必需密钥
 
 
54
  required_vars="ADMIN_PASSWORD JWT_SECRET TOTP_ENCRYPTION_KEY"
55
  for var in $required_vars; do
56
  eval "val=\${$var:-}"
@@ -61,25 +128,28 @@ for var in $required_vars; do
61
  done
62
 
63
  # ============================================================
64
- # 3. 默认值设置
65
  # ============================================================
66
  ADMIN_EMAIL="${ADMIN_EMAIL:-2691539771@qq.com}"
67
  SERVER_PORT="${SERVER_PORT:-7860}"
68
  DATA_DIR="${DATA_DIR:-/tmp/gateway-data}"
69
- DATABASE_SSLMODE="${DATABASE_SSLMODE:-require}" # Xata 强制 SSL
 
70
  REDIS_HOST="${REDIS_HOST:-127.0.0.1}"
71
  REDIS_PORT="${REDIS_PORT:-6379}"
72
  REDIS_PASSWORD="${REDIS_PASSWORD:-}"
73
  REDIS_DB="${REDIS_DB:-0}"
74
 
75
  # ============================================================
76
- # 4. 创建目录(无需 postgres 用户
77
  # ============================================================
78
  mkdir -p "$DATA_DIR" /tmp/gateway-redis
 
 
79
  chown -R sub2api:sub2api "$DATA_DIR" /tmp/gateway-redis
80
 
81
  # ============================================================
82
- # 5. 启动 Redis
83
  # ============================================================
84
  echo "Starting Redis on ${REDIS_HOST}:${REDIS_PORT}..."
85
  redis-server --daemonize yes \
@@ -90,7 +160,6 @@ redis-server --daemonize yes \
90
  --appendonly no \
91
  ${REDIS_PASSWORD:+--requirepass "$REDIS_PASSWORD"}
92
 
93
- # 等待 Redis 就绪
94
  echo "Waiting for Redis..."
95
  while ! redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" ${REDIS_PASSWORD:+-a "$REDIS_PASSWORD"} ping >/dev/null 2>&1; do
96
  sleep 1
@@ -98,7 +167,7 @@ done
98
  echo "Redis is ready."
99
 
100
  # ============================================================
101
- # 6. 导出环境变量供子进程使用
102
  # ============================================================
103
  export AUTO_SETUP="${AUTO_SETUP:-true}"
104
  export ADMIN_EMAIL ADMIN_PASSWORD JWT_SECRET TOTP_ENCRYPTION_KEY
@@ -107,10 +176,11 @@ export DATABASE_HOST DATABASE_PORT DATABASE_USER DATABASE_PASSWORD DATABASE_DBNA
107
  export REDIS_HOST REDIS_PORT REDIS_PASSWORD REDIS_DB
108
  export SERVER_HOST="${SERVER_HOST:-0.0.0.0}" SERVER_PORT
109
  export SERVER_MODE="${SERVER_MODE:-release}"
110
- export PORT="${PORT:-$SERVER_PORT}" GIN_MODE="${GIN_MODE:-release}"
 
111
 
112
  # ============================================================
113
- # 7. 辅助函数(完全保留原始逻辑,使用外部数据库
114
  # ============================================================
115
  migration_count() {
116
  PGPASSWORD="${DATABASE_PASSWORD:-}" psql \
@@ -134,7 +204,10 @@ sync_balance_cache_once() {
134
  start_balance_cache_sync() {
135
  [ "${BALANCE_CACHE_SYNC_ENABLED:-true}" != "true" ] && return 0
136
  ( interval="${BALANCE_CACHE_SYNC_INTERVAL_SECONDS:-60}"
137
- while :; do sync_balance_cache_once || true; sleep "$interval"; done ) &
 
 
 
138
  echo "Balance cache sync loop started."
139
  }
140
 
@@ -166,7 +239,7 @@ jwt:
166
  expire_hour: ${JWT_EXPIRE_HOUR:-24}
167
  totp:
168
  encryption_key: "${TOTP_ENCRYPTION_KEY}"
169
- timezone: "${TZ:-Asia/Shanghai}"
170
  default:
171
  user_concurrency: 5
172
  user_balance: 0
@@ -194,12 +267,12 @@ gateway:
194
  max_idle_per_account: ${OPENAI_WS_MAX_IDLE_PER_ACCOUNT:-4}
195
  event_flush_batch_size: ${OPENAI_WS_EVENT_FLUSH_BATCH_SIZE:-1}
196
  event_flush_interval_ms: ${OPENAI_WS_EVENT_FLUSH_INTERVAL_MS:-5}
197
- usage_record:
198
- worker_count: ${USAGE_RECORD_WORKER_COUNT:-16}
199
- queue_size: ${USAGE_RECORD_QUEUE_SIZE:-4096}
200
- task_timeout_seconds: ${USAGE_RECORD_TASK_TIMEOUT_SECONDS:-15}
201
- overflow_policy: "${USAGE_RECORD_OVERFLOW_POLICY:-sync}"
202
- auto_scale_enabled: ${USAGE_RECORD_AUTO_SCALE_ENABLED:-false}
203
  EOF
204
  printf 'installed_at=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >"$DATA_DIR/.installed"
205
  chown sub2api:sub2api "$DATA_DIR/config.yaml" "$DATA_DIR/.installed"
@@ -208,7 +281,12 @@ EOF
208
  }
209
 
210
  maybe_skip_auto_setup() {
211
- [ "${FORCE_RUNTIME_CONFIG:-false}" = "true" ] && { write_runtime_config; export AUTO_SETUP=false; echo "Runtime config forced; skipping auto setup."; return 0; }
 
 
 
 
 
212
  [ "${SKIP_AUTO_SETUP_WHEN_MIGRATED:-true}" != "true" ] && return 0
213
  applied_count="$(migration_count | tr -d '[:space:]')"
214
  case "$applied_count" in ''|*[!0-9]*) applied_count=0 ;; esac
@@ -229,13 +307,13 @@ sync_admin_password() {
229
  import bcrypt, os
230
  print(bcrypt.hashpw(os.environ["ADMIN_PASSWORD"].encode("utf-8"), bcrypt.gensalt()).decode("utf-8"))
231
  PY
232
- )"
233
  table_exists="$(PGPASSWORD="${DATABASE_PASSWORD:-}" psql -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USER" -d "$DATABASE_DBNAME" -tAc "select to_regclass('public.users') is not null;" 2>/tmp/admin-user-check.err || true)"
234
  table_exists="$(printf '%s' "$table_exists" | tr -d '[:space:]')"
235
  if [ "$table_exists" = "t" ]; then
236
  PGPASSWORD="${DATABASE_PASSWORD:-}" psql -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USER" -d "$DATABASE_DBNAME" -v ON_ERROR_STOP=1 \
237
  -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
238
- echo "Admin password synchronized from HF secret."
239
  return 0
240
  fi
241
  sleep 2
@@ -244,7 +322,7 @@ PY
244
  }
245
 
246
  # ============================================================
247
- # 8. 主流程
248
  # ============================================================
249
  maybe_skip_auto_setup
250
  start_balance_cache_sync
@@ -258,7 +336,6 @@ while :; do
258
  trap 'kill -TERM "$app_pid" 2>/dev/null || true' INT TERM
259
 
260
  sync_admin_password &
261
-
262
  set +e
263
  wait "$app_pid"
264
  app_status="$?"
 
12
  fi
13
 
14
  # ============================================================
15
+ # 2. 自部署 PostgreSQL 初始化与启动(新增)
16
  # ============================================================
17
+ init_postgres() {
18
+ echo "Initializing and starting self-deployed PostgreSQL..."
19
+
20
+ # 如果数据目录不存在,则执行初始化
21
+ if [ ! -d "$PGDATA" ]; then
22
+ echo "PostgreSQL data directory not found, initializing..."
23
+ mkdir -p "$PGDATA"
24
+ chown postgres:postgres "$PGDATA"
25
+ # 使用 initdb 初始化,设置密码认证方式为 scram-sha-256
26
+ su-exec postgres initdb -D "$PGDATA" --auth=scram-sha-256 --pwfile=<(echo "$POSTGRES_PASSWORD")
27
+ fi
28
+
29
+ # 修改 postgresql.conf:仅监听本地,使用默认端口 5432
30
+ echo "listen_addresses = 'localhost'" >> "$PGDATA/postgresql.conf"
31
+ echo "port = 5432" >> "$PGDATA/postgresql.conf"
32
+ # 允许本地 socket 连接
33
+ echo "unix_socket_directories = '/tmp'" >> "$PGDATA/postgresql.conf"
34
+
35
+ # 启动 PostgreSQL 服务
36
+ echo "Starting PostgreSQL daemon..."
37
+ su-exec postgres pg_ctl -D "$PGDATA" -o "-c unix_socket_directories=/tmp" start
38
+
39
+ # 等待 PostgreSQL 就绪
40
+ echo "Waiting for PostgreSQL to accept connections..."
41
+ for i in $(seq 1 30); do
42
+ if su-exec postgres pg_isready -U postgres -h localhost -p 5432 >/dev/null 2>&1; then
43
+ echo "PostgreSQL is ready."
44
+ break
45
+ fi
46
+ sleep 1
47
+ done
48
+
49
+ # 创建应用用户和数据库(如果不存在)
50
+ echo "Ensuring application user and database exist..."
51
+ su-exec postgres psql -v ON_ERROR_STOP=1 --username postgres <<-EOSQL
52
+ DO \$\$
53
+ BEGIN
54
+ IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '$POSTGRES_USER') THEN
55
+ CREATE ROLE $POSTGRES_USER WITH LOGIN PASSWORD '$POSTGRES_PASSWORD';
56
+ END IF;
57
+ END
58
+ \$\$;
59
+ SELECT 'CREATE DATABASE $POSTGRES_DB OWNER $POSTGRES_USER'
60
+ WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '$POSTGRES_DB')\gexec
61
+ EOSQL
62
+
63
+ # 设置 DATABASE_URL 及拆分变量,指向本地 PostgreSQL(不启用 SSL)
64
+ export DATABASE_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?sslmode=disable"
65
+ export DATABASE_HOST=localhost
66
+ export DATABASE_PORT=5432
67
+ export DATABASE_USER=$POSTGRES_USER
68
+ export DATABASE_PASSWORD=$POSTGRES_PASSWORD
69
+ export DATABASE_DBNAME=$POSTGRES_DB
70
+ export DATABASE_SSLMODE=disable
71
+
72
+ echo "PostgreSQL self-deployment ready. DATABASE_URL set to local instance."
73
+ }
74
+
75
+ # ============================================================
76
+ # 3. 原有数据库连接解析(若用户提供了外部 DATABASE_URL,则覆盖本地)
77
+ # ============================================================
78
+ if [ -n "${EXTERNAL_DATABASE_URL:-}" ]; then
79
+ echo "EXTERNAL_DATABASE_URL provided, using external database instead of self-deployed."
80
+ # 使用外部连接,覆盖本地设置
81
+ export DATABASE_URL="$EXTERNAL_DATABASE_URL"
82
  eval $(python3 -c "
83
  import os, urllib.parse
84
  url = os.environ['DATABASE_URL']
 
97
  print(f'export DATABASE_DBNAME={dbname}')
98
  print(f'export DATABASE_SSLMODE={sslmode}')
99
  ")
100
+ echo "Parsed external database: DATABASE_HOST=$DATABASE_HOST, DATABASE_DBNAME=$DATABASE_DBNAME"
101
  else
102
+ # 否则使用自部署 PostgreSQL
103
+ init_postgres
104
  fi
105
 
106
+ # ============================================================
107
+ # 4. 检查必需的数据库变量(无论来源)
108
+ # ============================================================
109
  required_db_vars="DATABASE_HOST DATABASE_PORT DATABASE_USER DATABASE_DBNAME"
110
  for var in $required_db_vars; do
111
  eval "val=\${$var:-}"
112
  if [ -z "$val" ]; then
113
+ echo "Missing required database variable: $var. Please set DATABASE_URL or EXTERNAL_DATABASE_URL." >&2
114
  exit 1
115
  fi
116
  done
117
 
118
+ # ============================================================
119
+ # 5. 检查其他必需密钥
120
+ # ============================================================
121
  required_vars="ADMIN_PASSWORD JWT_SECRET TOTP_ENCRYPTION_KEY"
122
  for var in $required_vars; do
123
  eval "val=\${$var:-}"
 
128
  done
129
 
130
  # ============================================================
131
+ # 6. 默认值设置
132
  # ============================================================
133
  ADMIN_EMAIL="${ADMIN_EMAIL:-2691539771@qq.com}"
134
  SERVER_PORT="${SERVER_PORT:-7860}"
135
  DATA_DIR="${DATA_DIR:-/tmp/gateway-data}"
136
+ # 如果使用自部署,SSL 模式已经设为 disable,此处作为后备
137
+ DATABASE_SSLMODE="${DATABASE_SSLMODE:-require}"
138
  REDIS_HOST="${REDIS_HOST:-127.0.0.1}"
139
  REDIS_PORT="${REDIS_PORT:-6379}"
140
  REDIS_PASSWORD="${REDIS_PASSWORD:-}"
141
  REDIS_DB="${REDIS_DB:-0}"
142
 
143
  # ============================================================
144
+ # 7. 创建目录(包括 PostgreSQL 数据目录的父目录
145
  # ============================================================
146
  mkdir -p "$DATA_DIR" /tmp/gateway-redis
147
+ # 如果 PGDATA 的父目录不存在,则创建(例如 /var/lib/postgresql)
148
+ mkdir -p "$(dirname "$PGDATA")"
149
  chown -R sub2api:sub2api "$DATA_DIR" /tmp/gateway-redis
150
 
151
  # ============================================================
152
+ # 8. 启动 Redis(与之前相同)
153
  # ============================================================
154
  echo "Starting Redis on ${REDIS_HOST}:${REDIS_PORT}..."
155
  redis-server --daemonize yes \
 
160
  --appendonly no \
161
  ${REDIS_PASSWORD:+--requirepass "$REDIS_PASSWORD"}
162
 
 
163
  echo "Waiting for Redis..."
164
  while ! redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" ${REDIS_PASSWORD:+-a "$REDIS_PASSWORD"} ping >/dev/null 2>&1; do
165
  sleep 1
 
167
  echo "Redis is ready."
168
 
169
  # ============================================================
170
+ # 9. 导出环境变量供子进程使用
171
  # ============================================================
172
  export AUTO_SETUP="${AUTO_SETUP:-true}"
173
  export ADMIN_EMAIL ADMIN_PASSWORD JWT_SECRET TOTP_ENCRYPTION_KEY
 
176
  export REDIS_HOST REDIS_PORT REDIS_PASSWORD REDIS_DB
177
  export SERVER_HOST="${SERVER_HOST:-0.0.0.0}" SERVER_PORT
178
  export SERVER_MODE="${SERVER_MODE:-release}"
179
+ export PORT="${PORT:-$SERVER_PORT}"
180
+ GIN_MODE="${GIN_MODE:-release}"
181
 
182
  # ============================================================
183
+ # 10. 辅助函数(完全保留原始逻辑)
184
  # ============================================================
185
  migration_count() {
186
  PGPASSWORD="${DATABASE_PASSWORD:-}" psql \
 
204
  start_balance_cache_sync() {
205
  [ "${BALANCE_CACHE_SYNC_ENABLED:-true}" != "true" ] && return 0
206
  ( interval="${BALANCE_CACHE_SYNC_INTERVAL_SECONDS:-60}"
207
+ while :; do
208
+ sync_balance_cache_once || true
209
+ sleep "$interval"
210
+ done ) &
211
  echo "Balance cache sync loop started."
212
  }
213
 
 
239
  expire_hour: ${JWT_EXPIRE_HOUR:-24}
240
  totp:
241
  encryption_key: "${TOTP_ENCRYPTION_KEY}"
242
+ timezone: "${TZ:-Asia/Shanghai}"
243
  default:
244
  user_concurrency: 5
245
  user_balance: 0
 
267
  max_idle_per_account: ${OPENAI_WS_MAX_IDLE_PER_ACCOUNT:-4}
268
  event_flush_batch_size: ${OPENAI_WS_EVENT_FLUSH_BATCH_SIZE:-1}
269
  event_flush_interval_ms: ${OPENAI_WS_EVENT_FLUSH_INTERVAL_MS:-5}
270
+ usage_record:
271
+ worker_count: ${USAGE_RECORD_WORKER_COUNT:-16}
272
+ queue_size: ${USAGE_RECORD_QUEUE_SIZE:-4096}
273
+ task_timeout_seconds: ${USAGE_RECORD_TASK_TIMEOUT_SECONDS:-15}
274
+ overflow_policy: "${USAGE_RECORD_OVERFLOW_POLICY:-sync}"
275
+ auto_scale_enabled: ${USAGE_RECORD_AUTO_SCALE_ENABLED:-false}
276
  EOF
277
  printf 'installed_at=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >"$DATA_DIR/.installed"
278
  chown sub2api:sub2api "$DATA_DIR/config.yaml" "$DATA_DIR/.installed"
 
281
  }
282
 
283
  maybe_skip_auto_setup() {
284
+ [ "${FORCE_RUNTIME_CONFIG:-false}" = "true" ] && {
285
+ write_runtime_config
286
+ export AUTO_SETUP=false
287
+ echo "Runtime config forced; skipping auto setup."
288
+ return 0
289
+ }
290
  [ "${SKIP_AUTO_SETUP_WHEN_MIGRATED:-true}" != "true" ] && return 0
291
  applied_count="$(migration_count | tr -d '[:space:]')"
292
  case "$applied_count" in ''|*[!0-9]*) applied_count=0 ;; esac
 
307
  import bcrypt, os
308
  print(bcrypt.hashpw(os.environ["ADMIN_PASSWORD"].encode("utf-8"), bcrypt.gensalt()).decode("utf-8"))
309
  PY
310
+ )"
311
  table_exists="$(PGPASSWORD="${DATABASE_PASSWORD:-}" psql -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USER" -d "$DATABASE_DBNAME" -tAc "select to_regclass('public.users') is not null;" 2>/tmp/admin-user-check.err || true)"
312
  table_exists="$(printf '%s' "$table_exists" | tr -d '[:space:]')"
313
  if [ "$table_exists" = "t" ]; then
314
  PGPASSWORD="${DATABASE_PASSWORD:-}" psql -h "$DATABASE_HOST" -p "$DATABASE_PORT" -U "$DATABASE_USER" -d "$DATABASE_DBNAME" -v ON_ERROR_STOP=1 \
315
  -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
316
+ echo "Admin password synchronized from secret."
317
  return 0
318
  fi
319
  sleep 2
 
322
  }
323
 
324
  # ============================================================
325
+ # 11. 主流程
326
  # ============================================================
327
  maybe_skip_auto_setup
328
  start_balance_cache_sync
 
336
  trap 'kill -TERM "$app_pid" 2>/dev/null || true' INT TERM
337
 
338
  sync_admin_password &
 
339
  set +e
340
  wait "$app_pid"
341
  app_status="$?"