mirror of
https://github.com/chatmail/core.git
synced 2026-05-05 06:16:30 +03:00
feat: For bots, wait with emitting IncomingMsg until the Post-Msg arrived
This commit is contained in:
@@ -1146,6 +1146,12 @@ ORDER BY m.timestamp DESC,m.id DESC",
|
|||||||
///
|
///
|
||||||
/// Blocked contacts and chats are excluded,
|
/// Blocked contacts and chats are excluded,
|
||||||
/// but self-sent messages and contact requests are included in the results.
|
/// but self-sent messages and contact requests are included in the results.
|
||||||
|
///
|
||||||
|
/// Note that this returns the pre-message's id as soon as it arrives.
|
||||||
|
/// The bot needs to wait for the post-message by itself if it wants to use this API
|
||||||
|
/// to get fully downloaded messages.
|
||||||
|
/// If the bot doesn't want this, then it should instead use the [`EventType::IncomingMsg`]
|
||||||
|
/// event for getting notified about new messages.
|
||||||
pub async fn get_next_msgs(&self) -> Result<Vec<MsgId>> {
|
pub async fn get_next_msgs(&self) -> Result<Vec<MsgId>> {
|
||||||
let last_msg_id = match self.get_config(Config::LastMsgId).await? {
|
let last_msg_id = match self.get_config(Config::LastMsgId).await? {
|
||||||
Some(s) => MsgId::new(s.parse()?),
|
Some(s) => MsgId::new(s.parse()?),
|
||||||
|
|||||||
@@ -730,10 +730,19 @@ impl Imap {
|
|||||||
info!(context, "{message_id:?} is a post-message.");
|
info!(context, "{message_id:?} is a post-message.");
|
||||||
available_post_msgs.push(message_id.clone());
|
available_post_msgs.push(message_id.clone());
|
||||||
|
|
||||||
|
let is_bot = context.get_config_bool(Config::Bot).await?;
|
||||||
|
if is_bot && download_limit.is_none_or(|download_limit| size <= download_limit)
|
||||||
|
{
|
||||||
|
uids_fetch.push(uid);
|
||||||
|
uid_message_ids.insert(uid, message_id);
|
||||||
|
} else {
|
||||||
if download_limit.is_none_or(|download_limit| size <= download_limit) {
|
if download_limit.is_none_or(|download_limit| size <= download_limit) {
|
||||||
|
// Download later after all the small messages are downloaded,
|
||||||
|
// so that large messages don't delay receiving small messages
|
||||||
download_later.push(message_id.clone());
|
download_later.push(message_id.clone());
|
||||||
}
|
}
|
||||||
largest_uid_skipped = Some(uid);
|
largest_uid_skipped = Some(uid);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
info!(context, "{message_id:?} is not a post-message.");
|
info!(context, "{message_id:?} is not a post-message.");
|
||||||
if download_limit.is_none_or(|download_limit| size <= download_limit) {
|
if download_limit.is_none_or(|download_limit| size <= download_limit) {
|
||||||
|
|||||||
@@ -1069,7 +1069,12 @@ UPDATE msgs SET state=? WHERE
|
|||||||
let fresh = received_msg.state == MessageState::InFresh
|
let fresh = received_msg.state == MessageState::InFresh
|
||||||
&& mime_parser.is_system_message != SystemMessage::CallAccepted
|
&& mime_parser.is_system_message != SystemMessage::CallAccepted
|
||||||
&& mime_parser.is_system_message != SystemMessage::CallEnded;
|
&& mime_parser.is_system_message != SystemMessage::CallEnded;
|
||||||
let important = mime_parser.incoming && fresh && !is_old_contact_request;
|
let is_bot = context.get_config_bool(Config::Bot).await?;
|
||||||
|
let is_pre_message = matches!(mime_parser.pre_message, PreMessageMode::Pre { .. });
|
||||||
|
let skip_bot_notify = is_bot && is_pre_message;
|
||||||
|
let important =
|
||||||
|
mime_parser.incoming && fresh && !is_old_contact_request && !skip_bot_notify;
|
||||||
|
|
||||||
for msg_id in &received_msg.msg_ids {
|
for msg_id in &received_msg.msg_ids {
|
||||||
chat_id.emit_msg_event(context, *msg_id, important);
|
chat_id.emit_msg_event(context, *msg_id, important);
|
||||||
}
|
}
|
||||||
@@ -1300,6 +1305,7 @@ async fn decide_chat_assignment(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
pre_message_exists
|
pre_message_exists
|
||||||
|
// TODO send incoming msg event
|
||||||
} else if let PreMessageMode::Pre {
|
} else if let PreMessageMode::Pre {
|
||||||
post_msg_rfc724_mid,
|
post_msg_rfc724_mid,
|
||||||
..
|
..
|
||||||
@@ -2573,7 +2579,22 @@ WHERE id=?
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
if context.get_config_bool(Config::Bot).await? {
|
||||||
|
if original_msg.hidden {
|
||||||
|
// No need to emit an event about the changed message
|
||||||
|
} else if !original_msg.chat_id.is_trash() {
|
||||||
|
let fresh = original_msg.state == MessageState::InFresh;
|
||||||
|
let important = mime_parser.incoming && fresh;
|
||||||
|
|
||||||
|
original_msg
|
||||||
|
.chat_id
|
||||||
|
.emit_msg_event(context, original_msg.id, important);
|
||||||
|
context.new_msgs_notify.notify_one();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
context.emit_msgs_changed(original_msg.chat_id, original_msg.id);
|
context.emit_msgs_changed(original_msg.chat_id, original_msg.id);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
mod additional_text;
|
mod additional_text;
|
||||||
|
mod bots_tests;
|
||||||
mod forward_and_save;
|
mod forward_and_save;
|
||||||
mod legacy;
|
mod legacy;
|
||||||
mod receiving;
|
mod receiving;
|
||||||
|
|||||||
55
src/tests/pre_messages/bots_tests.rs
Normal file
55
src/tests/pre_messages/bots_tests.rs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
use crate::EventType;
|
||||||
|
use crate::config::Config;
|
||||||
|
use crate::download::DownloadState;
|
||||||
|
use crate::message::Viewtype;
|
||||||
|
use crate::receive_imf::receive_imf;
|
||||||
|
use crate::test_utils::TestContextManager;
|
||||||
|
use crate::tests::pre_messages::util::send_large_file_message;
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
|
async fn test_bot_pre_message_notifications() -> Result<()> {
|
||||||
|
let mut tcm = TestContextManager::new();
|
||||||
|
let alice = tcm.alice().await;
|
||||||
|
let bob = tcm.bob().await;
|
||||||
|
|
||||||
|
// Configure Bob as a bot
|
||||||
|
bob.set_config_bool(Config::Bot, true).await?;
|
||||||
|
|
||||||
|
let alice_group_id = alice.create_group_with_members("test group", &[&bob]).await;
|
||||||
|
|
||||||
|
let (pre_message, post_message, _alice_msg_id) = send_large_file_message(
|
||||||
|
&alice,
|
||||||
|
alice_group_id,
|
||||||
|
Viewtype::File,
|
||||||
|
&vec![0u8; 1_000_000],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Bob receives pre-message
|
||||||
|
bob.evtracker.clear_events();
|
||||||
|
receive_imf(&bob, pre_message.payload().as_bytes(), false).await?;
|
||||||
|
|
||||||
|
// Verify Bob does NOT get an IncomingMsg event for the pre-message
|
||||||
|
assert!(
|
||||||
|
bob.evtracker
|
||||||
|
.get_matching_opt(&bob, |e| matches!(e, EventType::IncomingMsg { .. }))
|
||||||
|
.await
|
||||||
|
.is_none()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Bob receives post-message
|
||||||
|
receive_imf(&bob, post_message.payload().as_bytes(), false).await?;
|
||||||
|
|
||||||
|
// Verify Bob DOES get an IncomingMsg event for the complete message
|
||||||
|
bob.evtracker
|
||||||
|
.get_matching(|e| matches!(e, EventType::IncomingMsg { .. }))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let msg = bob.get_last_msg().await;
|
||||||
|
assert_eq!(msg.download_state, DownloadState::Done);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user