Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c288212
feat(send_queue): send redactions via the send queue
Johennes Mar 14, 2026
ba8f1bb
feat(timeline): handle local echoes of redactions
Johennes Mar 14, 2026
9fbe8d3
fixup! feat(timeline): handle local echoes of redactions
Johennes Mar 18, 2026
40f42ff
fixup! feat(timeline): handle local echoes of redactions
Johennes Mar 18, 2026
08e764b
fixup! feat(timeline): handle local echoes of redactions
Johennes Mar 18, 2026
d34a773
fixup! feat(timeline): handle local echoes of redactions
Johennes Mar 18, 2026
1d21e85
fixup! feat(send_queue): send redactions via the send queue
Johennes Mar 18, 2026
9719663
fixup! feat(send_queue): send redactions via the send queue
Johennes Mar 18, 2026
75896b2
Merge branch 'main' into johannes/send-queue-redactions
Johennes Mar 18, 2026
de1fae3
fixup! feat(send_queue): send redactions via the send queue
Johennes Mar 20, 2026
5007d2f
fixup! feat(send_queue): send redactions via the send queue
Johennes Mar 20, 2026
112ea05
fixup! feat(send_queue): send redactions via the send queue
Johennes Mar 20, 2026
44bc666
Merge branch 'main' into johannes/send-queue-redactions
Johennes Mar 20, 2026
4560ac8
fixup! feat(timeline): handle local echoes of redactions
Johennes Mar 23, 2026
b2007a6
Merge branch 'main' into johannes/send-queue-redactions
Johennes Mar 23, 2026
a25d0ed
Revert "fixup! feat(timeline): handle local echoes of redactions"
Johennes Mar 30, 2026
8e60190
fixup! feat(timeline): handle local echoes of redactions
Johennes Mar 30, 2026
6a4a0af
Merge branch 'main' into johannes/send-queue-redactions
Johennes Mar 31, 2026
78c4707
fixup! feat(timeline): handle local echoes of redactions
Johennes Mar 31, 2026
fc3fa36
fixup! feat(timeline): handle local echoes of redactions
Johennes Mar 31, 2026
78eb03d
fixup! feat(send_queue): send redactions via the send queue
Johennes Mar 31, 2026
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
26 changes: 25 additions & 1 deletion crates/matrix-sdk-base/src/store/send_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ pub enum QueuedRequestKind {
#[serde(default)]
accumulated: Vec<AccumulatedSentMediaInfo>,
},

/// A redaction of another event to send.
Redaction {
/// The ID of the event to redact.
redacts: OwnedEventId,
/// The reason for the event being redacted.
reason: Option<String>,
},
}

