Skip to content

Commit b79111b

Browse files
committed
feat(send queue): implement unwedging for media uploads
1 parent aa5e68e commit b79111b

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

crates/matrix-sdk/src/send_queue.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1816,6 +1816,23 @@ impl SendHandle {
18161816
.await
18171817
.map_err(RoomSendQueueError::StorageError)?;
18181818

1819+
// If we have media handles, also try to unwedge them.
1820+
//
1821+
// It's fine to always do it to *all* the transaction IDs at once, because only
1822+
// one of the three requests will be active at the same time, i.e. only
1823+
// one entry will be updated in the store. The other two are either
1824+
// done, or dependent requests.
1825+
if let Some(handles) = &self.media_handles {
1826+
room.queue
1827+
.mark_as_unwedged(&handles.upload_file_txn)
1828+
.await
1829+
.map_err(RoomSendQueueError::StorageError)?;
1830+
1831+
if let Some(txn) = &handles.upload_thumbnail_txn {
1832+
room.queue.mark_as_unwedged(txn).await.map_err(RoomSendQueueError::StorageError)?;
1833+
}
1834+
}
1835+
18191836
// Wake up the queue, in case the room was asleep before unwedging the request.
18201837
room.notifier.notify_one();
18211838

crates/matrix-sdk/tests/integration/send_queue.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2010,3 +2010,78 @@ async fn test_media_upload_retry() {
20102010
// That's all, folks!
20112011
assert!(watch.is_empty());
20122012
}
2013+
2014+
#[async_test]
2015+
async fn test_unwedging_media_upload() {
2016+
let mock = MatrixMockServer::new().await;
2017+
2018+
// Mark the room as joined.
2019+
let room_id = room_id!("!a:b.c");
2020+
let client = mock.client_builder().build().await;
2021+
let room = mock.sync_joined_room(&client, room_id).await;
2022+
2023+
let q = room.send_queue();
2024+
let (local_echoes, mut watch) = q.subscribe().await.unwrap();
2025+
assert!(local_echoes.is_empty());
2026+
2027+
// Create the media to send (no thumbnails).
2028+
let filename = "rickroll.gif";
2029+
let content_type = mime::IMAGE_JPEG;
2030+
let data = b"Never gonna give you up".to_vec();
2031+
2032+
let config = AttachmentConfig::new().info(AttachmentInfo::Image(BaseImageInfo {
2033+
height: Some(uint!(13)),
2034+
width: Some(uint!(37)),
2035+
size: Some(uint!(42)),
2036+
blurhash: None,
2037+
}));
2038+
2039+
// Prepare endpoints.
2040+
mock.mock_room_state_encryption().plain().mount().await;
2041+
2042+
// Fail for the first attempt with an error indicating the media's too large,
2043+
// wedging the upload.
2044+
mock.mock_upload().error_too_large().mock_once().mount().await;
2045+
2046+
// Send the media.
2047+
assert!(watch.is_empty());
2048+
q.send_attachment(filename, content_type, data, config)
2049+
.await
2050+
.expect("queuing the attachment works");
2051+
2052+
// Observe the local echo.
2053+
let (event_txn, send_handle, content) = assert_update!(watch => local echo event);
2054+
assert_let!(MessageType::Image(img_content) = content.msgtype);
2055+
assert_eq!(img_content.body, filename);
2056+
2057+
// Although the actual error happens on the file upload transaction id, it must
2058+
// be reported with the *event* transaction id.
2059+
let error = assert_update!(watch => error { recoverable=false, txn=event_txn });
2060+
let error = error.as_client_api_error().unwrap();
2061+
assert_eq!(error.status_code, 413);
2062+
assert!(q.is_enabled());
2063+
2064+
// Mount the mock for the upload and sending the event.
2065+
mock.mock_upload().ok(mxc_uri!("mxc://sdk.rs/media")).mock_once().mount().await;
2066+
mock.mock_room_send().ok(event_id!("$1")).mock_once().mount().await;
2067+
2068+
// Unwedge the upload.
2069+
send_handle.unwedge().await.unwrap();
2070+
2071+
// Observe the notification for the retry itself.
2072+
assert_update!(watch => retry { txn = event_txn });
2073+
2074+
// Observe the upload succeeding at some point.
2075+
assert_update!(watch => uploaded { related_to = event_txn, mxc = mxc_uri!("mxc://sdk.rs/media") });
2076+
2077+
let edit_msg = assert_update!(watch => edit local echo { txn = event_txn });
2078+
assert_let!(MessageType::Image(new_content) = edit_msg.msgtype);
2079+
assert_let!(MediaSource::Plain(new_uri) = &new_content.source);
2080+
assert_eq!(new_uri, mxc_uri!("mxc://sdk.rs/media"));
2081+
2082+
// The event is sent, at some point.
2083+
assert_update!(watch => sent { txn = event_txn, event_id = event_id!("$1") });
2084+
2085+
// That's all, folks!
2086+
assert!(watch.is_empty());
2087+
}

0 commit comments

Comments
 (0)