Commit 6b10fa3e authored by Kai Hiller's avatar Kai Hiller
Browse files

Track relations in MessageList

parent 9f686d14
Pipeline #256089 passed with stages
in 39 minutes and 5 seconds
......@@ -433,6 +433,15 @@ impl Message {
}
}
/// Returns all event IDs this message relates to.
pub fn relations(&self) -> Vec<EventId> {
vec![self.in_reply_to.as_ref(), self.replace.as_ref()]
.into_iter()
.flat_map(|r| r.into_iter())
.cloned()
.collect()
}
/// Generates an unique transaction id for this message
/// The txn_id is generated using the md5sum of a concatenation of the message room id, the
/// message body and the date.
......
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 {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment