Skip to content

Commit 1554e05

Browse files
Johennesbnjbvr
andauthored
refactor(send_queue): generalize SentRequestKey::Media and DependentQueuedRequestKind::UploadFileWithThumbnail to prepare for MSC4274 gallery uploads (matrix-org#4897)
This was broken out of matrix-org#4838 and is a preliminary step towards implementing [MSC4274](matrix-org/matrix-spec-proposals#4274). `SentRequestKey::Media` and `DependentQueuedRequestKind::UploadFileWithThumbnail` are generalized to allow chaining dependent media uploads and accumulating sent media sources. - [x] Public API changes documented in changelogs (optional) --------- Signed-off-by: Johannes Marbach <[email protected]> Co-authored-by: Benjamin Bouvier <[email protected]>
1 parent 8847750 commit 1554e05

File tree

10 files changed

+181
-28
lines changed

10 files changed

+181
-28
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/matrix-sdk-base/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ All notable changes to this project will be documented in this file.
4040
- [**breaking**] `BaseClient::set_session_metadata` is renamed
4141
`activate`, and `BaseClient::logged_in` is renamed `is_activated`
4242
([#4850](https://github.com/matrix-org/matrix-rust-sdk/pull/4850))
43+
- [**breaking] `DependentQueuedRequestKind::UploadFileWithThumbnail`
44+
was renamed to `DependentQueuedRequestKind::UploadFileOrThumbnail`.
45+
Under the `unstable-msc4274` feature, `DependentQueuedRequestKind::UploadFileOrThumbnail`
46+
and `SentMediaInfo` were generalized to allow chaining multiple dependent
47+
file / thumbnail uploads.
48+
([#4897](https://github.com/matrix-org/matrix-rust-sdk/pull/4897))
4349

4450
## [0.10.0] - 2025-02-04
4551

crates/matrix-sdk-base/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ testing = [
4343
"matrix-sdk-crypto?/testing",
4444
]
4545

46+
# Add support for inline media galleries via msgtypes
47+
unstable-msc4274 = []
48+
4649
[dependencies]
4750
as_variant = { workspace = true }
4851
assert_matches = { workspace = true, optional = true }

crates/matrix-sdk-base/src/store/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ mod send_queue;
7171

7272
#[cfg(any(test, feature = "testing"))]
7373
pub use self::integration_tests::StateStoreIntegrationTests;
74+
#[cfg(feature = "unstable-msc4274")]
75+
pub use self::send_queue::AccumulatedSentMediaInfo;
7476
pub use self::{
7577
memory_store::MemoryStore,
7678
send_queue::{

crates/matrix-sdk-base/src/store/send_queue.rs

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ pub enum QueuedRequestKind {
103103

104104
/// To which media event transaction does this upload relate?
105105
related_to: OwnedTransactionId,
106+
107+
/// Accumulated list of infos for previously uploaded files and
108+
/// thumbnails if used during a gallery transaction. Otherwise empty.
109+
#[cfg(feature = "unstable-msc4274")]
110+
#[serde(default)]
111+
accumulated: Vec<AccumulatedSentMediaInfo>,
106112
},
107113
}
108114

@@ -219,17 +225,23 @@ pub enum DependentQueuedRequestKind {
219225
key: String,
220226
},
221227

222-
/// Upload a file that had a thumbnail.
223-
UploadFileWithThumbnail {
224-
/// Content type for the file itself (not the thumbnail).
228+
/// Upload a file or thumbnail depending on another file or thumbnail
229+
/// upload.
230+
#[serde(alias = "UploadFileWithThumbnail")]
231+
UploadFileOrThumbnail {
232+
/// Content type for the file or thumbnail.
225233
content_type: String,
226234

227-
/// Media request necessary to retrieve the file itself (not the
228-
/// thumbnail).
235+
/// Media request necessary to retrieve the file or thumbnail itself.
229236
cache_key: MediaRequestParameters,
230237

231238
/// To which media transaction id does this upload relate to?
232239
related_to: OwnedTransactionId,
240+
241+
/// Whether the depended upon request was a thumbnail or a file upload.
242+
#[cfg(feature = "unstable-msc4274")]
243+
#[serde(default = "default_parent_is_thumbnail_upload")]
244+
parent_is_thumbnail_upload: bool,
233245
},
234246

235247
/// Finish an upload by updating references to the media cache and sending
@@ -248,6 +260,14 @@ pub enum DependentQueuedRequestKind {
248260
},
249261
}
250262

263+
/// If parent_is_thumbnail_upload is missing, we assume the request is for a
264+
/// file upload following a thumbnail upload. This was the only possible case
265+
/// before parent_is_thumbnail_upload was introduced.
266+
#[cfg(feature = "unstable-msc4274")]
267+
fn default_parent_is_thumbnail_upload() -> bool {
268+
true
269+
}
270+
251271
/// Detailed record about a thumbnail used when finishing a media upload.
252272
#[derive(Clone, Debug, Serialize, Deserialize)]
253273
pub struct FinishUploadThumbnailInfo {
@@ -310,7 +330,7 @@ impl From<OwnedTransactionId> for ChildTransactionId {
310330
}
311331
}
312332

313-
/// Information about a media (and its thumbnail) that have been sent to an
333+
/// Information about a media (and its thumbnail) that have been sent to a
314334
/// homeserver.
315335
#[derive(Clone, Debug, Serialize, Deserialize)]
316336
pub struct SentMediaInfo {
@@ -324,6 +344,29 @@ pub struct SentMediaInfo {
324344
///
325345
/// When uploading a thumbnail, this is set to `None`.
326346
pub thumbnail: Option<MediaSource>,
347+
348+
/// Accumulated list of infos for previously uploaded files and thumbnails
349+
/// if used during a gallery transaction. Otherwise empty.
350+
#[cfg(feature = "unstable-msc4274")]
351+
#[serde(default)]
352+
pub accumulated: Vec<AccumulatedSentMediaInfo>,
353+
}
354+
355+
/// Accumulated information about a media (and its thumbnail) that have been
356+
/// sent to a homeserver.
357+
#[cfg(feature = "unstable-msc4274")]
358+
#[derive(Clone, Debug, Serialize, Deserialize)]
359+
pub struct AccumulatedSentMediaInfo {
360+
/// File that was uploaded by this request.
361+
///
362+
/// If the request related to a thumbnail upload, this contains the
363+
/// thumbnail media source.
364+
pub file: MediaSource,
365+
366+
/// Optional thumbnail previously uploaded, when uploading a file.
367+
///
368+
/// When uploading a thumbnail, this is set to `None`.
369+
pub thumbnail: Option<MediaSource>,
327370
}
328371

329372
/// A unique key (identifier) indicating that a transaction has been
@@ -390,7 +433,7 @@ impl DependentQueuedRequest {
390433
DependentQueuedRequestKind::EditEvent { .. }
391434
| DependentQueuedRequestKind::RedactEvent
392435
| DependentQueuedRequestKind::ReactEvent { .. }
393-
| DependentQueuedRequestKind::UploadFileWithThumbnail { .. } => {
436+
| DependentQueuedRequestKind::UploadFileOrThumbnail { .. } => {
394437
// These are all aggregated events, or non-visible items (file upload producing
395438
// a new MXC ID).
396439
false

crates/matrix-sdk-sqlite/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ event-cache = ["dep:matrix-sdk-base"]
1717
state-store = ["dep:matrix-sdk-base"]
1818

1919
[dependencies]
20+
as_variant = { workspace = true }
2021
async-trait = { workspace = true }
2122
deadpool-sqlite = "0.10.0"
2223
itertools = { workspace = true }

crates/matrix-sdk-sqlite/src/state_store.rs

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,8 +2237,10 @@ mod migration_tests {
22372237
},
22382238
};
22392239

2240+
use as_variant::as_variant;
22402241
use deadpool_sqlite::Runtime;
22412242
use matrix_sdk_base::{
2243+
media::{MediaFormat, MediaRequestParameters},
22422244
store::{
22432245
ChildTransactionId, DependentQueuedRequestKind, RoomLoadSettings,
22442246
SerializableEventContent,
@@ -2250,13 +2252,14 @@ mod migration_tests {
22502252
use once_cell::sync::Lazy;
22512253
use ruma::{
22522254
events::{
2253-
room::{create::RoomCreateEventContent, message::RoomMessageEventContent},
2255+
room::{create::RoomCreateEventContent, message::RoomMessageEventContent, MediaSource},
22542256
StateEventType,
22552257
},
2256-
room_id, server_name, user_id, EventId, MilliSecondsSinceUnixEpoch, RoomId, TransactionId,
2257-
UserId,
2258+
room_id, server_name, user_id, EventId, MilliSecondsSinceUnixEpoch, OwnedTransactionId,
2259+
RoomId, TransactionId, UserId,
22582260
};
22592261
use rusqlite::Transaction;
2262+
use serde::{Deserialize, Serialize};
22602263
use serde_json::json;
22612264
use tempfile::{tempdir, TempDir};
22622265
use tokio::fs;
@@ -2597,4 +2600,41 @@ mod migration_tests {
25972600

25982601
Ok(())
25992602
}
2603+
2604+
#[derive(Clone, Debug, Serialize, Deserialize)]
2605+
pub enum LegacyDependentQueuedRequestKind {
2606+
UploadFileWithThumbnail {
2607+
content_type: String,
2608+
cache_key: MediaRequestParameters,
2609+
related_to: OwnedTransactionId,
2610+
},
2611+
}
2612+
2613+
#[async_test]
2614+
pub async fn test_dependent_queued_request_variant_renaming() {
2615+
let path = new_path();
2616+
let db = create_fake_db(&path, 7).await.unwrap();
2617+
2618+
let cache_key = MediaRequestParameters {
2619+
format: MediaFormat::File,
2620+
source: MediaSource::Plain("https://server.local/foobar".into()),
2621+
};
2622+
let related_to = TransactionId::new();
2623+
let request = LegacyDependentQueuedRequestKind::UploadFileWithThumbnail {
2624+
content_type: "image/png".to_owned(),
2625+
cache_key,
2626+
related_to: related_to.clone(),
2627+
};
2628+
2629+
let data = db
2630+
.serialize_json(&request)
2631+
.expect("should be able to serialize legacy dependent request");
2632+
let deserialized: DependentQueuedRequestKind = db.deserialize_json(&data).expect(
2633+
"should be able to deserialize dependent request from legacy dependent request",
2634+
);
2635+
2636+
as_variant!(deserialized, DependentQueuedRequestKind::UploadFileOrThumbnail { related_to: de_related_to, .. } => {
2637+
assert_eq!(de_related_to, related_to);
2638+
});
2639+
}
26002640
}

crates/matrix-sdk/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ experimental-widgets = ["dep:uuid"]
5050
docsrs = ["e2e-encryption", "sqlite", "indexeddb", "sso-login", "qrcode"]
5151
experimental-share-history-on-invite = []
5252

53+
# Add support for inline media galleries via msgtypes
54+
unstable-msc4274 = ["matrix-sdk-base/unstable-msc4274"]
55+
5356
[dependencies]
5457
anyhow = { workspace = true, optional = true }
5558
anymap2 = "0.13.0"
@@ -114,6 +117,7 @@ urlencoding = "2.1.3"
114117
uuid = { workspace = true, features = ["serde", "v4"], optional = true }
115118
vodozemac = { workspace = true }
116119
zeroize = { workspace = true }
120+
cfg-if = "1.0.0"
117121

118122
[target.'cfg(target_arch = "wasm32")'.dependencies]
119123
gloo-timers = { workspace = true, features = ["futures"] }

crates/matrix-sdk/src/send_queue/mod.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@
109109
//! - the thumbnail is sent first as an [`QueuedRequestKind::MediaUpload`]
110110
//! request,
111111
//! - the file upload is pushed as a dependent request of kind
112-
//! [`DependentQueuedRequestKind::UploadFileWithThumbnail`] (this variant
113-
//! keeps the file's key used to look it up in the cache store).
112+
//! [`DependentQueuedRequestKind::UploadFileOrThumbnail`] (this variant keeps
113+
//! the file's key used to look it up in the cache store).
114114
//! - the media event is then sent as a dependent request as described in the
115115
//! previous section.
116116
//!
@@ -699,6 +699,8 @@ impl RoomSendQueue {
699699
cache_key,
700700
thumbnail_source,
701701
related_to: relates_to,
702+
#[cfg(feature = "unstable-msc4274")]
703+
accumulated,
702704
} => {
703705
trace!(%relates_to, "uploading media related to event");
704706

@@ -757,6 +759,8 @@ impl RoomSendQueue {
757759
Ok(SentRequestKey::Media(SentMediaInfo {
758760
file: media_source,
759761
thumbnail: thumbnail_source,
762+
#[cfg(feature = "unstable-msc4274")]
763+
accumulated,
760764
}))
761765
};
762766

@@ -1215,6 +1219,8 @@ impl QueueStorage {
12151219
cache_key: thumbnail_media_request,
12161220
thumbnail_source: None, // the thumbnail has no thumbnails :)
12171221
related_to: send_event_txn.clone(),
1222+
#[cfg(feature = "unstable-msc4274")]
1223+
accumulated: vec![],
12181224
},
12191225
Self::LOW_PRIORITY,
12201226
)
@@ -1227,10 +1233,12 @@ impl QueueStorage {
12271233
&upload_thumbnail_txn,
12281234
upload_file_txn.clone().into(),
12291235
created_at,
1230-
DependentQueuedRequestKind::UploadFileWithThumbnail {
1236+
DependentQueuedRequestKind::UploadFileOrThumbnail {
12311237
content_type: content_type.to_string(),
12321238
cache_key: file_media_request,
12331239
related_to: send_event_txn.clone(),
1240+
#[cfg(feature = "unstable-msc4274")]
1241+
parent_is_thumbnail_upload: true,
12341242
},
12351243
)
12361244
.await?;
@@ -1248,6 +1256,8 @@ impl QueueStorage {
12481256
cache_key: file_media_request,
12491257
thumbnail_source: None,
12501258
related_to: send_event_txn.clone(),
1259+
#[cfg(feature = "unstable-msc4274")]
1260+
accumulated: vec![],
12511261
},
12521262
Self::LOW_PRIORITY,
12531263
)
@@ -1376,7 +1386,7 @@ impl QueueStorage {
13761386
},
13771387
}),
13781388

1379-
DependentQueuedRequestKind::UploadFileWithThumbnail { .. } => {
1389+
DependentQueuedRequestKind::UploadFileOrThumbnail { .. } => {
13801390
// Don't reflect these: only the associated event is interesting to observers.
13811391
None
13821392
}
@@ -1589,22 +1599,37 @@ impl QueueStorage {
15891599
}
15901600
}
15911601

1592-
DependentQueuedRequestKind::UploadFileWithThumbnail {
1602+
DependentQueuedRequestKind::UploadFileOrThumbnail {
15931603
content_type,
15941604
cache_key,
15951605
related_to,
1606+
#[cfg(feature = "unstable-msc4274")]
1607+
parent_is_thumbnail_upload,
15961608
} => {
15971609
let Some(parent_key) = parent_key else {
15981610
// Not finished yet, we should retry later => false.
15991611
return Ok(false);
16001612
};
1601-
self.handle_dependent_file_upload_with_thumbnail(
1613+
let parent_is_thumbnail_upload = {
1614+
cfg_if::cfg_if! {
1615+
if #[cfg(feature = "unstable-msc4274")] {
1616+
parent_is_thumbnail_upload
1617+
} else {
1618+
// Before parent_is_thumbnail_upload was introduced, the only
1619+
// possible usage for this request was a file upload following
1620+
// a thumbnail upload.
1621+
true
1622+
}
1623+
}
1624+
};
1625+
self.handle_dependent_file_or_thumbnail_upload(
16021626
client,
16031627
dependent_request.own_transaction_id.into(),
16041628
parent_key,
16051629
content_type,
16061630
cache_key,
16071631
related_to,
1632+
parent_is_thumbnail_upload,
16081633
)
16091634
.await?;
16101635
}
@@ -2209,7 +2234,7 @@ fn canonicalize_dependent_requests(
22092234
}
22102235
}
22112236

2212-
DependentQueuedRequestKind::UploadFileWithThumbnail { .. }
2237+
DependentQueuedRequestKind::UploadFileOrThumbnail { .. }
22132238
| DependentQueuedRequestKind::FinishUpload { .. }
22142239
| DependentQueuedRequestKind::ReactEvent { .. } => {
22152240
// These requests can't be canonicalized, push them as is.

0 commit comments

Comments
 (0)