Commit 5d2974de5826
tarball8 files changed+74-57
@@ -164,8 +164,8 @@ sdk's own patcher is private
164164
165165
## media166166
167
-media is a read. `ClientHandle::media` takes a `MediaId` a retained timeline168
-handed you, `mxc_media` takes any plain mxc uri. both share one bounded167
+media is a read. `ClientHandle::media` takes a `MediaId`, from a retained168
+timeline or an avatar, through one bounded169169
download path with the byte cap the sdk's own download lacks, an hour's total170170
deadline instead of the sdk client's thirty seconds, and a minute's patience171171
for a stalled stream. concurrent asks for the same bytes share one flight.@@ -181,6 +181,13 @@ checks the cached bytes against the file's hash and decrypts them if they match
181181
media ids are registered as timelines render and forgotten when their timeline182182
closes, least recently seen first once the cap is hit183183
184
+avatars are `MediaId`s too, so a host never handles an mxc uri. they aren't185
+registered, since they live in the room list and member lists for the whole186
+session and there can be thousands, and the cap would evict ones still on187
+screen. a plain avatar carries no keys, so its id is its mxc uri and resolves188
+without the registry. it never expires, and an mxc uri a host got some other way189
+parses into one. `set_avatar` still takes an mxc uri190
+184191
streaming decryption inside macltok was declined. in a browser the service185192
worker answering range requests is a separate context from the worker running186193
macltok, and streaming through macltok would carry every chunk through wasm@@ -35,7 +35,7 @@ use super::executor::EngineBoxFuture;
3535
use crate::{3636
AttachmentEncryption, AttachmentUpload, Error, ErrorKind, Media, MediaFile, MediaId, MediaKind,3737
MediaLocation, MediaSize, TimelineId,38
- normalise::{MediaRegistration, MediaScope},38
+ normalise::{MediaRegistration, MediaScope, MediaSourceInfo},3939
upload::prepare_upload,4040
};4141
@@ -137,6 +137,9 @@ impl MediaService {
137137
}138138
139139
async fn registered(&self, media_id: &MediaId) -> Result<MediaRegistration, Error> {140
+ if let Some(uri) = media_id.as_plain() {141
+ return plain_registration(media_id, uri);142
+ }140143
self.registry141144
.lock()142145
.await@@ -150,24 +153,6 @@ impl MediaService {
150153
})151154
}152155
153
- pub(crate) async fn mxc_media(&self, uri: &MxcUri, size: MediaSize) -> Result<Media, Error> {154
- if !uri.is_valid() {155
- return Err(Error::new(ErrorKind::Invalid, "mxc uri is malformed"));156
- }157
- let format = match size {158
- MediaSize::Full => MediaFormat::File,159
- MediaSize::Thumbnail { width, height } => thumbnail_format(width, height),160
- };161
- self.fetch_or_file(162
- MediaRequestParameters {163
- source: MediaSource::Plain(uri.to_owned()),164
- format,165
- },166
- None,167
- )168
- .await169
- }170
-171156
/// plenty of servers won't thumbnail everything, and the file itself is the next best172157
/// thing. the byte cap still holds either way173158
async fn fetch_or_file(@@ -233,6 +218,22 @@ struct ChosenSource {
233218
declared_size: Option<u64>,234219
}235220
221
+fn plain_registration(media_id: &MediaId, uri: &MxcUri) -> Result<MediaRegistration, Error> {222
+ if !uri.is_valid() {223
+ return Err(Error::new(ErrorKind::Invalid, "mxc uri is malformed"));224
+ }225
+ Ok(MediaRegistration {226
+ id: media_id.clone(),227
+ kind: MediaKind::Image,228
+ full: MediaSourceInfo {229
+ source: MediaSource::Plain(uri.to_owned()),230
+ mimetype: None,231
+ declared_size: None,232
+ },233
+ thumbnail: None,234
+ })235
+}236
+236237
fn choose_source(media: MediaRegistration, size: MediaSize) -> Result<ChosenSource, Error> {237238
let (source, format, mimetype, declared_size) = match size {238239
MediaSize::Full => (@@ -2,8 +2,8 @@ use std::{fmt, sync::Arc};
22
33
use imbl::Vector;44
use ruma::{5
- OwnedDeviceId, OwnedEventId, OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, OwnedRoomOrAliasId,6
- OwnedServerName, OwnedTransactionId, OwnedUserId,5
+ MxcUri, OwnedDeviceId, OwnedEventId, OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId,6
+ OwnedRoomOrAliasId, OwnedServerName, OwnedTransactionId, OwnedUserId,77
events::{88
AnyGlobalAccountDataEventContent, AnyRoomAccountDataEventContent, AnySyncTimelineEvent,99
GlobalAccountDataEventType, RoomAccountDataEventType,@@ -786,7 +786,7 @@ pub struct RoomSummary {
786786
pub direct: bool,787787
pub favourite: bool,788788
pub low_priority: bool,789
- pub avatar: Option<OwnedMxcUri>,789
+ pub avatar: Option<MediaId>,790790
pub latest_event_timestamp_ms: Option<u64>,791791
pub latest_event: Option<LatestEvent>,792792
pub notification_mode: Option<RoomNotificationMode>,@@ -812,7 +812,7 @@ pub struct RoomSummary {
812812
pub struct RoomHero {813813
pub user_id: OwnedUserId,814814
pub display_name: Option<String>,815
- pub avatar: Option<OwnedMxcUri>,815
+ pub avatar: Option<MediaId>,816816
}817817
818818
/// enough for a room list preview line. `kind` and `body` are only set for messages,@@ -834,7 +834,7 @@ pub struct LatestEvent {
834834
pub struct Profile {835835
pub user_id: OwnedUserId,836836
pub display_name: Option<String>,837
- pub avatar: Option<OwnedMxcUri>,837
+ pub avatar: Option<MediaId>,838838
}839839
840840
/// one room in a space's hierarchy, as the server describes it, which may be a room you're not in@@ -845,7 +845,7 @@ pub struct SpaceChild {
845845
pub room_id: OwnedRoomId,846846
pub name: String,847847
pub topic: Option<String>,848
- pub avatar: Option<OwnedMxcUri>,848
+ pub avatar: Option<MediaId>,849849
pub canonical_alias: Option<OwnedRoomAliasId>,850850
pub joined_members: u64,851851
pub space: bool,@@ -903,7 +903,7 @@ pub struct PushNotification {
903903
pub struct PushNotificationSender {904904
pub user_id: OwnedUserId,905905
pub display_name: Option<String>,906
- pub avatar_url: Option<OwnedMxcUri>,906
+ pub avatar_url: Option<MediaId>,907907
pub name_ambiguous: bool,908908
}909909
@@ -913,7 +913,7 @@ pub struct PushNotificationSender {
913913
pub struct PushNotificationRoom {914914
pub room_id: OwnedRoomId,915915
pub name: String,916
- pub avatar_url: Option<OwnedMxcUri>,916
+ pub avatar_url: Option<MediaId>,917917
pub canonical_alias: Option<OwnedRoomAliasId>,918918
pub topic: Option<String>,919919
pub encrypted: Option<bool>,@@ -1107,7 +1107,7 @@ pub struct MemberSummary {
11071107
pub user_id: OwnedUserId,11081108
pub name: String,11091109
pub display_name: Option<String>,1110
- pub avatar: Option<OwnedMxcUri>,1110
+ pub avatar: Option<MediaId>,11111111
pub membership: MemberMembership,11121112
pub own: bool,11131113
pub name_ambiguous: bool,@@ -1422,7 +1422,7 @@ impl From<OwnedEventId> for EventRef {
14221422
pub struct Sender {14231423
pub user_id: OwnedUserId,14241424
pub display_name: Option<String>,1425
- pub avatar: Option<OwnedMxcUri>,1425
+ pub avatar: Option<MediaId>,14261426
/// someone else in the room goes by the same name, so show the user id too14271427
pub name_ambiguous: bool,14281428
}@@ -1458,12 +1458,12 @@ pub enum TimelineContent {
14581458
Profile {14591459
user_id: OwnedUserId,14601460
display_name: Option<Change<Option<String>>>,1461
- avatar: Option<Change<Option<OwnedMxcUri>>>,1461
+ avatar: Option<Change<Option<MediaId>>>,14621462
},14631463
/// `None` means it was cleared, or the event was redacted14641464
RoomName(Option<String>),14651465
RoomTopic(Option<String>),1466
- RoomAvatar(Option<OwnedMxcUri>),1466
+ RoomAvatar(Option<MediaId>),14671467
EncryptionEnabled,14681468
RoomCreated,14691469
RoomUpgraded {@@ -1635,6 +1635,15 @@ impl MediaId {
16351635
Self(value)16361636
}16371637
1638
+ /// plain media carries no keys, so it needs no registering and never expires1639
+ pub(crate) fn plain<U: AsRef<str> + ?Sized>(uri: &U) -> Self {1640
+ Self(uri.as_ref().to_owned())1641
+ }1642
+1643
+ pub(crate) fn as_plain(&self) -> Option<&MxcUri> {1644
+ self.0.starts_with("mxc://").then(|| self.0.as_str().into())1645
+ }1646
+16381647
#[must_use]16391648
pub fn as_str(&self) -> &str {16401649
&self.0@@ -1,14 +1,14 @@
11
use matrix_sdk::room::RoomMember;22
use ruma::events::room::member::MembershipState;33
4
-use crate::{MemberMembership, MemberSummary};4
+use crate::{MediaId, MemberMembership, MemberSummary};55
66
pub(crate) fn member_summary(member: RoomMember) -> MemberSummary {77
MemberSummary {88
user_id: member.user_id().to_owned(),99
name: member.name().to_owned(),1010
display_name: member.display_name().map(ToOwned::to_owned),11
- avatar: member.avatar_url().map(ToOwned::to_owned),11
+ avatar: member.avatar_url().map(MediaId::plain),1212
membership: match member.membership() {1313
MembershipState::Join => MemberMembership::Joined,1414
MembershipState::Invite => MemberMembership::Invited,@@ -3,7 +3,7 @@ mod member;
33
mod room;44
mod timeline;55
6
-pub(crate) use media::{MediaRegistration, MediaScope};6
+pub(crate) use media::{MediaRegistration, MediaScope, MediaSourceInfo};77
pub(crate) use member::member_summary;88
pub(crate) use room::notification_mode;99
pub(crate) use room::{room_summaries, space_child};@@ -14,7 +14,7 @@ use ruma::OwnedRoomId;
1414
1515
use super::message_kind;1616
use crate::{17
- LatestEvent, MessageKind, RoomHero, RoomMembership, RoomNotificationMode, RoomSummary,17
+ LatestEvent, MediaId, MessageKind, RoomHero, RoomMembership, RoomNotificationMode, RoomSummary,1818
SendState, SpaceChild,1919
};2020
@@ -70,7 +70,7 @@ async fn room_summary(room: &Room, spaces: &SpaceService) -> RoomSummary {
7070
direct: room.is_direct().await.unwrap_or(false),7171
favourite: room.is_favourite(),7272
low_priority: room.is_low_priority(),73
- avatar: room.avatar_url(),73
+ avatar: room.avatar_url().as_deref().map(MediaId::plain),7474
latest_event_timestamp_ms: room7575
.latest_event_timestamp()7676
.map(|value| value.get().into()),@@ -87,7 +87,7 @@ async fn room_summary(room: &Room, spaces: &SpaceService) -> RoomSummary {
8787
.map(|hero| RoomHero {8888
user_id: hero.user_id,8989
display_name: hero.display_name,90
- avatar: hero.avatar_url,90
+ avatar: hero.avatar_url.as_deref().map(MediaId::plain),9191
})9292
.collect(),9393
successor: room.successor_room().map(|successor| successor.room_id),@@ -197,7 +197,7 @@ pub(crate) fn space_child(room: SpaceRoom) -> SpaceChild {
197197
name: room.display_name,198198
room_id: room.room_id,199199
topic: room.topic,200
- avatar: room.avatar_url,200
+ avatar: room.avatar_url.as_deref().map(MediaId::plain),201201
canonical_alias: room.canonical_alias,202202
joined_members: room.num_joined_members,203203
space: room.room_type == Some(ruma::room::RoomType::Space),@@ -19,9 +19,9 @@ use ruma::{
1919
};2020
2121
use crate::{22
- Change, MembershipChange, Message, MessageKind, MessageMentions, Reaction, ReplyDetails,23
- ReplyReference, SendState, Sender, ThreadSummary, TimelineContent, TimelineDiff, TimelineEvent,24
- TimelineItem, TimelineItemId, UtdCause,22
+ Change, MediaId, MembershipChange, Message, MessageKind, MessageMentions, Reaction,23
+ ReplyDetails, ReplyReference, SendState, Sender, ThreadSummary, TimelineContent, TimelineDiff,24
+ TimelineEvent, TimelineItem, TimelineItemId, UtdCause,2525
};2626
2727
use super::media::{@@ -198,8 +198,8 @@ fn content(content: &TimelineItemContent, media_identity: Option<&str>) -> Timel
198198
new: change.new.clone(),199199
}),200200
avatar: change.avatar_url_change().map(|change| Change {201
- old: change.old.clone(),202
- new: change.new.clone(),201
+ old: change.old.as_deref().map(MediaId::plain),202
+ new: change.new.as_deref().map(MediaId::plain),203203
}),204204
},205205
TimelineItemContent::OtherState(state) => match state.content() {@@ -210,7 +210,7 @@ fn content(content: &TimelineItemContent, media_identity: Option<&str>) -> Timel
210210
original(change).and_then(|content| non_empty(&content.topic)),211211
),212212
AnyOtherStateEventContentChange::RoomAvatar(change) => TimelineContent::RoomAvatar(213
- original(change).and_then(|content| content.url.clone()),213
+ original(change).and_then(|content| content.url.as_deref().map(MediaId::plain)),214214
),215215
AnyOtherStateEventContentChange::RoomEncryption(_) => {216216
TimelineContent::EncryptionEnabled@@ -380,7 +380,7 @@ fn sender(user_id: &UserId, profile: &TimelineDetails<Profile>) -> Sender {
380380
Sender {381381
user_id: user_id.to_owned(),382382
display_name: profile.and_then(|profile| profile.display_name.clone()),383
- avatar: profile.and_then(|profile| profile.avatar_url.clone()),383
+ avatar: profile.and_then(|profile| profile.avatar_url.as_deref().map(MediaId::plain)),384384
name_ambiguous: profile.is_some_and(|profile| profile.display_name_ambiguous),385385
}386386
}@@ -15,7 +15,7 @@ use matrix_sdk_ui::{
1515
sync_service::SyncService,1616
};1717
use ruma::{18
- EventId, MxcUri, OwnedDeviceId, OwnedEventId, OwnedMxcUri, OwnedRoomId, OwnedRoomOrAliasId,18
+ EventId, OwnedDeviceId, OwnedEventId, OwnedMxcUri, OwnedRoomId, OwnedRoomOrAliasId,1919
OwnedServerName, OwnedTransactionId, OwnedUserId, RoomId, UserId,2020
events::{2121
AnyGlobalAccountDataEventContent, AnyRoomAccountDataEvent, AnyRoomAccountDataEventContent,@@ -555,7 +555,8 @@ impl ClientHandle {
555555
.await556556
}557557
558
- /// bytes for media a retained timeline showed you. concurrent asks share one download558
+ /// bytes for an avatar, or for media a retained timeline showed you. concurrent asks share559
+ /// one download559560
pub async fn media(&self, media_id: &MediaId, size: MediaSize) -> Result<Media, Error> {560561
self.media.timeline_media(media_id, size).await561562
}@@ -570,11 +571,6 @@ impl ClientHandle {
570571
self.media.media_location(media_id, size).await571572
}572573
573
- /// bytes for any plain mxc uri, avatars mostly. same byte cap as everything else574
- pub async fn mxc_media(&self, uri: &MxcUri, size: MediaSize) -> Result<Media, Error> {575
- self.media.mxc_media(uri, size).await576
- }577
-578574
/// the space graph builds on first use and then keeps itself current579575
async fn spaces(&self) -> &SpaceService {580576
self.spaces@@ -908,7 +904,11 @@ fn profile(
908904
Ok(Profile {909905
user_id,910906
display_name: response.get_static::<DisplayName>().map_err(malformed)?,911
- avatar: response.get_static::<AvatarUrl>().map_err(malformed)?,907
+ avatar: response908
+ .get_static::<AvatarUrl>()909
+ .map_err(malformed)?910
+ .as_deref()911
+ .map(MediaId::plain),912912
})913913
}914914
@@ -1069,13 +1069,13 @@ fn normalise_push_notification(
10691069
sender: PushNotificationSender {10701070
user_id: item.event.sender().to_owned(),10711071
display_name: item.sender_display_name,1072
- avatar_url: item.sender_avatar_url.map(Into::into),1072
+ avatar_url: item.sender_avatar_url.as_deref().map(MediaId::plain),10731073
name_ambiguous: item.is_sender_name_ambiguous,10741074
},10751075
room: PushNotificationRoom {10761076
room_id: room_id.to_owned(),10771077
name: item.room_computed_display_name,1078
- avatar_url: item.room_avatar_url.map(Into::into),1078
+ avatar_url: item.room_avatar_url.as_deref().map(MediaId::plain),10791079
canonical_alias: item10801080
.room_canonical_alias10811081
.as_deref()