Files
climperor/web/cloudflare/_retry_r2_only.py
T
vosonandCursor f5b7011c45 Ship Steam login, D1 player sync, and cached「我」dashboard.
Players get a fast TTL-backed homepage (local profile / Cloudflare D1) with dense UI polish; login unlocks /home without blocking on every OpenDota refresh.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-01 01:24:30 +08:00

94 lines
3.0 KiB
Python

"""Hammer R2 create/list until Cloudflare API stops returning 52x."""
from __future__ import annotations
import json
import os
import time
import urllib.error
import urllib.request
ACCT = "510534f7f6284344aadaf2f5a0794d48"
BUCKET = "climperor-player-data"
API = "https://api.cloudflare.com/client/v4"
def creds():
email = os.environ.get("CLOUDFLARE_EMAIL") or os.environ.get(
"KEYZOO_ASSET_META_USERNAME"
)
key = os.environ.get("CLOUDFLARE_API_KEY") or os.environ.get(
"KEYZOO_ASSET_SECRET_GLOBAL_API_KEY"
)
if not email or not key:
raise SystemExit("missing credentials")
return email, key
def call(method: str, path: str, body: dict | None = None) -> tuple[int, dict | str]:
email, key = creds()
data = None if body is None else json.dumps(body).encode()
req = urllib.request.Request(
API + path,
data=data,
method=method,
headers={
"X-Auth-Email": email,
"X-Auth-Key": key,
"Content-Type": "application/json",
"User-Agent": "climperor-retry-r2",
},
)
try:
with urllib.request.urlopen(req, timeout=60) as resp:
return resp.status, json.loads(resp.read().decode())
except urllib.error.HTTPError as e:
raw = e.read().decode("utf-8", errors="replace")
try:
return e.code, json.loads(raw)
except Exception:
return e.code, raw[:120]
def main() -> int:
list_path = f"/accounts/{ACCT}/r2/buckets"
get_path = f"/accounts/{ACCT}/r2/buckets/{BUCKET}"
for i in range(20):
code, payload = call("GET", get_path)
print(f"[{i+1}] GET {BUCKET} -> {code}", flush=True)
if code == 200:
print("bucket ready", flush=True)
return 0
if code == 404 or (isinstance(payload, dict) and not payload.get("success")):
# not found → create
code2, payload2 = call("POST", list_path, {"name": BUCKET})
print(f"[{i+1}] POST create -> {code2}", flush=True)
if code2 in (200, 201):
print("created", flush=True)
return 0
text = str(payload2).lower()
if "already exists" in text or "10004" in text:
print("exists", flush=True)
return 0
# also try list
code3, payload3 = call("GET", list_path)
names = []
if isinstance(payload3, dict):
buckets = (payload3.get("result") or {}).get("buckets") or payload3.get(
"result"
)
if isinstance(buckets, list):
for b in buckets:
if isinstance(b, dict):
names.append(b.get("name"))
print(f"[{i+1}] LIST -> {code3} names={names}", flush=True)
if BUCKET in names:
print("bucket ready via list", flush=True)
return 0
time.sleep(5 + (i % 5))
return 1
if __name__ == "__main__":
raise SystemExit(main())