2023-08-23 04:13:56 +03:00
|
|
|
|
import asyncio
|
|
|
|
|
import concurrent.futures as pool
|
2023-08-27 16:27:28 +03:00
|
|
|
|
import subprocess
|
|
|
|
|
|
2023-08-24 03:28:55 +03:00
|
|
|
|
from functools import partial
|
2023-08-23 04:13:56 +03:00
|
|
|
|
|
|
|
|
|
from fastapi import HTTPException
|
|
|
|
|
|
2023-08-27 16:27:28 +03:00
|
|
|
|
from src.core.async_queue import AsyncQueue
|
2023-08-24 16:45:55 +03:00
|
|
|
|
from src.core.rabbitmq import get_messages
|
2023-08-27 16:27:28 +03:00
|
|
|
|
from src.core.redis_client import RedisClient
|
2023-08-24 16:45:55 +03:00
|
|
|
|
from src.core.result import Result, ResultTypeEnum
|
2023-08-23 04:13:56 +03:00
|
|
|
|
from src.exceptions.download_exceptions import SiteNotImplementedException
|
2023-09-15 01:29:43 +03:00
|
|
|
|
from src.parsers.MyMail.my_mail_parser import MyMailParser
|
|
|
|
|
from src.parsers.Yappy.yappy_parser import YappyParser
|
|
|
|
|
from src.parsers.base_parser import BaseParser
|
2023-08-23 04:13:56 +03:00
|
|
|
|
|
|
|
|
|
|
2023-08-24 03:28:55 +03:00
|
|
|
|
class MasterService:
|
|
|
|
|
def __init__(self):
|
2023-08-24 16:45:55 +03:00
|
|
|
|
self.loop = asyncio.get_event_loop()
|
2023-08-24 03:28:55 +03:00
|
|
|
|
self.MAX_EXECUTOR_WORKERS = 8
|
2023-08-24 16:45:55 +03:00
|
|
|
|
self.executor = pool.ProcessPoolExecutor(max_workers=self.MAX_EXECUTOR_WORKERS,
|
|
|
|
|
initializer=executor_initializer)
|
2023-08-27 16:27:28 +03:00
|
|
|
|
self.queue = AsyncQueue()
|
2023-08-24 03:28:55 +03:00
|
|
|
|
self.rabbit_consumer = get_messages
|
2023-08-24 16:45:55 +03:00
|
|
|
|
self.currently_underway = {} # contains currently in progress videos
|
2023-08-23 04:13:56 +03:00
|
|
|
|
|
2023-08-24 03:28:55 +03:00
|
|
|
|
async def run(self):
|
2023-08-27 16:27:28 +03:00
|
|
|
|
subprocess.run(
|
|
|
|
|
"for pid in $(ps -ef | grep video_downloader_executor_process | awk '{print $2}'); do kill -9 $pid; done",
|
|
|
|
|
shell=True, capture_output=True
|
|
|
|
|
)
|
|
|
|
|
|
2023-08-24 16:45:55 +03:00
|
|
|
|
tasks = [self.loop.create_task(self.create_workers()) for i in range(self.MAX_EXECUTOR_WORKERS + 1)]
|
|
|
|
|
|
2023-08-24 03:28:55 +03:00
|
|
|
|
await asyncio.gather(self.rabbit_consumer(self.queue), *tasks)
|
2023-08-23 04:13:56 +03:00
|
|
|
|
|
2023-08-24 16:45:55 +03:00
|
|
|
|
async def create_workers(self):
|
|
|
|
|
while True:
|
|
|
|
|
video_params = await self.queue.get()
|
2023-09-21 00:21:03 +03:00
|
|
|
|
#TODO: позднее написать функцию для определения парсера автоматически
|
2023-08-27 16:27:28 +03:00
|
|
|
|
redis = RedisClient()
|
2023-09-21 00:21:03 +03:00
|
|
|
|
# TODO: проверить что в редисе задача либо уже выполнена, т.е. сразу отдать ссылку, либо что она ранее была закончена с ошибкой
|
|
|
|
|
# и проверять словарь self.currently_underway, для надёжности
|
2023-08-27 16:27:28 +03:00
|
|
|
|
await redis.del_task_from_queue_and_add_to_tasks(task=video_params)
|
2023-08-24 16:45:55 +03:00
|
|
|
|
self.currently_underway[video_params['link']] = video_params
|
|
|
|
|
download_task = self.loop.run_in_executor(self.executor, partial(
|
|
|
|
|
MasterService.video_processing_executor, video_params=video_params
|
2023-08-27 16:27:28 +03:00
|
|
|
|
)
|
2023-08-24 16:45:55 +03:00
|
|
|
|
)
|
2023-08-27 16:27:28 +03:00
|
|
|
|
|
|
|
|
|
result = await download_task
|
2023-09-20 14:43:59 +03:00
|
|
|
|
await redis.del_task_from_tasks_and_add_to_task_done(task={"link": video_params["link"], "result": result})
|
2023-08-27 16:27:28 +03:00
|
|
|
|
# TODO process result
|
2023-09-21 00:21:03 +03:00
|
|
|
|
'''
|
|
|
|
|
Result.Done \ Result.Exist - уведомить что задача выполнена, и отослать во вторую очередь сообщений RabbitMQ сообщение об этом
|
|
|
|
|
Result.Error - в таблице Редиса для выполненых задач, пометить, что это ошибка и уведомить об этом по второй очереди сообщений
|
|
|
|
|
и потом почистить self.currently_underway
|
|
|
|
|
'''
|
2023-08-24 16:45:55 +03:00
|
|
|
|
self.queue.task_done()
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def video_download(video_params: dict):
|
2023-09-15 01:29:43 +03:00
|
|
|
|
downloader: BaseParser | YappyParser | MyMailParser = MasterService.get_parser(video_params)
|
2023-08-24 16:45:55 +03:00
|
|
|
|
try:
|
2023-09-15 01:29:43 +03:00
|
|
|
|
result = downloader.video_download()
|
2023-08-24 16:45:55 +03:00
|
|
|
|
return result
|
|
|
|
|
except SiteNotImplementedException as ex:
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=400,
|
|
|
|
|
detail=ex.message
|
|
|
|
|
)
|
|
|
|
|
|
2023-09-15 01:29:43 +03:00
|
|
|
|
@staticmethod
|
|
|
|
|
def get_parser(params: dict):
|
|
|
|
|
parser_mapping = {
|
|
|
|
|
"MyMailRu": MyMailParser(params),
|
|
|
|
|
"base": BaseParser(params),
|
|
|
|
|
"Yappy": YappyParser(params),
|
|
|
|
|
}
|
|
|
|
|
return parser_mapping[params["parser"]]
|
|
|
|
|
|
2023-08-24 16:45:55 +03:00
|
|
|
|
@staticmethod
|
|
|
|
|
def video_processing_executor(video_params: dict):
|
|
|
|
|
try:
|
2023-09-20 14:43:59 +03:00
|
|
|
|
result = MasterService.video_download(video_params=video_params)
|
|
|
|
|
return result
|
2023-08-24 16:45:55 +03:00
|
|
|
|
except Exception as ex:
|
|
|
|
|
return Result(result_type=ResultTypeEnum.EXCEPTION, value=ex)
|
|
|
|
|
# TODO upload to server
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def executor_initializer():
|
|
|
|
|
import setproctitle
|
|
|
|
|
setproctitle.setproctitle(f'video_downloader_executor_process')
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|