""" S3 Service - Загрузка файлов в S3 (Timeweb Cloud Storage) """ import boto3 from botocore.client import Config from typing import Optional import logging from datetime import datetime import uuid from ..config import settings logger = logging.getLogger(__name__) class S3Service: """Сервис для работы с S3 хранилищем""" def __init__(self): self.client = None self.bucket = settings.s3_bucket def connect(self): """Подключение к S3""" try: self.client = boto3.client( 's3', endpoint_url=settings.s3_endpoint, aws_access_key_id=settings.s3_access_key, aws_secret_access_key=settings.s3_secret_key, config=Config(signature_version='s3v4'), region_name=settings.s3_region ) logger.info(f"✅ S3 connected: {settings.s3_endpoint}/{settings.s3_bucket}") except Exception as e: logger.error(f"❌ S3 connection error: {e}") raise async def upload_file( self, file_content: bytes, filename: str, content_type: str = 'application/octet-stream', folder: str = 'uploads' ) -> Optional[str]: """ Загрузить файл в S3 Args: file_content: Содержимое файла в bytes filename: Имя файла content_type: MIME тип folder: Папка в bucket Returns: URL файла в S3 или None при ошибке """ if not self.client: self.connect() try: # Генерируем уникальное имя файла timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') unique_id = str(uuid.uuid4())[:8] safe_filename = f"{folder}/{timestamp}_{unique_id}_{filename}" # Загружаем файл self.client.put_object( Bucket=self.bucket, Key=safe_filename, Body=file_content, ContentType=content_type ) # Генерируем URL file_url = f"{settings.s3_endpoint}/{self.bucket}/{safe_filename}" logger.info(f"✅ File uploaded to S3: {safe_filename}") return file_url except Exception as e: logger.error(f"❌ S3 upload error: {e}") return None async def delete_file(self, file_key: str) -> bool: """Удалить файл из S3""" if not self.client: self.connect() try: self.client.delete_object( Bucket=self.bucket, Key=file_key ) logger.info(f"✅ File deleted from S3: {file_key}") return True except Exception as e: logger.error(f"❌ S3 delete error: {e}") return False # Глобальный экземпляр s3_service = S3Service()