()
| 41 | |
| 42 | |
| 43 | def _get_client(): |
| 44 | global _client |
| 45 | if _client is not None: |
| 46 | return _client |
| 47 | |
| 48 | if not all([R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY]): |
| 49 | raise RuntimeError("R2 credentials are not configured (R2_ACCOUNT_ID / R2_ACCESS_KEY_ID / R2_SECRET_ACCESS_KEY)") |
| 50 | |
| 51 | _client = boto3.client( |
| 52 | "s3", |
| 53 | endpoint_url=f"https://{R2_ACCOUNT_ID}.r2.cloudflarestorage.com", |
| 54 | aws_access_key_id=R2_ACCESS_KEY_ID, |
| 55 | aws_secret_access_key=R2_SECRET_ACCESS_KEY, |
| 56 | region_name="auto", |
| 57 | config=Config(retries={"max_attempts": 3, "mode": "standard"}), |
| 58 | ) |
| 59 | return _client |
| 60 | |
| 61 | |
| 62 | def _get_json_sync(key: str) -> Tuple[Optional[dict], Optional[str]]: |
no test coverage detected