|
|
|
|
@ -1,5 +1,7 @@
|
|
|
|
|
use crate::model::message::Message; |
|
|
|
|
use matrix_sdk::identifiers::EventId; |
|
|
|
|
use std::collections::{HashMap, HashSet}; |
|
|
|
|
use std::iter; |
|
|
|
|
use std::iter::FromIterator; |
|
|
|
|
use std::slice::Iter; |
|
|
|
|
|
|
|
|
|
@ -7,6 +9,7 @@ use std::slice::Iter;
|
|
|
|
|
#[derive(Debug, Default, Clone)] |
|
|
|
|
pub struct MessageList { |
|
|
|
|
messages: Vec<Message>, |
|
|
|
|
relating_messages: HashMap<EventId, HashSet<EventId>>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl MessageList { |
|
|
|
|
@ -34,6 +37,11 @@ impl MessageList {
|
|
|
|
|
/// Inserts the message at the correct position replacing its older version.
|
|
|
|
|
pub fn add(&mut self, msg: Message) { |
|
|
|
|
assert!(msg.id.is_some()); |
|
|
|
|
let id = msg.id.clone().unwrap(); |
|
|
|
|
|
|
|
|
|
if msg.redacted { |
|
|
|
|
self.remove_relations(&id); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Deduplication only happens for messages with the same date, so we have
|
|
|
|
|
// to manually go through the message list and remove possible duplicates.
|
|
|
|
|
@ -45,6 +53,10 @@ impl MessageList {
|
|
|
|
|
// brute-force-fix this by searching all messages for duplicates.
|
|
|
|
|
self.messages.retain(|m| m.id != msg.id); |
|
|
|
|
|
|
|
|
|
if !msg.redacted { |
|
|
|
|
self.populate_relations(&msg); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
match self.messages.binary_search(&msg) { |
|
|
|
|
Ok(idx) => self.messages[idx] = msg, |
|
|
|
|
Err(idx) => self.messages.insert(idx, msg), |
|
|
|
|
@ -52,6 +64,59 @@ impl MessageList {
|
|
|
|
|
// TODO: Use is_sorted (https://github.com/rust-lang/rust/issues/53485)
|
|
|
|
|
// debug_assert!(self.messages.is_sorted());
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Updates records of those relations the message is involved in.
|
|
|
|
|
///
|
|
|
|
|
/// This updates both, relating and related, messages.
|
|
|
|
|
fn populate_relations(&mut self, msg: &Message) { |
|
|
|
|
// Other messages relate to `msg`
|
|
|
|
|
let id = msg.id.as_ref().cloned().unwrap(); |
|
|
|
|
let relating = self.find_and_get_relating(&id); |
|
|
|
|
self.relating_messages.insert(id.clone(), relating); |
|
|
|
|
|
|
|
|
|
// `msg` relates to other messages
|
|
|
|
|
if let Some(replace_id) = &msg.replace { |
|
|
|
|
self.update_relating(replace_id, iter::once(&id).cloned().collect()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Remove all outgoing relations for the given event.
|
|
|
|
|
fn remove_relations(&mut self, event_id: &EventId) { |
|
|
|
|
let msg = unwrap_or_unit_return!(self.get(event_id)); |
|
|
|
|
let relations = msg.relations(); |
|
|
|
|
|
|
|
|
|
let event_sets = self.relating_messages.iter_mut().filter_map(|(id, rs)| { |
|
|
|
|
if relations.contains(&id) { |
|
|
|
|
Some(rs) |
|
|
|
|
} else { |
|
|
|
|
None |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
for set in event_sets { |
|
|
|
|
set.retain(|id| id != event_id); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Records new messages relating to the message with the given id.
|
|
|
|
|
///
|
|
|
|
|
/// This does not remove other messages relating to the given id.
|
|
|
|
|
fn update_relating(&mut self, id: &EventId, relating: HashSet<EventId>) { |
|
|
|
|
let new_relating = match self.relating_messages.remove(id) { |
|
|
|
|
Some(old_relating) => old_relating.union(&relating).cloned().collect(), |
|
|
|
|
None => relating, |
|
|
|
|
}; |
|
|
|
|
self.relating_messages.insert(id.clone(), new_relating); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Finds and returns all messages relating to the given one.
|
|
|
|
|
fn find_and_get_relating(&self, id: &EventId) -> HashSet<EventId> { |
|
|
|
|
self.messages |
|
|
|
|
.iter() |
|
|
|
|
.filter(|m| m.replace.as_ref() == Some(id) || m.in_reply_to.as_ref() == Some(id)) |
|
|
|
|
.map(|m| m.id.clone().unwrap()) |
|
|
|
|
.collect() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl FromIterator<Message> for MessageList { |
|
|
|
|
|