Create book_bot crate and add log_handler annotations

This commit is contained in:
2026-03-02 20:11:20 +01:00
parent bacab9ee32
commit ee3a2cdfc7
61 changed files with 145 additions and 86 deletions

10
Cargo.lock generated
View File

@@ -372,6 +372,7 @@ dependencies = [
"axum", "axum",
"axum-prometheus", "axum-prometheus",
"base64", "base64",
"book_bot_macros",
"chrono", "chrono",
"ctrlc", "ctrlc",
"dateparser", "dateparser",
@@ -400,6 +401,15 @@ dependencies = [
"url", "url",
] ]
[[package]]
name = "book_bot_macros"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.19.0" version = "3.19.0"

View File

@@ -1,70 +1,9 @@
[package] [workspace]
name = "book_bot" members = ["book_bot", "book_bot_macros"]
version = "0.1.0" resolver = "2"
edition = "2021"
[profile.release]
opt-level = 3
debug = false
strip = true
lto = true
codegen-units = 1
panic = 'abort'
[profile.profiling]
inherits = "release"
debug = true
strip = false
[dependencies]
once_cell = "1.21.3"
tokio = { version = "1.44.2", features = ["rt-multi-thread", "macros"] }
tokio-util = { version = "0.7.14", features = ["compat"] }
tokio-stream = "0.1.17"
futures = "0.3.31"
axum = "0.8.3"
axum-prometheus = "0.9.0"
tower = "0.5.2"
tower-http = { version = "0.6.2", features = ["trace"] }
[workspace.dependencies]
tracing = "0.1.41" tracing = "0.1.41"
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } syn = { version = "2.0", features = ["full"] }
sentry-tracing = "0.42.0" quote = "1.0"
proc-macro2 = "1.0"
reqwest = { version = "0.12.15", features = ["json", "stream"] }
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
teloxide = { version = "0.17.0", features = [
"macros",
"webhooks-axum",
"cache-me",
"throttle",
] }
url = "2.5.4"
ctrlc = { version = "3.4.5", features = ["termination"] }
strum = "0.27.1"
strum_macros = "0.27.1"
base64 = "0.22.1"
textwrap = "0.16.2"
regex = "1.11.1"
chrono = "0.4.40"
dateparser = "0.2.1"
smallvec = { version = "1.14.0", features = ["serde"] }
smartstring = { version = "1.0.1", features = ["serde"] }
moka = { version = "0.12.10", features = ["future"] }
sentry = { version = "0.42.0", features = ["debug-images"] }
anyhow = "1.0.98"

78
book_bot/Cargo.toml Normal file
View File

@@ -0,0 +1,78 @@
[package]
name = "book_bot"
version = "0.1.0"
edition = "2021"
description = "Binary crate for the book_bot application."
[dependencies]
# Local procedural-macro crate (path is relative to this crate directory)
book_bot_macros = { path = "../book_bot_macros" }
# Core runtime / async
once_cell = "1.21.3"
tokio = { version = "1.44.2", features = ["rt-multi-thread", "macros"] }
tokio-util = { version = "0.7.14", features = ["compat"] }
tokio-stream = "0.1.17"
futures = "0.3.31"
# Web / server / metrics
axum = "0.8.3"
axum-prometheus = "0.9.0"
# Middleware / tower
tower = "0.5.2"
tower-http = { version = "0.6.2", features = ["trace"] }
# Observability
tracing = "0.1.41"
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
sentry-tracing = "0.42.0"
sentry = { version = "0.42.0", features = ["debug-images"] }
# HTTP client
reqwest = { version = "0.12.15", features = ["json", "stream"] }
# Serialization
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
# Telegram bot framework
teloxide = { version = "0.17.0", features = [
"macros",
"webhooks-axum",
"cache-me",
"throttle",
] }
# Utilities and helpers
url = "2.5.4"
ctrlc = { version = "3.4.5", features = ["termination"] }
strum = "0.27.1"
strum_macros = "0.27.1"
base64 = "0.22.1"
textwrap = "0.16.2"
regex = "1.11.1"
chrono = "0.4.40"
dateparser = "0.2.1"
smallvec = { version = "1.14.0", features = ["serde"] }
smartstring = { version = "1.0.1", features = ["serde"] }
moka = { version = "0.12.10", features = ["future"] }
anyhow = "1.0.98"
[profile.release]
opt-level = 3
debug = false
strip = true
lto = true
codegen-units = 1
panic = "abort"
[profile.profiling]
inherits = "release"
debug = true
strip = false

