Bug fixes

This commit is contained in:
unknown
2026-05-22 04:00:02 +02:00
parent 7227bc97fc
commit 10bfdfb914
8 changed files with 1308 additions and 43 deletions

View File

@@ -124,8 +124,28 @@ struct BotContext {
sem: Arc<tokio::sync::Semaphore>,
}
#[tokio::main]
async fn main() {
fn main() {
// Windows default thread stack is 1MB; teloxide futures + large Telegram types
// (CallbackQuery/Message ~5KB each) can exhaust this during dptree dispatch.
// Spawn the tokio runtime on a thread with an 8MB stack.
let stack_size = 8 * 1024 * 1024;
std::thread::Builder::new()
.name("cgcx-bot-main".into())
.stack_size(stack_size)
.spawn(|| {
tokio::runtime::Builder::new_multi_thread()
.worker_threads(4)
.enable_all()
.build()
.expect("tokio runtime")
.block_on(run_bot());
})
.expect("spawn main thread")
.join()
.expect("main thread panicked");
}
async fn run_bot() {
tracing_subscriber::fmt::init();
let config = Arc::new(Config::load().expect("Failed to load config"));
@@ -175,6 +195,7 @@ async fn main() {
.await;
}
#[inline(never)]
async fn handle_message(
bot: Bot,
msg: Message,
@@ -285,27 +306,33 @@ async fn handle_message(
Ok(())
}
#[inline(never)]
async fn handle_callback(
bot: Bot,
q: CallbackQuery,
storage: Arc<InMemStorage<BotState>>,
ctx: BotContext,
) -> HandlerResult {
let data = q.data.as_deref().unwrap_or("");
let user = q.from;
let user_id = user.id.0 as i64;
// CallbackQuery (and the Message it may contain) are very large structs.
// Extract only the fields we need and drop q before the first .await so
// the compiler can keep the async state machine small.
let callback_id = q.id.clone();
let data = q.data.as_deref().unwrap_or("").to_string();
let user_id = q.from.id.0 as i64;
let chat_id = q.message.as_ref().map(|m| m.chat().id).unwrap_or(ChatId(user_id));
let message_id = q.message.as_ref().map(|m| m.id());
drop(q);
if !ctx.moderation.is_allowed(user_id).await {
bot.answer_callback_query(&q.id).text("Not allowed").await?;
bot.answer_callback_query(&callback_id).text("Not allowed").await?;
return Ok(());
}
let chat_id = q.message.as_ref().map(|m| m.chat().id).unwrap_or(ChatId(user_id));
let dialogue = BotDialogue { chat_id, storage };
let parts: Vec<&str> = data.split(':').collect();
if parts.len() < 3 || parts[0] != "v1" {
bot.answer_callback_query(&q.id).await?;
bot.answer_callback_query(&callback_id).await?;
return Ok(());
}
@@ -314,14 +341,14 @@ async fn handle_callback(
"accept" => {
let user_repo = UserRepo::new(ctx.db.conn());
user_repo.set_accepted_terms(user_id).await?;
if let Some(msg) = &q.message {
bot.delete_message(chat_id, msg.id()).await.ok();
if let Some(mid) = message_id {
bot.delete_message(chat_id, mid).await.ok();
}
send_main_menu(&bot, chat_id, &dialogue).await?;
}
"reject" => {
if let Some(msg) = &q.message {
bot.delete_message(chat_id, msg.id()).await.ok();
if let Some(mid) = message_id {
bot.delete_message(chat_id, mid).await.ok();
}
dialogue.reset().await?;
}
@@ -358,7 +385,7 @@ async fn handle_callback(
let state = dialogue.get_or_default().await?;
if let BotState::UploadStaging { items, .. } = state {
if items.is_empty() {
bot.answer_callback_query(&q.id).text("No items to upload.").await?;
bot.answer_callback_query(&callback_id).text("No items to upload.").await?;
} else {
let options = UploadOptions {
allow_download: true,
@@ -370,8 +397,8 @@ async fn handle_callback(
}
}
"cancel" => {
if let Some(msg) = &q.message {
bot.edit_message_text(chat_id, msg.id(), "Upload cancelled.").await.ok();
if let Some(mid) = message_id {
bot.edit_message_text(chat_id, mid, "Upload cancelled.").await.ok();
}
dialogue.update(BotState::MainMenu).await?;
}
@@ -429,7 +456,7 @@ async fn handle_callback(
_ => {}
}
bot.answer_callback_query(&q.id).await?;
bot.answer_callback_query(&callback_id).await?;
Ok(())
}
@@ -491,6 +518,7 @@ async fn send_staging_message(bot: &Bot, chat_id: ChatId, items: &[StagedItem],
Ok(())
}
#[inline(never)]
async fn handle_staging_message(
bot: &Bot,
msg: Message,
@@ -504,6 +532,8 @@ async fn handle_staging_message(
return Ok(());
}
let chat_id = msg.chat.id;
let caption = msg.caption().map(|s| s.to_string());
let mut new_item = None;
match upload_type {
@@ -516,7 +546,7 @@ async fn handle_staging_message(
file_name: format!("photo_{}.jpg", items.len()),
mime_type: "image/jpeg".to_string(),
size: p.file.size as u64,
caption: msg.caption().map(|s| s.to_string()),
caption: caption.clone(),
});
}
} else if let Some(video) = msg.video() {
@@ -525,7 +555,7 @@ async fn handle_staging_message(
file_name: video.file_name.clone().unwrap_or_else(|| format!("video_{}.mp4", items.len())),
mime_type: "video/mp4".to_string(),
size: video.file.size as u64,
caption: msg.caption().map(|s| s.to_string()),
caption: caption.clone(),
});
} else if let Some(audio) = msg.audio() {
new_item = Some(StagedItem {
@@ -533,7 +563,7 @@ async fn handle_staging_message(
file_name: audio.file_name.clone().unwrap_or_else(|| format!("audio_{}.mp3", items.len())),
mime_type: "audio/mpeg".to_string(),
size: audio.file.size as u64,
caption: msg.caption().map(|s| s.to_string()),
caption: caption.clone(),
});
}
}
@@ -544,7 +574,7 @@ async fn handle_staging_message(
file_name: doc.file_name.clone().unwrap_or_else(|| format!("file_{}", items.len())),
mime_type: doc.mime_type.clone().map(|m| m.to_string()).unwrap_or_else(|| "application/octet-stream".to_string()),
size: doc.file.size as u64,
caption: msg.caption().map(|s| s.to_string()),
caption: caption.clone(),
});
}
}
@@ -563,10 +593,12 @@ async fn handle_staging_message(
}
}
drop(msg);
if let Some(item) = new_item {
items.push(item);
dialogue.update(BotState::UploadStaging { items: items.clone(), upload_type }).await?;
send_staging_message(bot, msg.chat.id, &items, upload_type).await?;
send_staging_message(bot, chat_id, &items, upload_type).await?;
}
Ok(())