Files
flow-manager/backend/app/core/storage.py
2026-01-27 17:40:37 +01:00

71 lines
3.0 KiB
Python

import boto3
from botocore.exceptions import ClientError
from app.core.config import settings
class StorageClient:
def __init__(self):
self.s3_client = boto3.client(
"s3",
endpoint_url=f"http://{settings.MINIO_ENDPOINT}",
aws_access_key_id=settings.MINIO_ACCESS_KEY,
aws_secret_access_key=settings.MINIO_SECRET_KEY,
config=boto3.session.Config(signature_version='s3v4')
)
self.bucket_name = settings.MINIO_BUCKET
self._ensure_bucket_exists()
def _ensure_bucket_exists(self):
try:
self.s3_client.head_bucket(Bucket=self.bucket_name)
except ClientError:
try:
self.s3_client.create_bucket(Bucket=self.bucket_name)
# Set bucket policy to public read if needed, or rely on presigned URLs
# For now, we will rely on presigned URLs for security
except ClientError as e:
print(f"Could not create bucket {self.bucket_name}: {e}")
def upload_file(self, file_obj, object_name: str, content_type: str = None) -> bool:
try:
extra_args = {}
if content_type:
extra_args["ContentType"] = content_type
self.s3_client.upload_fileobj(file_obj, self.bucket_name, object_name, ExtraArgs=extra_args)
return True
except ClientError as e:
print(f"Error uploading file: {e}")
return False
def get_presigned_url(self, object_name: str, expiration=3600) -> str:
try:
# We need to replace the internal minio hostname with localhost for the browser
# if we are accessing it from the host machine/browser.
# But the backend sees "minio".
# This is tricky in docker-compose.
# The client needs a URL that resolves.
# Usually we use a proxy or just configure the endpoint on the frontend.
# For now generate the URL and we might need to swap the host in the frontend or
# ensure the backend generates a URL accessible to the user.
# Actually, standard practice: Backend generates URL using its known endpoint.
# If that endpoint is "minio:9000", the browser can't resolve it.
# So we might need to override the endpoint for presigning.
url = self.s3_client.generate_presigned_url(
'get_object',
Params={'Bucket': self.bucket_name, 'Key': object_name},
ExpiresIn=expiration
)
# Hack for localhost dev: replace minio:9000 with localhost:9000
# dependent on where the request comes from.
# Ideally getting this from config would be better.
return url.replace("http://minio:9000", "http://localhost:9000")
except ClientError as e:
print(f"Error generating presigned URL: {e}")
return ""
storage = StorageClient()