View File

@@ -3,6 +3,8 @@ pub mod commands;
pub mod errors; pub mod errors;
pub mod formatter; pub mod formatter;
use book_bot_macros::log_handler;
use std::convert::TryInto; use std::convert::TryInto;
use futures::TryStreamExt; use futures::TryStreamExt;
@@ -40,6 +42,7 @@ async fn download_image(
Ok(reqwest::get(file).await?.error_for_status()?) Ok(reqwest::get(file).await?.error_for_status()?)
} }
#[log_handler("annotations")]
pub async fn send_annotation_handler<T, Fut>( pub async fn send_annotation_handler<T, Fut>(
message: Message, message: Message,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
@@ -115,6 +118,7 @@ where
Ok(()) Ok(())
} }
#[log_handler("annotations")]
pub async fn annotation_pagination_handler<T, Fut>( pub async fn annotation_pagination_handler<T, Fut>(
cq: CallbackQuery, cq: CallbackQuery,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,

View File

@@ -1,6 +1,8 @@
pub mod callback_data; pub mod callback_data;
pub mod commands; pub mod commands;
use book_bot_macros::log_handler;
use core::fmt::Debug; use core::fmt::Debug;
use smartstring::alias::String as SmartString; use smartstring::alias::String as SmartString;
@@ -31,6 +33,7 @@ use self::{callback_data::BookCallbackData, commands::BookCommand};
use super::utils::{filter_command::filter_command, pagination::generic_get_pagination_keyboard}; use super::utils::{filter_command::filter_command, pagination::generic_get_pagination_keyboard};
#[log_handler("book")]
async fn send_book_handler<T, P, Fut>( async fn send_book_handler<T, P, Fut>(
message: Message, message: Message,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
@@ -49,9 +52,7 @@ where
}; };
let chat_id = message.chat.id; let chat_id = message.chat.id;
let user_id = message.from.map(|from| from.id); let user_id = match message.from.map(|from| from.id) {
let user_id = match user_id {
Some(v) => v, Some(v) => v,
None => { None => {
return match bot return match bot
@@ -102,6 +103,7 @@ where
Ok(()) Ok(())
} }
#[log_handler("book")]
async fn send_pagination_book_handler<T, P, Fut>( async fn send_pagination_book_handler<T, P, Fut>(
cq: CallbackQuery, cq: CallbackQuery,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,

View File

@@ -1,6 +1,8 @@
pub mod callback_data; pub mod callback_data;
pub mod commands; pub mod commands;
use book_bot_macros::log_handler;
use std::time::Duration; use std::time::Duration;
use chrono::Utc; use chrono::Utc;
@@ -187,6 +189,7 @@ async fn download_handler(
} }
} }
#[log_handler("download")]
async fn get_download_keyboard_handler( async fn get_download_keyboard_handler(
message: Message, message: Message,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
@@ -231,6 +234,7 @@ async fn get_download_keyboard_handler(
Ok(()) Ok(())
} }
#[log_handler("download")]
async fn get_download_archive_keyboard_handler( async fn get_download_archive_keyboard_handler(
message: Message, message: Message,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
@@ -434,6 +438,7 @@ async fn wait_archive(
Ok(()) Ok(())
} }
#[log_handler("download")]
async fn download_archive( async fn download_archive(
cq: CallbackQuery, cq: CallbackQuery,
download_archive_query_data: DownloadArchiveQueryData, download_archive_query_data: DownloadArchiveQueryData,
@@ -482,6 +487,16 @@ async fn download_archive(
Ok(()) Ok(())
} }
#[log_handler("download")]
async fn download_query_handler(
cq: CallbackQuery,
download_query_data: DownloadQueryData,
bot: CacheMe<Throttle<Bot>>,
cache: BotCache,
) -> BotHandlerInternal {
download_handler(cq.message.unwrap(), bot, cache, download_query_data, true).await
}
pub fn get_download_handler() -> crate::bots::BotHandler { pub fn get_download_handler() -> crate::bots::BotHandler {
dptree::entry() dptree::entry()
.branch( .branch(
@@ -492,21 +507,7 @@ pub fn get_download_handler() -> crate::bots::BotHandler {
.branch( .branch(
Update::filter_callback_query() Update::filter_callback_query()
.chain(filter_callback_query::<DownloadQueryData>()) .chain(filter_callback_query::<DownloadQueryData>())
.endpoint( .endpoint(download_query_handler),
|cq: CallbackQuery,
download_query_data: DownloadQueryData,
bot: CacheMe<Throttle<Bot>>,
cache: BotCache| async move {
download_handler(
cq.message.unwrap(),
bot,
cache,
download_query_data,
true,
)
.await
},
),
) )
.branch( .branch(
Update::filter_message() Update::filter_message()

View File

@@ -1,6 +1,7 @@
pub mod commands; pub mod commands;
use crate::bots::BotHandlerInternal; use crate::bots::BotHandlerInternal;
use book_bot_macros::log_handler;
use teloxide::{ use teloxide::{
adaptors::{CacheMe, Throttle}, adaptors::{CacheMe, Throttle},
@@ -10,6 +11,7 @@ use teloxide::{
use self::commands::HelpCommand; use self::commands::HelpCommand;
#[log_handler("help")]
pub async fn help_handler(message: Message, bot: CacheMe<Throttle<Bot>>) -> BotHandlerInternal { pub async fn help_handler(message: Message, bot: CacheMe<Throttle<Bot>>) -> BotHandlerInternal {
let name = message let name = message
.from .from

View File

@@ -1,6 +1,8 @@
pub mod callback_data; pub mod callback_data;
pub mod commands; pub mod commands;
use book_bot_macros::log_handler;
use smallvec::SmallVec; use smallvec::SmallVec;
use smartstring::alias::String as SmartString; use smartstring::alias::String as SmartString;
use teloxide::{ use teloxide::{
@@ -23,6 +25,7 @@ use crate::bots::{
use self::commands::RandomCommand; use self::commands::RandomCommand;
#[log_handler("random")]
async fn random_handler( async fn random_handler(
message: Message, message: Message,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
@@ -111,6 +114,7 @@ where
} }
} }
#[log_handler("random")]
async fn get_random_item_handler<T, Fut>( async fn get_random_item_handler<T, Fut>(
cq: CallbackQuery, cq: CallbackQuery,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
@@ -127,6 +131,7 @@ where
get_random_item_handler_internal(cq, bot, item).await get_random_item_handler_internal(cq, bot, item).await
} }
#[log_handler("random")]
async fn get_genre_metas_handler( async fn get_genre_metas_handler(
cq: CallbackQuery, cq: CallbackQuery,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
@@ -169,6 +174,7 @@ async fn get_genre_metas_handler(
Ok(()) Ok(())
} }
#[log_handler("random")]
async fn get_genres_by_meta_handler( async fn get_genres_by_meta_handler(
cq: CallbackQuery, cq: CallbackQuery,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
@@ -233,6 +239,7 @@ async fn get_genres_by_meta_handler(
Ok(()) Ok(())
} }
#[log_handler("random")]
async fn get_random_book_by_genre( async fn get_random_book_by_genre(
cq: CallbackQuery, cq: CallbackQuery,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,

View File

@@ -1,6 +1,8 @@
pub mod callback_data; pub mod callback_data;
pub mod utils; pub mod utils;
use book_bot_macros::log_handler;
use core::fmt::Debug; use core::fmt::Debug;
use smartstring::alias::String as SmartString; use smartstring::alias::String as SmartString;
@@ -35,6 +37,7 @@ use self::{
use super::utils::pagination::generic_get_pagination_keyboard; use super::utils::pagination::generic_get_pagination_keyboard;
#[log_handler("search")]
async fn generic_search_pagination_handler<T, P, Fut>( async fn generic_search_pagination_handler<T, P, Fut>(
cq: CallbackQuery, cq: CallbackQuery,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,
@@ -126,6 +129,7 @@ where
} }
} }
#[log_handler("search")]
pub async fn message_handler(message: Message, bot: CacheMe<Throttle<Bot>>) -> BotHandlerInternal { pub async fn message_handler(message: Message, bot: CacheMe<Throttle<Bot>>) -> BotHandlerInternal {
let query = message.text().map(|t| t.trim()).filter(|t| !t.is_empty()); let query = message.text().map(|t| t.trim()).filter(|t| !t.is_empty());
let user_id = message.from.as_ref().map(|u| u.id); let user_id = message.from.as_ref().map(|u| u.id);

View File

@@ -1,6 +1,8 @@
pub mod callback_data; pub mod callback_data;
pub mod commands; pub mod commands;
use book_bot_macros::log_handler;
use std::collections::HashSet; use std::collections::HashSet;
use smallvec::SmallVec; use smallvec::SmallVec;
@@ -44,6 +46,7 @@ fn get_main_settings_keyboard() -> InlineKeyboardMarkup {
} }
} }
#[log_handler("settings")]
async fn settings_handler(message: Message, bot: CacheMe<Throttle<Bot>>) -> BotHandlerInternal { async fn settings_handler(message: Message, bot: CacheMe<Throttle<Bot>>) -> BotHandlerInternal {
bot.send_message(message.chat.id, "Настройки") bot.send_message(message.chat.id, "Настройки")
.reply_markup(get_main_settings_keyboard()) .reply_markup(get_main_settings_keyboard())
@@ -149,6 +152,7 @@ fn get_default_search_keyboard(current: Option<DefaultSearchType>) -> InlineKeyb
} }
} }
#[log_handler("settings")]
async fn settings_callback_handler( async fn settings_callback_handler(
cq: CallbackQuery, cq: CallbackQuery,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,

View File

@@ -1,4 +1,5 @@
use crate::bots::BotHandlerInternal; use crate::bots::BotHandlerInternal;
use book_bot_macros::log_handler;
use teloxide::{ use teloxide::{
adaptors::{CacheMe, Throttle}, adaptors::{CacheMe, Throttle},
@@ -14,6 +15,7 @@ enum SupportCommand {
Donate, Donate,
} }
#[log_handler("support")]
pub async fn support_command_handler( pub async fn support_command_handler(
message: Message, message: Message,
bot: &CacheMe<Throttle<Bot>>, bot: &CacheMe<Throttle<Bot>>,

View File

@@ -1,6 +1,7 @@
pub mod callback_data; pub mod callback_data;
pub mod commands; pub mod commands;
use book_bot_macros::log_handler;
use chrono::{prelude::*, Duration}; use chrono::{prelude::*, Duration};
use crate::bots::{ use crate::bots::{
@@ -21,6 +22,7 @@ use self::{callback_data::UpdateLogCallbackData, commands::UpdateLogCommand};
use super::utils::pagination::generic_get_pagination_keyboard; use super::utils::pagination::generic_get_pagination_keyboard;
#[log_handler("update_history")]
async fn update_log_command(message: Message, bot: CacheMe<Throttle<Bot>>) -> BotHandlerInternal { async fn update_log_command(message: Message, bot: CacheMe<Throttle<Bot>>) -> BotHandlerInternal {
let now = Utc::now().date_naive(); let now = Utc::now().date_naive();
let d3 = now - Duration::days(3); let d3 = now - Duration::days(3);
@@ -76,6 +78,7 @@ async fn update_log_command(message: Message, bot: CacheMe<Throttle<Bot>>) -> Bo
} }
} }
#[log_handler("update_history")]
async fn update_log_pagination_handler( async fn update_log_pagination_handler(
cq: CallbackQuery, cq: CallbackQuery,
bot: CacheMe<Throttle<Bot>>, bot: CacheMe<Throttle<Bot>>,

View File

@@ -1,4 +1,5 @@
use anyhow; use anyhow;
use book_bot_macros::log_handler;
use teloxide::{ use teloxide::{
adaptors::{CacheMe, Throttle}, adaptors::{CacheMe, Throttle},
prelude::*, prelude::*,
@@ -11,8 +12,10 @@ pub mod register;
pub mod strings; pub mod strings;
pub mod utils; pub mod utils;
#[log_handler("manager")]
pub async fn message_handler(message: Message, bot: CacheMe<Throttle<Bot>>) -> anyhow::Result<()> { pub async fn message_handler(message: Message, bot: CacheMe<Throttle<Bot>>) -> anyhow::Result<()> {
let from_user = message.clone().from.unwrap(); let from_user = message.clone().from.unwrap();
let text = message.text().unwrap_or(""); let text = message.text().unwrap_or("");
let result = register::register(from_user.id, text).await; let result = register::register(from_user.id, text).await;