atagen

matrix-rust-sdk

public
Star0
Watch0

Commit cabc67b5cc05

tarball

atagen <boss@atagen.co>2026-10-22 12:30 UTC

3 files changed+127-21
send_queue: optionally report upload progress to global listeners
Modified file: crates/matrix-sdk/src/send_queue/mod.rs+57 additions−9 deletions
@@ -255,6 +255,7 @@ impl SendQueue {
255255 &self.client,
256256 owned_room_id.clone(),
257257 data.report_media_upload_progress.clone(),
258+ data.report_global_upload_progress.clone(),
258259 );
259260
260261 map.insert(owned_room_id, room_q.clone());
@@ -297,6 +298,17 @@ impl SendQueue {
297298 self.data().report_media_upload_progress.store(enabled, Ordering::SeqCst);
298299 }
299300
301+ /// Enable or disable sending media upload progress updates
302+ /// ([`RoomSendQueueUpdate::MediaUpload`]) to the global listeners of
303+ /// [`SendQueue::subscribe`], in addition to the room's listeners.
304+ ///
305+ /// Incremental progress is only reported if it's been enabled with
306+ /// [`SendQueue::enable_upload_progress`]; otherwise, only the final
307+ /// update of each upload is sent.
308+ pub fn enable_global_upload_progress(&self, enabled: bool) {
309+ self.data().report_global_upload_progress.store(enabled, Ordering::SeqCst);
310+ }
311+
300312 /// Subscribe to all updates for all rooms.
301313 ///
302314 /// Use [`RoomSendQueue::subscribe`] to subscribe to update for a _specific
@@ -402,6 +414,10 @@ pub(super) struct SendQueueData {
402414
403415 /// Will media upload progress be reported via send queue updates?
404416 report_media_upload_progress: Arc<AtomicBool>,
417+
418+ /// Will media upload progress updates be sent to the global listeners
419+ /// too?
420+ report_global_upload_progress: Arc<AtomicBool>,
405421 }
406422
407423 impl SendQueueData {
@@ -417,6 +433,7 @@ impl SendQueueData {
417433 error_sender,
418434 is_dropping: Arc::new(false.into()),
419435 report_media_upload_progress: Arc::new(false.into()),
436+ report_global_upload_progress: Arc::new(false.into()),
420437 }
421438 }
422439 }
@@ -466,6 +483,7 @@ impl RoomSendQueue {
466483 client: &Client,
467484 room_id: OwnedRoomId,
468485 report_media_upload_progress: Arc<AtomicBool>,
486+ report_global_upload_progress: Arc<AtomicBool>,
469487 ) -> Self {
470488 let (update_sender, _) = broadcast::channel(32);
471489
@@ -487,6 +505,7 @@ impl RoomSendQueue {
487505 global_error_sender,
488506 is_dropping,
489507 report_media_upload_progress,
508+ report_global_upload_progress,
490509 ),
491510 );
492511
@@ -665,6 +684,7 @@ impl RoomSendQueue {
665684 global_error_sender: broadcast::Sender<SendQueueRoomError>,
666685 is_dropping: Arc<AtomicBool>,
667686 report_media_upload_progress: Arc<AtomicBool>,
687+ report_global_upload_progress: Arc<AtomicBool>,
668688 ) {
669689 trace!("spawned the sending task");
670690
@@ -756,7 +776,10 @@ impl RoomSendQueue {
756776 let progress = RoomSendQueue::create_media_upload_progress_observable(
757777 &media_upload_progress_info,
758778 related_to,
779+ room_id,
780+ &global_update_sender,
759781 &update_sender,
782+ &report_global_upload_progress,
760783 );
761784
762785 (Some(media_upload_progress_info), Some(progress))
@@ -883,14 +906,20 @@ impl RoomSendQueue {
883906 })
884907 .unwrap_or(AbstractProgress { current: 1, total: 1 });
885908
886- // Purposefully don't use `send_update` here, because we don't want to
887- // notify the global listeners about an upload progress update.
888- let _ = update_sender.send(RoomSendQueueUpdate::MediaUpload {
889- related_to: related_txn_id.as_ref().unwrap_or(&txn_id).clone(),
890- file: Some(sent_media_info.file),
891- index,
892- progress,
893- });
909+ // Purposefully don't use `send_update` here, because the global
910+ // listeners only get upload progress updates when they asked for them.
911+ send_upload_progress(
912+ &global_update_sender,
913+ &update_sender,
914+ room_id,
915+ &report_global_upload_progress,
916+ RoomSendQueueUpdate::MediaUpload {
917+ related_to: related_txn_id.as_ref().unwrap_or(&txn_id).clone(),
918+ file: Some(sent_media_info.file),
919+ index,
920+ progress,
921+ },
922+ );
894923 }
895924
896925 SentRequestKey::Redaction { event_id, redacts, reason } => {
@@ -1252,6 +1281,23 @@ fn send_update(
12521281 let _ = global_update_sender.send(SendQueueUpdate { room_id: room_id.to_owned(), update });
12531282 }
12541283
1284+/// Send a media upload progress update to the room's listeners, and to the
1285+/// global listeners only if [`SendQueue::enable_global_upload_progress`] was
1286+/// called.
1287+fn send_upload_progress(
1288+ global_update_sender: &broadcast::Sender<SendQueueUpdate>,
1289+ update_sender: &broadcast::Sender<RoomSendQueueUpdate>,
1290+ room_id: &RoomId,
1291+ report_global_upload_progress: &AtomicBool,
1292+ update: RoomSendQueueUpdate,
1293+) {
1294+ if report_global_upload_progress.load(Ordering::SeqCst) {
1295+ send_update(global_update_sender, update_sender, room_id, update);
1296+ } else {
1297+ let _ = update_sender.send(update);
1298+ }
1299+}
1300+
12551301 impl From<&crate::Error> for QueueWedgeError {
12561302 fn from(value: &crate::Error) -> Self {
12571303 match value {
@@ -3388,7 +3434,9 @@ mod tests {
33883434 let react_id = ChildTransactionId::new();
33893435 let react = DependentQueuedRequest {
33903436 own_transaction_id: react_id.clone(),
3391- kind: DependentQueuedRequestKind::ReactEvent { key: "🧠".to_owned(), shortcode: None },
3437+ kind: DependentQueuedRequestKind::ReactEvent {
3438+ key: "🧠".to_owned(), shortcode: None
3439+ },
33923440 parent_transaction_id: txn.clone(),
33933441 parent_key: None,
33943442 created_at: MilliSecondsSinceUnixEpoch::now(),
Modified file: crates/matrix-sdk/src/send_queue/progress.rs+30 additions−12 deletions
@@ -14,20 +14,26 @@
1414
1515 //! Progress facilities for the media upload system.
1616
17-use std::ops::Add;
17+use std::{
18+ ops::Add,
19+ sync::{Arc, atomic::AtomicBool},
20+};
1821
1922 use eyeball::SharedObservable;
2023 #[cfg(feature = "unstable-msc4274")]
2124 use matrix_sdk_base::store::AccumulatedSentMediaInfo;
2225 use matrix_sdk_base::{media::MediaRequestParameters, store::DependentQueuedRequestKind};
2326 use matrix_sdk_common::executor::spawn;
24-use ruma::{TransactionId, events::room::MediaSource};
27+use ruma::{RoomId, TransactionId, events::room::MediaSource};
2528 use tokio::sync::broadcast;
2629 use tracing::warn;
2730
2831 use crate::{
2932 Room, TransmissionProgress,
30- send_queue::{QueueStorage, RoomSendQueue, RoomSendQueueStorageError, RoomSendQueueUpdate},
33+ send_queue::{
34+ QueueStorage, RoomSendQueue, RoomSendQueueStorageError, RoomSendQueueUpdate,
35+ SendQueueUpdate, send_upload_progress,
36+ },
3137 };
3238
3339 /// Progress of an operation in abstract units.
@@ -208,13 +214,19 @@ impl RoomSendQueue {
208214 pub(super) fn create_media_upload_progress_observable(
209215 media_upload_info: &MediaUploadProgressInfo,
210216 related_txn_id: &TransactionId,
217+ room_id: &RoomId,
218+ global_update_sender: &broadcast::Sender<SendQueueUpdate>,
211219 update_sender: &broadcast::Sender<RoomSendQueueUpdate>,
220+ report_global_upload_progress: &Arc<AtomicBool>,
212221 ) -> SharedObservable<TransmissionProgress> {
213222 let progress: SharedObservable<TransmissionProgress> = Default::default();
214223 let mut subscriber = progress.subscribe();
215224
216225 let related_txn_id = related_txn_id.to_owned();
226+ let room_id = room_id.to_owned();
227+ let global_update_sender = global_update_sender.clone();
217228 let update_sender = update_sender.clone();
229+ let report_global_upload_progress = report_global_upload_progress.clone();
218230 let media_upload_info = *media_upload_info;
219231
220232 // Watch and communicate the progress on a detached background task. Once
@@ -222,15 +234,21 @@ impl RoomSendQueue {
222234 // task will end.
223235 spawn(async move {
224236 while let Some(progress) = subscriber.next().await {
225- // Purposefully don't use `send_update` here, because we don't want to notify
226- // the global listeners about an upload progress update.
227- let _ = update_sender.send(RoomSendQueueUpdate::MediaUpload {
228- related_to: related_txn_id.clone(),
229- file: None,
230- index: media_upload_info.index,
231- progress: estimate_media_upload_progress(progress, media_upload_info.bytes)
232- + media_upload_info.offsets,
233- });
237+ // Purposefully don't use `send_update` here, because the global listeners
238+ // only get upload progress updates when they asked for them.
239+ send_upload_progress(
240+ &global_update_sender,
241+ &update_sender,
242+ &room_id,
243+ &report_global_upload_progress,
244+ RoomSendQueueUpdate::MediaUpload {
245+ related_to: related_txn_id.clone(),
246+ file: None,
247+ index: media_upload_info.index,
248+ progress: estimate_media_upload_progress(progress, media_upload_info.bytes)
249+ + media_upload_info.offsets,
250+ },
251+ );
234252 }
235253 });
236254
Modified file: crates/matrix-sdk/tests/integration/send_queue.rs+40 additions
@@ -2991,6 +2991,46 @@ async fn abort_and_verify(
29912991 }
29922992
29932993 #[async_test]
2994+async fn test_global_upload_progress() {
2995+ let mock = MatrixMockServer::new().await;
2996+
2997+ let room_id = room_id!("!a:b.c");
2998+ let client = mock.client_builder().build().await;
2999+ let room = mock.sync_joined_room(&client, room_id).await;
3000+
3001+ // Enabling global upload progress applies to an existing room queue.
3002+ let q = room.send_queue();
3003+ client.send_queue().enable_upload_progress(true);
3004+ client.send_queue().enable_global_upload_progress(true);
3005+ let mut global_watch = client.send_queue().subscribe();
3006+
3007+ mock.mock_authenticated_media_config().ok_default().mount().await;
3008+ mock.mock_room_state_encryption().plain().mount().await;
3009+ mock.mock_upload().ok(mxc_uri!("mxc://sdk.rs/media")).mock_once().mount().await;
3010+ mock.mock_room_send().ok(event_id!("$media")).mock_once().mount().await;
3011+
3012+ queue_attachment_no_thumbnail(&q).await;
3013+
3014+ let mut uploaded_file = None;
3015+ loop {
3016+ let update = timeout(Duration::from_secs(5), global_watch.recv()).await.unwrap().unwrap();
3017+ assert_eq!(update.room_id, room_id);
3018+ match update.update {
3019+ RoomSendQueueUpdate::MediaUpload { file, .. } => {
3020+ if file.is_some() {
3021+ uploaded_file = file;
3022+ }
3023+ }
3024+ RoomSendQueueUpdate::SentEvent { .. } => break,
3025+ _ => {}
3026+ }
3027+ }
3028+
3029+ assert_let!(Some(MediaSource::Plain(mxc)) = uploaded_file);
3030+ assert_eq!(mxc, mxc_uri!("mxc://sdk.rs/media"));
3031+}
3032+
3033+#[async_test]
29943034 async fn test_media_event_is_sent_in_order() {
29953035 // Test that despite happening in multiple requests, sending a media maintains
29963036 // the ordering.