diff --git a/src/bots/approved_bot/modules/download.rs b/src/bots/approved_bot/modules/download.rs index 6e0f3dc..0bae038 100644 --- a/src/bots/approved_bot/modules/download.rs +++ b/src/bots/approved_bot/modules/download.rs @@ -1,4 +1,4 @@ -use std::str::FromStr; +use std::{str::FromStr, time::Duration}; use futures::TryStreamExt; use moka::future::Cache; @@ -11,7 +11,9 @@ use teloxide::{ prelude::*, types::*, }; +use tokio::time::sleep; use tokio_util::compat::FuturesAsyncReadCompatExt; +use url::Url; use crate::{ bots::{ @@ -22,7 +24,9 @@ use crate::{ types::{CachedMessage, DownloadFile}, }, book_library::{get_book, get_author_books_available_types, get_translator_books_available_types, get_sequence_books_available_types}, - donation_notificatioins::send_donation_notification, user_settings::get_user_or_default_lang_codes, + donation_notificatioins::send_donation_notification, user_settings::get_user_or_default_lang_codes, batch_downloader::{TaskObjectType, CreateTaskData}, + batch_downloader::{create_task, get_task, TaskStatus} + }, tools::filter_callback_query, }, @@ -410,18 +414,93 @@ async fn get_download_archive_keyboard_handler( Ok(()) } +async fn download_archive( + cq: CallbackQuery, + download_archive_query_data: DownloadArchiveQueryData, + bot: CacheMe>, + app_state: AppState +) -> BotHandlerInternal { + let allowed_langs = get_user_or_default_lang_codes( + cq.from.id, + app_state.user_langs_cache + ).await; + + let (id, file_type, task_type) = match download_archive_query_data { + DownloadArchiveQueryData::Sequence { id, file_type } => (id, file_type, TaskObjectType::Sequence), + DownloadArchiveQueryData::Author { id, file_type } => (id, file_type, TaskObjectType::Author), + DownloadArchiveQueryData::Translator { id, file_type } => (id, file_type, TaskObjectType::Translator), + }; + + let message = cq.message.unwrap(); + + let task = create_task(CreateTaskData { + object_id: id, + object_type: task_type, + file_format: file_type, + allowed_langs + }).await; + + let mut task = match task { + Ok(v) => v, + Err(err) => { + bot + .edit_message_text(message.chat.id, message.id, "Ошибка! Попробуйте позже :(") + .reply_markup(InlineKeyboardMarkup { + inline_keyboard: vec![], + }) + .send() + .await?; + + return Err(err); + }, + }; + + bot + .edit_message_text(message.chat.id, message.id, "Подготовка архива...") + .reply_markup(InlineKeyboardMarkup { + inline_keyboard: vec![], + }) + .send() + .await?; + + while task.status != TaskStatus::Complete { + task = match get_task(task.id).await { + Ok(v) => v, + Err(err) => { + bot + .edit_message_text(message.chat.id, message.id, "Ошибка! Попробуйте позже :(") + .reply_markup(InlineKeyboardMarkup { + inline_keyboard: vec![], + }) + .send() + .await?; + + return Err(err); + }, + }; + + sleep(Duration::from_secs(5)).await; + } + + bot + .send_document( + message.chat.id, + InputFile::url( + Url::from_str(&task.result_link.unwrap() + ).unwrap()) + ) + .send() + .await?; + + Ok(()) +} + pub fn get_download_hander() -> crate::bots::BotHandler { dptree::entry() .branch( Update::filter_message() .chain(filter_command::()) - .endpoint( - |message: Message, - bot: CacheMe>, - download_data: StartDownloadCommand| async move { - get_download_keyboard_handler(message, bot, download_data).await - }, - ), + .endpoint(get_download_keyboard_handler), ) .branch( Update::filter_callback_query() @@ -447,10 +526,11 @@ pub fn get_download_hander() -> crate::bots::BotHandler { .branch( Update::filter_message() .chain(filter_command::()) - .endpoint(| - message: Message, bot: CacheMe>, command: DownloadArchiveCommand, app_state: AppState - | async move { - get_download_archive_keyboard_handler(message, bot, command, app_state.user_langs_cache).await - }) + .endpoint(get_download_archive_keyboard_handler) + ) + .branch( + Update::filter_callback_query() + .chain(filter_callback_query::()) + .endpoint(download_archive) ) } diff --git a/src/bots/approved_bot/services/batch_downloader.rs b/src/bots/approved_bot/services/batch_downloader.rs new file mode 100644 index 0000000..af0f262 --- /dev/null +++ b/src/bots/approved_bot/services/batch_downloader.rs @@ -0,0 +1,64 @@ +use serde::{Deserialize, Serialize}; + +use crate::config; + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum TaskObjectType { + Sequence, + Author, + Translator, +} + +#[derive(Deserialize, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum TaskStatus { + InProgress, + Archiving, + Complete, +} + +#[derive(Serialize)] +pub struct CreateTaskData { + pub object_id: u32, + pub object_type: TaskObjectType, + pub file_format: String, + pub allowed_langs: Vec, +} + +#[derive(Deserialize)] +pub struct Task { + pub id: String, + pub object_id: u32, + pub object_type: TaskObjectType, + pub status: TaskStatus, + pub result_link: Option, +} + +pub async fn create_task( + data: CreateTaskData, +) -> Result> { + Ok(reqwest::Client::new() + .post(format!("{}/api/", &config::CONFIG.batch_downloader_url)) + .body(serde_json::to_string(&data).unwrap()) + .header("Authorization", &config::CONFIG.batch_downloader_api_key) + .send() + .await? + .error_for_status()? + .json::() + .await?) +} + +pub async fn get_task(task_id: String) -> Result> { + Ok(reqwest::Client::new() + .get(format!( + "{}/api/check_archive/{task_id}/", + &config::CONFIG.batch_downloader_url + )) + .header("Authorization", &config::CONFIG.batch_downloader_api_key) + .send() + .await? + .error_for_status()? + .json::() + .await?) +} diff --git a/src/bots/approved_bot/services/mod.rs b/src/bots/approved_bot/services/mod.rs index 1dbcb4e..8415e8f 100644 --- a/src/bots/approved_bot/services/mod.rs +++ b/src/bots/approved_bot/services/mod.rs @@ -2,3 +2,4 @@ pub mod book_cache; pub mod book_library; pub mod user_settings; pub mod donation_notificatioins; +pub mod batch_downloader; diff --git a/src/config.rs b/src/config.rs index 8d6ecc2..cc58498 100644 --- a/src/config.rs +++ b/src/config.rs @@ -17,6 +17,9 @@ pub struct Config { pub cache_server_url: String, pub cache_server_api_key: String, + pub batch_downloader_url: String, + pub batch_downloader_api_key: String, + pub sentry_dsn: String, } @@ -48,6 +51,9 @@ impl Config { cache_server_url: get_env("CACHE_SERVER_URL"), cache_server_api_key: get_env("CACHE_SERVER_API_KEY"), + batch_downloader_url: get_env("BATCH_DOWNLOADER_URL"), + batch_downloader_api_key: get_env("BATCH_DOWNLOADER_API_KEY"), + sentry_dsn: get_env("SENTRY_DSN"), } }