Skip to content

Commit 9b97a2e

Browse files
committed
timeline: when an edit fails on a stale local echo, retry on the matching remote echo
1 parent aff07c1 commit 9b97a2e

File tree

5 files changed

+54
-11
lines changed

5 files changed

+54
-11
lines changed

crates/matrix-sdk-ui/src/timeline/day_dividers.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ mod tests {
622622
fn event_with_ts(timestamp: MilliSecondsSinceUnixEpoch) -> EventTimelineItem {
623623
let event_kind = EventTimelineItemKind::Remote(RemoteEventTimelineItem {
624624
event_id: owned_event_id!("$1"),
625+
transaction_id: None,
625626
reactions: Default::default(),
626627
read_receipts: Default::default(),
627628
is_own: false,

crates/matrix-sdk-ui/src/timeline/event_handler.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,7 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> {
891891
}
892892
.into(),
893893

894-
Flow::Remote { event_id, raw_event, position, .. } => {
894+
Flow::Remote { event_id, raw_event, position, txn_id, .. } => {
895895
// Drop pending reactions if the message is redacted.
896896
if let TimelineItemContent::RedactedMessage = content {
897897
if !reactions.is_empty() {
@@ -916,6 +916,7 @@ impl<'a, 'o> TimelineEventHandler<'a, 'o> {
916916

917917
RemoteEventTimelineItem {
918918
event_id: event_id.clone(),
919+
transaction_id: txn_id.clone(),
919920
reactions,
920921
read_receipts: self.ctx.read_receipts.clone(),
921922
is_own: self.ctx.is_own_event,

crates/matrix-sdk-ui/src/timeline/event_item/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ impl EventTimelineItem {
140140

141141
let event_kind = RemoteEventTimelineItem {
142142
event_id,
143+
transaction_id: None,
143144
reactions,
144145
read_receipts,
145146
is_own,

crates/matrix-sdk-ui/src/timeline/event_item/remote.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use matrix_sdk::deserialized_responses::EncryptionInfo;
1919
use ruma::{
2020
events::{receipt::Receipt, AnySyncTimelineEvent},
2121
serde::Raw,
22-
OwnedEventId, OwnedUserId,
22+
OwnedEventId, OwnedTransactionId, OwnedUserId,
2323
};
2424

2525
use super::BundledReactions;
@@ -30,6 +30,9 @@ pub(in crate::timeline) struct RemoteEventTimelineItem {
3030
/// The event ID.
3131
pub event_id: OwnedEventId,
3232

33+
/// If available, the transaction id we've used to send this event.
34+
pub transaction_id: Option<OwnedTransactionId>,
35+
3336
/// All bundled reactions about the event.
3437
pub reactions: BundledReactions,
3538

@@ -107,6 +110,7 @@ impl fmt::Debug for RemoteEventTimelineItem {
107110
// skip raw JSON, too noisy
108111
let Self {
109112
event_id,
113+
transaction_id,
110114
reactions,
111115
read_receipts,
112116
is_own,
@@ -119,6 +123,7 @@ impl fmt::Debug for RemoteEventTimelineItem {
119123

120124
f.debug_struct("RemoteEventTimelineItem")
121125
.field("event_id", event_id)
126+
.field("transaction_id", transaction_id)
122127
.field("reactions", reactions)
123128
.field("read_receipts", read_receipts)
124129
.field("is_own", is_own)

crates/matrix-sdk-ui/src/timeline/mod.rs

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,22 @@ impl Timeline {
477477
})
478478
}
479479

480+
/// Given a transaction id, try to find a remote echo that used this
481+
/// transaction id upon sending.
482+
async fn find_remote_by_transaction_id(&self, txn_id: &TransactionId) -> Option<OwnedEventId> {
483+
let items = self.inner.items().await;
484+
485+
let (_, found) = rfind_event_item(&items, |item| {
486+
if let Some(remote) = item.as_remote() {
487+
remote.transaction_id.as_deref() == Some(txn_id)
488+
} else {
489+
false
490+
}
491+
})?;
492+
493+
Some(found.event_id().expect("remote echoes have event id").to_owned())
494+
}
495+
480496
/// Edit an event.
481497
///
482498
/// Only supports events for which [`EventTimelineItem::is_editable()`]
@@ -503,19 +519,38 @@ impl Timeline {
503519
) -> Result<bool, RoomSendQueueError> {
504520
let event_id = match edit_info.id {
505521
TimelineEventItemId::TransactionId(txn_id) => {
506-
let Some(item) = self.item_by_transaction_id(&txn_id).await else {
507-
warn!("Couldn't find the local echo anymore");
508-
return Ok(false);
509-
};
522+
if let Some(item) = self.item_by_transaction_id(&txn_id).await {
523+
let Some(handle) = item.as_local().and_then(|item| item.send_handle.clone())
524+
else {
525+
warn!("No handle for a local echo; is this a test?");
526+
return Ok(false);
527+
};
510528

511-
if let Some(handle) = item.as_local().and_then(|item| item.send_handle.clone()) {
512529
// Assume no relations, since it's not been sent yet.
513-
let new_content: RoomMessageEventContent = new_content.into();
514-
return Ok(handle.edit(new_content.into()).await?);
530+
let new_content: RoomMessageEventContent = new_content.clone().into();
531+
532+
if handle.edit(new_content.into()).await? {
533+
return Ok(true);
534+
}
515535
}
516536

517-
warn!("No handle for a local echo; should only happen in testing situations");
518-
return Ok(false);
537+
// We end up here in two cases: either there wasn't a local echo with this
538+
// transaction id, or the send queue refused to edit the local echo (likely
539+
// because it's sent).
540+
//
541+
// Try to find a matching local echo that now has an event id (it's been sent),
542+
// or a remote echo with a matching transaction id, so as to
543+
// send an actual edit.
544+
if let Some(TimelineEventItemId::EventId(event_id)) =
545+
self.item_by_transaction_id(&txn_id).await.map(|item| item.identifier())
546+
{
547+
event_id
548+
} else if let Some(event_id) = self.find_remote_by_transaction_id(&txn_id).await {
549+
event_id
550+
} else {
551+
warn!("Couldn't find the local echo anymore, nor a matching remote echo");
552+
return Ok(false);
553+
}
519554
}
520555

521556
TimelineEventItemId::EventId(event_id) => event_id,

0 commit comments

Comments
 (0)