Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 67 additions & 37 deletions src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! The types defined here get used throughout iamb.
use std::borrow::Cow;
use std::collections::hash_map::IntoIter;
use std::collections::{BTreeSet, HashMap, HashSet};
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::convert::TryFrom;
use std::fmt::{self, Display};
use std::hash::Hash;
Expand Down Expand Up @@ -690,6 +690,8 @@ pub type IambResult<T> = UIResult<T, IambInfo>;
/// it's reacting to.
pub type MessageReactions = HashMap<OwnedEventId, (String, OwnedUserId)>;

pub type MessageEdits = BTreeMap<MessageKey, RoomMessageEventContentWithoutRelation>;

/// Errors encountered during application use.
#[derive(thiserror::Error, Debug)]
pub enum IambError {
Expand Down Expand Up @@ -839,6 +841,7 @@ pub enum RoomFetchStatus {
}

/// Indicates where an [EventId] lives in the [ChatStore].
#[derive(Clone)]
pub enum EventLocation {
/// The [EventId] belongs to a message.
///
Expand All @@ -851,6 +854,9 @@ pub enum EventLocation {

/// The [EventId] belongs to a state event in the main timeline of the room.
State(MessageKey),

/// The [EventId] belongs to an edit for the given event and has key [MessageKey].
Edit(OwnedEventId, MessageKey),
}

impl EventLocation {
Expand Down Expand Up @@ -903,6 +909,8 @@ pub struct RoomInfo {
pub user_receipts: HashMap<ReceiptThread, HashMap<OwnedUserId, OwnedEventId>>,
/// A map of message identifiers to a map of reaction events.
pub reactions: HashMap<OwnedEventId, MessageReactions>,
/// A map of message identifiers to a list of edit events for message that are not yet cached.
pub unloaded_edits: HashMap<OwnedEventId, MessageEdits>,

/// A map of message identifiers to thread replies.
threads: HashMap<OwnedEventId, Messages>,
Expand Down Expand Up @@ -944,6 +952,7 @@ impl Default for RoomInfo {
users_typing: Default::default(),
display_names: Default::default(),
draw_last: Default::default(),
unloaded_edits: Default::default(),
}
}
}
Expand All @@ -970,6 +979,8 @@ impl RoomInfo {
/// Get the event for the last message in a thread (or the thread root if there are no
/// in-thread replies yet).
///
/// This does not apply edits to the returned event.
///
/// This returns `None` if the event identifier isn't in the room.
pub fn get_thread_last<'a>(
&'a self,
Expand All @@ -986,7 +997,7 @@ impl RoomInfo {
return None;
};

if let MessageEvent::Original(ev) = &msg {
if let MessageEvent::Original(ev, _) = &msg {
Some(ev)
} else {
None
Expand Down Expand Up @@ -1039,6 +1050,24 @@ impl RoomInfo {

match self.keys.get(redacts) {
None => return,
Some(EventLocation::Edit(msg_event_id, edit_key)) => {
let edit_key = edit_key.clone();
let msg_loc = self.keys.get(msg_event_id).cloned();
if let Some(EventLocation::Message(thread, msg_key)) = msg_loc {
if let Some(msg) = self.get_thread_mut(thread).get_mut(&msg_key) {
msg.remove_edit(&edit_key);
}
} else {
self.unloaded_edits
.get_mut(msg_event_id)
.and_then(|edits| edits.remove(&edit_key));
}

if let Some(msg) = self.messages.get_mut(&edit_key) {
let ev = SyncRoomRedactionEvent::Original(ev);
msg.redact(ev, rules);
}
},
Some(EventLocation::State(key)) => {
if let Some(msg) = self.messages.get_mut(key) {
let ev = SyncRoomRedactionEvent::Original(ev);
Expand Down Expand Up @@ -1092,42 +1121,32 @@ impl RoomInfo {
}

/// Insert an edit.
pub fn insert_edit(&mut self, msg: Replacement<RoomMessageEventContentWithoutRelation>) {
let event_id = msg.event_id;
let new_msgtype = msg.new_content;

let Some(EventLocation::Message(thread, key)) = self.keys.get(&event_id) else {
return;
};

let source = if let Some(thread) = thread {
self.threads
.entry(thread.clone())
.or_insert_with(|| Messages::thread(thread.clone()))
} else {
&mut self.messages
};

let Some(msg) = source.get_mut(key) else {
fn insert_edit(
&mut self,
edit_msg: RoomMessageEvent,
replacement: Replacement<RoomMessageEventContentWithoutRelation>,
) {
let RoomMessageEvent::Original(edit_msg) = edit_msg else {
return;
};
let edit_key = (edit_msg.origin_server_ts.into(), edit_msg.event_id.clone());
let msg_loc = self.keys.get(&replacement.event_id).cloned();

match &mut msg.event {
MessageEvent::Original(orig) => {
orig.content.apply_replacement(new_msgtype);
},
MessageEvent::Local(_, content) => {
content.apply_replacement(new_msgtype);
},
MessageEvent::Redacted(_) |
MessageEvent::State(_) |
MessageEvent::EncryptedOriginal(_) |
MessageEvent::EncryptedRedacted(_) => {
if let Some(EventLocation::Message(thread, key)) = msg_loc {
// The edited message is already loaded in cache
let Some(msg) = self.get_thread_mut(thread).get_mut(&key) else {
return;
},
};
msg.insert_edit(edit_key.clone(), replacement.new_content);
} else {
// The edited message is not yet loaded
let entry = self.unloaded_edits.entry(replacement.event_id.clone());
entry.or_default().insert(edit_key.clone(), replacement.new_content);
}

msg.html = msg.event.html();
let loc = EventLocation::Edit(replacement.event_id.clone(), edit_key.clone());
self.keys.insert(edit_msg.event_id.clone(), loc);
self.messages.insert_message(edit_key, Message::new_edit(edit_msg));
}

pub fn insert_any_state(&mut self, msg: AnySyncStateEvent) {
Expand All @@ -1150,7 +1169,7 @@ impl RoomInfo {
let last_receipt = last_receipt.as_ref().and_then(|event_id| {
match &self.keys.get(*event_id)? {
EventLocation::Message(_, key) | EventLocation::State(key) => Some(key),
EventLocation::Reaction(_) => None,
EventLocation::Reaction(_) | EventLocation::Edit(_, _) => None,
}
});

Expand All @@ -1161,7 +1180,7 @@ impl RoomInfo {
let last_unthreaded = last_unthreaded.as_ref().and_then(|event_id| {
match &self.keys.get(*event_id)? {
EventLocation::Message(_, key) | EventLocation::State(key) => Some(key),
EventLocation::Reaction(_) => None,
EventLocation::Reaction(_) | EventLocation::Edit(_, _) => None,
}
});

Expand Down Expand Up @@ -1195,8 +1214,12 @@ impl RoomInfo {
let key = (msg.origin_server_ts().into(), event_id.clone());

let loc = EventLocation::Message(None, key.clone());
let mut message: Message = msg.into();
if let Some(edits) = self.unloaded_edits.remove(&event_id) {
message.set_edits(edits);
}
self.keys.insert(event_id, loc);
self.messages.insert_message(key, msg);
self.messages.insert_message(key, message);
}

fn insert_thread(&mut self, msg: RoomMessageEvent, thread_root: OwnedEventId) {
Expand All @@ -1208,8 +1231,12 @@ impl RoomInfo {
.entry(thread_root.clone())
.or_insert_with(|| Messages::thread(thread_root.clone()));
let loc = EventLocation::Message(Some(thread_root), key.clone());
let mut message: Message = msg.into();
if let Some(edits) = self.unloaded_edits.remove(&event_id) {
message.set_edits(edits);
}
self.keys.insert(event_id, loc);
replies.insert_message(key, msg);
replies.insert_message(key, message);
}

/// Insert a new message event.
Expand All @@ -1220,7 +1247,10 @@ impl RoomInfo {
..
}) => {
match relates_to {
Relation::Replacement(repl) => self.insert_edit(repl.clone()),
Relation::Replacement(repl) => {
let repl = repl.clone();
self.insert_edit(msg, repl)
},
Relation::Thread(Thread { event_id, .. }) => {
let event_id = event_id.clone();
self.insert_thread(msg, event_id);
Expand Down
Loading
Loading