71 lines
3.0 KiB
Python
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()
|