commit
This commit is contained in:
70
backend/app/core/storage.py
Normal file
70
backend/app/core/storage.py
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
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()
|
||||
Reference in New Issue
Block a user