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>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
"""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())
|
||||
Reference in New Issue
Block a user