mirror of
https://github.com/flibusta-apps/book_bot.git
synced 2025-12-06 15:35:35 +01:00
Compare commits
7 Commits
6990f01275
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| fc10c4c576 | |||
| 359a6b6137 | |||
| 17ef8a7f3d | |||
| 0d028b6a66 | |||
| 9fb550404e | |||
| 07c725e0df | |||
|
|
6f2de597b4 |
2
.github/workflows/rust-clippy.yml
vendored
2
.github/workflows/rust-clippy.yml
vendored
@@ -49,7 +49,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- name: Upload analysis results to GitHub
|
- name: Upload analysis results to GitHub
|
||||||
uses: github/codeql-action/upload-sarif@v3
|
uses: github/codeql-action/upload-sarif@v4
|
||||||
with:
|
with:
|
||||||
sarif_file: rust-clippy-results.sarif
|
sarif_file: rust-clippy-results.sarif
|
||||||
wait-for-processing: true
|
wait-for-processing: true
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ use tokio_util::compat::FuturesAsyncReadCompatExt;
|
|||||||
|
|
||||||
use crate::bots::{
|
use crate::bots::{
|
||||||
approved_bot::{
|
approved_bot::{
|
||||||
modules::utils::pagination::generic_get_pagination_keyboard,
|
modules::utils::{
|
||||||
|
message_text::is_message_text_equals, pagination::generic_get_pagination_keyboard,
|
||||||
|
},
|
||||||
services::book_library::{get_author_annotation, get_book_annotation},
|
services::book_library::{get_author_annotation, get_book_annotation},
|
||||||
tools::filter_callback_query,
|
tools::filter_callback_query,
|
||||||
},
|
},
|
||||||
@@ -145,17 +147,24 @@ where
|
|||||||
} else {
|
} else {
|
||||||
chunked_text.len()
|
chunked_text.len()
|
||||||
};
|
};
|
||||||
let current_text = chunked_text.get(page_index - 1).unwrap();
|
let new_text = chunked_text.get(page_index - 1).unwrap();
|
||||||
|
|
||||||
let keyboard =
|
let keyboard =
|
||||||
generic_get_pagination_keyboard(page, chunked_text.len().try_into()?, callback_data, false);
|
generic_get_pagination_keyboard(page, chunked_text.len().try_into()?, callback_data, false);
|
||||||
|
|
||||||
bot.edit_message_text(message.chat().id, message.id(), current_text)
|
if is_message_text_equals(Some(message.clone()), new_text) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
match bot
|
||||||
|
.edit_message_text(message.chat().id, message.id(), new_text)
|
||||||
.reply_markup(keyboard)
|
.reply_markup(keyboard)
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await
|
||||||
|
{
|
||||||
Ok(())
|
Ok(_) => Ok(()),
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_annotations_handler() -> crate::bots::BotHandler {
|
pub fn get_annotations_handler() -> crate::bots::BotHandler {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use teloxide::{
|
|||||||
use tracing::log;
|
use tracing::log;
|
||||||
|
|
||||||
use crate::bots::approved_bot::{
|
use crate::bots::approved_bot::{
|
||||||
|
modules::utils::message_text::is_message_text_equals,
|
||||||
services::{
|
services::{
|
||||||
book_library::{
|
book_library::{
|
||||||
formatters::{Format, FormatTitle},
|
formatters::{Format, FormatTitle},
|
||||||
@@ -176,12 +177,19 @@ where
|
|||||||
|
|
||||||
let keyboard = generic_get_pagination_keyboard(page, items_page.pages, callback_data, true);
|
let keyboard = generic_get_pagination_keyboard(page, items_page.pages, callback_data, true);
|
||||||
|
|
||||||
bot.edit_message_text(chat_id, message_id, formatted_page)
|
if is_message_text_equals(cq.message, &formatted_page) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
match bot
|
||||||
|
.edit_message_text(chat_id, message_id, formatted_page)
|
||||||
.reply_markup(keyboard)
|
.reply_markup(keyboard)
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await
|
||||||
|
{
|
||||||
Ok(())
|
Ok(_) => Ok(()),
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_book_handler() -> crate::bots::BotHandler {
|
pub fn get_book_handler() -> crate::bots::BotHandler {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use teloxide::{
|
|||||||
|
|
||||||
use crate::bots::{
|
use crate::bots::{
|
||||||
approved_bot::{
|
approved_bot::{
|
||||||
|
modules::utils::message_text::is_message_text_equals,
|
||||||
services::{
|
services::{
|
||||||
book_library::{
|
book_library::{
|
||||||
formatters::{Format, FormatTitle},
|
formatters::{Format, FormatTitle},
|
||||||
@@ -45,7 +46,7 @@ where
|
|||||||
let chat_id = cq.chat_id();
|
let chat_id = cq.chat_id();
|
||||||
let user_id = cq.from.id;
|
let user_id = cq.from.id;
|
||||||
let message_id = cq.message.as_ref().map(|message| message.id());
|
let message_id = cq.message.as_ref().map(|message| message.id());
|
||||||
let query = get_query(cq);
|
let query = get_query(cq.clone());
|
||||||
|
|
||||||
let (chat_id, query, message_id) = match (chat_id, query, message_id) {
|
let (chat_id, query, message_id) = match (chat_id, query, message_id) {
|
||||||
(Some(chat_id), Some(query), Some(message_id)) => (chat_id, query, message_id),
|
(Some(chat_id), Some(query), Some(message_id)) => (chat_id, query, message_id),
|
||||||
@@ -106,15 +107,20 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
let formatted_page = items_page.format(page, 4096);
|
let formatted_page = items_page.format(page, 4096);
|
||||||
|
if is_message_text_equals(cq.message, &formatted_page) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let keyboard = generic_get_pagination_keyboard(page, items_page.pages, search_data, true);
|
let keyboard = generic_get_pagination_keyboard(page, items_page.pages, search_data, true);
|
||||||
|
match bot
|
||||||
bot.edit_message_text(chat_id, message_id, formatted_page)
|
.edit_message_text(chat_id, message_id, formatted_page)
|
||||||
.reply_markup(keyboard)
|
.reply_markup(keyboard)
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await
|
||||||
|
{
|
||||||
Ok(())
|
Ok(_) => Ok(()),
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn message_handler(message: Message, bot: CacheMe<Throttle<Bot>>) -> BotHandlerInternal {
|
pub async fn message_handler(message: Message, bot: CacheMe<Throttle<Bot>>) -> BotHandlerInternal {
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ pub mod commands;
|
|||||||
use chrono::{prelude::*, Duration};
|
use chrono::{prelude::*, Duration};
|
||||||
|
|
||||||
use crate::bots::{
|
use crate::bots::{
|
||||||
approved_bot::{services::book_library::get_uploaded_books, tools::filter_callback_query},
|
approved_bot::{
|
||||||
|
modules::utils::message_text::is_message_text_equals,
|
||||||
|
services::book_library::get_uploaded_books, tools::filter_callback_query,
|
||||||
|
},
|
||||||
BotHandlerInternal,
|
BotHandlerInternal,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -78,7 +81,7 @@ async fn update_log_pagination_handler(
|
|||||||
bot: CacheMe<Throttle<Bot>>,
|
bot: CacheMe<Throttle<Bot>>,
|
||||||
update_callback_data: UpdateLogCallbackData,
|
update_callback_data: UpdateLogCallbackData,
|
||||||
) -> BotHandlerInternal {
|
) -> BotHandlerInternal {
|
||||||
let message = match cq.message {
|
let message = match cq.message.clone() {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => {
|
None => {
|
||||||
bot.send_message(cq.from.id, "Ошибка! Попробуйте заново(")
|
bot.send_message(cq.from.id, "Ошибка! Попробуйте заново(")
|
||||||
@@ -138,14 +141,20 @@ async fn update_log_pagination_handler(
|
|||||||
let formatted_page = items_page.format(page, 4096);
|
let formatted_page = items_page.format(page, 4096);
|
||||||
|
|
||||||
let message_text = format!("{header}{formatted_page}");
|
let message_text = format!("{header}{formatted_page}");
|
||||||
|
if is_message_text_equals(cq.message, &message_text) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let keyboard = generic_get_pagination_keyboard(page, total_pages, update_callback_data, true);
|
let keyboard = generic_get_pagination_keyboard(page, total_pages, update_callback_data, true);
|
||||||
bot.edit_message_text(message.chat().id, message.id(), message_text)
|
match bot
|
||||||
|
.edit_message_text(message.chat().id, message.id(), message_text)
|
||||||
.reply_markup(keyboard)
|
.reply_markup(keyboard)
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await
|
||||||
|
{
|
||||||
Ok(())
|
Ok(_) => Ok(()),
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_update_log_handler() -> crate::bots::BotHandler {
|
pub fn get_update_log_handler() -> crate::bots::BotHandler {
|
||||||
|
|||||||
18
src/bots/approved_bot/modules/utils/message_text.rs
Normal file
18
src/bots/approved_bot/modules/utils/message_text.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
use teloxide::types::*;
|
||||||
|
|
||||||
|
pub fn is_message_text_equals(message: Option<MaybeInaccessibleMessage>, text: &str) -> bool {
|
||||||
|
let message = match message {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let message = match message {
|
||||||
|
MaybeInaccessibleMessage::Inaccessible(_) => return false,
|
||||||
|
MaybeInaccessibleMessage::Regular(v) => v,
|
||||||
|
};
|
||||||
|
|
||||||
|
match message.text() {
|
||||||
|
Some(msg_text) => text == msg_text,
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod filter_command;
|
pub mod filter_command;
|
||||||
|
pub mod message_text;
|
||||||
pub mod pagination;
|
pub mod pagination;
|
||||||
pub mod split_text;
|
pub mod split_text;
|
||||||
|
|||||||
@@ -32,12 +32,6 @@ impl BookGenre {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
|
||||||
pub struct Source {
|
|
||||||
// id: u32,
|
|
||||||
// name: String
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
pub struct Author {
|
pub struct Author {
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
|
|||||||
@@ -19,9 +19,10 @@ pub async fn message_handler(message: Message, bot: CacheMe<Throttle<Bot>>) -> a
|
|||||||
|
|
||||||
let message_text = match result {
|
let message_text = match result {
|
||||||
register::RegisterStatus::Success { ref username } => format_registered_message(username),
|
register::RegisterStatus::Success { ref username } => format_registered_message(username),
|
||||||
register::RegisterStatus::RegisterFail => strings::ALREADY_REGISTERED.to_string(),
|
register::RegisterStatus::RegisterFail => strings::MAY_BE_ALREADY_REGISTERED.to_string(),
|
||||||
register::RegisterStatus::LimitExtended => strings::LIMIT_EXTENDED_MESSAGE.to_string(),
|
register::RegisterStatus::LimitExtended => strings::LIMIT_EXTENDED_MESSAGE.to_string(),
|
||||||
register::RegisterStatus::WrongToken => strings::ERROR_MESSAGE.to_string(),
|
register::RegisterStatus::WrongToken => strings::ERROR_MESSAGE.to_string(),
|
||||||
|
register::RegisterStatus::AlreadyExists => strings::ALREADY_EXISTS_MESSAGE.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
bot.send_message(message.chat.id, message_text)
|
bot.send_message(message.chat.id, message_text)
|
||||||
|
|||||||
@@ -12,12 +12,14 @@ pub enum RegisterStatus {
|
|||||||
WrongToken,
|
WrongToken,
|
||||||
RegisterFail,
|
RegisterFail,
|
||||||
LimitExtended,
|
LimitExtended,
|
||||||
|
AlreadyExists,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum RegisterRequestStatus {
|
pub enum RegisterRequestStatus {
|
||||||
Success,
|
Success,
|
||||||
LimitExtended,
|
LimitExtended,
|
||||||
|
AlreadyExists,
|
||||||
UnknownError,
|
UnknownError,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,6 +54,7 @@ async fn make_register_request(
|
|||||||
Ok(match result.status().as_u16() {
|
Ok(match result.status().as_u16() {
|
||||||
200 => RegisterRequestStatus::Success,
|
200 => RegisterRequestStatus::Success,
|
||||||
402 => RegisterRequestStatus::LimitExtended,
|
402 => RegisterRequestStatus::LimitExtended,
|
||||||
|
409 => RegisterRequestStatus::AlreadyExists,
|
||||||
_ => RegisterRequestStatus::UnknownError,
|
_ => RegisterRequestStatus::UnknownError,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -81,5 +84,6 @@ pub async fn register(user_id: UserId, message_text: &str) -> RegisterStatus {
|
|||||||
},
|
},
|
||||||
RegisterRequestStatus::LimitExtended => RegisterStatus::LimitExtended,
|
RegisterRequestStatus::LimitExtended => RegisterStatus::LimitExtended,
|
||||||
RegisterRequestStatus::UnknownError => RegisterStatus::RegisterFail,
|
RegisterRequestStatus::UnknownError => RegisterStatus::RegisterFail,
|
||||||
|
RegisterRequestStatus::AlreadyExists => RegisterStatus::AlreadyExists,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ pub fn format_registered_message(username: &str) -> String {
|
|||||||
format!("@{username} зарегистрирован и через несколько минут будет подключен!")
|
format!("@{username} зарегистрирован и через несколько минут будет подключен!")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ALREADY_REGISTERED: &str = "Ошибка! Возможно бот уже зарегистрирован!";
|
pub const MAY_BE_ALREADY_REGISTERED: &str = "Ошибка! Возможно бот уже зарегистрирован!";
|
||||||
|
|
||||||
pub const ERROR_MESSAGE: &str = "Ошибка! Что-то не так с ботом!";
|
pub const ERROR_MESSAGE: &str = "Ошибка! Что-то не так с ботом!";
|
||||||
|
|
||||||
pub const LIMIT_EXTENDED_MESSAGE: &str = "Вы достигли максимального количества ботов!";
|
pub const LIMIT_EXTENDED_MESSAGE: &str = "Вы достигли максимального количества ботов!";
|
||||||
|
|
||||||
|
pub const ALREADY_EXISTS_MESSAGE: &str = "Ошибка! Бот с таким токеном уже зарегистрирован!";
|
||||||
|
|||||||
85
src/bots_manager/custom_error_handler.rs
Normal file
85
src/bots_manager/custom_error_handler.rs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
use std::future::Future;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tracing::log;
|
||||||
|
|
||||||
|
pub struct CustomErrorHandler {
|
||||||
|
pub text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CustomErrorHandler {
|
||||||
|
pub fn with_custom_text<T>(text: T) -> Arc<Self>
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
Arc::new(Self { text: text.into() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> teloxide::error_handlers::ErrorHandler<E> for CustomErrorHandler
|
||||||
|
where
|
||||||
|
E: std::fmt::Debug + Send + 'static,
|
||||||
|
{
|
||||||
|
fn handle_error(
|
||||||
|
self: Arc<Self>,
|
||||||
|
error: E,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let error_string = format!("{:?}", error);
|
||||||
|
|
||||||
|
if error_string.contains("Bad Request: message to be replied not found") {
|
||||||
|
log::debug!("Ignoring Telegram reply error: {:?}", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let backtrace = std::backtrace::Backtrace::force_capture();
|
||||||
|
|
||||||
|
let error_chain = if let Some(std_error) =
|
||||||
|
(&error as &dyn std::any::Any).downcast_ref::<Box<dyn std::error::Error>>()
|
||||||
|
{
|
||||||
|
let mut chain = Vec::new();
|
||||||
|
let mut source = std_error.source();
|
||||||
|
while let Some(err) = source {
|
||||||
|
chain.push(format!(" Caused by: {}", err));
|
||||||
|
source = err.source();
|
||||||
|
}
|
||||||
|
if chain.is_empty() {
|
||||||
|
String::new()
|
||||||
|
} else {
|
||||||
|
format!("\nError chain:\n{}", chain.join("\n"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
let backtrace_info = match backtrace.status() {
|
||||||
|
std::backtrace::BacktraceStatus::Captured => {
|
||||||
|
format!("\nBacktrace:\n{}", backtrace)
|
||||||
|
}
|
||||||
|
std::backtrace::BacktraceStatus::Disabled => {
|
||||||
|
"\nBacktrace: disabled (compile with debug info for stack traces)".to_string()
|
||||||
|
}
|
||||||
|
std::backtrace::BacktraceStatus::Unsupported => {
|
||||||
|
"\nBacktrace: unsupported on this platform".to_string()
|
||||||
|
}
|
||||||
|
_ => String::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
log::error!(
|
||||||
|
"{}: {:?}{}{}",
|
||||||
|
self.text,
|
||||||
|
error,
|
||||||
|
error_chain,
|
||||||
|
backtrace_info
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CustomErrorHandler {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
text: "An error from the update listener".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
|
use super::custom_error_handler::CustomErrorHandler;
|
||||||
use teloxide::adaptors::throttle::Limits;
|
use teloxide::adaptors::throttle::Limits;
|
||||||
use teloxide::dispatching::Dispatcher;
|
use teloxide::dispatching::Dispatcher;
|
||||||
use teloxide::error_handlers::LoggingErrorHandler;
|
|
||||||
use teloxide::requests::{Request, Requester, RequesterExt};
|
use teloxide::requests::{Request, Requester, RequesterExt};
|
||||||
use teloxide::stop::StopToken;
|
use teloxide::stop::StopToken;
|
||||||
use teloxide::stop::{mk_stop_token, StopFlag};
|
use teloxide::stop::{mk_stop_token, StopFlag};
|
||||||
@@ -108,7 +109,7 @@ pub async fn start_bot(bot_data: &BotData) {
|
|||||||
dispatcher
|
dispatcher
|
||||||
.dispatch_with_listener(
|
.dispatch_with_listener(
|
||||||
listener,
|
listener,
|
||||||
LoggingErrorHandler::with_custom_text("An error from the update listener"),
|
CustomErrorHandler::with_custom_text("An error from the update listener"),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
pub mod axum_server;
|
pub mod axum_server;
|
||||||
pub mod bot_manager_client;
|
pub mod bot_manager_client;
|
||||||
pub mod closable_sender;
|
pub mod closable_sender;
|
||||||
|
pub mod custom_error_handler;
|
||||||
pub mod internal;
|
pub mod internal;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user