Skip to content

Commit 10fd5d0

Browse files
committed
sdk: don't clobber the DM list if we failed to deserialize the previous m.direct event
Report a deserialization failure and do not mark the room as a DM, instead of incorrectly restarting from an empty DM list. Fixes #3410.
1 parent 2be8466 commit 10fd5d0

File tree

2 files changed

+56
-15
lines changed

2 files changed

+56
-15
lines changed

crates/matrix-sdk/src/account.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -839,22 +839,21 @@ impl Account {
839839
// existing `m.direct` event and append the room to the list of DMs we
840840
// have with this user.
841841

842-
// TODO: Uncomment this once we can rely on `/sync`. Because of the
843-
// `unwrap_or_default()` we're using, this may lead to us resetting the
844-
// `m.direct` account data event and unmarking the user's DMs.
845-
// let mut content = self
846-
// .account_data::<DirectEventContent>()
847-
// .await?
848-
// .map(|c| c.deserialize())
849-
// .transpose()?
850-
// .unwrap_or_default();
851-
852842
// We are fetching the content from the server because we currently can't rely
853843
// on `/sync` giving us the correct data in a timely manner.
854844
let raw_content = self.fetch_account_data(GlobalAccountDataEventType::Direct).await?;
855-
let mut content = raw_content
856-
.and_then(|content| content.deserialize_as::<DirectEventContent>().ok())
857-
.unwrap_or_default();
845+
846+
let mut content = if let Some(raw_content) = raw_content {
847+
// Log the error and pass it upwards if we fail to deserialize the m.direct
848+
// event.
849+
raw_content.deserialize_as::<DirectEventContent>().map_err(|err| {
850+
error!("unable to deserialize m.direct event content; aborting request to mark {room_id} as dm: {err}");
851+
err
852+
})?
853+
} else {
854+
// If there was no m.direct event server-side, create a default one.
855+
Default::default()
856+
};
858857

859858
for user_id in user_ids {
860859
content.entry(user_id.to_owned()).or_default().push(room_id.to_owned());

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

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{collections::BTreeMap, time::Duration};
22

3-
use assert_matches2::assert_let;
3+
use assert_matches2::{assert_let, assert_matches};
44
use eyeball_im::VectorDiff;
55
use futures_util::FutureExt;
66
use matrix_sdk::{
@@ -442,7 +442,7 @@ async fn test_marking_room_as_dm() {
442442
client
443443
.sync_once(SyncSettings::default())
444444
.await
445-
.expect("We should be able to performa an initial sync");
445+
.expect("We should be able to perform an initial sync");
446446

447447
let account_data = client
448448
.account()
@@ -504,6 +504,48 @@ async fn test_marking_room_as_dm() {
504504
server.verify().await;
505505
}
506506

507+
// Check that we're fetching account data from the server when marking a room as
508+
// a DM, and that we don't clobber the previous entry if it was impossible to
509+
// deserialize.
510+
#[async_test]
511+
async fn test_marking_room_as_dm_fails_if_undeserializable() {
512+
let (client, server) = logged_in_client_with_server().await;
513+
514+
mock_sync(&server, &*test_json::SYNC, None).await;
515+
client
516+
.sync_once(SyncSettings::default())
517+
.await
518+
.expect("We should be able to perform an initial sync");
519+
520+
let account_data = client
521+
.account()
522+
.account_data::<DirectEventContent>()
523+
.await
524+
.expect("We should be able to fetch the account data event from the store");
525+
526+
assert!(account_data.is_none(), "We should not have any account data initially");
527+
528+
let bob = user_id!("@bob:example.com");
529+
let users = vec![bob.to_owned()];
530+
531+
// The response must be valid JSON, but not a valid `DirectEventContent`
532+
// representation.
533+
Mock::given(method("GET"))
534+
.and(path("_matrix/client/r0/user/@example:localhost/account_data/m.direct"))
535+
.and(header("authorization", "Bearer 1234"))
536+
.respond_with(ResponseTemplate::new(200).set_body_json(json!(["hey", null, true, 42])))
537+
.expect(1)
538+
.named("m.direct account data GET")
539+
.mount(&server)
540+
.await;
541+
542+
let result = client.account().mark_as_dm(&DEFAULT_TEST_ROOM_ID, &users).await;
543+
544+
assert_matches!(result, Err(matrix_sdk::Error::SerdeJson(_)));
545+
546+
server.verify().await;
547+
}
548+
507549
#[cfg(feature = "e2e-encryption")]
508550
#[async_test]
509551
async fn test_get_own_device() {

0 commit comments

Comments
 (0)