impl From<SerializableEventContent> for QueuedRequestKind {
Expand Down Expand Up @@ -421,12 +429,28 @@ pub enum SentRequestKey {

/// The parent transaction returned an uploaded resource URL.
Media(SentMediaInfo),

/// The parent transaction returned a redaction event when it succeeded.
Redaction {
/// The event ID returned by the server.
event_id: OwnedEventId,

/// The ID of the redacted event.
redacts: OwnedEventId,

/// The reason for the event being redacted.
reason: Option<String>,
},
}

impl SentRequestKey {
/// Converts the current parent key into an event id, if possible.
pub fn into_event_id(self) -> Option<OwnedEventId> {
as_variant!(self, Self::Event { event_id, .. } => event_id)
match self {
Self::Event { event_id, .. } => Some(event_id),
Self::Redaction { event_id, .. } => Some(event_id),
_ => None,
}
}

/// Converts the current parent key into information about a sent media, if
Expand Down
4 changes: 4 additions & 0 deletions crates/matrix-sdk-ui/src/timeline/controller/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1268,6 +1268,10 @@ impl<P: RoomDataProvider> TimelineController<P> {
LocalEchoContent::React { key, send_handle, applies_to } => {
self.handle_local_reaction(key, send_handle, applies_to).await;
}

LocalEchoContent::Redaction { .. } => {
// TODO: Handle local redactions in the timeline.
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions crates/matrix-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ All notable changes to this project will be documented in this file.

### Features

- Enable sending redaction events through the send queue via `RoomSendQueue::send_redaction`.
This includes local echoes for redaction events through the new `LocalEchoContent::Redaction`
variant.
([#6250](https://github.com/matrix-org/matrix-rust-sdk/pull/6250))
- [**breaking**]: The unread count computation has now moved from the sliding sync processing, to
the event cache. As a result, it is necessary to enable the event cache if you want to keep a
precise unread counts, using `Client::event_cache().subscribe()`. The unread counts will now also
Expand Down
5 changes: 5 additions & 0 deletions crates/matrix-sdk/src/event_cache/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,11 @@ async fn handle_thread_subscriber_send_queue_update(
// Nothing to do, reactions don't count as a thread
// subscription.
}

LocalEchoContent::Redaction { .. } => {
// Nothing to do, redactions don't count as a thread
// subscription.
}
}
return true;
}
Expand Down
111 changes: 110 additions & 1 deletion crates/matrix-sdk/src/latest_events/latest_event/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,11 @@ impl Builder {
}

LocalEchoContent::React { .. } => None,

// TODO: Rework the latest event system to handle local redactions. This will
// require mixing the processing of local and remote events since a local redaction
// will target a previous remote event.
LocalEchoContent::Redaction { .. } => None,
},

// A local event has been cancelled before being sent.
Expand Down Expand Up @@ -1639,7 +1644,7 @@ mod builder_tests {
Client, Error,
send_queue::{
AbstractProgress, LocalEcho, LocalEchoContent, RoomSendQueue, SendHandle,
SendReactionHandle,
SendReactionHandle, SendRedactionHandle,
},
test_utils::mocks::MatrixMockServer,
};
Expand Down Expand Up @@ -3601,4 +3606,108 @@ mod builder_tests {
);
assert!(buffer.buffer.is_empty());
}

#[async_test]
async fn test_local_redaction() {
let room_id = room_id!("!r0");
let user_id = user_id!("@mnt_io:matrix.org");
let event_factory = EventFactory::new().sender(user_id).room(room_id);
let event_id = event_id!("$ev0");

let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;

// Prelude.
{
// Create the room.
client.base_client().get_or_create_room(room_id, RoomState::Joined);

// Initialise the event cache store.
client
.event_cache_store()
.lock()
.await
.expect("Could not acquire the event cache lock")
.as_clean()
.expect("Could not acquire a clean event cache lock")
.handle_linked_chunk_updates(
LinkedChunkId::Room(room_id),
vec![
Update::NewItemsChunk {
previous: None,
new: ChunkIdentifier::new(0),
next: None,
},
Update::PushItems {
at: Position::new(ChunkIdentifier::new(0), 0),
items: vec![event_factory.text_msg("hello").event_id(event_id).into()],
},
],
)
.await
.unwrap();
}

let event_cache = client.event_cache();
event_cache.subscribe().unwrap();

let (room_event_cache, _) = event_cache.for_room(room_id).await.unwrap();
let send_queue = client.send_queue();
let room = client.get_room(room_id).unwrap();
let room_send_queue = send_queue.for_room(room);

let mut buffer = BufferOfValuesForLocalEvents::new();

// We get a `Remote` because there is no `Local*` values!
assert_remote_value_matches_room_message_with_body!(
Builder::new_local(
// An update that won't create a new `LatestEventValue`: it maps
// to zero existing local value.
&RoomSendQueueUpdate::SentEvent {
transaction_id: OwnedTransactionId::from("txnid"),
event_id: event_id.to_owned(),
},
&mut buffer,
&room_event_cache,
None,
user_id,
None,
)
.await
=> with body = "hello"
);

// A local redaction of the latest event value is being sent
{
let transaction_id = OwnedTransactionId::from("txnid0");
let content = LocalEchoContent::Redaction {
redacts: event_id.to_owned(),
reason: Some("whatever".to_owned()),
send_handle: SendRedactionHandle::new(
room_send_queue.clone(),
transaction_id.clone(),
),
send_error: None,
};
let update = RoomSendQueueUpdate::NewLocalEvent(LocalEcho {
transaction_id: transaction_id.clone(),
content,
});

// Local redactions are currently ignored.
assert_matches!(
Builder::new_local(
&update,
&mut buffer,
&room_event_cache,
Some(event_id.to_owned()),
user_id,
None
)
.await,
None
);
};
assert_eq!(buffer.buffer.len(), 0);
}
}
Loading