Download deploy/docker-entrypoint.sh from cjovs/su2a: direct link, hf CLI and curl.
- Browser
- Download file 7.05 kB
-
https://huggingface.co/spaces/cjovs/su2a/resolve/main/deploy/docker-entrypoint.sh
- Command line
-
hf download hf://spaces/cjovs/su2a/deploy/docker-entrypoint.sh
-
curl -L -o docker-entrypoint.sh https://huggingface.co/spaces/cjovs/su2a/resolve/main/deploy/docker-entrypoint.sh
7.05 kB
| set -e | |
| PGDATA="/tmp/pgdata" | |
| PGUSER="postgres" | |
| PGPASS="postgres" | |
| PGDB="su2adb" | |
| REDIS_DIR="/tmp/redis" | |
| BUCKET_DUMP="hf://buckets/cjovs/su2a-data/su2adb_dump.sql" | |
| if [ "$(id -u)" = "0" ]; then | |
| mkdir -p /tmp/redis 2>/dev/null || true | |
| chown -R su2a:su2a /app/data 2>/dev/null & | |
| chown su2a:su2a /app 2>/dev/null || true | |
| sleep 2 | |
| kill %1 2>/dev/null || true | |
| exec su-exec su2a "$0" "$@" | |
| fi | |
| echo "=== Starting PostgreSQL ===" | |
| rm -f "$PGDATA/postmaster.pid" 2>/dev/null || true | |
| if [ ! -f "$PGDATA/PG_VERSION" ]; then | |
| echo "[pg] Initializing $PGDATA ..." | |
| initdb -D "$PGDATA" --username="$PGUSER" --auth=trust | |
| echo "host all all 127.0.0.1/32 trust" >> "$PGDATA/pg_hba.conf" | |
| echo "host all all ::1/128 trust" >> "$PGDATA/pg_hba.conf" | |
| fi | |
| pg_ctl -D "$PGDATA" -l "$PGDATA/logfile" -o "-k /tmp -p 5432" start | |
| until pg_isready -h localhost -p 5432 -U "$PGUSER" -q 2>/dev/null; do sleep 1; done | |
| echo "[pg] PostgreSQL ready." | |
| psql -h localhost -p 5432 -U "$PGUSER" -d postgres -c "ALTER USER $PGUSER WITH PASSWORD '$PGPASS';" 2>/dev/null || true | |
| if ! psql -h localhost -p 5432 -U "$PGUSER" -lqt 2>/dev/null | cut -d \| -f 1 | grep -qw "$PGDB"; then | |
| echo "[pg] Creating database $PGDB ..." | |
| createdb -h localhost -p 5432 -U "$PGUSER" "$PGDB" | |
| # Restore from bucket if dump exists | |
| if [ -n "$HF_TOKEN" ]; then | |
| echo "[pg] Checking bucket for backup..." | |
| if hf buckets list cjovs/su2a-data --quiet 2>/dev/null | grep -q "su2adb_dump.sql"; then | |
| echo "[pg] Restoring from bucket backup..." | |
| hf buckets cp "$BUCKET_DUMP" /tmp/restore.sql --quiet 2>/dev/null || true | |
| if [ -f /tmp/restore.sql ] && [ -s /tmp/restore.sql ]; then | |
| psql -h localhost -p 5432 -U "$PGUSER" -d "$PGDB" -f /tmp/restore.sql 2>/dev/null || true | |
| rm -f /tmp/restore.sql | |
| echo "[pg] Restore complete." | |
| fi | |
| fi | |
| fi | |
| fi | |
| echo "[pg] Database $PGDB ready." | |
| echo "=== Starting Redis ===" | |
| mkdir -p "$REDIS_DIR" 2>/dev/null || true | |
| redis-server --daemonize yes --dir "$REDIS_DIR" --save "" --port 6379 --bind 127.0.0.1 | |
| echo "[redis] Redis started." | |
| # === Auto-update: download latest binary from GitHub === | |
| echo "[update] Checking for latest version..." | |
| set +e | |
| python3 <<'PYEOF' | |
| import os, json, tarfile, io | |
| from urllib.request import Request, urlopen | |
| try: | |
| req = Request('https://api.github.com/repos/Wei-Shaw/sub2api/releases/latest') | |
| req.add_header('Accept', 'application/vnd.github.v3+json') | |
| req.add_header('User-Agent', 'Sub2API-AutoUpdater') | |
| with urlopen(req, timeout=30) as resp: | |
| release = json.loads(resp.read()) | |
| tag = release['tag_name'].lstrip('v') | |
| for asset in release.get('assets', []): | |
| name = asset.get('name', '') | |
| if 'linux_amd64' in name and name.endswith('.tar.gz'): | |
| url = asset['browser_download_url'] | |
| print(f'[update] v{tag} found, downloading {name} ...') | |
| req2 = Request(url) | |
| req2.add_header('User-Agent', 'Sub2API-AutoUpdater') | |
| with urlopen(req2, timeout=600) as resp: | |
| data = resp.read() | |
| with tarfile.open(fileobj=io.BytesIO(data), mode='r:gz') as tar: | |
| for member in tar: | |
| mname = member.name.rstrip('/') | |
| if mname == 'sub2api' or mname == './sub2api': | |
| f = tar.extractfile(member) | |
| if f: | |
| tmp = '/tmp/.su2a.new' | |
| with open(tmp, 'wb') as out: | |
| out.write(f.read()) | |
| os.chmod(tmp, 0o755) | |
| import shutil | |
| shutil.move(tmp, '/app/su2a') | |
| print(f'[update] Updated to v{tag}') | |
| exit(0) | |
| break | |
| print('[update] No matching linux_amd64 asset found') | |
| exit(1) | |
| except Exception as e: | |
| print(f'[update] Skipped: {e}') | |
| exit(1) | |
| PYEOF | |
| UPDATE_EXIT=$? | |
| set -e | |
| if [ $UPDATE_EXIT -eq 0 ]; then | |
| echo "[update] Running latest version" | |
| else | |
| echo "[update] Running built-in version (will retry next restart)" | |
| fi | |
| cleanup() { | |
| echo "=== Shutting down ===" | |
| redis-cli -h 127.0.0.1 -p 6379 shutdown 2>/dev/null || true | |
| # Backup database to bucket | |
| if [ -n "$HF_TOKEN" ]; then | |
| echo "[pg] Backing up database to bucket..." | |
| pg_dump -h localhost -p 5432 -U "$PGUSER" -d "$PGDB" --no-owner --no-acl -f /tmp/su2adb_dump.sql 2>/dev/null || true | |
| if [ -f /tmp/su2adb_dump.sql ] && [ -s /tmp/su2adb_dump.sql ]; then | |
| hf buckets cp /tmp/su2adb_dump.sql "$BUCKET_DUMP" --quiet 2>/dev/null || true | |
| echo "[pg] Backup uploaded." | |
| fi | |
| fi | |
| pg_ctl -D "$PGDATA" stop -m fast 2>/dev/null || true | |
| } | |
| trap cleanup EXIT INT TERM | |
| export DATABASE_DBNAME="$PGDB" | |
| # Override config via env vars to bypass FUSE read corruption | |
| export DATABASE_HOST=localhost | |
| export DATABASE_PORT=5432 | |
| export DATABASE_USER="$PGUSER" | |
| export DATABASE_PASSWORD="$PGPASS" | |
| export DATABASE_SSLMODE=disable | |
| export REDIS_HOST=localhost | |
| export REDIS_PORT=6379 | |
| export REDIS_DB=0 | |
| export REDIS_ENABLE_TLS=false | |
| export SERVER_HOST=0.0.0.0 | |
| export SERVER_PORT=8080 | |
| export SERVER_MODE=release | |
| export JWT_SECRET=e32467771e531062d2b2d68919e7430e60c32f0f0381320ed068cd6d61435e9c | |
| export JWT_EXPIRE_HOUR=24 | |
| echo "=== Starting su2a ===" | |
| while true; do | |
| echo "[su2a] Starting..." | |
| /app/su2a "$@" & | |
| PID=$! | |
| # On fresh DB: wait for tables then create admin user | |
| if [ ! -f /tmp/.init_done ] && [ -n "$ADMIN_EMAIL" ] && [ -n "$ADMIN_PASSWORD" ]; then | |
| for i in $(seq 1 30); do | |
| if psql -h localhost -p 5432 -U "$PGUSER" -d "$PGDB" -c "SELECT 1 FROM users LIMIT 1" >/dev/null 2>&1; then | |
| echo "[init] Tables ready, creating admin user..." | |
| pip3 install --no-cache-dir --break-system-packages -q bcrypt 2>/dev/null | |
| python3 -c " | |
| import os, bcrypt, subprocess | |
| email = os.environ['ADMIN_EMAIL'] | |
| password = os.environ['ADMIN_PASSWORD'] | |
| hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode() | |
| sql = f\"\"\"INSERT INTO users (email, password_hash, role, status, balance, concurrency, signup_source) | |
| VALUES ('{email}', '{hashed}', 'admin', 'active', 0, 5, 'email') | |
| ON CONFLICT (email) WHERE deleted_at IS NULL | |
| DO UPDATE SET password_hash = EXCLUDED.password_hash, role = 'admin'\"\"\" | |
| r = subprocess.run(['psql', '-h', 'localhost', '-p', '5432', '-U', 'postgres', '-d', 'su2adb', '-c', sql], capture_output=True, text=True) | |
| if r.returncode == 0: | |
| print('[init] Admin user created: ' + email) | |
| else: | |
| print('[init] ERROR creating admin: ' + r.stderr.strip()) | |
| " | |
| touch /tmp/.init_done | |
| break | |
| fi | |
| sleep 2 | |
| done | |
| fi | |
| wait $PID | |
| echo "[su2a] Exited, restarting in 2s..." | |
| sleep 2 | |
| done |