GemmaE4B / setup-cloudflare.py
Doom01's picture
Update setup-cloudflare.py
68d6089 verified
Raw
History Blame Contribute Delete
7.86 kB
"""
Deploys two Cloudflare Workers:
1. Keep-alive cron worker β€” pings the HF Space every 4 minutes
2. Telegram proxy worker β€” forwards Telegram API calls
"""
import os, json, requests, time
ACCOUNT_ID = os.environ.get("CLOUDFLARE_ACCOUNT_ID")
CF_TOKEN = os.environ.get("CLOUDFLARE_WORKERS_TOKEN")
SPACE_URL = os.environ.get("SPACE_URL", "https://your-space.hf.space")
BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN", "")
GATEWAY_TOKEN = os.environ.get("GATEWAY_TOKEN", "changeme")
AUTH_HEADERS = {"Authorization": f"Bearer {CF_TOKEN}"}
# ── 1. Keep-alive Worker Script ───────────────────────────────────────────────
KEEPALIVE_SCRIPT = f"""
addEventListener('scheduled', event => {{
event.waitUntil(handleScheduled());
}});
async function handleScheduled() {{
const url = '{SPACE_URL}/health';
try {{
const res = await fetch(url, {{ method: 'GET' }});
console.log('[keep-alive]', new Date().toISOString(), res.status);
}} catch (e) {{
console.error('[keep-alive] failed:', e.message);
}}
}}
"""
# ── 2. Telegram Proxy Worker Script ───────────────────────────────────────────
TELEGRAM_PROXY_SCRIPT = """
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const url = new URL(request.url);
const target = 'https://api.telegram.org' + url.pathname + url.search;
const newReq = new Request(target, {
method: request.method,
headers: request.headers,
body: request.method !== 'GET' && request.method !== 'HEAD'
? request.body : undefined
});
const response = await fetch(newReq);
// Pass response back with CORS headers
const newHeaders = new Headers(response.headers);
newHeaders.set('Access-Control-Allow-Origin', '*');
return new Response(response.body, {
status: response.status,
headers: newHeaders
});
}
"""
def get_subdomain():
"""Get the workers.dev subdomain for this account."""
resp = requests.get(
f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/workers/subdomain",
headers=AUTH_HEADERS
)
data = resp.json()
if data.get("success"):
return data["result"]["subdomain"]
return None
def deploy_worker(name, script):
"""
Deploy a Worker script using the correct multipart format.
Cloudflare requires TWO parts:
- 'metadata' : JSON describing the script
- 'script' : The actual JS content
"""
url = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/workers/scripts/{name}"
# ── CRITICAL: metadata part is REQUIRED ──────────────────────────────────
metadata = {
"body_part" : "script", # tells CF which part contains the code
"bindings" : [], # no KV / D1 / R2 bindings needed
"compatibility_date": "2024-01-01"
}
resp = requests.put(
url,
headers=AUTH_HEADERS, # NO Content-Type here β€” requests sets it for multipart
files={
"metadata": ( # part name must be "metadata"
"metadata.json",
json.dumps(metadata),
"application/json"
),
"script": ( # part name must match body_part value above
"worker.js",
script,
"application/javascript"
)
}
)
result = resp.json()
if result.get("success"):
print(f"βœ… Worker '{name}' deployed successfully")
return True
else:
print(f"❌ Failed to deploy '{name}': {result.get('errors')}")
return False
def set_cron(name, cron_expression):
"""Attach a cron trigger to an existing worker."""
url = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/workers/scripts/{name}/schedules"
resp = requests.put(
url,
headers={**AUTH_HEADERS, "Content-Type": "application/json"},
json=[{"cron": cron_expression}]
)
result = resp.json()
if result.get("success"):
print(f" ⏰ Cron trigger set: {cron_expression}")
return True
else:
print(f" ⚠️ Cron setup failed: {result.get('errors')}")
return False
def enable_workers_dev_route(name):
"""Enable the workers.dev route so the worker has a public URL."""
url = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/workers/scripts/{name}/subdomain"
resp = requests.post(
url,
headers={**AUTH_HEADERS, "Content-Type": "application/json"},
json={"enabled": True}
)
result = resp.json()
if result.get("success"):
print(f" 🌐 workers.dev route enabled")
return True
else:
# Not fatal β€” worker still works, just no public URL
print(f" ⚠️ Could not enable workers.dev route: {result.get('errors')}")
return False
def set_telegram_webhook(proxy_url):
"""Point Telegram webhook at our HF Space β€” via Cloudflare proxy."""
if not BOT_TOKEN:
print(" ⚠️ TELEGRAM_BOT_TOKEN not set β€” skipping webhook")
return
if not proxy_url:
print(" ⚠️ No proxy_url provided β€” skipping webhook")
return
webhook_url = f"{SPACE_URL}/telegram"
# βœ… Route through Cloudflare proxy instead of calling api.telegram.org directly
# Your proxy worker forwards: proxy_url/bot<TOKEN>/setWebhook β†’ api.telegram.org/bot<TOKEN>/setWebhook
resp = requests.get(
f"{proxy_url}/bot{BOT_TOKEN}/setWebhook", # ← goes to Cloudflare Worker
params={"url": webhook_url},
timeout=30
)
try:
data = resp.json()
if data.get("ok"):
print(f" πŸ“‘ Telegram webhook set β†’ {webhook_url}")
else:
print(f" ⚠️ Webhook set failed: {data}")
except Exception as e:
print(f" ❌ Failed to parse webhook response: {e}")
print(f" Raw response: {resp.text}")
if __name__ == "__main__":
if not ACCOUNT_ID or not CF_TOKEN:
print("⚠️ CLOUDFLARE_ACCOUNT_ID or CLOUDFLARE_WORKERS_TOKEN not set β€” skipping")
exit(0)
print("☁️ Deploying Cloudflare Workers...")
# ── Deploy keep-alive worker ──────────────────────────────────────────────
if deploy_worker("llm-space-keepalive", KEEPALIVE_SCRIPT):
set_cron("llm-space-keepalive", "*/4 * * * *")
# ── Deploy Telegram proxy worker ──────────────────────────────────────────
if deploy_worker("llm-space-telegram-proxy", TELEGRAM_PROXY_SCRIPT):
enable_workers_dev_route("llm-space-telegram-proxy")
# Build the proxy public URL
subdomain = get_subdomain()
if subdomain:
proxy_url = f"https://llm-space-telegram-proxy.{subdomain}.workers.dev"
print(f"\n βœ… Telegram Proxy URL: {proxy_url}")
print(f" πŸ‘‰ Add this to HF Space Secrets:")
print(f" CLOUDFLARE_TELEGRAM_PROXY_URL = {proxy_url}")
time.sleep(3) # ⏳ Wait for Cloudflare route to propagate
set_telegram_webhook(proxy_url)
else:
print(" ⚠️ Could not determine workers.dev subdomain")
else:
print(" ❌ Telegram proxy worker deployment failed β€” skipping webhook setup")
print("\n☁️ Cloudflare setup complete!")