|
| 1 | +import os |
| 2 | +from functools import lru_cache |
| 3 | + |
| 4 | +from beartype import beartype |
| 5 | +from temporalio import workflow |
| 6 | + |
| 7 | +with workflow.unsafe.imports_passed_through(): |
| 8 | + import botocore |
| 9 | + from xxhash import xxh3_64_hexdigest as xxhash_key |
| 10 | + |
| 11 | + from ..env import blob_store_bucket |
| 12 | + |
| 13 | + |
| 14 | +@lru_cache(maxsize=1) |
| 15 | +def setup(): |
| 16 | + # INIT S3 # |
| 17 | + s3_access_key = os.environ.get("S3_ACCESS_KEY") |
| 18 | + s3_secret_key = os.environ.get("S3_SECRET_KEY") |
| 19 | + s3_endpoint = os.environ.get("S3_ENDPOINT") |
| 20 | + |
| 21 | + session = botocore.session.Session() |
| 22 | + client = session.create_client( |
| 23 | + "s3", |
| 24 | + endpoint_url=s3_endpoint, |
| 25 | + aws_access_key_id=s3_access_key, |
| 26 | + aws_secret_access_key=s3_secret_key, |
| 27 | + config=botocore.config.Config(signature_version="s3v4", retries={"max_attempts": 3}), |
| 28 | + ) |
| 29 | + |
| 30 | + try: |
| 31 | + client.head_bucket(Bucket=blob_store_bucket) |
| 32 | + except botocore.exceptions.ClientError as e: |
| 33 | + if e.response["Error"]["Code"] == "404": |
| 34 | + client.create_bucket(Bucket=blob_store_bucket) |
| 35 | + else: |
| 36 | + raise e |
| 37 | + |
| 38 | + return client |
| 39 | + |
| 40 | + |
| 41 | +@lru_cache(maxsize=1024) |
| 42 | +def list_buckets() -> list[str]: |
| 43 | + client = setup() |
| 44 | + |
| 45 | + data = client.list_buckets() |
| 46 | + return [bucket["Name"] for bucket in data["Buckets"]] |
| 47 | + |
| 48 | + |
| 49 | +@lru_cache(maxsize=10_000) |
| 50 | +def exists(key: str) -> bool: |
| 51 | + client = setup() |
| 52 | + |
| 53 | + try: |
| 54 | + client.head_object(Bucket=blob_store_bucket, Key=key) |
| 55 | + return True |
| 56 | + except botocore.exceptions.ClientError as e: |
| 57 | + if e.response["Error"]["Code"] == "404": |
| 58 | + return False |
| 59 | + raise e |
| 60 | + |
| 61 | + |
| 62 | +@beartype |
| 63 | +def add_object(key: str, body: bytes, replace: bool = False) -> None: |
| 64 | + client = setup() |
| 65 | + |
| 66 | + if replace: |
| 67 | + client.put_object(Bucket=blob_store_bucket, Key=key, Body=body) |
| 68 | + return |
| 69 | + |
| 70 | + if exists(key): |
| 71 | + return |
| 72 | + |
| 73 | + client.put_object(Bucket=blob_store_bucket, Key=key, Body=body) |
| 74 | + |
| 75 | + |
| 76 | +@beartype |
| 77 | +def get_object(key: str) -> bytes: |
| 78 | + client = setup() |
| 79 | + |
| 80 | + response = client.get_object(Bucket=blob_store_bucket, Key=key) |
| 81 | + return response["Body"].read() |
| 82 | + |
| 83 | + |
| 84 | +@beartype |
| 85 | +def delete_object(key: str) -> None: |
| 86 | + client = setup() |
| 87 | + client.delete_object(Bucket=blob_store_bucket, Key=key) |
| 88 | + |
| 89 | + |
| 90 | +@beartype |
| 91 | +def add_object_with_hash(body: bytes, replace: bool = False) -> str: |
| 92 | + key = xxhash_key(body) |
| 93 | + add_object(key, body, replace=replace) |
| 94 | + |
| 95 | + return key |
0 commit comments