mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 09:26:29 +03:00
fix: Fix emitting ContactsChanged events on "recently seen" status change (#5377)
- Always emit `ContactsChanged` from `contact::update_last_seen()` if a contact was seen recently just for simplicity and symmetry with `RecentlySeenLoop::run()` which also may emit several events for single contact. - Fix sleep time calculation in `RecentlySeenLoop::run()` -- `now` must be updated on every iteration, before the initial value was used every time which led to progressively long sleeps.
This commit is contained in:
@@ -1632,6 +1632,7 @@ pub(crate) async fn update_last_seen(
|
|||||||
> 0
|
> 0
|
||||||
&& timestamp > time() - SEEN_RECENTLY_SECONDS
|
&& timestamp > time() - SEEN_RECENTLY_SECONDS
|
||||||
{
|
{
|
||||||
|
context.emit_event(EventType::ContactsChanged(Some(contact_id)));
|
||||||
context
|
context
|
||||||
.scheduler
|
.scheduler
|
||||||
.interrupt_recently_seen(contact_id, timestamp)
|
.interrupt_recently_seen(contact_id, timestamp)
|
||||||
@@ -1762,6 +1763,7 @@ impl RecentlySeenLoop {
|
|||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
let now = SystemTime::now();
|
||||||
let (until, contact_id) =
|
let (until, contact_id) =
|
||||||
if let Some((Reverse(timestamp), contact_id)) = unseen_queue.peek() {
|
if let Some((Reverse(timestamp), contact_id)) = unseen_queue.peek() {
|
||||||
(
|
(
|
||||||
@@ -1804,7 +1806,10 @@ impl RecentlySeenLoop {
|
|||||||
timestamp,
|
timestamp,
|
||||||
})) => {
|
})) => {
|
||||||
// Received an interrupt.
|
// Received an interrupt.
|
||||||
unseen_queue.push((Reverse(timestamp + SEEN_RECENTLY_SECONDS), contact_id));
|
if contact_id != ContactId::UNDEFINED {
|
||||||
|
unseen_queue
|
||||||
|
.push((Reverse(timestamp + SEEN_RECENTLY_SECONDS), contact_id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1822,7 +1827,7 @@ impl RecentlySeenLoop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn interrupt(&self, contact_id: ContactId, timestamp: i64) {
|
pub(crate) fn try_interrupt(&self, contact_id: ContactId, timestamp: i64) {
|
||||||
self.interrupt_send
|
self.interrupt_send
|
||||||
.try_send(RecentlySeenInterrupt {
|
.try_send(RecentlySeenInterrupt {
|
||||||
contact_id,
|
contact_id,
|
||||||
@@ -1831,6 +1836,17 @@ impl RecentlySeenLoop {
|
|||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub(crate) async fn interrupt(&self, contact_id: ContactId, timestamp: i64) {
|
||||||
|
self.interrupt_send
|
||||||
|
.send(RecentlySeenInterrupt {
|
||||||
|
contact_id,
|
||||||
|
timestamp,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn abort(self) {
|
pub(crate) fn abort(self) {
|
||||||
self.handle.abort();
|
self.handle.abort();
|
||||||
}
|
}
|
||||||
@@ -2812,6 +2828,44 @@ Hi."#;
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
|
async fn test_was_seen_recently_event() -> Result<()> {
|
||||||
|
let mut tcm = TestContextManager::new();
|
||||||
|
let alice = tcm.alice().await;
|
||||||
|
let bob = tcm.bob().await;
|
||||||
|
let recently_seen_loop = RecentlySeenLoop::new(bob.ctx.clone());
|
||||||
|
let chat = bob.create_chat(&alice).await;
|
||||||
|
let contacts = chat::get_chat_contacts(&bob, chat.id).await?;
|
||||||
|
|
||||||
|
for _ in 0..2 {
|
||||||
|
let chat = alice.create_chat(&bob).await;
|
||||||
|
let sent_msg = alice.send_text(chat.id, "moin").await;
|
||||||
|
let contact = Contact::get_by_id(&bob, *contacts.first().unwrap()).await?;
|
||||||
|
assert!(!contact.was_seen_recently());
|
||||||
|
while bob.evtracker.try_recv().is_ok() {}
|
||||||
|
bob.recv_msg(&sent_msg).await;
|
||||||
|
let contact = Contact::get_by_id(&bob, *contacts.first().unwrap()).await?;
|
||||||
|
assert!(contact.was_seen_recently());
|
||||||
|
bob.evtracker
|
||||||
|
.get_matching(|evt| matches!(evt, EventType::ContactsChanged { .. }))
|
||||||
|
.await;
|
||||||
|
recently_seen_loop
|
||||||
|
.interrupt(contact.id, contact.last_seen)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// Wait for `was_seen_recently()` to turn off.
|
||||||
|
while bob.evtracker.try_recv().is_ok() {}
|
||||||
|
SystemTime::shift(Duration::from_secs(SEEN_RECENTLY_SECONDS as u64 * 2));
|
||||||
|
recently_seen_loop.interrupt(ContactId::UNDEFINED, 0).await;
|
||||||
|
let contact = Contact::get_by_id(&bob, *contacts.first().unwrap()).await?;
|
||||||
|
assert!(!contact.was_seen_recently());
|
||||||
|
bob.evtracker
|
||||||
|
.get_matching(|evt| matches!(evt, EventType::ContactsChanged { .. }))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
async fn test_verified_by_none() -> Result<()> {
|
async fn test_verified_by_none() -> Result<()> {
|
||||||
let mut tcm = TestContextManager::new();
|
let mut tcm = TestContextManager::new();
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ pub enum EventType {
|
|||||||
timer: EphemeralTimer,
|
timer: EphemeralTimer,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Contact(s) created, renamed, blocked or deleted.
|
/// Contact(s) created, renamed, blocked, deleted or changed their "recently seen" status.
|
||||||
///
|
///
|
||||||
/// @param data1 (int) If set, this is the contact_id of an added contact that should be selected.
|
/// @param data1 (int) If set, this is the contact_id of an added contact that should be selected.
|
||||||
ContactsChanged(Option<ContactId>),
|
ContactsChanged(Option<ContactId>),
|
||||||
|
|||||||
@@ -924,7 +924,7 @@ impl Scheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn interrupt_recently_seen(&self, contact_id: ContactId, timestamp: i64) {
|
fn interrupt_recently_seen(&self, contact_id: ContactId, timestamp: i64) {
|
||||||
self.recently_seen_loop.interrupt(contact_id, timestamp);
|
self.recently_seen_loop.try_interrupt(contact_id, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Halt the scheduler.
|
/// Halt the scheduler.
|
||||||
|
|||||||
@@ -1100,7 +1100,10 @@ fn print_event(event: &Event) {
|
|||||||
"Received MSGS_CHANGED(chat_id={chat_id}, msg_id={msg_id})",
|
"Received MSGS_CHANGED(chat_id={chat_id}, msg_id={msg_id})",
|
||||||
))
|
))
|
||||||
),
|
),
|
||||||
EventType::ContactsChanged(_) => format!("{}", green.paint("Received CONTACTS_CHANGED()")),
|
EventType::ContactsChanged(contact) => format!(
|
||||||
|
"{}",
|
||||||
|
green.paint(format!("Received CONTACTS_CHANGED(contact={contact:?})"))
|
||||||
|
),
|
||||||
EventType::LocationChanged(contact) => format!(
|
EventType::LocationChanged(contact) => format!(
|
||||||
"{}",
|
"{}",
|
||||||
green.paint(format!("Received LOCATION_CHANGED(contact={contact:?})"))
|
green.paint(format!("Received LOCATION_CHANGED(contact={contact:?})"))
|
||||||
|
|||||||
Reference in New Issue
Block a user