import aioboto3 import asyncio import logging import os import aiohttp from app.config import settings logger = logging.getLogger(__name__) async def download_and_upload_stream(url: str, key_name: str) -> bool: """ Скачивает аудиофайл по URL потоками и передаёт в upload_file_to_s3 для загрузки. """ try: logger.info(f"[INFO] Начало скачивания {url}") async with aiohttp.ClientSession() as http_session: async with http_session.get(url) as resp: resp.raise_for_status() # читаем файл по частям и собираем в bytes chunks = [] while True: chunk = await resp.content.read(1024 * 1024) # 1 МБ if not chunk: break chunks.append(chunk) file_bytes = b"".join(chunks) logger.info(f"[INFO] Скачивание {url} завершено, размер {len(file_bytes)} байт") # передаём в функцию загрузки с retry success = await upload_file_to_s3(file_bytes, key_name) return success except Exception as e: logger.error(f"[FAILED] Не удалось скачать или загрузить {url}: {e}") return False async def upload_file_to_s3(file_bytes: bytes, key_name: str) -> bool: """ Асинхронно загружает файл в S3 с ретраями. Возвращает True при успехе, False при ошибке. """ session = aioboto3.Session() for attempt in range(1, settings.MAX_RETRIES + 1): try: logger.info(f"Попытка {attempt} загрузки {key_name} в S3") #logger.info(f"Параметры S3: {S3_ENDPOINT_URL}, {S3_BUCKET_NAME}, {AWS_REGION}") async with session.client( "s3", endpoint_url=settings.S3_ENDPOINT_URL, aws_access_key_id=settings.AWS_ACCESS_KEY_ID, aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, region_name=settings.AWS_REGION ) as s3: await s3.put_object(Bucket=settings.S3_BUCKET_NAME, Key=key_name, Body=file_bytes) logger.info(f"[OK] Файл {key_name} загружен в S3!") return True except Exception as e: logger.exception(f"[ERROR] Попытка {attempt} для {key_name} не удалась: {e}") if attempt < settings.MAX_RETRIES: await asyncio.sleep(settings.RETRY_DELAY) else: logger.error(f"[FAILED] Файл {key_name} не удалось загрузить после {settings.MAX_RETRIES} попыток") return False