Skip to content

Commit a7e4849

Browse files
zecakehpoljar
authored andcommitted
sdk: Use strongly-typed strings where it makes sense
Where a string is clearly documented as a room ID, event ID or mxc URI, use OwnedRoomId, OwnedEventId and OwnedMxcURI, respectively. Signed-off-by: Kévin Commaille <[email protected]>
1 parent 769fe8b commit a7e4849

File tree

10 files changed

+133
-64
lines changed

10 files changed

+133
-64
lines changed

bindings/matrix-sdk-ffi/src/client.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ impl Client {
548548

549549
/// Retrieves an avatar cached from a previous call to [`Self::avatar_url`].
550550
pub fn cached_avatar_url(&self) -> Result<Option<String>, ClientError> {
551-
Ok(RUNTIME.block_on(self.inner.account().get_cached_avatar_url())?)
551+
Ok(RUNTIME.block_on(self.inner.account().get_cached_avatar_url())?.map(Into::into))
552552
}
553553

554554
pub fn device_id(&self) -> Result<String, ClientError> {
@@ -873,11 +873,19 @@ impl Client {
873873
}
874874

875875
pub async fn get_recently_visited_rooms(&self) -> Result<Vec<String>, ClientError> {
876-
Ok(self.inner.account().get_recently_visited_rooms().await?)
876+
Ok(self
877+
.inner
878+
.account()
879+
.get_recently_visited_rooms()
880+
.await?
881+
.into_iter()
882+
.map(Into::into)
883+
.collect())
877884
}
878885

879886
pub async fn track_recently_visited_room(&self, room: String) -> Result<(), ClientError> {
880-
self.inner.account().track_recently_visited_room(room).await?;
887+
let room_id = RoomId::parse(room)?;
888+
self.inner.account().track_recently_visited_room(room_id).await?;
881889
Ok(())
882890
}
883891

bindings/matrix-sdk-ffi/src/room.rs

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use anyhow::{Context, Result};
44
use matrix_sdk::{
55
event_cache::paginator::PaginatorError,
66
room::{power_levels::RoomPowerLevelChanges, Room as SdkRoom, RoomMemberRole},
7-
ComposerDraft, RoomHero as SdkRoomHero, RoomMemberships, RoomState,
7+
ComposerDraft as SdkComposerDraft, ComposerDraftType as SdkComposerDraftType,
8+
RoomHero as SdkRoomHero, RoomMemberships, RoomState,
89
};
910
use matrix_sdk_ui::timeline::{PaginationError, RoomExt, TimelineFocus};
1011
use mime::Mime;
@@ -677,12 +678,12 @@ impl Room {
677678
/// Store the given `ComposerDraft` in the state store using the current
678679
/// room id, as identifier.
679680
pub async fn save_composer_draft(&self, draft: ComposerDraft) -> Result<(), ClientError> {
680-
Ok(self.inner.save_composer_draft(draft).await?)
681+
Ok(self.inner.save_composer_draft(draft.try_into()?).await?)
681682
}
682683

683684
/// Retrieve the `ComposerDraft` stored in the state store for this room.
684685
pub async fn load_composer_draft(&self) -> Result<Option<ComposerDraft>, ClientError> {
685-
Ok(self.inner.load_composer_draft().await?)
686+
Ok(self.inner.load_composer_draft().await?.map(Into::into))
686687
}
687688

688689
/// Remove the `ComposerDraft` stored in the state store for this room.
@@ -848,3 +849,72 @@ impl From<RtcApplicationType> for notify::ApplicationType {
848849
}
849850
}
850851
}
852+
853+
/// Current draft of the composer for the room.
854+
#[derive(uniffi::Record)]
855+
pub struct ComposerDraft {
856+
/// The draft content in plain text.
857+
pub plain_text: String,
858+
/// If the message is formatted in HTML, the HTML representation of the
859+
/// message.
860+
pub html_text: Option<String>,
861+
/// The type of draft.
862+
pub draft_type: ComposerDraftType,
863+
}
864+
865+
impl From<SdkComposerDraft> for ComposerDraft {
866+
fn from(value: SdkComposerDraft) -> Self {
867+
let SdkComposerDraft { plain_text, html_text, draft_type } = value;
868+
Self { plain_text, html_text, draft_type: draft_type.into() }
869+
}
870+
}
871+
872+
impl TryFrom<ComposerDraft> for SdkComposerDraft {
873+
type Error = ruma::IdParseError;
874+
875+
fn try_from(value: ComposerDraft) -> std::result::Result<Self, Self::Error> {
876+
let ComposerDraft { plain_text, html_text, draft_type } = value;
877+
Ok(Self { plain_text, html_text, draft_type: draft_type.try_into()? })
878+
}
879+
}
880+
881+
/// The type of draft of the composer.
882+
#[derive(uniffi::Enum)]
883+
pub enum ComposerDraftType {
884+
/// The draft is a new message.
885+
NewMessage,
886+
/// The draft is a reply to an event.
887+
Reply {
888+
/// The ID of the event being replied to.
889+
event_id: String,
890+
},
891+
/// The draft is an edit of an event.
892+
Edit {
893+
/// The ID of the event being edited.
894+
event_id: String,
895+
},
896+
}
897+
898+
impl From<SdkComposerDraftType> for ComposerDraftType {
899+
fn from(value: SdkComposerDraftType) -> Self {
900+
match value {
901+
SdkComposerDraftType::NewMessage => Self::NewMessage,
902+
SdkComposerDraftType::Reply { event_id } => Self::Reply { event_id: event_id.into() },
903+
SdkComposerDraftType::Edit { event_id } => Self::Edit { event_id: event_id.into() },
904+
}
905+
}
906+
}
907+
908+
impl TryFrom<ComposerDraftType> for SdkComposerDraftType {
909+
type Error = ruma::IdParseError;
910+
911+
fn try_from(value: ComposerDraftType) -> std::result::Result<Self, Self::Error> {
912+
let draft_type = match value {
913+
ComposerDraftType::NewMessage => Self::NewMessage,
914+
ComposerDraftType::Reply { event_id } => Self::Reply { event_id: event_id.try_into()? },
915+
ComposerDraftType::Edit { event_id } => Self::Edit { event_id: event_id.try_into()? },
916+
};
917+
918+
Ok(draft_type)
919+
}
920+
}

crates/matrix-sdk-base/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ pub use rooms::{
5656
RoomMember, RoomMemberships, RoomState, RoomStateFilter,
5757
};
5858
pub use store::{
59-
ComposerDraft, StateChanges, StateStore, StateStoreDataKey, StateStoreDataValue, StoreError,
59+
ComposerDraft, ComposerDraftType, StateChanges, StateStore, StateStoreDataKey,
60+
StateStoreDataValue, StoreError,
6061
};
6162
pub use utils::{
6263
MinimalRoomMemberEvent, MinimalStateEvent, OriginalMinimalStateEvent, RedactedMinimalStateEvent,

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use ruma::{
2828
AnySyncStateEvent, GlobalAccountDataEventType, RoomAccountDataEventType, StateEventType,
2929
SyncStateEvent,
3030
},
31-
mxc_uri, room_id,
31+
mxc_uri, owned_mxc_uri, room_id,
3232
serde::Raw,
3333
uint, user_id, EventId, OwnedEventId, OwnedUserId, RoomId, TransactionId, UserId,
3434
};
@@ -548,11 +548,11 @@ impl StateStoreIntegrationTests for DynStateStore {
548548

549549
async fn test_user_avatar_url_saving(&self) {
550550
let user_id = user_id!("@alice:example.org");
551-
let url = "https://example.org";
551+
let url = owned_mxc_uri!("mxc://example.org/poiuyt098");
552552

553553
self.set_kv_data(
554554
StateStoreDataKey::UserAvatarUrl(user_id),
555-
StateStoreDataValue::UserAvatarUrl(url.to_owned()),
555+
StateStoreDataValue::UserAvatarUrl(url.clone()),
556556
)
557557
.await
558558
.unwrap();

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ use crate::{
5252
#[allow(clippy::type_complexity)]
5353
#[derive(Debug)]
5454
pub struct MemoryStore {
55-
recently_visited_rooms: StdRwLock<HashMap<String, Vec<String>>>,
55+
recently_visited_rooms: StdRwLock<HashMap<OwnedUserId, Vec<OwnedRoomId>>>,
5656
composer_drafts: StdRwLock<HashMap<OwnedRoomId, ComposerDraft>>,
57-
user_avatar_url: StdRwLock<HashMap<String, String>>,
57+
user_avatar_url: StdRwLock<HashMap<OwnedUserId, OwnedMxcUri>>,
5858
sync_token: StdRwLock<Option<String>>,
5959
filters: StdRwLock<HashMap<String, String>>,
6060
utd_hook_manager_data: StdRwLock<Option<GrowableBloom>>,
@@ -186,14 +186,14 @@ impl StateStore for MemoryStore {
186186
.user_avatar_url
187187
.read()
188188
.unwrap()
189-
.get(user_id.as_str())
189+
.get(user_id)
190190
.cloned()
191191
.map(StateStoreDataValue::UserAvatarUrl),
192192
StateStoreDataKey::RecentlyVisitedRooms(user_id) => self
193193
.recently_visited_rooms
194194
.read()
195195
.unwrap()
196-
.get(user_id.as_str())
196+
.get(user_id)
197197
.cloned()
198198
.map(StateStoreDataValue::RecentlyVisitedRooms),
199199
StateStoreDataKey::UtdHookManagerData => self
@@ -230,13 +230,13 @@ impl StateStore for MemoryStore {
230230
}
231231
StateStoreDataKey::UserAvatarUrl(user_id) => {
232232
self.user_avatar_url.write().unwrap().insert(
233-
user_id.to_string(),
233+
user_id.to_owned(),
234234
value.into_user_avatar_url().expect("Session data not a user avatar url"),
235235
);
236236
}
237237
StateStoreDataKey::RecentlyVisitedRooms(user_id) => {
238238
self.recently_visited_rooms.write().unwrap().insert(
239-
user_id.to_string(),
239+
user_id.to_owned(),
240240
value
241241
.into_recently_visited_rooms()
242242
.expect("Session data not a list of recently visited rooms"),
@@ -267,10 +267,10 @@ impl StateStore for MemoryStore {
267267
self.filters.write().unwrap().remove(filter_name);
268268
}
269269
StateStoreDataKey::UserAvatarUrl(user_id) => {
270-
self.user_avatar_url.write().unwrap().remove(user_id.as_str());
270+
self.user_avatar_url.write().unwrap().remove(user_id);
271271
}
272272
StateStoreDataKey::RecentlyVisitedRooms(user_id) => {
273-
self.recently_visited_rooms.write().unwrap().remove(user_id.as_str());
273+
self.recently_visited_rooms.write().unwrap().remove(user_id);
274274
}
275275
StateStoreDataKey::UtdHookManagerData => {
276276
*self.utd_hook_manager_data.write().unwrap() = None

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ use ruma::{
3434
StateEventType, StaticEventContent, StaticStateEventContent,
3535
},
3636
serde::Raw,
37-
EventId, MxcUri, OwnedEventId, OwnedRoomId, OwnedTransactionId, OwnedUserId, RoomId,
38-
TransactionId, UserId,
37+
EventId, MxcUri, OwnedEventId, OwnedMxcUri, OwnedRoomId, OwnedTransactionId, OwnedUserId,
38+
RoomId, TransactionId, UserId,
3939
};
4040
use serde::{Deserialize, Serialize};
4141

@@ -914,10 +914,10 @@ pub enum StateStoreDataValue {
914914
Filter(String),
915915

916916
/// The user avatar url
917-
UserAvatarUrl(String),
917+
UserAvatarUrl(OwnedMxcUri),
918918

919919
/// A list of recently visited room identifiers for the current user
920-
RecentlyVisitedRooms(Vec<String>),
920+
RecentlyVisitedRooms(Vec<OwnedRoomId>),
921921

922922
/// Persistent data for
923923
/// `matrix_sdk_ui::unable_to_decrypt_hook::UtdHookManager`.
@@ -932,7 +932,6 @@ pub enum StateStoreDataValue {
932932

933933
/// Current draft of the composer for the room.
934934
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
935-
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
936935
pub struct ComposerDraft {
937936
/// The draft content in plain text.
938937
pub plain_text: String,
@@ -945,19 +944,18 @@ pub struct ComposerDraft {
945944

946945
/// The type of draft of the composer.
947946
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
948-
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
949947
pub enum ComposerDraftType {
950948
/// The draft is a new message.
951949
NewMessage,
952950
/// The draft is a reply to an event.
953951
Reply {
954952
/// The ID of the event being replied to.
955-
event_id: String,
953+
event_id: OwnedEventId,
956954
},
957955
/// The draft is an edit of an event.
958956
Edit {
959957
/// The ID of the event being edited.
960-
event_id: String,
958+
event_id: OwnedEventId,
961959
},
962960
}
963961

@@ -973,12 +971,12 @@ impl StateStoreDataValue {
973971
}
974972

975973
/// Get this value if it is a user avatar url.
976-
pub fn into_user_avatar_url(self) -> Option<String> {
974+
pub fn into_user_avatar_url(self) -> Option<OwnedMxcUri> {
977975
as_variant!(self, Self::UserAvatarUrl)
978976
}
979977

980978
/// Get this value if it is a list of recently visited rooms.
981-
pub fn into_recently_visited_rooms(self) -> Option<Vec<String>> {
979+
pub fn into_recently_visited_rooms(self) -> Option<Vec<OwnedRoomId>> {
982980
as_variant!(self, Self::RecentlyVisitedRooms)
983981
}
984982

crates/matrix-sdk-indexeddb/src/state_store/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ use ruma::{
4444
GlobalAccountDataEventType, RoomAccountDataEventType, StateEventType, SyncStateEvent,
4545
},
4646
serde::Raw,
47-
CanonicalJsonObject, EventId, MxcUri, OwnedEventId, OwnedRoomId, OwnedTransactionId,
48-
OwnedUserId, RoomId, RoomVersionId, TransactionId, UserId,
47+
CanonicalJsonObject, EventId, MxcUri, OwnedEventId, OwnedMxcUri, OwnedRoomId,
48+
OwnedTransactionId, OwnedUserId, RoomId, RoomVersionId, TransactionId, UserId,
4949
};
5050
use serde::{de::DeserializeOwned, Deserialize, Serialize};
5151
use tracing::{debug, warn};
@@ -471,11 +471,11 @@ impl_state_store!({
471471
.transpose()?
472472
.map(StateStoreDataValue::Filter),
473473
StateStoreDataKey::UserAvatarUrl(_) => value
474-
.map(|f| self.deserialize_value::<String>(&f))
474+
.map(|f| self.deserialize_value::<OwnedMxcUri>(&f))
475475
.transpose()?
476476
.map(StateStoreDataValue::UserAvatarUrl),
477477
StateStoreDataKey::RecentlyVisitedRooms(_) => value
478-
.map(|f| self.deserialize_value::<Vec<String>>(&f))
478+
.map(|f| self.deserialize_value::<Vec<OwnedRoomId>>(&f))
479479
.transpose()?
480480
.map(StateStoreDataValue::RecentlyVisitedRooms),
481481
StateStoreDataKey::UtdHookManagerData => value

crates/matrix-sdk/src/account.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use ruma::{
4444
push::Ruleset,
4545
serde::Raw,
4646
thirdparty::Medium,
47-
ClientSecret, MxcUri, OwnedMxcUri, OwnedUserId, RoomId, SessionId, UInt, UserId,
47+
ClientSecret, MxcUri, OwnedMxcUri, OwnedRoomId, OwnedUserId, RoomId, SessionId, UInt, UserId,
4848
};
4949
use serde::Deserialize;
5050
use tracing::error;
@@ -155,7 +155,7 @@ impl Account {
155155
.store()
156156
.set_kv_data(
157157
StateStoreDataKey::UserAvatarUrl(user_id),
158-
StateStoreDataValue::UserAvatarUrl(url.to_string()),
158+
StateStoreDataValue::UserAvatarUrl(url),
159159
)
160160
.await;
161161
} else {
@@ -167,7 +167,7 @@ impl Account {
167167
}
168168

169169
/// Get the URL of the account's avatar, if is stored in cache.
170-
pub async fn get_cached_avatar_url(&self) -> Result<Option<String>> {
170+
pub async fn get_cached_avatar_url(&self) -> Result<Option<OwnedMxcUri>> {
171171
let user_id = self.client.user_id().ok_or(Error::AuthenticationRequired)?;
172172
let data =
173173
self.client.store().get_kv_data(StateStoreDataKey::UserAvatarUrl(user_id)).await?;
@@ -927,7 +927,7 @@ impl Account {
927927
}
928928

929929
/// Retrieves the user's recently visited room list
930-
pub async fn get_recently_visited_rooms(&self) -> Result<Vec<String>> {
930+
pub async fn get_recently_visited_rooms(&self) -> Result<Vec<OwnedRoomId>> {
931931
let user_id = self.client.user_id().ok_or(Error::AuthenticationRequired)?;
932932
let data = self
933933
.client
@@ -944,14 +944,9 @@ impl Account {
944944
}
945945

946946
/// Moves/inserts the given room to the front of the recently visited list
947-
pub async fn track_recently_visited_room(&self, room_id: String) -> Result<(), Error> {
947+
pub async fn track_recently_visited_room(&self, room_id: OwnedRoomId) -> Result<(), Error> {
948948
let user_id = self.client.user_id().ok_or(Error::AuthenticationRequired)?;
949949

950-
if let Err(error) = RoomId::parse(&room_id) {
951-
error!("Invalid room id: {}", error);
952-
return Err(Error::Identifier(error));
953-
}
954-
955950
// Get the previously stored recently visited rooms
956951
let mut recently_visited_rooms = self.get_recently_visited_rooms().await?;
957952

0 commit comments

Comments
 (0)