Spaces:
Running
Running
| FROM decolua/9router:latest | |
| # 1. Switch to root to install system packages | |
| USER root | |
| # 2. Install Python for the backup script | |
| RUN apk add --no-cache python3 py3-pip tar \ | |
| && pip3 install --break-system-packages --no-cache-dir huggingface_hub | |
| WORKDIR /app | |
| # 3. Create the Python sync script | |
| RUN cat > /app/sync.py <<'PY' | |
| import os | |
| import tarfile | |
| import time | |
| import sys | |
| from pathlib import Path | |
| from huggingface_hub import HfApi, hf_hub_download | |
| REPO_ID = os.environ.get("DATASET_REPO") | |
| TOKEN = os.environ.get("HF_TOKEN") | |
| BACKUP_FILE = "/tmp/9router_backup.tar.gz" | |
| DATA_DIR = Path("/app/data") | |
| def safe_extract(tar, path): | |
| base = Path(path).resolve() | |
| for member in tar.getmembers(): | |
| target = (base / member.name).resolve() | |
| if not str(target).startswith(str(base)): | |
| raise RuntimeError(f"Unsafe tar member: {member.name}") | |
| tar.extractall(path) | |
| def upload(): | |
| if not REPO_ID or not TOKEN: | |
| print(">>> [Sync] DATASET_REPO or HF_TOKEN not configured. Skipping backup.") | |
| return | |
| if not DATA_DIR.exists(): | |
| print(">>> [Sync] Data directory does not exist. Skipping backup.") | |
| return | |
| try: | |
| with tarfile.open(BACKUP_FILE, "w:gz") as tar: | |
| # We pack the /app/data folder as 'data' | |
| tar.add(str(DATA_DIR), arcname="data") | |
| HfApi(token=TOKEN).upload_file( | |
| path_or_fileobj=BACKUP_FILE, | |
| path_in_repo="9router_backup.tar.gz", | |
| repo_id=REPO_ID, | |
| repo_type="dataset", | |
| ) | |
| print(f">>> [Sync] Backup successful: {time.strftime('%Y-%m-%d %H:%M:%S')}", flush=True) | |
| except Exception as e: | |
| print(f">>> [Sync] Backup failed: {e}", flush=True) | |
| def download(): | |
| if not REPO_ID or not TOKEN: | |
| print(">>> [Sync] DATASET_REPO or HF_TOKEN not configured. Skipping restore.") | |
| return | |
| try: | |
| print(">>> [Sync] Downloading data from Dataset...", flush=True) | |
| path = hf_hub_download( | |
| repo_id=REPO_ID, | |
| filename="9router_backup.tar.gz", | |
| repo_type="dataset", | |
| token=TOKEN, | |
| ) | |
| with tarfile.open(path, "r:gz") as tar: | |
| # Extracting into /app will perfectly place it at /app/data | |
| safe_extract(tar, "/app") | |
| print(">>> [Sync] Data restore successful.", flush=True) | |
| except Exception as e: | |
| print(f">>> [Sync] Skipping restore (might be first run): {e}", flush=True) | |
| if __name__ == "__main__": | |
| if len(sys.argv) > 1 and sys.argv[1] == "upload": | |
| upload() | |
| elif len(sys.argv) > 1 and sys.argv[1] == "download": | |
| download() | |
| PY | |
| # 4. Create the startup shell script | |
| RUN cat > /app/run.sh <<'SH' | |
| #!/bin/sh | |
| set -e | |
| echo '=== 0. Resetting Local Data ===' | |
| mkdir -p /app/data | |
| echo '=== 1. Restoring Data ===' | |
| python3 /app/sync.py download | |
| echo '=== 2. Starting Scheduled Backup (Every 10 minutes) ===' | |
| (while true; do sleep 600; python3 /app/sync.py upload; done) & | |
| echo '=== 3. Starting 9router ===' | |
| export PORT=7860 | |
| export HOSTNAME=0.0.0.0 | |
| export DATA_DIR=/app/data | |
| export NEXT_PUBLIC_BASE_URL="https://${SPACE_HOST:-otnansirk-9router.hf.space}" | |
| echo '=== Checking 9router files ===' | |
| pwd | |
| ls -la | |
| node -e "console.log(require('./package.json').version)" || true | |
| cat package.json | grep version || true | |
| echo '=== 3. Starting 9router ===' | |
| exec node server.js | |
| SH | |
| RUN chmod +x /app/run.sh | |
| EXPOSE 7860 | |
| CMD ["/bin/sh", "/app/run.sh"] | |