feat: Add EventType::CallMissed and emit it for missed calls (#7840)

Before, only `CallEnded` was emitted for missed calls, or, if a call arrives already being stale,
`IncomingMsg`. Now:
- `CallMissed` is emitted in addition to `CallEnded`.
- `IncomingMsg` is replaced with `CallMissed` for stale calls.
Having only one event type for missed calls should simplify handling them in the apps.

This doesn't emit `CallMissed` for those who aren't allowed to call us. Also, don't emit `CallEnded`
if the caller isn't allowed to call us and the call wasn't accepted, as there's no previous
`IncomingCall` event in this case.
This commit is contained in:
iequidoo
2026-03-04 20:12:47 -03:00
parent d6971ee4ac
commit 9cb2077c94
6 changed files with 197 additions and 51 deletions

View File

@@ -5,6 +5,7 @@ use crate::constants::DC_CHAT_ID_TRASH;
use crate::message::MessageState;
use crate::receive_imf::receive_imf;
use crate::test_utils::{TestContext, TestContextManager};
use crate::tools::SystemTime;
struct CallSetup {
pub alice: TestContext,
@@ -490,6 +491,9 @@ async fn test_caller_cancels_call() -> Result<()> {
// Bob receives the ending message
bob.recv_msg_trash(&sent3).await;
assert_text(&bob, bob_call.id, "Missed call").await?;
bob.evtracker
.get_matching(|evt| matches!(evt, EventType::CallMissed { .. }))
.await;
bob.evtracker
.get_matching(|evt| matches!(evt, EventType::CallEnded { .. }))
.await;
@@ -502,6 +506,9 @@ async fn test_caller_cancels_call() -> Result<()> {
bob2.recv_msg_trash(&sent3).await;
assert_text(&bob2, bob2_call.id, "Missed call").await?;
bob2.evtracker
.get_matching(|evt| matches!(evt, EventType::CallMissed { .. }))
.await;
bob2.evtracker
.get_matching(|evt| matches!(evt, EventType::CallEnded { .. }))
.await;
@@ -510,6 +517,95 @@ async fn test_caller_cancels_call() -> Result<()> {
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_stale_call() -> Result<()> {
let mut tcm = TestContextManager::new();
for accepted in [false, true] {
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;
info!(bob, "Alice is accepted: {accepted}.");
if accepted {
bob.create_chat(alice).await;
}
let alice_chat = alice.create_chat(bob).await;
alice
.place_outgoing_call(alice_chat.id, PLACE_INFO.to_string(), true)
.await?;
let sent1 = alice.pop_sent_msg().await;
SystemTime::shift(Duration::from_secs(3600));
let bob_call = bob.recv_msg(&sent1).await;
let EventType::MsgsChanged { msg_id, chat_id } = bob
.evtracker
.get_matching(|evt| {
matches!(
evt,
EventType::MsgsChanged { .. }
| EventType::CallMissed { .. }
| EventType::CallEnded { .. }
)
})
.await
else {
unreachable!();
};
assert_eq!(chat_id, bob_call.chat_id);
let msg = Message::load_from_db(bob, msg_id).await?;
assert_eq!(msg.text, stock_str::messages_e2ee_info_msg(bob));
if accepted {
let EventType::CallMissed { msg_id, chat_id } = bob
.evtracker
.get_matching(|evt| {
matches!(
evt,
EventType::CallMissed { .. } | EventType::CallEnded { .. }
)
})
.await
else {
unreachable!();
};
assert_eq!(msg_id, bob_call.id);
assert_eq!(chat_id, bob_call.chat_id);
}
let EventType::MsgsChanged { msg_id, chat_id } = bob
.evtracker
.get_matching(|evt| {
matches!(
evt,
EventType::MsgsChanged { .. }
| EventType::CallMissed { .. }
| EventType::CallEnded { .. }
)
})
.await
else {
unreachable!();
};
assert_eq!(msg_id, bob_call.id);
assert_eq!(chat_id, bob_call.chat_id);
let evt = bob
.evtracker
.get_matching_opt(bob, |evt| {
matches!(
evt,
EventType::CallMissed { .. } | EventType::CallEnded { .. }
)
})
.await;
assert!(evt.is_none());
assert_text(bob, bob_call.id, "Missed call").await?;
assert_eq!(call_state(bob, bob_call.id).await?, CallState::Missed);
// Test that message summary says it is a missed call.
let bob_call_msg = Message::load_from_db(bob, bob_call.id).await?;
let summary = bob_call_msg.get_summary(bob, None).await?;
assert_eq!(summary.text, "🎥 Missed call");
}
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_is_stale_call() -> Result<()> {
// a call started now is not stale