Add user langs cache

This commit is contained in:
2023-05-22 11:36:53 +02:00
parent f028c00152
commit aee1f80726
7 changed files with 73 additions and 32 deletions

View File

@@ -19,8 +19,13 @@ use self::{
use super::{ignore_channel_messages, BotCommands, BotHandler, bots_manager::get_manager_handler, ignore_chat_member_update}; use super::{ignore_channel_messages, BotCommands, BotHandler, bots_manager::get_manager_handler, ignore_chat_member_update};
async fn _update_activity(me: teloxide::types::Me, user: teloxide::types::User, cache: Cache<UserId, bool>) -> Option<()> { async fn _update_activity(
if cache.contains_key(&user.id) { me: teloxide::types::Me,
user: teloxide::types::User,
activity_cache: Cache<UserId, bool>,
user_langs_cache: Cache<UserId, Vec<String>>,
) -> Option<()> {
if activity_cache.contains_key(&user.id) {
return None; return None;
} }
@@ -28,7 +33,7 @@ async fn _update_activity(me: teloxide::types::Me, user: teloxide::types::User,
let mut update_result = update_user_activity(user.id).await; let mut update_result = update_user_activity(user.id).await;
if update_result.is_err() { if update_result.is_err() {
let allowed_langs = get_user_or_default_lang_codes(user.id).await; let allowed_langs = get_user_or_default_lang_codes(user.id, user_langs_cache.clone()).await;
if create_or_update_user_settings( if create_or_update_user_settings(
user.id, user.id,
@@ -37,6 +42,7 @@ async fn _update_activity(me: teloxide::types::Me, user: teloxide::types::User,
user.username.clone().unwrap_or("".to_string()), user.username.clone().unwrap_or("".to_string()),
me.username.clone().unwrap(), me.username.clone().unwrap(),
allowed_langs, allowed_langs,
user_langs_cache,
).await.is_ok() ).await.is_ok()
{ {
update_result = update_user_activity(user.id).await; update_result = update_user_activity(user.id).await;
@@ -44,7 +50,7 @@ async fn _update_activity(me: teloxide::types::Me, user: teloxide::types::User,
} }
if update_result.is_ok() { if update_result.is_ok() {
cache.insert(user.id, true).await; activity_cache.insert(user.id, true).await;
} }
}); });
@@ -56,14 +62,14 @@ fn update_user_activity_handler() -> BotHandler {
.branch( .branch(
Update::filter_callback_query().chain(dptree::filter_map_async( Update::filter_callback_query().chain(dptree::filter_map_async(
|cq: CallbackQuery, bot: CacheMe<Throttle<Bot>>, app_state: AppState| async move { |cq: CallbackQuery, bot: CacheMe<Throttle<Bot>>, app_state: AppState| async move {
_update_activity(bot.get_me().await.unwrap(), cq.from, app_state.user_activity_cache).await _update_activity(bot.get_me().await.unwrap(), cq.from, app_state.user_activity_cache, app_state.user_langs_cache).await
}, },
)), )),
) )
.branch(Update::filter_message().chain(dptree::filter_map_async( .branch(Update::filter_message().chain(dptree::filter_map_async(
|message: Message, bot: CacheMe<Throttle<Bot>>, app_state: AppState| async move { |message: Message, bot: CacheMe<Throttle<Bot>>, app_state: AppState| async move {
match message.from() { match message.from() {
Some(user) => _update_activity(bot.get_me().await.unwrap(), user.clone(), app_state.user_activity_cache).await, Some(user) => _update_activity(bot.get_me().await.unwrap(), user.clone(), app_state.user_activity_cache, app_state.user_langs_cache).await,
None => None, None => None,
} }
}, },

View File

@@ -1,5 +1,6 @@
use std::str::FromStr; use std::str::FromStr;
use moka::future::Cache;
use regex::Regex; use regex::Regex;
use teloxide::{dispatching::UpdateFilterExt, dptree, prelude::*, adaptors::{Throttle, CacheMe}}; use teloxide::{dispatching::UpdateFilterExt, dptree, prelude::*, adaptors::{Throttle, CacheMe}};
@@ -117,6 +118,7 @@ async fn send_book_handler<T, Fut>(
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
command: BookCommand, command: BookCommand,
books_getter: fn(id: u32, page: u32, allowed_langs: Vec<String>) -> Fut, books_getter: fn(id: u32, page: u32, allowed_langs: Vec<String>) -> Fut,
user_langs_cache: Cache<UserId, Vec<String>>,
) -> crate::bots::BotHandlerInternal ) -> crate::bots::BotHandlerInternal
where where
T: Format + Clone, T: Format + Clone,
@@ -145,7 +147,7 @@ where
} }
}; };
let allowed_langs = get_user_or_default_lang_codes(user_id).await; let allowed_langs = get_user_or_default_lang_codes(user_id, user_langs_cache).await;
let items_page = match books_getter(id, 1, allowed_langs.clone()).await { let items_page = match books_getter(id, 1, allowed_langs.clone()).await {
Ok(v) => v, Ok(v) => v,
@@ -191,6 +193,7 @@ async fn send_pagination_book_handler<T, Fut>(
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
callback_data: BookCallbackData, callback_data: BookCallbackData,
books_getter: fn(id: u32, page: u32, allowed_langs: Vec<String>) -> Fut, books_getter: fn(id: u32, page: u32, allowed_langs: Vec<String>) -> Fut,
user_langs_cache: Cache<UserId, Vec<String>>,
) -> crate::bots::BotHandlerInternal ) -> crate::bots::BotHandlerInternal
where where
T: Format + Clone, T: Format + Clone,
@@ -217,7 +220,7 @@ where
} }
}; };
let allowed_langs = get_user_or_default_lang_codes(user_id).await; let allowed_langs = get_user_or_default_lang_codes(user_id, user_langs_cache).await;
let mut items_page = match books_getter(id, page, allowed_langs.clone()).await { let mut items_page = match books_getter(id, page, allowed_langs.clone()).await {
Ok(v) => v, Ok(v) => v,
@@ -277,7 +280,7 @@ pub fn get_book_handler() -> crate::bots::BotHandler {
Update::filter_message() Update::filter_message()
.chain(filter_command::<BookCommand>()) .chain(filter_command::<BookCommand>())
.endpoint( .endpoint(
|message: Message, bot: CacheMe<Throttle<Bot>>, command: BookCommand| async move { |message: Message, bot: CacheMe<Throttle<Bot>>, command: BookCommand, user_langs_cache: Cache<UserId, Vec<String>>| async move {
match command { match command {
BookCommand::Author { .. } => { BookCommand::Author { .. } => {
send_book_handler( send_book_handler(
@@ -285,6 +288,7 @@ pub fn get_book_handler() -> crate::bots::BotHandler {
bot, bot,
command, command,
get_author_books, get_author_books,
user_langs_cache
) )
.await .await
} }
@@ -294,6 +298,7 @@ pub fn get_book_handler() -> crate::bots::BotHandler {
bot, bot,
command, command,
get_translator_books, get_translator_books,
user_langs_cache
) )
.await .await
} }
@@ -303,6 +308,7 @@ pub fn get_book_handler() -> crate::bots::BotHandler {
bot, bot,
command, command,
get_sequence_books, get_sequence_books,
user_langs_cache,
) )
.await .await
} }
@@ -313,11 +319,11 @@ pub fn get_book_handler() -> crate::bots::BotHandler {
.branch( .branch(
Update::filter_callback_query() Update::filter_callback_query()
.chain(filter_callback_query::<BookCallbackData>()) .chain(filter_callback_query::<BookCallbackData>())
.endpoint(|cq: CallbackQuery, bot: CacheMe<Throttle<Bot>>, callback_data: BookCallbackData| async move { .endpoint(|cq: CallbackQuery, bot: CacheMe<Throttle<Bot>>, callback_data: BookCallbackData, user_langs_cache: Cache<UserId, Vec<String>>| async move {
match callback_data { match callback_data {
BookCallbackData::Author { .. } => send_pagination_book_handler(cq, bot, callback_data, get_author_books).await, BookCallbackData::Author { .. } => send_pagination_book_handler(cq, bot, callback_data, get_author_books, user_langs_cache).await,
BookCallbackData::Translator { .. } => send_pagination_book_handler(cq, bot, callback_data, get_translator_books).await, BookCallbackData::Translator { .. } => send_pagination_book_handler(cq, bot, callback_data, get_translator_books, user_langs_cache).await,
BookCallbackData::Sequence { .. } => send_pagination_book_handler(cq, bot, callback_data, get_sequence_books).await, BookCallbackData::Sequence { .. } => send_pagination_book_handler(cq, bot, callback_data, get_sequence_books, user_langs_cache).await,
} }
}), }),
) )

View File

@@ -1,3 +1,4 @@
use moka::future::Cache;
use strum_macros::{Display, EnumIter}; use strum_macros::{Display, EnumIter};
use teloxide::{ use teloxide::{
prelude::*, prelude::*,
@@ -168,12 +169,13 @@ async fn get_random_item_handler<T, Fut>(
cq: CallbackQuery, cq: CallbackQuery,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
item_getter: fn(allowed_langs: Vec<String>) -> Fut, item_getter: fn(allowed_langs: Vec<String>) -> Fut,
user_langs_cache: Cache<UserId, Vec<String>>,
) -> BotHandlerInternal ) -> BotHandlerInternal
where where
T: Format, T: Format,
Fut: std::future::Future<Output = Result<T, Box<dyn std::error::Error + Send + Sync>>>, Fut: std::future::Future<Output = Result<T, Box<dyn std::error::Error + Send + Sync>>>,
{ {
let allowed_langs = get_user_or_default_lang_codes(cq.from.id).await; let allowed_langs = get_user_or_default_lang_codes(cq.from.id, user_langs_cache).await;
let item = item_getter(allowed_langs).await; let item = item_getter(allowed_langs).await;
@@ -292,8 +294,9 @@ async fn get_random_book_by_genre(
cq: CallbackQuery, cq: CallbackQuery,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
genre_id: u32, genre_id: u32,
user_langs_cache: Cache<UserId, Vec<String>>,
) -> BotHandlerInternal { ) -> BotHandlerInternal {
let allowed_langs = get_user_or_default_lang_codes(cq.from.id).await; let allowed_langs = get_user_or_default_lang_codes(cq.from.id, user_langs_cache).await;
let item = book_library::get_random_book_by_genre(allowed_langs, Some(genre_id)).await; let item = book_library::get_random_book_by_genre(allowed_langs, Some(genre_id)).await;
@@ -317,14 +320,14 @@ pub fn get_random_hander() -> crate::bots::BotHandler {
.branch( .branch(
Update::filter_callback_query() Update::filter_callback_query()
.chain(filter_callback_query::<RandomCallbackData>()) .chain(filter_callback_query::<RandomCallbackData>())
.endpoint(|cq: CallbackQuery, callback_data: RandomCallbackData, bot: CacheMe<Throttle<Bot>>| async move { .endpoint(|cq: CallbackQuery, callback_data: RandomCallbackData, bot: CacheMe<Throttle<Bot>>, user_langs_cache: Cache<UserId, Vec<String>>| async move {
match callback_data { match callback_data {
RandomCallbackData::RandomBook => get_random_item_handler(cq, bot, book_library::get_random_book).await, RandomCallbackData::RandomBook => get_random_item_handler(cq, bot, book_library::get_random_book, user_langs_cache).await,
RandomCallbackData::RandomAuthor => get_random_item_handler(cq, bot, book_library::get_random_author).await, RandomCallbackData::RandomAuthor => get_random_item_handler(cq, bot, book_library::get_random_author, user_langs_cache).await,
RandomCallbackData::RandomSequence => get_random_item_handler(cq, bot, book_library::get_random_sequence).await, RandomCallbackData::RandomSequence => get_random_item_handler(cq, bot, book_library::get_random_sequence, user_langs_cache).await,
RandomCallbackData::RandomBookByGenreRequest => get_genre_metas_handler(cq, bot).await, RandomCallbackData::RandomBookByGenreRequest => get_genre_metas_handler(cq, bot).await,
RandomCallbackData::Genres { index } => get_genres_by_meta_handler(cq, bot, index).await, RandomCallbackData::Genres { index } => get_genres_by_meta_handler(cq, bot, index).await,
RandomCallbackData::RandomBookByGenre { id } => get_random_book_by_genre(cq, bot, id).await, RandomCallbackData::RandomBookByGenre { id } => get_random_book_by_genre(cq, bot, id, user_langs_cache).await,
} }
}) })
) )

View File

@@ -1,5 +1,6 @@
use std::str::FromStr; use std::str::FromStr;
use moka::future::Cache;
use regex::Regex; use regex::Regex;
use strum_macros::EnumIter; use strum_macros::EnumIter;
use teloxide::{ use teloxide::{
@@ -110,6 +111,7 @@ async fn generic_search_pagination_handler<T, Fut>(
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
search_data: SearchCallbackData, search_data: SearchCallbackData,
items_getter: fn(query: String, page: u32, allowed_langs: Vec<String>) -> Fut, items_getter: fn(query: String, page: u32, allowed_langs: Vec<String>) -> Fut,
user_langs_cache: Cache<UserId, Vec<String>>,
) -> BotHandlerInternal ) -> BotHandlerInternal
where where
T: Format + Clone, T: Format + Clone,
@@ -133,7 +135,7 @@ where
} }
}; };
let allowed_langs = get_user_or_default_lang_codes(user_id).await; let allowed_langs = get_user_or_default_lang_codes(user_id, user_langs_cache).await;
let page = match search_data { let page = match search_data {
SearchCallbackData::Book { page } => page, SearchCallbackData::Book { page } => page,
@@ -253,12 +255,12 @@ pub fn get_search_handler() -> crate::bots::BotHandler {
).branch( ).branch(
Update::filter_callback_query() Update::filter_callback_query()
.chain(filter_callback_query::<SearchCallbackData>()) .chain(filter_callback_query::<SearchCallbackData>())
.endpoint(|cq: CallbackQuery, callback_data: SearchCallbackData, bot: CacheMe<Throttle<Bot>>| async move { .endpoint(|cq: CallbackQuery, callback_data: SearchCallbackData, bot: CacheMe<Throttle<Bot>>, user_langs_cache: Cache<UserId, Vec<String>>| async move {
match callback_data { match callback_data {
SearchCallbackData::Book { .. } => generic_search_pagination_handler(cq, bot, callback_data, search_book).await, SearchCallbackData::Book { .. } => generic_search_pagination_handler(cq, bot, callback_data, search_book, user_langs_cache).await,
SearchCallbackData::Authors { .. } => generic_search_pagination_handler(cq, bot, callback_data, search_author).await, SearchCallbackData::Authors { .. } => generic_search_pagination_handler(cq, bot, callback_data, search_author, user_langs_cache).await,
SearchCallbackData::Sequences { .. } => generic_search_pagination_handler(cq, bot, callback_data, search_sequence).await, SearchCallbackData::Sequences { .. } => generic_search_pagination_handler(cq, bot, callback_data, search_sequence, user_langs_cache).await,
SearchCallbackData::Translators { .. } => generic_search_pagination_handler(cq, bot, callback_data, search_translator).await, SearchCallbackData::Translators { .. } => generic_search_pagination_handler(cq, bot, callback_data, search_translator, user_langs_cache).await,
} }
}) })
) )

View File

@@ -10,6 +10,7 @@ use crate::bots::{
BotHandlerInternal, BotHandlerInternal,
}; };
use moka::future::Cache;
use regex::Regex; use regex::Regex;
use teloxide::{ use teloxide::{
prelude::*, prelude::*,
@@ -118,6 +119,7 @@ async fn settings_callback_handler(
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
callback_data: SettingsCallbackData, callback_data: SettingsCallbackData,
me: Me, me: Me,
user_langs_cache: Cache<UserId, Vec<String>>,
) -> BotHandlerInternal { ) -> BotHandlerInternal {
let message = match cq.message { let message = match cq.message {
Some(v) => v, Some(v) => v,
@@ -129,7 +131,7 @@ async fn settings_callback_handler(
let user = cq.from; let user = cq.from;
let allowed_langs = get_user_or_default_lang_codes(user.id).await; let allowed_langs = get_user_or_default_lang_codes(user.id, user_langs_cache.clone()).await;
let mut allowed_langs_set: HashSet<String> = HashSet::new(); let mut allowed_langs_set: HashSet<String> = HashSet::new();
allowed_langs.clone().into_iter().for_each(|v| { allowed_langs.clone().into_iter().for_each(|v| {
@@ -164,6 +166,7 @@ async fn settings_callback_handler(
user.username.clone().unwrap_or("".to_string()), user.username.clone().unwrap_or("".to_string()),
me.username.clone().unwrap(), me.username.clone().unwrap(),
allowed_langs_set.clone().into_iter().collect(), allowed_langs_set.clone().into_iter().collect(),
user_langs_cache,
) )
.await { .await {
bot.send_message(user.id, "Ошибка! Попробуйте заново(").send().await?; bot.send_message(user.id, "Ошибка! Попробуйте заново(").send().await?;
@@ -205,8 +208,9 @@ pub fn get_settings_handler() -> crate::bots::BotHandler {
|cq: CallbackQuery, |cq: CallbackQuery,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
callback_data: SettingsCallbackData, callback_data: SettingsCallbackData,
me: Me| async move { me: Me,
settings_callback_handler(cq, bot, callback_data, me).await user_langs_cache: Cache<UserId, Vec<String>>| async move {
settings_callback_handler(cq, bot, callback_data, me, user_langs_cache).await
}, },
), ),
) )

View File

@@ -1,3 +1,4 @@
use moka::future::Cache;
use serde::Deserialize; use serde::Deserialize;
use serde_json::json; use serde_json::json;
use teloxide::types::UserId; use teloxide::types::UserId;
@@ -38,11 +39,22 @@ pub async fn get_user_settings(
Ok(response.json::<UserSettings>().await?) Ok(response.json::<UserSettings>().await?)
} }
pub async fn get_user_or_default_lang_codes(user_id: UserId) -> Vec<String> { pub async fn get_user_or_default_lang_codes(
user_id: UserId,
cache: Cache<UserId, Vec<String>>
) -> Vec<String> {
if let Some(cached_langs) = cache.get(&user_id) {
return cached_langs;
}
let default_lang_codes = vec![String::from("ru"), String::from("be"), String::from("uk")]; let default_lang_codes = vec![String::from("ru"), String::from("be"), String::from("uk")];
match get_user_settings(user_id).await { match get_user_settings(user_id).await {
Ok(v) => v.allowed_langs.into_iter().map(|lang| lang.code).collect(), Ok(v) => {
let langs: Vec<String> = v.allowed_langs.into_iter().map(|lang| lang.code).collect();
cache.insert(user_id, langs.clone()).await;
langs
},
Err(_) => default_lang_codes, Err(_) => default_lang_codes,
} }
} }
@@ -54,7 +66,10 @@ pub async fn create_or_update_user_settings(
username: String, username: String,
source: String, source: String,
allowed_langs: Vec<String>, allowed_langs: Vec<String>,
cache: Cache<UserId, Vec<String>>
) -> Result<UserSettings, Box<dyn std::error::Error + Send + Sync>> { ) -> Result<UserSettings, Box<dyn std::error::Error + Send + Sync>> {
cache.invalidate(&user_id).await;
let body = json!({ let body = json!({
"user_id": user_id, "user_id": user_id,
"last_name": last_name, "last_name": last_name,

View File

@@ -24,6 +24,7 @@ use self::bot_manager_client::get_bots;
#[derive(Clone)] #[derive(Clone)]
pub struct AppState { pub struct AppState {
pub user_activity_cache: Cache<UserId, bool>, pub user_activity_cache: Cache<UserId, bool>,
pub user_langs_cache: Cache<UserId, Vec<String>>,
} }
pub struct BotsManager { pub struct BotsManager {
@@ -41,7 +42,11 @@ impl BotsManager {
user_activity_cache: Cache::builder() user_activity_cache: Cache::builder()
.time_to_live(Duration::from_secs(5 * 60)) .time_to_live(Duration::from_secs(5 * 60))
.max_capacity(4096) .max_capacity(4096)
.build() .build(),
user_langs_cache: Cache::builder()
.time_to_live(Duration::from_secs(5 * 60))
.max_capacity(4096)
.build(),
}, },
next_port: 8000, next_port: 8000,
bot_port_map: HashMap::new(), bot_port_map: HashMap::new(),