From 3b9c98d1b111b18104429df599f56efffcc534e9 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 26 Apr 2023 17:31:47 +0200 Subject: [PATCH 01/27] Revert "fix(sdk): Try to find workarounds about the bug in SlidingSync Proxy." This reverts commit bd6075f6b4fda70bfac7c10da5564468852bcec2. --- .../matrix-sdk/src/sliding_sync/list/mod.rs | 92 +++++++------------ 1 file changed, 31 insertions(+), 61 deletions(-) diff --git a/crates/matrix-sdk/src/sliding_sync/list/mod.rs b/crates/matrix-sdk/src/sliding_sync/list/mod.rs index 6f8a8b356..274edadc0 100644 --- a/crates/matrix-sdk/src/sliding_sync/list/mod.rs +++ b/crates/matrix-sdk/src/sliding_sync/list/mod.rs @@ -654,7 +654,7 @@ fn apply_sync_operations( ))); } - let mut room_entry_range = start..end; + let room_entry_range = start..end; // `room_ids` is absent. if operation.room_ids.is_empty() { @@ -667,18 +667,6 @@ fn apply_sync_operations( // Mismatch between the `range` and `room_ids`. if room_entry_range.len() != room_ids.len() { - // Because of https://github.com/matrix-org/sliding-sync/issues/52, we - // can't trust the `range` returned by the server. That's a - // problem. Let's try to work around - // that. - // - // Let's pretend the `start` bound of the range is… correct. - room_entry_range = start..room_ids.len(); - - // Once the bug is fixed on the Sliding Sync Proxy side, we - // can remove this code, and uncomment - // the code below. - /* return Err(Error::BadResponse( format!( "There is a mismatch between the number of items in `range` and `room_ids` ({} != {})", @@ -686,7 +674,6 @@ fn apply_sync_operations( room_ids.len(), ) )); - */ } // Update parts `room_list`. @@ -783,7 +770,7 @@ fn apply_sync_operations( // > arrive from the server. v4::SlidingOp::Invalidate => { // Extract `start` and `end` from the operation's range. - let (start, mut end) = operation + let (start, end) = operation .range .ok_or_else(|| { Error::BadResponse( @@ -797,23 +784,6 @@ fn apply_sync_operations( ) })?; - // The `end` bound of the range might not be correct… At the time of writing, - // there is a bug in the Sliding Sync Proxy that can return - // ranges greater than the `room_list` size. - // - // For example, if the client asks for a range `0..=9`, and there is only one - // room, the server will reply with one `room_id` (which is correct) but with - // the range `0..=9` instead of `0..=0`. - // - // So, a safe workaround is to take the minimum between `end` and the - // `room_list`'s length. - // - // The “safety” is ensured by the fact we also compare the size of the new range - // with the size of the `operation.room_ids` length later on. - // - // See https://github.com/matrix-org/sliding-sync/issues/52. - end = min(end, room_list.len()); - // Range is invalid. if start > end { return Err(Error::BadResponse(format!( @@ -822,6 +792,15 @@ fn apply_sync_operations( ))); } + // Range is too big. + if end > room_list.len() { + return Err(Error::BadResponse(format!( + "`range` is out of the `room_list`' bounds ({} > {})", + end, + room_list.len(), + ))); + } + let room_entry_range = start..end; // Invalidate parts of `room_list`. @@ -1884,8 +1863,6 @@ mod tests { // The range returned by the server is too large compared to the `room_ids` but // we can fix it on-the-fly. - // - // See https://github.com/matrix-org/sliding-sync/issues/52. assert_sync_operations! { room_list = [E], sync_operations = [ @@ -1945,7 +1922,7 @@ mod tests { // Out of bounds operation. assert_sync_operations! { - room_list = [E, E, E], + room_list = [E, F("!r1:x.y"), E], sync_operations = [ { "op": SlidingOp::Sync, @@ -1954,14 +1931,8 @@ mod tests { } ] => - // As soon https://github.com/matrix-org/sliding-sync/issues/52 - // is fixed, let's uncomment the real test. - result = is_ok, - room_list = [E, E, E], - /* result = is_err, - room_list = [E, E, E], - */ + room_list = [E, F("!r1:x.y"), E], }; // The server replies with a particular range, but some room IDs are @@ -1976,14 +1947,8 @@ mod tests { } ] => - // As soon https://github.com/matrix-org/sliding-sync/issues/52 - // is fixed, let's uncomment the real test. - result = is_ok, - room_list = [F("!r0:x.y"), E, E], - /* result = is_err, room_list = [E, E, E], - */ }; // The server replies with a particular range, but there is too much @@ -1998,14 +1963,8 @@ mod tests { } ] => - // As soon https://github.com/matrix-org/sliding-sync/issues/52 - // is fixed, let's uncomment the real test. - result = is_ok, - room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!extra:x.y")], - /* result = is_err, room_list = [E, E, E], - */ }; } @@ -2225,10 +2184,7 @@ mod tests { room_list = [I("!r0:x.y"), I("!r1:x.y"), I("!r2:x.y")], }; - // The range returned by the server is too large compared to the `room_lists` - // but we can fix it on-the-fly. - // - // See https://github.com/matrix-org/sliding-sync/issues/52. + // The range returned by the server is too large compared to the `room_lists`. assert_sync_operations! { room_list = [F("!r0:x.y")], sync_operations = [ @@ -2238,7 +2194,7 @@ mod tests { } ] => - result = is_ok, // <- because we have fixed it + result = is_err, room_list = [I("!r0:x.y")], }; @@ -2247,7 +2203,7 @@ mod tests { room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], sync_operations = [ { - "op": SlidingOp::Invalidate, + "op": SlidingOp::Delete, } ] => @@ -2260,7 +2216,7 @@ mod tests { room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], sync_operations = [ { - "op": SlidingOp::Invalidate, + "op": SlidingOp::Delete, "range": [12, 0], } ] @@ -2268,5 +2224,19 @@ mod tests { result = is_err, room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], }; + + // Out of bounds operation. + assert_sync_operations! { + room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], + operations = [ + { + "op": SlidingOp::Delete, + "range": [2, 3], + } + ] + => + result = is_err, + room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], + }; } } From deeefdfe90fa524952628b90daf9fda0c1c12615 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 27 Apr 2023 09:03:12 +0200 Subject: [PATCH 02/27] Revert "fix(sdk): Try to find a workaround for a bug in the SS Proxy." This reverts commit f269202ece36a46563568aaf6c55483f7e781ce7. --- .../matrix-sdk/src/sliding_sync/list/mod.rs | 114 +++++++++--------- 1 file changed, 59 insertions(+), 55 deletions(-) diff --git a/crates/matrix-sdk/src/sliding_sync/list/mod.rs b/crates/matrix-sdk/src/sliding_sync/list/mod.rs index 274edadc0..81ea9cf89 100644 --- a/crates/matrix-sdk/src/sliding_sync/list/mod.rs +++ b/crates/matrix-sdk/src/sliding_sync/list/mod.rs @@ -615,7 +615,7 @@ fn apply_sync_operations( // > knew about entries in this range. v4::SlidingOp::Sync => { // Extract `start` and `end` from the operation's range. - let (start, mut end) = operation + let (start, end) = operation .range .ok_or_else(|| { Error::BadResponse( @@ -629,23 +629,6 @@ fn apply_sync_operations( ) })?; - // The `end` bound of the range might not be correct… At the time of writing, - // there is a bug in the Sliding Sync Proxy that can return - // ranges greater than the `room_list` size. - // - // For example, if the client asks for a range `0..=9`, and there is only one - // room, the server will reply with one `room_id` (which is correct) but with - // the range `0..=9` instead of `0..=0`. - // - // So, a safe workaround is to take the minimum between `end` and the - // `room_list`'s length. - // - // The “safety” is ensured by the fact we also compare the size of the new range - // with the size of the `operation.room_ids` length later on. - // - // See https://github.com/matrix-org/sliding-sync/issues/52. - end = min(end, room_list.len()); - // Range is invalid. if start > end { return Err(Error::BadResponse(format!( @@ -654,6 +637,15 @@ fn apply_sync_operations( ))); } + // Range is too big. + if end > room_list.len() { + return Err(Error::BadResponse(format!( + "`range` is out of the `rooms_list`'s bounds ({} > {})", + end, + room_list.len(), + ))); + } + let room_entry_range = start..end; // `room_ids` is absent. @@ -1760,6 +1752,7 @@ mod tests { macro_rules! assert_sync_operations { ( + $assert_description:literal : room_list = [ $( $room_list_entries:tt )* ], sync_operations = [ $( @@ -1796,8 +1789,13 @@ mod tests { let result = apply_sync_operations(operations, &mut room_list, &mut rooms_that_have_received_an_update); - assert!(result.$result()); - assert_eq!(*room_list, entries![ $( $expected_room_list_entries )* ]); + assert!(result.$result(), "{}; assert the `Result`", $assert_description); + assert_eq!( + *room_list, + entries![ $( $expected_room_list_entries )* ], + "{}; asserting the `room_list`", + $assert_description, + ); $( #[allow(unused_mut)] @@ -1809,15 +1807,20 @@ mod tests { )* } - assert_eq!(rooms_that_have_received_an_update, expected_rooms_that_have_received_an_update); + assert_eq!( + rooms_that_have_received_an_update, + expected_rooms_that_have_received_an_update, + "{}; asserting the rooms that have received an update", + $assert_description, + ); )? }; } #[test] fn test_sync_operations_sync() { - // All room list is updated. assert_sync_operations! { + "All room list is updated": room_list = [E, E, E, F("!r3:x.y")], sync_operations = [ { @@ -1833,8 +1836,8 @@ mod tests { rooms = ["!r3:x.y"], }; - // Partial update. assert_sync_operations! { + "Partial update": room_list = [E, E, E], sync_operations = [ { @@ -1847,7 +1850,9 @@ mod tests { result = is_ok, room_list = [F("!r0:x.y"), F("!r1:x.y"), E], }; + assert_sync_operations! { + "Partial update": room_list = [E, E, E], sync_operations = [ { @@ -1861,24 +1866,23 @@ mod tests { room_list = [E, F("!r1:x.y"), F("!r2:x.y")], }; - // The range returned by the server is too large compared to the `room_ids` but - // we can fix it on-the-fly. assert_sync_operations! { + "The range returned by the server is too large compared to the `room_ids`": room_list = [E], sync_operations = [ { "op": SlidingOp::Sync, - "range": [0, 9], // <- it should be [0, 0] + "range": [0, 2], // <- it should be [0, 0] "room_ids": ["!r0:x.y"], } ] => - result = is_ok, // <- because we have fixed it - room_list = [F("!r0:x.y")], + result = is_err, + room_list = [E], }; - // Missing `range`. assert_sync_operations! { + "Missing `range`": room_list = [E, E, E], sync_operations = [ { @@ -1891,8 +1895,8 @@ mod tests { room_list = [E, E, E], }; - // Invalid `range`. assert_sync_operations! { + "Invalid `range`": room_list = [E, E, E], sync_operations = [ { @@ -1906,8 +1910,8 @@ mod tests { room_list = [E, E, E], }; - // Missing `room_ids`. assert_sync_operations! { + "Missing `room_ids`": room_list = [E, E, E], sync_operations = [ { @@ -1920,8 +1924,8 @@ mod tests { room_list = [E, E, E], }; - // Out of bounds operation. assert_sync_operations! { + "Out of bounds operation": room_list = [E, F("!r1:x.y"), E], sync_operations = [ { @@ -1935,9 +1939,8 @@ mod tests { room_list = [E, F("!r1:x.y"), E], }; - // The server replies with a particular range, but some room IDs are - // missing. assert_sync_operations! { + "The server replies with a particular range, but some room IDs are missing": room_list = [E, E, E], sync_operations = [ { @@ -1951,9 +1954,8 @@ mod tests { room_list = [E, E, E], }; - // The server replies with a particular range, but there is too much - // room IDs. assert_sync_operations! { + "The server replies with a particular range, but there is too much room IDs": room_list = [E, E, E], sync_operations = [ { @@ -1970,8 +1972,8 @@ mod tests { #[test] fn test_sync_operations_delete() { - // Delete a room entry in the middle. assert_sync_operations! { + "Delete a room entry in the middle": room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], sync_operations = [ { @@ -1986,8 +1988,8 @@ mod tests { rooms = ["!r0:x.y"], }; - // Delete a room entry at the beginning. assert_sync_operations! { + "Delete a room entry at the beginning": room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], sync_operations = [ { @@ -2000,8 +2002,8 @@ mod tests { room_list = [F("!r1:x.y"), F("!r2:x.y")], }; - // Delete a room entry at the end. assert_sync_operations! { + "Delete a room entry at the end": room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], sync_operations = [ { @@ -2014,8 +2016,8 @@ mod tests { room_list = [F("!r0:x.y"), F("!r1:x.y")], }; - // Delete an out of bounds room entry. assert_sync_operations! { + "Delete an out of bounds room entry": room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], sync_operations = [ { @@ -2031,8 +2033,8 @@ mod tests { #[test] fn test_sync_operations_insert() { - // Insert a room entry in the middle. assert_sync_operations! { + "Insert a room entry in the middle": room_list = [E, E, E], sync_operations = [ { @@ -2048,8 +2050,8 @@ mod tests { rooms = ["!r0:x.y"], }; - // Insert a room entry at the beginning. assert_sync_operations! { + "Insert a room entry at the beginning": room_list = [E, E, E], sync_operations = [ { @@ -2063,8 +2065,8 @@ mod tests { room_list = [F("!r0:x.y"), E, E, E], }; - // Insert a room entry at the end assert_sync_operations! { + "Insert a room entry at the end": room_list = [E, E, E], sync_operations = [ { @@ -2078,8 +2080,8 @@ mod tests { room_list = [E, E, E, F("!r3:x.y")], }; - // Insert an out of bounds room entry. assert_sync_operations! { + "Insert an out of bounds room entry": room_list = [E, F("!r1:x.y"), E], sync_operations = [ { @@ -2096,8 +2098,8 @@ mod tests { #[test] fn test_sync_operations_invalidate() { - // Invalidating an empty room. assert_sync_operations! { + "Invalidating an empty room": room_list = [E, F("!r1:x.y")], sync_operations = [ { @@ -2112,8 +2114,8 @@ mod tests { rooms = ["!r1:x.y"], }; - // Invalidating a filled room. assert_sync_operations! { + "Invalidating a filled room": room_list = [F("!r0:x.y"), F("!r1:x.y")], sync_operations = [ { @@ -2128,8 +2130,8 @@ mod tests { rooms = ["!r1:x.y"], }; - // Invalidating an invalidated room. assert_sync_operations! { + "Invalidating an invalidated room": room_list = [I("!r0:x.y"), F("!r1:x.y")], sync_operations = [ { @@ -2144,8 +2146,8 @@ mod tests { rooms = ["!r1:x.y"], }; - // Partial update. assert_sync_operations! { + "Partial update from the beginning": room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], sync_operations = [ { @@ -2157,7 +2159,9 @@ mod tests { result = is_ok, room_list = [I("!r0:x.y"), I("!r1:x.y"), F("!r2:x.y")], }; + assert_sync_operations! { + "Partial update from the end": room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], sync_operations = [ { @@ -2170,8 +2174,8 @@ mod tests { room_list = [F("!r0:x.y"), I("!r1:x.y"), I("!r2:x.y")], }; - // Full update. assert_sync_operations! { + "Full update": room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], sync_operations = [ { @@ -2184,8 +2188,8 @@ mod tests { room_list = [I("!r0:x.y"), I("!r1:x.y"), I("!r2:x.y")], }; - // The range returned by the server is too large compared to the `room_lists`. assert_sync_operations! { + "The range returned by the server is too large compared to the `room_lists`": room_list = [F("!r0:x.y")], sync_operations = [ { @@ -2195,11 +2199,11 @@ mod tests { ] => result = is_err, - room_list = [I("!r0:x.y")], + room_list = [F("!r0:x.y")], }; - // Missing `range`. assert_sync_operations! { + "Missing `range`": room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], sync_operations = [ { @@ -2211,8 +2215,8 @@ mod tests { room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], }; - // Invalid `range`. assert_sync_operations! { + "Invalid `range`": room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], sync_operations = [ { @@ -2225,10 +2229,10 @@ mod tests { room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], }; - // Out of bounds operation. assert_sync_operations! { + "Out of bounds operation": room_list = [F("!r0:x.y"), F("!r1:x.y"), F("!r2:x.y")], - operations = [ + sync_operations = [ { "op": SlidingOp::Delete, "range": [2, 3], From 13088dff721cfd87219bcf8bf3e322e20163b4f9 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 27 Apr 2023 10:02:50 +0200 Subject: [PATCH 03/27] test: Use the latest Sliding Sync proxy version. --- testing/sliding-sync-integration-test/assets/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/sliding-sync-integration-test/assets/docker-compose.yml b/testing/sliding-sync-integration-test/assets/docker-compose.yml index f906b9edd..f60296880 100644 --- a/testing/sliding-sync-integration-test/assets/docker-compose.yml +++ b/testing/sliding-sync-integration-test/assets/docker-compose.yml @@ -28,7 +28,7 @@ services: - ./data/db:/var/lib/postgresql/data sliding-sync-proxy: - image: ghcr.io/matrix-org/sliding-sync:v0.99.1 + image: ghcr.io/matrix-org/sliding-sync:main depends_on: postgres: condition: service_healthy From a719f35a3e482a4d0035f01ecd547125ed1c96dc Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 27 Apr 2023 10:21:04 +0200 Subject: [PATCH 04/27] test: Use the latest Sliding Sync proxy version. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e0c95c419..d3aacbf75 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -436,7 +436,7 @@ jobs: # run sliding sync and point it at the postgres container and synapse container. # the postgres container needs to be above this to make sure it has started prior to this service. slidingsync: - image: "ghcr.io/matrix-org/sliding-sync:v0.99.0" + image: "ghcr.io/matrix-org/sliding-sync:main" env: SYNCV3_SERVER: "http://synapse:8008" SYNCV3_SECRET: "SUPER_CI_SECRET" From 3a8b6696f7fbef87f96fcc523b952358efa9bf87 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 27 Apr 2023 14:07:39 +0200 Subject: [PATCH 05/27] test: Install SS proxy v0.99.2. --- .github/workflows/ci.yml | 2 +- testing/sliding-sync-integration-test/assets/docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3aacbf75..92e6722c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -436,7 +436,7 @@ jobs: # run sliding sync and point it at the postgres container and synapse container. # the postgres container needs to be above this to make sure it has started prior to this service. slidingsync: - image: "ghcr.io/matrix-org/sliding-sync:main" + image: "ghcr.io/matrix-org/sliding-sync:v0.99.2" env: SYNCV3_SERVER: "http://synapse:8008" SYNCV3_SECRET: "SUPER_CI_SECRET" diff --git a/testing/sliding-sync-integration-test/assets/docker-compose.yml b/testing/sliding-sync-integration-test/assets/docker-compose.yml index f60296880..3b86c7182 100644 --- a/testing/sliding-sync-integration-test/assets/docker-compose.yml +++ b/testing/sliding-sync-integration-test/assets/docker-compose.yml @@ -28,7 +28,7 @@ services: - ./data/db:/var/lib/postgresql/data sliding-sync-proxy: - image: ghcr.io/matrix-org/sliding-sync:main + image: ghcr.io/matrix-org/sliding-sync:v0.99.2 depends_on: postgres: condition: service_healthy From d54b4a1d5a68a72a93259a08c19c34584e6798d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Thu, 27 Apr 2023 16:00:21 +0200 Subject: [PATCH 06/27] sdk: Use new_content of edits instead of content MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- .../matrix-sdk/src/room/timeline/event_handler.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/crates/matrix-sdk/src/room/timeline/event_handler.rs b/crates/matrix-sdk/src/room/timeline/event_handler.rs index 6f10c9f56..55c65eb95 100644 --- a/crates/matrix-sdk/src/room/timeline/event_handler.rs +++ b/crates/matrix-sdk/src/room/timeline/event_handler.rs @@ -26,7 +26,7 @@ use ruma::{ room::{ encrypted::RoomEncryptedEventContent, member::{Change, RoomMemberEventContent}, - message::{self, MessageType, RoomMessageEventContent, SyncRoomMessageEvent}, + message::{self, MessageType, Relation, RoomMessageEventContent, SyncRoomMessageEvent}, redaction::{ OriginalSyncRoomRedactionEvent, RoomRedactionEventContent, SyncRoomRedactionEvent, }, @@ -946,7 +946,16 @@ impl NewEventTimelineItem { ) -> Self { let edited = relations.has_replacement(); let edit = relations.replace.and_then(|r| match *r { - AnySyncMessageLikeEvent::RoomMessage(SyncRoomMessageEvent::Original(ev)) => Some(ev), + AnySyncMessageLikeEvent::RoomMessage(SyncRoomMessageEvent::Original(ev)) => match ev + .content + .relates_to + { + Some(Relation::Replacement(re)) => Some(re), + _ => { + error!("got m.room.message event with an edit without a valid m.relate relation"); + None + } + }, AnySyncMessageLikeEvent::RoomMessage(SyncRoomMessageEvent::Redacted(_)) => None, _ => { error!("got m.room.message event with an edit of a different event type"); @@ -955,7 +964,7 @@ impl NewEventTimelineItem { }); let content = TimelineItemContent::Message(Message { - msgtype: edit.map_or(c.msgtype, |e| e.content.msgtype), + msgtype: edit.map_or(c.msgtype, |e| e.new_content), in_reply_to: c.relates_to.and_then(InReplyToDetails::from_relation), edited, }); From 404d5003f3043a41c1d89c40a51766050d6c300e Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 27 Apr 2023 17:00:28 +0200 Subject: [PATCH 07/27] `unused_fallback_keys` is optional in `machine.rs` --- bindings/matrix-sdk-crypto-js/src/machine.rs | 21 ++++++++++++------- .../tests/machine.test.js | 13 ++++++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/bindings/matrix-sdk-crypto-js/src/machine.rs b/bindings/matrix-sdk-crypto-js/src/machine.rs index 1a3163647..7fb0c4331 100644 --- a/bindings/matrix-sdk-crypto-js/src/machine.rs +++ b/bindings/matrix-sdk-crypto-js/src/machine.rs @@ -222,7 +222,7 @@ impl OlmMachine { to_device_events: &str, changed_devices: &sync_events::DeviceLists, one_time_key_counts: &Map, - unused_fallback_keys: &Set, + unused_fallback_keys: Option, ) -> Result { let to_device_events = serde_json::from_str(to_device_events)?; let changed_devices = changed_devices.inner.clone(); @@ -239,13 +239,18 @@ impl OlmMachine { Some((key, value)) }) .collect(); - let unused_fallback_keys: Option> = Some( - unused_fallback_keys - .values() - .into_iter() - .filter_map(|js_value| Some(DeviceKeyAlgorithm::from(js_value.ok()?.as_string()?))) - .collect(), - ); + + // Convert the unused_fallback_keys JS Set to a `Vec` + let unused_fallback_keys: Option> = match unused_fallback_keys { + Some(fallback_keys) => { + Some(fallback_keys + .values() + .into_iter() + .filter_map(|js_value| Some(DeviceKeyAlgorithm::from(js_value.ok()?.as_string()?))) + .collect()) + }, + _ => None, + }; let me = self.inner.clone(); diff --git a/bindings/matrix-sdk-crypto-js/tests/machine.test.js b/bindings/matrix-sdk-crypto-js/tests/machine.test.js index 9ab0cceca..c65094e91 100644 --- a/bindings/matrix-sdk-crypto-js/tests/machine.test.js +++ b/bindings/matrix-sdk-crypto-js/tests/machine.test.js @@ -220,6 +220,19 @@ describe(OlmMachine.name, () => { expect(receiveSyncChanges).toEqual([]); }); + test("can receive sync changes with unusedFallbackKeys as undefined", async () => { + const m = await machine(); + const toDeviceEvents = JSON.stringify([]); + const changedDevices = new DeviceLists(); + const oneTimeKeyCounts = new Map(); + + const receiveSyncChanges = JSON.parse( + await m.receiveSyncChanges(toDeviceEvents, changedDevices, oneTimeKeyCounts, undefined), + ); + + expect(receiveSyncChanges).toEqual([]); + }); + test("can get the outgoing requests that need to be send out", async () => { const m = await machine(); const toDeviceEvents = JSON.stringify([]); From 2b3d5e09e2a2691bb944e07eb2fac6a181b0d48d Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 27 Apr 2023 17:02:53 +0200 Subject: [PATCH 08/27] Update changelog --- bindings/matrix-sdk-crypto-js/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bindings/matrix-sdk-crypto-js/CHANGELOG.md b/bindings/matrix-sdk-crypto-js/CHANGELOG.md index b2f2829e7..1642a2fd6 100644 --- a/bindings/matrix-sdk-crypto-js/CHANGELOG.md +++ b/bindings/matrix-sdk-crypto-js/CHANGELOG.md @@ -1,3 +1,7 @@ +# v0.1.0-alpha.8 + +- Make `unused_fallback_keys` as optional in `Machine.receive_sync_changes` + # v0.1.0-alpha.7 - Add new accessors `Device.algorithms` and `Device.isSignedByOwner` From 31b81cbf6aa44c98ef7c7eac3c435e8af5b8db87 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 27 Apr 2023 17:30:55 +0200 Subject: [PATCH 09/27] Run prettier --- bindings/matrix-sdk-crypto-js/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/matrix-sdk-crypto-js/CHANGELOG.md b/bindings/matrix-sdk-crypto-js/CHANGELOG.md index 1642a2fd6..f5563d8e3 100644 --- a/bindings/matrix-sdk-crypto-js/CHANGELOG.md +++ b/bindings/matrix-sdk-crypto-js/CHANGELOG.md @@ -1,6 +1,6 @@ # v0.1.0-alpha.8 -- Make `unused_fallback_keys` as optional in `Machine.receive_sync_changes` +- Make `unused_fallback_keys` as optional in `Machine.receive_sync_changes` # v0.1.0-alpha.7 From d919642dd6ef751a5fe97f72d55502525dd7ad6f Mon Sep 17 00:00:00 2001 From: Mauro <34335419+Velin92@users.noreply.github.com> Date: Thu, 27 Apr 2023 17:35:46 +0200 Subject: [PATCH 10/27] ffi: Exposing register_notification_handler in bindings --- bindings/matrix-sdk-ffi/src/api.udl | 18 ++ bindings/matrix-sdk-ffi/src/client.rs | 36 +++- bindings/matrix-sdk-ffi/src/event.rs | 194 ++++++++++++++++++ bindings/matrix-sdk-ffi/src/lib.rs | 5 +- .../src/notification_service.rs | 66 ++++-- bindings/matrix-sdk-ffi/src/timeline.rs | 112 +++++----- 6 files changed, 361 insertions(+), 70 deletions(-) create mode 100644 bindings/matrix-sdk-ffi/src/event.rs diff --git a/bindings/matrix-sdk-ffi/src/api.udl b/bindings/matrix-sdk-ffi/src/api.udl index 2ec81b96c..f84e818de 100644 --- a/bindings/matrix-sdk-ffi/src/api.udl +++ b/bindings/matrix-sdk-ffi/src/api.udl @@ -9,6 +9,24 @@ callback interface ClientDelegate { void did_receive_auth_error(boolean is_soft_logout); }; +callback interface NotificationDelegate { + void did_receive_notification(NotificationItem notification); +}; + +dictionary NotificationItem { + TimelineEvent event; + string room_id; + string? sender_display_name; + string? sender_avatar_url; + string room_display_name; + string? room_avatar_url; + boolean is_noisy; + boolean is_direct; + boolean is_encrypted; +}; + +interface TimelineEvent {}; + dictionary UpdateSummary { sequence lists; sequence rooms; diff --git a/bindings/matrix-sdk-ffi/src/client.rs b/bindings/matrix-sdk-ffi/src/client.rs index bff556779..14b05bd7b 100644 --- a/bindings/matrix-sdk-ffi/src/client.rs +++ b/bindings/matrix-sdk-ffi/src/client.rs @@ -32,7 +32,7 @@ use tokio::sync::broadcast::error::RecvError; use tracing::{debug, error, warn}; use super::{room::Room, session_verification::SessionVerificationController, RUNTIME}; -use crate::{client, ClientError}; +use crate::{client, ClientError, NotificationItem}; #[derive(Clone, uniffi::Record)] pub struct PusherIdentifiers { @@ -105,10 +105,15 @@ pub trait ClientDelegate: Sync + Send { fn did_receive_auth_error(&self, is_soft_logout: bool); } +pub trait NotificationDelegate: Sync + Send { + fn did_receive_notification(&self, notification: NotificationItem); +} + #[derive(Clone, uniffi::Object)] pub struct Client { pub(crate) client: MatrixClient, delegate: Arc>>>, + notification_delegate: Arc>>>, session_verification_controller: Arc>>, /// The sliding sync proxy that the client is configured to use by default. @@ -139,6 +144,7 @@ impl Client { let client = Client { client, delegate: Arc::new(RwLock::new(None)), + notification_delegate: Arc::new(RwLock::new(None)), session_verification_controller, sliding_sync_proxy: Arc::new(RwLock::new(None)), sliding_sync_reset_broadcast_tx: Default::default(), @@ -547,6 +553,34 @@ impl Client { Ok(user_profile) }) } + + /// Sets a notification delegate and a handler. + /// + /// The sliding sync requires to have registered m.room.member with value + /// $ME and m.room.power_levels to be able to intercept the events. + /// This function blocks execution and should be dispatched concurrently. + pub fn set_notification_delegate( + &self, + notification_delegate: Option>, + ) { + *self.notification_delegate.write().unwrap() = notification_delegate; + let notification_delegate = Arc::clone(&self.notification_delegate); + let handler = move |notification, room: SdkRoom, _| { + let notification_delegate = Arc::clone(¬ification_delegate); + async move { + if let Ok(notification_item) = NotificationItem::new(notification, room).await { + if let Some(notification_delegate) = + notification_delegate.read().unwrap().as_ref() + { + notification_delegate.did_receive_notification(notification_item); + } + } + } + }; + RUNTIME.block_on(async move { + self.client.register_notification_handler(handler).await; + }) + } } #[derive(uniffi::Record)] diff --git a/bindings/matrix-sdk-ffi/src/event.rs b/bindings/matrix-sdk-ffi/src/event.rs new file mode 100644 index 000000000..0c30d7780 --- /dev/null +++ b/bindings/matrix-sdk-ffi/src/event.rs @@ -0,0 +1,194 @@ +use anyhow::{bail, Context}; +use ruma::events::{ + AnySyncMessageLikeEvent, AnySyncStateEvent, AnySyncTimelineEvent, + MessageLikeEventContent as RumaMessageLikeEventContent, RedactContent, + RedactedStateEventContent, StaticStateEventContent, SyncMessageLikeEvent, SyncStateEvent, +}; + +use crate::{ClientError, MembershipState, MessageType}; + +pub struct TimelineEvent(pub(crate) AnySyncTimelineEvent); + +#[uniffi::export] +impl TimelineEvent { + pub fn event_id(&self) -> String { + self.0.event_id().to_string() + } + + pub fn sender_id(&self) -> String { + self.0.sender().to_string() + } + + pub fn event_type(&self) -> Result { + let event_type = match &self.0 { + AnySyncTimelineEvent::MessageLike(event) => { + TimelineEventType::MessageLike { content: event.clone().try_into()? } + } + AnySyncTimelineEvent::State(event) => { + TimelineEventType::State { content: event.clone().try_into()? } + } + }; + Ok(event_type) + } +} + +#[derive(uniffi::Enum)] +pub enum TimelineEventType { + MessageLike { content: MessageLikeEventContent }, + State { content: StateEventContent }, +} + +#[derive(uniffi::Enum)] +pub enum StateEventContent { + PolicyRuleRoom, + PolicyRuleServer, + PolicyRuleUser, + RoomAliases, + RoomAvatar, + RoomCanonicalAlias, + RoomCreate, + RoomEncryption, + RoomGuestAccess, + RoomHistoryVisibility, + RoomJoinRules, + RoomMemberContent { user_id: String, membership_state: MembershipState }, + RoomName, + RoomPinnedEvents, + RoomPowerLevels, + RoomServerAcl, + RoomThirdPartyInvite, + RoomTombstone, + RoomTopic, + SpaceChild, + SpaceParent, +} + +impl TryFrom for StateEventContent { + type Error = anyhow::Error; + + fn try_from(value: AnySyncStateEvent) -> anyhow::Result { + let event = match value { + AnySyncStateEvent::PolicyRuleRoom(_) => StateEventContent::PolicyRuleRoom, + AnySyncStateEvent::PolicyRuleServer(_) => StateEventContent::PolicyRuleServer, + AnySyncStateEvent::PolicyRuleUser(_) => StateEventContent::PolicyRuleUser, + AnySyncStateEvent::RoomAliases(_) => StateEventContent::RoomAliases, + AnySyncStateEvent::RoomAvatar(_) => StateEventContent::RoomAvatar, + AnySyncStateEvent::RoomCanonicalAlias(_) => StateEventContent::RoomCanonicalAlias, + AnySyncStateEvent::RoomCreate(_) => StateEventContent::RoomCreate, + AnySyncStateEvent::RoomEncryption(_) => StateEventContent::RoomEncryption, + AnySyncStateEvent::RoomGuestAccess(_) => StateEventContent::RoomGuestAccess, + AnySyncStateEvent::RoomHistoryVisibility(_) => StateEventContent::RoomHistoryVisibility, + AnySyncStateEvent::RoomJoinRules(_) => StateEventContent::RoomJoinRules, + AnySyncStateEvent::RoomMember(content) => { + let state_key = content.state_key().to_string(); + let original_content = get_state_event_original_content(content)?; + StateEventContent::RoomMemberContent { + user_id: state_key, + membership_state: original_content.membership.into(), + } + } + AnySyncStateEvent::RoomName(_) => StateEventContent::RoomName, + AnySyncStateEvent::RoomPinnedEvents(_) => StateEventContent::RoomPinnedEvents, + AnySyncStateEvent::RoomPowerLevels(_) => StateEventContent::RoomPowerLevels, + AnySyncStateEvent::RoomServerAcl(_) => StateEventContent::RoomServerAcl, + AnySyncStateEvent::RoomThirdPartyInvite(_) => StateEventContent::RoomThirdPartyInvite, + AnySyncStateEvent::RoomTombstone(_) => StateEventContent::RoomTombstone, + AnySyncStateEvent::RoomTopic(_) => StateEventContent::RoomTopic, + AnySyncStateEvent::SpaceChild(_) => StateEventContent::SpaceChild, + AnySyncStateEvent::SpaceParent(_) => StateEventContent::SpaceParent, + _ => bail!("Unsupported state event"), + }; + Ok(event) + } +} + +#[derive(uniffi::Enum)] +pub enum MessageLikeEventContent { + CallAnswer, + CallInvite, + CallHangup, + CallCandidates, + KeyVerificationReady, + KeyVerificationStart, + KeyVerificationCancel, + KeyVerificationAccept, + KeyVerificationKey, + KeyVerificationMac, + KeyVerificationDone, + ReactionContent { related_event_id: String }, + RoomEncrypted, + RoomMessage { message_type: MessageType }, + RoomRedaction, + Sticker, +} + +impl TryFrom for MessageLikeEventContent { + type Error = anyhow::Error; + + fn try_from(value: AnySyncMessageLikeEvent) -> anyhow::Result { + let content = match value { + AnySyncMessageLikeEvent::CallAnswer(_) => MessageLikeEventContent::CallAnswer, + AnySyncMessageLikeEvent::CallInvite(_) => MessageLikeEventContent::CallInvite, + AnySyncMessageLikeEvent::CallHangup(_) => MessageLikeEventContent::CallHangup, + AnySyncMessageLikeEvent::CallCandidates(_) => MessageLikeEventContent::CallCandidates, + AnySyncMessageLikeEvent::KeyVerificationReady(_) => { + MessageLikeEventContent::KeyVerificationReady + } + AnySyncMessageLikeEvent::KeyVerificationStart(_) => { + MessageLikeEventContent::KeyVerificationStart + } + AnySyncMessageLikeEvent::KeyVerificationCancel(_) => { + MessageLikeEventContent::KeyVerificationCancel + } + AnySyncMessageLikeEvent::KeyVerificationAccept(_) => { + MessageLikeEventContent::KeyVerificationAccept + } + AnySyncMessageLikeEvent::KeyVerificationKey(_) => { + MessageLikeEventContent::KeyVerificationKey + } + AnySyncMessageLikeEvent::KeyVerificationMac(_) => { + MessageLikeEventContent::KeyVerificationMac + } + AnySyncMessageLikeEvent::KeyVerificationDone(_) => { + MessageLikeEventContent::KeyVerificationDone + } + AnySyncMessageLikeEvent::Reaction(content) => { + let original_content = get_message_like_event_original_content(content)?; + MessageLikeEventContent::ReactionContent { + related_event_id: original_content.relates_to.event_id.to_string(), + } + } + AnySyncMessageLikeEvent::RoomEncrypted(_) => MessageLikeEventContent::RoomEncrypted, + AnySyncMessageLikeEvent::RoomMessage(content) => { + let original_content = get_message_like_event_original_content(content)?; + MessageLikeEventContent::RoomMessage { + message_type: original_content.msgtype.try_into()?, + } + } + AnySyncMessageLikeEvent::RoomRedaction(_) => MessageLikeEventContent::RoomRedaction, + AnySyncMessageLikeEvent::Sticker(_) => MessageLikeEventContent::Sticker, + _ => bail!("Unsupported Event Type"), + }; + Ok(content) + } +} + +fn get_state_event_original_content(event: SyncStateEvent) -> anyhow::Result +where + C: StaticStateEventContent + RedactContent + Clone, + ::Redacted: RedactedStateEventContent, +{ + let original_content = + event.as_original().context("Failed to get original content")?.content.clone(); + Ok(original_content) +} + +fn get_message_like_event_original_content(event: SyncMessageLikeEvent) -> anyhow::Result +where + C: RumaMessageLikeEventContent + RedactContent + Clone, + ::Redacted: ruma::events::RedactedMessageLikeEventContent, +{ + let original_content = + event.as_original().context("Failed to get original content")?.content.clone(); + Ok(original_content) +} diff --git a/bindings/matrix-sdk-ffi/src/lib.rs b/bindings/matrix-sdk-ffi/src/lib.rs index f094b85e8..152c3e62c 100644 --- a/bindings/matrix-sdk-ffi/src/lib.rs +++ b/bindings/matrix-sdk-ffi/src/lib.rs @@ -26,6 +26,7 @@ pub mod authentication_service; pub mod client; pub mod client_builder; mod error; +pub mod event; mod helpers; pub mod notification_service; pub mod room; @@ -51,8 +52,8 @@ pub use matrix_sdk::{ pub use platform::*; pub use self::{ - authentication_service::*, client::*, notification_service::*, room::*, room_member::*, - session_verification::*, sliding_sync::*, timeline::*, tracing::*, + authentication_service::*, client::*, event::*, notification_service::*, room::*, + room_member::*, session_verification::*, sliding_sync::*, timeline::*, tracing::*, }; uniffi::include_scaffolding!("api"); diff --git a/bindings/matrix-sdk-ffi/src/notification_service.rs b/bindings/matrix-sdk-ffi/src/notification_service.rs index 941af436d..6d2029305 100644 --- a/bindings/matrix-sdk-ffi/src/notification_service.rs +++ b/bindings/matrix-sdk-ffi/src/notification_service.rs @@ -1,6 +1,54 @@ use std::sync::Arc; -use crate::{error::ClientError, TimelineItem}; +use matrix_sdk::room::Room; +use ruma::api::client::push::get_notifications::v3::Notification; + +use crate::{error::ClientError, event::TimelineEvent}; + +pub struct NotificationItem { + pub event: Arc, + pub room_id: String, + + pub sender_display_name: Option, + pub sender_avatar_url: Option, + + pub room_display_name: String, + pub room_avatar_url: Option, + + pub is_noisy: bool, + pub is_direct: bool, + pub is_encrypted: bool, +} + +impl NotificationItem { + pub(crate) async fn new(notification: Notification, room: Room) -> anyhow::Result { + let deserialized_event = notification.event.deserialize()?; + + let sender = room.get_member(deserialized_event.sender()).await?; + let mut sender_display_name = None; + let mut sender_avatar_url = None; + if let Some(sender) = sender { + sender_display_name = sender.display_name().map(|s| s.to_owned()); + sender_avatar_url = sender.avatar_url().map(|s| s.to_string()); + } + + let is_noisy = + notification.actions.iter().any(|a| a.sound().is_some() && a.should_notify()); + + let item = Self { + event: Arc::new(TimelineEvent(deserialized_event)), + room_id: room.room_id().to_string(), + sender_display_name, + sender_avatar_url, + room_display_name: room.display_name().await?.to_string(), + room_avatar_url: room.avatar_url().map(|s| s.to_string()), + is_noisy, + is_direct: room.is_direct().await?, + is_encrypted: room.is_encrypted().await?, + }; + Ok(item) + } +} #[allow(dead_code)] pub struct NotificationService { @@ -8,22 +56,6 @@ pub struct NotificationService { user_id: String, } -/// Notification item struct. -#[derive(uniffi::Record)] -pub struct NotificationItem { - /// Actual timeline item for the event sent. - pub item: Arc, - /// Title of the notification. Usually would be event sender's display name. - pub title: String, - /// Subtitle of the notification. Usually would be the room name for - /// non-direct rooms, and none for direct rooms. - pub subtitle: Option, - /// Flag indicating the notification should play a sound. - pub is_noisy: bool, - /// Avatar url of the room the event sent to (if any). - pub avatar_url: Option, -} - impl NotificationService { /// Creates a new notification service. /// diff --git a/bindings/matrix-sdk-ffi/src/timeline.rs b/bindings/matrix-sdk-ffi/src/timeline.rs index ab836fe6f..67d5ce8f0 100644 --- a/bindings/matrix-sdk-ffi/src/timeline.rs +++ b/bindings/matrix-sdk-ffi/src/timeline.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use anyhow::bail; use extension_trait::extension_trait; use eyeball_im::VectorDiff; use matrix_sdk::room::timeline::{Profile, TimelineDetails}; @@ -449,56 +450,7 @@ pub struct Message(matrix_sdk::room::timeline::Message); #[uniffi::export] impl Message { pub fn msgtype(&self) -> Option { - use matrix_sdk::ruma::events::room::message::MessageType as MTy; - match self.0.msgtype() { - MTy::Emote(c) => Some(MessageType::Emote { - content: EmoteMessageContent { - body: c.body.clone(), - formatted: c.formatted.as_ref().map(Into::into), - }, - }), - MTy::Image(c) => Some(MessageType::Image { - content: ImageMessageContent { - body: c.body.clone(), - source: Arc::new(c.source.clone()), - info: c.info.as_deref().map(Into::into), - }, - }), - MTy::Audio(c) => Some(MessageType::Audio { - content: AudioMessageContent { - body: c.body.clone(), - source: Arc::new(c.source.clone()), - info: c.info.as_deref().map(Into::into), - }, - }), - MTy::Video(c) => Some(MessageType::Video { - content: VideoMessageContent { - body: c.body.clone(), - source: Arc::new(c.source.clone()), - info: c.info.as_deref().map(Into::into), - }, - }), - MTy::File(c) => Some(MessageType::File { - content: FileMessageContent { - body: c.body.clone(), - source: Arc::new(c.source.clone()), - info: c.info.as_deref().map(Into::into), - }, - }), - MTy::Notice(c) => Some(MessageType::Notice { - content: NoticeMessageContent { - body: c.body.clone(), - formatted: c.formatted.as_ref().map(Into::into), - }, - }), - MTy::Text(c) => Some(MessageType::Text { - content: TextMessageContent { - body: c.body.clone(), - formatted: c.formatted.as_ref().map(Into::into), - }, - }), - _ => None, - } + self.0.msgtype().clone().try_into().ok() } pub fn body(&self) -> String { @@ -525,6 +477,66 @@ pub enum MessageType { Text { content: TextMessageContent }, } +impl TryFrom for MessageType { + type Error = anyhow::Error; + + fn try_from( + value: matrix_sdk::ruma::events::room::message::MessageType, + ) -> anyhow::Result { + use matrix_sdk::ruma::events::room::message::MessageType as MTy; + let message_type = match value { + MTy::Emote(c) => MessageType::Emote { + content: EmoteMessageContent { + body: c.body.clone(), + formatted: c.formatted.as_ref().map(Into::into), + }, + }, + MTy::Image(c) => MessageType::Image { + content: ImageMessageContent { + body: c.body.clone(), + source: Arc::new(c.source.clone()), + info: c.info.as_deref().map(Into::into), + }, + }, + MTy::Audio(c) => MessageType::Audio { + content: AudioMessageContent { + body: c.body.clone(), + source: Arc::new(c.source.clone()), + info: c.info.as_deref().map(Into::into), + }, + }, + MTy::Video(c) => MessageType::Video { + content: VideoMessageContent { + body: c.body.clone(), + source: Arc::new(c.source.clone()), + info: c.info.as_deref().map(Into::into), + }, + }, + MTy::File(c) => MessageType::File { + content: FileMessageContent { + body: c.body.clone(), + source: Arc::new(c.source.clone()), + info: c.info.as_deref().map(Into::into), + }, + }, + MTy::Notice(c) => MessageType::Notice { + content: NoticeMessageContent { + body: c.body.clone(), + formatted: c.formatted.as_ref().map(Into::into), + }, + }, + MTy::Text(c) => MessageType::Text { + content: TextMessageContent { + body: c.body.clone(), + formatted: c.formatted.as_ref().map(Into::into), + }, + }, + _ => bail!("Unsupported type"), + }; + Ok(message_type) + } +} + #[derive(Clone, uniffi::Record)] pub struct EmoteMessageContent { pub body: String, From 2de2a14ee6a9970deb7925bb6f570d097468656e Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 27 Apr 2023 17:42:19 +0200 Subject: [PATCH 11/27] Run rustfmt --- bindings/matrix-sdk-crypto-js/src/machine.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/bindings/matrix-sdk-crypto-js/src/machine.rs b/bindings/matrix-sdk-crypto-js/src/machine.rs index 7fb0c4331..216e620c1 100644 --- a/bindings/matrix-sdk-crypto-js/src/machine.rs +++ b/bindings/matrix-sdk-crypto-js/src/machine.rs @@ -241,14 +241,16 @@ impl OlmMachine { .collect(); // Convert the unused_fallback_keys JS Set to a `Vec` - let unused_fallback_keys: Option> = match unused_fallback_keys { - Some(fallback_keys) => { - Some(fallback_keys + let unused_fallback_keys: Option> = match unused_fallback_keys { + Some(fallback_keys) => Some( + fallback_keys .values() .into_iter() - .filter_map(|js_value| Some(DeviceKeyAlgorithm::from(js_value.ok()?.as_string()?))) - .collect()) - }, + .filter_map(|js_value| { + Some(DeviceKeyAlgorithm::from(js_value.ok()?.as_string()?)) + }) + .collect(), + ), _ => None, }; From 75870dd60787885509e7900c37533118f550c73e Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 27 Apr 2023 17:57:30 +0200 Subject: [PATCH 12/27] Run clippy --- bindings/matrix-sdk-crypto-js/src/machine.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/bindings/matrix-sdk-crypto-js/src/machine.rs b/bindings/matrix-sdk-crypto-js/src/machine.rs index 216e620c1..82f1e290c 100644 --- a/bindings/matrix-sdk-crypto-js/src/machine.rs +++ b/bindings/matrix-sdk-crypto-js/src/machine.rs @@ -241,18 +241,16 @@ impl OlmMachine { .collect(); // Convert the unused_fallback_keys JS Set to a `Vec` - let unused_fallback_keys: Option> = match unused_fallback_keys { - Some(fallback_keys) => Some( + let unused_fallback_keys: Option> = + unused_fallback_keys.map(|fallback_keys| { fallback_keys .values() .into_iter() .filter_map(|js_value| { Some(DeviceKeyAlgorithm::from(js_value.ok()?.as_string()?)) }) - .collect(), - ), - _ => None, - }; + .collect() + }); let me = self.inner.clone(); From 8aad6156bccac48780727617d06d4dda00a3a542 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 26 Apr 2023 18:14:41 +0200 Subject: [PATCH 13/27] Upgrade UniFFI --- Cargo.lock | 18 +++++++++--------- Cargo.toml | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 437f13e5e..087b91ef1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5529,7 +5529,7 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "uniffi" version = "0.23.0" -source = "git+https://github.com/mozilla/uniffi-rs?rev=aa91307b6ac27aae6d5c7ad971b762df952d2745#aa91307b6ac27aae6d5c7ad971b762df952d2745" +source = "git+https://github.com/mozilla/uniffi-rs?rev=9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb#9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb" dependencies = [ "anyhow", "camino", @@ -5550,7 +5550,7 @@ dependencies = [ [[package]] name = "uniffi_bindgen" version = "0.23.0" -source = "git+https://github.com/mozilla/uniffi-rs?rev=aa91307b6ac27aae6d5c7ad971b762df952d2745#aa91307b6ac27aae6d5c7ad971b762df952d2745" +source = "git+https://github.com/mozilla/uniffi-rs?rev=9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb#9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb" dependencies = [ "anyhow", "askama", @@ -5572,7 +5572,7 @@ dependencies = [ [[package]] name = "uniffi_build" version = "0.23.0" -source = "git+https://github.com/mozilla/uniffi-rs?rev=aa91307b6ac27aae6d5c7ad971b762df952d2745#aa91307b6ac27aae6d5c7ad971b762df952d2745" +source = "git+https://github.com/mozilla/uniffi-rs?rev=9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb#9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb" dependencies = [ "anyhow", "camino", @@ -5582,7 +5582,7 @@ dependencies = [ [[package]] name = "uniffi_checksum_derive" version = "0.23.0" -source = "git+https://github.com/mozilla/uniffi-rs?rev=aa91307b6ac27aae6d5c7ad971b762df952d2745#aa91307b6ac27aae6d5c7ad971b762df952d2745" +source = "git+https://github.com/mozilla/uniffi-rs?rev=9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb#9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb" dependencies = [ "quote", "syn 1.0.109", @@ -5591,7 +5591,7 @@ dependencies = [ [[package]] name = "uniffi_core" version = "0.23.0" -source = "git+https://github.com/mozilla/uniffi-rs?rev=aa91307b6ac27aae6d5c7ad971b762df952d2745#aa91307b6ac27aae6d5c7ad971b762df952d2745" +source = "git+https://github.com/mozilla/uniffi-rs?rev=9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb#9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb" dependencies = [ "anyhow", "bytes", @@ -5606,7 +5606,7 @@ dependencies = [ [[package]] name = "uniffi_macros" version = "0.23.0" -source = "git+https://github.com/mozilla/uniffi-rs?rev=aa91307b6ac27aae6d5c7ad971b762df952d2745#aa91307b6ac27aae6d5c7ad971b762df952d2745" +source = "git+https://github.com/mozilla/uniffi-rs?rev=9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb#9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb" dependencies = [ "bincode", "camino", @@ -5624,7 +5624,7 @@ dependencies = [ [[package]] name = "uniffi_meta" version = "0.23.0" -source = "git+https://github.com/mozilla/uniffi-rs?rev=aa91307b6ac27aae6d5c7ad971b762df952d2745#aa91307b6ac27aae6d5c7ad971b762df952d2745" +source = "git+https://github.com/mozilla/uniffi-rs?rev=9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb#9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb" dependencies = [ "anyhow", "bytes", @@ -5637,7 +5637,7 @@ dependencies = [ [[package]] name = "uniffi_testing" version = "0.23.0" -source = "git+https://github.com/mozilla/uniffi-rs?rev=aa91307b6ac27aae6d5c7ad971b762df952d2745#aa91307b6ac27aae6d5c7ad971b762df952d2745" +source = "git+https://github.com/mozilla/uniffi-rs?rev=9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb#9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb" dependencies = [ "anyhow", "camino", @@ -5936,7 +5936,7 @@ dependencies = [ [[package]] name = "weedle2" version = "4.0.0" -source = "git+https://github.com/mozilla/uniffi-rs?rev=aa91307b6ac27aae6d5c7ad971b762df952d2745#aa91307b6ac27aae6d5c7ad971b762df952d2745" +source = "git+https://github.com/mozilla/uniffi-rs?rev=9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb#9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb" dependencies = [ "nom", ] diff --git a/Cargo.toml b/Cargo.toml index d9d522acb..d38f351e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,8 +42,8 @@ thiserror = "1.0.38" tokio = { version = "1.24", default-features = false, features = ["sync"] } tracing = { version = "0.1.36", default-features = false, features = ["std"] } tracing-core = "0.1.30" -uniffi = { git = "https://github.com/mozilla/uniffi-rs", rev = "aa91307b6ac27aae6d5c7ad971b762df952d2745" } -uniffi_bindgen = { git = "https://github.com/mozilla/uniffi-rs", rev = "aa91307b6ac27aae6d5c7ad971b762df952d2745" } +uniffi = { git = "https://github.com/mozilla/uniffi-rs", rev = "9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb" } +uniffi_bindgen = { git = "https://github.com/mozilla/uniffi-rs", rev = "9e01d2281bb4a603fc9ed6409a02ad1854cdc8fb" } vodozemac = { git = "https://github.com/matrix-org/vodozemac", rev = "fb609ca1e4df5a7a818490ae86ac694119e41e71" } zeroize = "1.3.0" From 6b8ec0936543725cc24ad318fa94584fee17e435 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 27 Apr 2023 13:36:40 +0200 Subject: [PATCH 14/27] crypto-ffi: Use proc-macros for constructors --- .../src/backup_recovery_key.rs | 59 +++++++------- bindings/matrix-sdk-crypto-ffi/src/lib.rs | 7 +- bindings/matrix-sdk-crypto-ffi/src/machine.rs | 80 ++++++++++--------- bindings/matrix-sdk-crypto-ffi/src/olm.udl | 22 ----- 4 files changed, 78 insertions(+), 90 deletions(-) diff --git a/bindings/matrix-sdk-crypto-ffi/src/backup_recovery_key.rs b/bindings/matrix-sdk-crypto-ffi/src/backup_recovery_key.rs index 5cf6e3974..2de8c2b20 100644 --- a/bindings/matrix-sdk-crypto-ffi/src/backup_recovery_key.rs +++ b/bindings/matrix-sdk-crypto-ffi/src/backup_recovery_key.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, iter, ops::DerefMut}; +use std::{collections::HashMap, iter, ops::DerefMut, sync::Arc}; use hmac::Hmac; use matrix_sdk_crypto::{ @@ -12,6 +12,7 @@ use thiserror::Error; use zeroize::Zeroize; /// The private part of the backup key, the one used for recovery. +#[derive(uniffi::Object)] pub struct BackupRecoveryKey { pub(crate) inner: RecoveryKey, pub(crate) passphrase_info: Option, @@ -62,46 +63,40 @@ pub struct MegolmV1BackupKey { pub backup_algorithm: String, } -#[uniffi::export] -impl BackupRecoveryKey { - /// Convert the recovery key to a base 58 encoded string. - pub fn to_base58(&self) -> String { - self.inner.to_base58() - } - - /// Convert the recovery key to a base 64 encoded string. - pub fn to_base64(&self) -> String { - self.inner.to_base64() - } -} - impl BackupRecoveryKey { const KEY_SIZE: usize = 32; const SALT_SIZE: usize = 32; const PBKDF_ROUNDS: i32 = 500_000; +} +#[uniffi::export] +impl BackupRecoveryKey { /// Create a new random [`BackupRecoveryKey`]. #[allow(clippy::new_without_default)] - pub fn new() -> Self { - Self { + #[uniffi::constructor] + pub fn new() -> Arc { + Arc::new(Self { inner: RecoveryKey::new() .expect("Can't gather enough randomness to create a recovery key"), passphrase_info: None, - } + }) } /// Try to create a [`BackupRecoveryKey`] from a base 64 encoded string. - pub fn from_base64(key: String) -> Result { - Ok(Self { inner: RecoveryKey::from_base64(&key)?, passphrase_info: None }) + #[uniffi::constructor] + pub fn from_base64(key: String) -> Result, DecodeError> { + Ok(Arc::new(Self { inner: RecoveryKey::from_base64(&key)?, passphrase_info: None })) } /// Try to create a [`BackupRecoveryKey`] from a base 58 encoded string. - pub fn from_base58(key: String) -> Result { - Ok(Self { inner: RecoveryKey::from_base58(&key)?, passphrase_info: None }) + #[uniffi::constructor] + pub fn from_base58(key: String) -> Result, DecodeError> { + Ok(Arc::new(Self { inner: RecoveryKey::from_base58(&key)?, passphrase_info: None })) } /// Create a new [`BackupRecoveryKey`] from the given passphrase. - pub fn new_from_passphrase(passphrase: String) -> Self { + #[uniffi::constructor] + pub fn new_from_passphrase(passphrase: String) -> Arc { let mut rng = thread_rng(); let salt: String = iter::repeat(()) .map(|()| rng.sample(Alphanumeric)) @@ -113,7 +108,8 @@ impl BackupRecoveryKey { } /// Restore a [`BackupRecoveryKey`] from the given passphrase. - pub fn from_passphrase(passphrase: String, salt: String, rounds: i32) -> Self { + #[uniffi::constructor] + pub fn from_passphrase(passphrase: String, salt: String, rounds: i32) -> Arc { let mut key = Box::new([0u8; Self::KEY_SIZE]); let rounds = rounds as u32; @@ -123,18 +119,25 @@ impl BackupRecoveryKey { key.zeroize(); - Self { + Arc::new(Self { inner: recovery_key, passphrase_info: Some(PassphraseInfo { private_key_salt: salt, private_key_iterations: rounds as i32, }), - } + }) + } + + /// Convert the recovery key to a base 58 encoded string. + pub fn to_base58(&self) -> String { + self.inner.to_base58() + } + + /// Convert the recovery key to a base 64 encoded string. + pub fn to_base64(&self) -> String { + self.inner.to_base64() } -} -#[uniffi::export] -impl BackupRecoveryKey { /// Get the public part of the backup key. pub fn megolm_v1_public_key(&self) -> MegolmV1BackupKey { let public_key = self.inner.megolm_v1_public_key(); diff --git a/bindings/matrix-sdk-crypto-ffi/src/lib.rs b/bindings/matrix-sdk-crypto-ffi/src/lib.rs index d26ea8d04..9674954b5 100644 --- a/bindings/matrix-sdk-crypto-ffi/src/lib.rs +++ b/bindings/matrix-sdk-crypto-ffi/src/lib.rs @@ -972,7 +972,12 @@ mod test { migrate(migration_data, path.clone(), None, Box::new(|_, _| {}))?; - let machine = OlmMachine::new("@ganfra146:matrix.org", "DEWRCMENGS", &path, None)?; + let machine = OlmMachine::new( + "@ganfra146:matrix.org".to_owned(), + "DEWRCMENGS".to_owned(), + path, + None, + )?; assert_eq!( machine.identity_keys()["ed25519"], diff --git a/bindings/matrix-sdk-crypto-ffi/src/machine.rs b/bindings/matrix-sdk-crypto-ffi/src/machine.rs index e9f267601..7e156baa1 100644 --- a/bindings/matrix-sdk-crypto-ffi/src/machine.rs +++ b/bindings/matrix-sdk-crypto-ffi/src/machine.rs @@ -59,6 +59,7 @@ use crate::{ }; /// A high level state machine that handles E2EE for Matrix. +#[derive(uniffi::Object)] pub struct OlmMachine { pub(crate) inner: ManuallyDrop, pub(crate) runtime: Runtime, @@ -128,6 +129,7 @@ impl From for SignatureVerification { } } +#[uniffi::export] impl OlmMachine { /// Create a new `OlmMachine` /// @@ -142,14 +144,15 @@ impl OlmMachine { /// * `passphrase` - The passphrase that should be used to encrypt the data /// at rest in the Sled store. **Warning**, if no passphrase is given, the /// store and all its data will remain unencrypted. + #[uniffi::constructor] pub fn new( - user_id: &str, - device_id: &str, - path: &str, + user_id: String, + device_id: String, + path: String, mut passphrase: Option, - ) -> Result { - let user_id = parse_user_id(user_id)?; - let device_id = device_id.into(); + ) -> Result, CryptoStoreError> { + let user_id = parse_user_id(&user_id)?; + let device_id = device_id.as_str().into(); let runtime = Runtime::new().expect("Couldn't create a tokio runtime"); let store = runtime @@ -160,41 +163,9 @@ impl OlmMachine { let inner = runtime.block_on(InnerMachine::with_store(&user_id, device_id, Arc::new(store)))?; - Ok(OlmMachine { inner: ManuallyDrop::new(inner), runtime }) + Ok(Arc::new(OlmMachine { inner: ManuallyDrop::new(inner), runtime })) } - fn import_room_keys_helper( - &self, - keys: Vec, - from_backup: bool, - progress_listener: Box, - ) -> Result { - let listener = |progress: usize, total: usize| { - progress_listener.on_progress(progress as i32, total as i32) - }; - - let result = - self.runtime.block_on(self.inner.import_room_keys(keys, from_backup, listener))?; - - Ok(KeysImportResult { - imported: result.imported_count as i64, - total: result.total_count as i64, - keys: result - .keys - .into_iter() - .map(|(r, m)| { - ( - r.to_string(), - m.into_iter().map(|(s, k)| (s, k.into_iter().collect())).collect(), - ) - }) - .collect(), - }) - } -} - -#[uniffi::export] -impl OlmMachine { /// Get the user ID of the owner of this `OlmMachine`. pub fn user_id(&self) -> String { self.inner.user_id().to_string() @@ -1402,3 +1373,34 @@ impl OlmMachine { .into()) } } + +impl OlmMachine { + fn import_room_keys_helper( + &self, + keys: Vec, + from_backup: bool, + progress_listener: Box, + ) -> Result { + let listener = |progress: usize, total: usize| { + progress_listener.on_progress(progress as i32, total as i32) + }; + + let result = + self.runtime.block_on(self.inner.import_room_keys(keys, from_backup, listener))?; + + Ok(KeysImportResult { + imported: result.imported_count as i64, + total: result.total_count as i64, + keys: result + .keys + .into_iter() + .map(|(r, m)| { + ( + r.to_string(), + m.into_iter().map(|(s, k)| (s, k.into_iter().collect())).collect(), + ) + }) + .collect(), + }) + } +} diff --git a/bindings/matrix-sdk-crypto-ffi/src/olm.udl b/bindings/matrix-sdk-crypto-ffi/src/olm.udl index b98565243..e9480a2d7 100644 --- a/bindings/matrix-sdk-crypto-ffi/src/olm.udl +++ b/bindings/matrix-sdk-crypto-ffi/src/olm.udl @@ -71,31 +71,9 @@ enum LocalTrust { "Unset", }; -interface OlmMachine { - [Throws=CryptoStoreError] - constructor( - [ByRef] string user_id, - [ByRef] string device_id, - [ByRef] string path, - string? passphrase - ); -}; - enum SignatureState { "Missing", "Invalid", "ValidButNotTrusted", "ValidAndTrusted", }; - -interface BackupRecoveryKey { - constructor(); - [Name=from_passphrase] - constructor(string passphrase, string salt, i32 rounds); - [Name=new_from_passphrase] - constructor(string passphrase); - [Name=from_base64, Throws=DecodeError] - constructor(string key); - [Name=from_base58, Throws=DecodeError] - constructor(string key); -}; From 34d2a20b15c808ab8ef59c0f4ad95180f41d46cf Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 27 Apr 2023 13:36:42 +0200 Subject: [PATCH 15/27] ffi: Use proc-macros for constructors --- bindings/matrix-sdk-ffi/src/api.udl | 22 ------- .../src/authentication_service.rs | 60 ++++++++++--------- bindings/matrix-sdk-ffi/src/client_builder.rs | 35 ++++++----- bindings/matrix-sdk-ffi/src/lib.rs | 2 +- .../src/notification_service.rs | 10 ++-- bindings/matrix-sdk-ffi/src/sliding_sync.rs | 13 ++-- bindings/matrix-sdk-ffi/src/tracing.rs | 20 ++++--- 7 files changed, 72 insertions(+), 90 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/api.udl b/bindings/matrix-sdk-ffi/src/api.udl index f84e818de..0c0a2bf9a 100644 --- a/bindings/matrix-sdk-ffi/src/api.udl +++ b/bindings/matrix-sdk-ffi/src/api.udl @@ -96,14 +96,6 @@ callback interface SlidingSyncListRoomItemsObserver { void did_receive_update(); }; -interface SlidingSyncListBuilder { - constructor(); -}; - -interface ClientBuilder { - constructor(); -}; - dictionary CreateRoomParameters { string? name; string? topic = null; @@ -164,14 +156,6 @@ interface MediaSource { string url(); }; -interface AuthenticationService { - constructor(string base_path, string? passphrase, string? custom_sliding_sync_proxy); -}; - -interface NotificationService { - constructor(string base_path, string user_id); -}; - interface SessionVerificationEmoji {}; callback interface SessionVerificationControllerDelegate { @@ -183,12 +167,6 @@ callback interface SessionVerificationControllerDelegate { void did_finish(); }; -interface Span { - constructor(string file, u32 line, u32 column, LogLevel level, string target, string name); - [Name=current] - constructor(); -}; - enum LogLevel { "Error", "Warn", diff --git a/bindings/matrix-sdk-ffi/src/authentication_service.rs b/bindings/matrix-sdk-ffi/src/authentication_service.rs index 58df9ef2a..fae7387d8 100644 --- a/bindings/matrix-sdk-ffi/src/authentication_service.rs +++ b/bindings/matrix-sdk-ffi/src/authentication_service.rs @@ -11,6 +11,7 @@ use zeroize::Zeroize; use super::{client::Client, client_builder::ClientBuilder, RUNTIME}; use crate::error::ClientError; +#[derive(uniffi::Object)] pub struct AuthenticationService { base_path: String, passphrase: Option, @@ -78,44 +79,24 @@ impl HomeserverLoginDetails { } } +#[uniffi::export] impl AuthenticationService { /// Creates a new service to authenticate a user with. + #[uniffi::constructor] pub fn new( base_path: String, passphrase: Option, custom_sliding_sync_proxy: Option, - ) -> Self { - AuthenticationService { + ) -> Arc { + Arc::new(AuthenticationService { base_path, passphrase, client: RwLock::new(None), homeserver_details: RwLock::new(None), custom_sliding_sync_proxy: RwLock::new(custom_sliding_sync_proxy), - } + }) } - /// Get the homeserver login details from a client. - async fn details_from_client( - &self, - client: &Arc, - ) -> Result { - let login_details = join3( - client.async_homeserver(), - client.authentication_issuer(), - client.supports_password_login(), - ) - .await; - - let url = login_details.0; - let authentication_issuer = login_details.1; - let supports_password_login = login_details.2?; - - Ok(HomeserverLoginDetails { url, authentication_issuer, supports_password_login }) - } -} - -#[uniffi::export] -impl AuthenticationService { pub fn homeserver_details(&self) -> Option> { self.homeserver_details.read().unwrap().clone() } @@ -126,7 +107,7 @@ impl AuthenticationService { &self, server_name_or_homeserver_url: String, ) -> Result<(), AuthenticationError> { - let mut builder = Arc::new(ClientBuilder::new()).base_path(self.base_path.clone()); + let mut builder = ClientBuilder::new().base_path(self.base_path.clone()); // Attempt discovery as a server name first. let result = matrix_sdk::sanitize_server_name(&server_name_or_homeserver_url); @@ -152,7 +133,7 @@ impl AuthenticationService { return Err(e); } // When discovery fails, fallback to the homeserver URL if supplied. - let mut builder = Arc::new(ClientBuilder::new()).base_path(self.base_path.clone()); + let mut builder = ClientBuilder::new().base_path(self.base_path.clone()); builder = builder.homeserver_url(server_name_or_homeserver_url); builder.build_inner() })?; @@ -205,7 +186,7 @@ impl AuthenticationService { sliding_sync_proxy = None; } - let client = Arc::new(ClientBuilder::new()) + let client = ClientBuilder::new() .base_path(self.base_path.clone()) .passphrase(self.passphrase.clone()) .homeserver_url(homeserver_url) @@ -258,7 +239,7 @@ impl AuthenticationService { user_id: whoami.user_id.clone(), device_id, }; - let client = Arc::new(ClientBuilder::new()) + let client = ClientBuilder::new() .base_path(self.base_path.clone()) .passphrase(self.passphrase.clone()) .homeserver_url(homeserver_url) @@ -270,3 +251,24 @@ impl AuthenticationService { Ok(client) } } + +impl AuthenticationService { + /// Get the homeserver login details from a client. + async fn details_from_client( + &self, + client: &Arc, + ) -> Result { + let login_details = join3( + client.async_homeserver(), + client.authentication_issuer(), + client.supports_password_login(), + ) + .await; + + let url = login_details.0; + let authentication_issuer = login_details.1; + let supports_password_login = login_details.2?; + + Ok(HomeserverLoginDetails { url, authentication_issuer, supports_password_login }) + } +} diff --git a/bindings/matrix-sdk-ffi/src/client_builder.rs b/bindings/matrix-sdk-ffi/src/client_builder.rs index 539b4e6b8..118640262 100644 --- a/bindings/matrix-sdk-ffi/src/client_builder.rs +++ b/bindings/matrix-sdk-ffi/src/client_builder.rs @@ -15,7 +15,7 @@ use zeroize::Zeroizing; use super::{client::Client, RUNTIME}; use crate::{error::ClientError, helpers::unwrap_or_clone_arc}; -#[derive(Clone)] +#[derive(Clone, uniffi::Object)] pub struct ClientBuilder { base_path: Option, username: Option, @@ -28,24 +28,13 @@ pub struct ClientBuilder { inner: MatrixClientBuilder, } -impl ClientBuilder { - pub fn new() -> Self { - Self { - base_path: None, - username: None, - server_name: None, - homeserver_url: None, - server_versions: None, - passphrase: Zeroizing::new(None), - user_agent: None, - sliding_sync_proxy: None, - inner: MatrixClient::builder(), - } - } -} - #[uniffi::export] impl ClientBuilder { + #[uniffi::constructor] + pub fn new() -> Arc { + Arc::new(Self::default()) + } + pub fn base_path(self: Arc, path: String) -> Arc { let mut builder = unwrap_or_clone_arc(self); builder.base_path = Some(path); @@ -168,6 +157,16 @@ impl ClientBuilder { impl Default for ClientBuilder { fn default() -> Self { - Self::new() + Self { + base_path: None, + username: None, + server_name: None, + homeserver_url: None, + server_versions: None, + passphrase: Zeroizing::new(None), + user_agent: None, + sliding_sync_proxy: None, + inner: MatrixClient::builder(), + } } } diff --git a/bindings/matrix-sdk-ffi/src/lib.rs b/bindings/matrix-sdk-ffi/src/lib.rs index 152c3e62c..546f5f625 100644 --- a/bindings/matrix-sdk-ffi/src/lib.rs +++ b/bindings/matrix-sdk-ffi/src/lib.rs @@ -40,7 +40,7 @@ use once_cell::sync::Lazy; use tokio::runtime::Runtime; // Re-exports for more convenient use inside other submodules -use self::{client::Client, client_builder::ClientBuilder, error::ClientError}; +use self::{client::Client, error::ClientError}; pub static RUNTIME: Lazy = Lazy::new(|| Runtime::new().expect("Can't start Tokio runtime")); diff --git a/bindings/matrix-sdk-ffi/src/notification_service.rs b/bindings/matrix-sdk-ffi/src/notification_service.rs index 6d2029305..64f3d8977 100644 --- a/bindings/matrix-sdk-ffi/src/notification_service.rs +++ b/bindings/matrix-sdk-ffi/src/notification_service.rs @@ -51,24 +51,24 @@ impl NotificationItem { } #[allow(dead_code)] +#[derive(uniffi::Object)] pub struct NotificationService { base_path: String, user_id: String, } +#[uniffi::export] impl NotificationService { /// Creates a new notification service. /// /// Will be used to fetch an event after receiving a notification. /// Please note that this will be called on a new process than the /// application context. - pub fn new(base_path: String, user_id: String) -> Self { - Self { base_path, user_id } + #[uniffi::constructor] + pub fn new(base_path: String, user_id: String) -> Arc { + Arc::new(Self { base_path, user_id }) } -} -#[uniffi::export] -impl NotificationService { /// Get notification item for a given `room_id `and `event_id`. /// /// Returns `None` if this notification should not be displayed to the user. diff --git a/bindings/matrix-sdk-ffi/src/sliding_sync.rs b/bindings/matrix-sdk-ffi/src/sliding_sync.rs index 1ae7a0cbc..b712b91b3 100644 --- a/bindings/matrix-sdk-ffi/src/sliding_sync.rs +++ b/bindings/matrix-sdk-ffi/src/sliding_sync.rs @@ -430,7 +430,7 @@ pub trait SlidingSyncListStateObserver: Sync + Send { fn did_receive_update(&self, new_state: SlidingSyncState); } -#[derive(Clone)] +#[derive(Clone, uniffi::Object)] pub struct SlidingSyncListBuilder { inner: matrix_sdk::SlidingSyncListBuilder, } @@ -471,14 +471,13 @@ impl From for SyncRequestListFilters { } } -impl SlidingSyncListBuilder { - pub fn new() -> Self { - Self { inner: matrix_sdk::SlidingSyncList::builder() } - } -} - #[uniffi::export] impl SlidingSyncListBuilder { + #[uniffi::constructor] + pub fn new() -> Arc { + Arc::new(Self { inner: matrix_sdk::SlidingSyncList::builder() }) + } + pub fn sync_mode(self: Arc, mode: SlidingSyncMode) -> Arc { let mut builder = unwrap_or_clone_arc(self); builder.inner = builder.inner.sync_mode(mode); diff --git a/bindings/matrix-sdk-ffi/src/tracing.rs b/bindings/matrix-sdk-ffi/src/tracing.rs index cd266658e..6286bc13a 100644 --- a/bindings/matrix-sdk-ffi/src/tracing.rs +++ b/bindings/matrix-sdk-ffi/src/tracing.rs @@ -1,4 +1,7 @@ -use std::{collections::BTreeMap, sync::Mutex}; +use std::{ + collections::BTreeMap, + sync::{Arc, Mutex}, +}; use once_cell::sync::OnceCell; use tracing::{callsite::DefaultCallsite, field::FieldSet, Callsite}; @@ -92,8 +95,10 @@ fn span_or_event_enabled(callsite: &'static DefaultCallsite) -> bool { } } +#[derive(uniffi::Object)] pub struct Span(tracing::Span); +#[uniffi::export] impl Span { /// Create a span originating at the given callsite (file, line and column). /// @@ -119,6 +124,7 @@ impl Span { /// case it should also be exited on all of them individually; that is, /// unless you *want* the span to be attached to all further events created /// on that thread. + #[uniffi::constructor] pub fn new( file: String, line: u32, @@ -126,7 +132,7 @@ impl Span { level: LogLevel, target: String, name: String, - ) -> Self { + ) -> Arc { static CALLSITES: Mutex> = Mutex::new(BTreeMap::new()); let loc = Location::new(file, line, column); @@ -143,16 +149,14 @@ impl Span { tracing::Span::none() }; - Span(span) + Arc::new(Self(span)) } - pub fn current() -> Self { - Self(tracing::Span::current()) + #[uniffi::constructor] + pub fn current() -> Arc { + Arc::new(Self(tracing::Span::current())) } -} -#[uniffi::export] -impl Span { fn enter(&self) { self.0.with_subscriber(|(id, dispatch)| dispatch.enter(id)); } From b4faef7867d172c0b7edd1bf7e4589c41fbbf3ed Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 27 Apr 2023 14:47:11 +0200 Subject: [PATCH 16/27] bindings: Use proc-macros for types no longer referenced in UDL --- bindings/matrix-sdk-crypto-ffi/src/error.rs | 3 ++- bindings/matrix-sdk-crypto-ffi/src/olm.udl | 10 ---------- bindings/matrix-sdk-ffi/src/api.udl | 13 ------------- bindings/matrix-sdk-ffi/src/error.rs | 2 +- bindings/matrix-sdk-ffi/src/tracing.rs | 1 + 5 files changed, 4 insertions(+), 25 deletions(-) diff --git a/bindings/matrix-sdk-crypto-ffi/src/error.rs b/bindings/matrix-sdk-crypto-ffi/src/error.rs index 04bcc9e55..3cb6d30fe 100644 --- a/bindings/matrix-sdk-crypto-ffi/src/error.rs +++ b/bindings/matrix-sdk-crypto-ffi/src/error.rs @@ -42,7 +42,8 @@ pub enum SignatureError { UnknownUserIdentity(String), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi(flat_error)] pub enum CryptoStoreError { #[error("Failed to open the store")] OpenStore(#[from] OpenStoreError), diff --git a/bindings/matrix-sdk-crypto-ffi/src/olm.udl b/bindings/matrix-sdk-crypto-ffi/src/olm.udl index e9480a2d7..71adf3d83 100644 --- a/bindings/matrix-sdk-crypto-ffi/src/olm.udl +++ b/bindings/matrix-sdk-crypto-ffi/src/olm.udl @@ -8,16 +8,6 @@ callback interface ProgressListener { void on_progress(i32 progress, i32 total); }; -[Error] -enum CryptoStoreError { - "OpenStore", - "CryptoStore", - "OlmError", - "Serialization", - "InvalidUserId", - "Identifier", -}; - dictionary CancelInfo { string cancel_code; string reason; diff --git a/bindings/matrix-sdk-ffi/src/api.udl b/bindings/matrix-sdk-ffi/src/api.udl index 0c0a2bf9a..dabf4c60d 100644 --- a/bindings/matrix-sdk-ffi/src/api.udl +++ b/bindings/matrix-sdk-ffi/src/api.udl @@ -1,10 +1,5 @@ namespace matrix_sdk_ffi {}; -[Error] -interface ClientError { - Generic(string msg); -}; - callback interface ClientDelegate { void did_receive_auth_error(boolean is_soft_logout); }; @@ -166,11 +161,3 @@ callback interface SessionVerificationControllerDelegate { void did_cancel(); void did_finish(); }; - -enum LogLevel { - "Error", - "Warn", - "Info", - "Debug", - "Trace", -}; diff --git a/bindings/matrix-sdk-ffi/src/error.rs b/bindings/matrix-sdk-ffi/src/error.rs index fe809fa71..ee9f01bdc 100644 --- a/bindings/matrix-sdk-ffi/src/error.rs +++ b/bindings/matrix-sdk-ffi/src/error.rs @@ -1,6 +1,6 @@ use matrix_sdk::{self, encryption::CryptoStoreError, HttpError, IdParseError, StoreError}; -#[derive(thiserror::Error, Debug)] +#[derive(Debug, thiserror::Error, uniffi::Error)] pub enum ClientError { #[error("client error: {msg}")] Generic { msg: String }, diff --git a/bindings/matrix-sdk-ffi/src/tracing.rs b/bindings/matrix-sdk-ffi/src/tracing.rs index 6286bc13a..c530f33f3 100644 --- a/bindings/matrix-sdk-ffi/src/tracing.rs +++ b/bindings/matrix-sdk-ffi/src/tracing.rs @@ -170,6 +170,7 @@ impl Span { } } +#[derive(uniffi::Enum)] pub enum LogLevel { Error, Warn, From 4ee4198e83b7f20e5d58d016292d08dcdb275362 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 26 Apr 2023 18:51:21 +0200 Subject: [PATCH 17/27] ci: Remove build caching for infrequently used release workflows --- .github/workflows/release-crypto-nodejs.yml | 2 -- .github/workflows/release_crypto_js.yml | 3 --- 2 files changed, 5 deletions(-) diff --git a/.github/workflows/release-crypto-nodejs.yml b/.github/workflows/release-crypto-nodejs.yml index 9448e0bdc..2802ff199 100644 --- a/.github/workflows/release-crypto-nodejs.yml +++ b/.github/workflows/release-crypto-nodejs.yml @@ -83,8 +83,6 @@ jobs: targets: ${{ matrix.target }} - name: Install Node.js uses: actions/setup-node@v3 - - name: Load cache - uses: Swatinem/rust-cache@v2 - if: ${{ matrix.apt_install }} run: | sudo apt-get update diff --git a/.github/workflows/release_crypto_js.yml b/.github/workflows/release_crypto_js.yml index 9dc21348a..af69d9f2b 100644 --- a/.github/workflows/release_crypto_js.yml +++ b/.github/workflows/release_crypto_js.yml @@ -33,9 +33,6 @@ jobs: with: targets: wasm32-unknown-unknown - - name: Load cache - uses: Swatinem/rust-cache@v2 - - name: Install Node.js uses: actions/setup-node@v3 with: From cca8ac7aeac13f84d43ba718ee51d6f458655764 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 26 Apr 2023 18:52:56 +0200 Subject: [PATCH 18/27] ci: Only save caches from main branch Caches saved from a PR can't be loaded from other unrelated PRs, wasting space and possibly getting older previously-saved caches evicted first. --- .github/workflows/bindings_ci.yml | 8 ++++++++ .github/workflows/ci.yml | 14 ++++++++++++++ .github/workflows/coverage.yml | 2 ++ .github/workflows/documentation.yml | 2 ++ 4 files changed, 26 insertions(+) diff --git a/.github/workflows/bindings_ci.yml b/.github/workflows/bindings_ci.yml index a8f98565e..401db957a 100644 --- a/.github/workflows/bindings_ci.yml +++ b/.github/workflows/bindings_ci.yml @@ -45,6 +45,8 @@ jobs: - name: Load cache uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.ref == 'refs/head/main' }} - name: Get xtask uses: actions/cache/restore@v3 @@ -115,6 +117,8 @@ jobs: - name: Load cache uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.ref == 'refs/head/main' }} - name: Install Node.js uses: actions/setup-node@v3 @@ -171,6 +175,8 @@ jobs: - name: Load cache uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.ref == 'refs/head/main' }} - name: Install Node.js uses: actions/setup-node@v3 @@ -217,6 +223,8 @@ jobs: - name: Load cache uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.ref == 'refs/head/main' }} - name: Get xtask uses: actions/cache/restore@v3 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92e6722c1..a53c585c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,6 +89,8 @@ jobs: - name: Load cache uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.ref == 'refs/head/main' }} - name: Install nextest uses: taiki-e/install-action@nextest @@ -119,6 +121,8 @@ jobs: - name: Load cache uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.ref == 'refs/head/main' }} - name: Install nextest uses: taiki-e/install-action@nextest @@ -172,6 +176,8 @@ jobs: - name: Load cache uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.ref == 'refs/head/main' }} - name: Install nextest uses: taiki-e/install-action@nextest @@ -294,6 +300,8 @@ jobs: - name: Load cache uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.ref == 'refs/head/main' }} - name: Install nextest uses: taiki-e/install-action@nextest @@ -361,6 +369,8 @@ jobs: - name: Load cache uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.ref == 'refs/head/main' }} - name: Get xtask uses: actions/cache/restore@v3 @@ -388,6 +398,8 @@ jobs: - name: Load cache uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.ref == 'refs/head/main' }} - name: Install nextest uses: taiki-e/install-action@nextest @@ -464,6 +476,8 @@ jobs: - name: Load cache uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.ref == 'refs/head/main' }} - name: Install nextest uses: taiki-e/install-action@nextest diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 07355e53e..33abd9d9e 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -30,6 +30,8 @@ jobs: - name: Load cache uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.ref == 'refs/head/main' }} - name: Install tarpaulin uses: taiki-e/install-action@v2 diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index e85110aa8..47dc3a535 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -29,6 +29,8 @@ jobs: - name: Load cache uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.ref == 'refs/head/main' }} # Keep in sync with xtask docs - name: Build rust documentation From 640e74c76aa208ebf1f463492979806f19f17476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= <76261501+zecakeh@users.noreply.github.com> Date: Fri, 28 Apr 2023 13:12:38 +0200 Subject: [PATCH 19/27] chore: Update Ruma MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- Cargo.lock | 18 ++-- Cargo.toml | 4 +- crates/matrix-sdk-base/src/sliding_sync.rs | 90 ++++++------------- crates/matrix-sdk/src/sliding_sync/builder.rs | 56 ++++++------ crates/matrix-sdk/src/sliding_sync/cache.rs | 5 +- crates/matrix-sdk/src/sliding_sync/mod.rs | 41 ++++----- crates/matrix-sdk/src/sliding_sync/room.rs | 2 +- 7 files changed, 86 insertions(+), 130 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 087b91ef1..c601d3e76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4336,7 +4336,7 @@ dependencies = [ [[package]] name = "ruma" version = "0.8.2" -source = "git+https://github.com/ruma/ruma?rev=0143bd9b9f5dcfcaa835afb76f342c12f014f945#0143bd9b9f5dcfcaa835afb76f342c12f014f945" +source = "git+https://github.com/ruma/ruma?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" dependencies = [ "assign", "js_int", @@ -4351,7 +4351,7 @@ dependencies = [ [[package]] name = "ruma-appservice-api" version = "0.8.1" -source = "git+https://github.com/ruma/ruma?rev=0143bd9b9f5dcfcaa835afb76f342c12f014f945#0143bd9b9f5dcfcaa835afb76f342c12f014f945" +source = "git+https://github.com/ruma/ruma?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" dependencies = [ "js_int", "ruma-common", @@ -4362,7 +4362,7 @@ dependencies = [ [[package]] name = "ruma-client-api" version = "0.16.2" -source = "git+https://github.com/ruma/ruma?rev=0143bd9b9f5dcfcaa835afb76f342c12f014f945#0143bd9b9f5dcfcaa835afb76f342c12f014f945" +source = "git+https://github.com/ruma/ruma?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" dependencies = [ "assign", "bytes", @@ -4379,7 +4379,7 @@ dependencies = [ [[package]] name = "ruma-common" version = "0.11.3" -source = "git+https://github.com/ruma/ruma?rev=0143bd9b9f5dcfcaa835afb76f342c12f014f945#0143bd9b9f5dcfcaa835afb76f342c12f014f945" +source = "git+https://github.com/ruma/ruma?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" dependencies = [ "base64 0.21.0", "bytes", @@ -4412,7 +4412,7 @@ dependencies = [ [[package]] name = "ruma-federation-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=0143bd9b9f5dcfcaa835afb76f342c12f014f945#0143bd9b9f5dcfcaa835afb76f342c12f014f945" +source = "git+https://github.com/ruma/ruma?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" dependencies = [ "js_int", "ruma-common", @@ -4423,7 +4423,7 @@ dependencies = [ [[package]] name = "ruma-identifiers-validation" version = "0.9.1" -source = "git+https://github.com/ruma/ruma?rev=0143bd9b9f5dcfcaa835afb76f342c12f014f945#0143bd9b9f5dcfcaa835afb76f342c12f014f945" +source = "git+https://github.com/ruma/ruma?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" dependencies = [ "js_int", "thiserror", @@ -4432,7 +4432,7 @@ dependencies = [ [[package]] name = "ruma-macros" version = "0.11.3" -source = "git+https://github.com/ruma/ruma?rev=0143bd9b9f5dcfcaa835afb76f342c12f014f945#0143bd9b9f5dcfcaa835afb76f342c12f014f945" +source = "git+https://github.com/ruma/ruma?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" dependencies = [ "once_cell", "proc-macro-crate", @@ -4440,14 +4440,14 @@ dependencies = [ "quote", "ruma-identifiers-validation", "serde", - "syn 1.0.109", + "syn 2.0.15", "toml 0.7.3", ] [[package]] name = "ruma-push-gateway-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=0143bd9b9f5dcfcaa835afb76f342c12f014f945#0143bd9b9f5dcfcaa835afb76f342c12f014f945" +source = "git+https://github.com/ruma/ruma?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" dependencies = [ "js_int", "ruma-common", diff --git a/Cargo.toml b/Cargo.toml index d38f351e8..2925e5380 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,8 +32,8 @@ eyeball = "0.6.0" eyeball-im = "0.2.0" futures-util = { version = "0.3.26", default-features = false, features = ["alloc"] } http = "0.2.6" -ruma = { git = "https://github.com/ruma/ruma", rev = "0143bd9b9f5dcfcaa835afb76f342c12f014f945", features = ["client-api-c", "compat-user-id"] } -ruma-common = { git = "https://github.com/ruma/ruma", rev = "0143bd9b9f5dcfcaa835afb76f342c12f014f945" } +ruma = { git = "https://github.com/ruma/ruma", rev = "54a4223caa1c1052464ecdba0f1e08f126e07bcd", features = ["client-api-c", "compat-user-id"] } +ruma-common = { git = "https://github.com/ruma/ruma", rev = "54a4223caa1c1052464ecdba0f1e08f126e07bcd" } once_cell = "1.16.0" serde = "1.0.151" serde_html_form = "0.2.0" diff --git a/crates/matrix-sdk-base/src/sliding_sync.rs b/crates/matrix-sdk-base/src/sliding_sync.rs index 60951eaa7..b4282f4f4 100644 --- a/crates/matrix-sdk-base/src/sliding_sync.rs +++ b/crates/matrix-sdk-base/src/sliding_sync.rs @@ -1,13 +1,9 @@ -use std::collections::BTreeMap; #[cfg(feature = "e2e-encryption")] use std::ops::Deref; -use ruma::{ - api::client::sync::sync_events::{ - v3::{self, Ephemeral}, - v4, DeviceLists, - }, - DeviceKeyAlgorithm, UInt, +use ruma::api::client::sync::sync_events::{ + v3::{self, Ephemeral}, + v4, }; use tracing::{debug, info, instrument}; @@ -56,51 +52,26 @@ impl BaseClient { let to_device_events = to_device.as_ref().map(|v4| v4.events.clone()).unwrap_or_default(); - // Destructure the single `None` of the E2EE extension into separate objects - // since that's what the `OlmMachine` API expects. Passing in the default - // empty maps and vecs for this is completely fine, since the `OlmMachine` - // assumes empty maps/vecs mean no change in the one-time key counts. - - // We declare default values that can be referenced hereinbelow. When we try to - // extract values from `e2ee`, that would be unfortunate to clone the - // value just to pass them (to remove them `e2ee`) as a reference later. - let device_one_time_keys_count = BTreeMap::::default(); - let device_unused_fallback_key_types = None; - - let (device_lists, device_one_time_keys_count, device_unused_fallback_key_types) = e2ee - .as_ref() - .map(|e2ee| { - ( - e2ee.device_lists.clone(), - &e2ee.device_one_time_keys_count, - &e2ee.device_unused_fallback_key_types, - ) - }) - .unwrap_or_else(|| { - ( - DeviceLists::default(), - &device_one_time_keys_count, - &device_unused_fallback_key_types, - ) - }); - info!( to_device_events = to_device_events.len(), - device_one_time_keys_count = device_one_time_keys_count.len(), + device_one_time_keys_count = e2ee.device_one_time_keys_count.len(), device_unused_fallback_key_types = - device_unused_fallback_key_types.as_ref().map(|v| v.len()) + e2ee.device_unused_fallback_key_types.as_ref().map(|v| v.len()) ); // Process the to-device events and other related e2ee data. This returns a list // of all the to-device events that were passed in but encrypted ones // were replaced with their decrypted version. + // Passing in the default empty maps and vecs for this is completely fine, since + // the `OlmMachine` assumes empty maps/vecs mean no change in the one-time key + // counts. #[cfg(feature = "e2e-encryption")] let to_device_events = { self.preprocess_to_device_events( to_device_events, - &device_lists, - device_one_time_keys_count, - device_unused_fallback_key_types.as_deref(), + &e2ee.device_lists, + &e2ee.device_one_time_keys_count, + e2ee.device_unused_fallback_key_types.as_deref(), ) .await? }; @@ -109,8 +80,8 @@ impl BaseClient { let mut changes = StateChanges::default(); let mut ambiguity_cache = AmbiguityCache::new(store.inner.clone()); - if let Some(global_data) = account_data.as_ref() { - self.handle_account_data(&global_data.global, &mut changes).await; + if !account_data.is_empty() { + self.handle_account_data(&account_data.global, &mut changes).await; } let push_rules = self.get_push_rules(&changes).await?; @@ -118,8 +89,7 @@ impl BaseClient { let mut new_rooms = Rooms::default(); for (room_id, room_data) in rooms { - if !room_data.invite_state.is_empty() { - let invite_states = &room_data.invite_state; + if let Some(invite_state) = &room_data.invite_state { let room = store.get_or_create_stripped_room(room_id).await; let mut room_info = room.clone_info(); room_info.mark_state_partially_synced(); @@ -131,11 +101,11 @@ impl BaseClient { changes.add_room(room_info); } - self.handle_invited_state(invite_states.as_slice(), &mut room_info, &mut changes); + self.handle_invited_state(invite_state.as_slice(), &mut room_info, &mut changes); new_rooms.invite.insert( room_id.clone(), - v3::InvitedRoom::from(v3::InviteState::from(invite_states.clone())), + v3::InvitedRoom::from(v3::InviteState::from(invite_state.clone())), ); } else { let room = store.get_or_create_room(room_id, RoomState::Joined).await; @@ -160,13 +130,9 @@ impl BaseClient { Default::default() }; - let room_account_data = if let Some(inner_account_data) = &account_data { - if let Some(events) = inner_account_data.rooms.get(room_id) { - self.handle_room_account_data(room_id, events, &mut changes).await; - Some(events.to_vec()) - } else { - None - } + let room_account_data = if let Some(events) = account_data.rooms.get(room_id) { + self.handle_room_account_data(room_id, events, &mut changes).await; + Some(events.to_vec()) } else { None }; @@ -225,11 +191,9 @@ impl BaseClient { } // Process receipts now we have rooms - if let Some(receipts) = &receipts { - for (room_id, receipt_edu) in &receipts.rooms { - if let Ok(receipt_edu) = receipt_edu.deserialize() { - changes.add_receipts(room_id, receipt_edu.content); - } + for (room_id, receipt_edu) in &receipts.rooms { + if let Ok(receipt_edu) = receipt_edu.deserialize() { + changes.add_receipts(room_id, receipt_edu.content); } } @@ -237,8 +201,8 @@ impl BaseClient { // because we want to have the push rules in place before we process // rooms and their events, but we want to create the rooms before we // process the `m.direct` account data event. - if let Some(global_data) = account_data.as_ref() { - self.handle_account_data(&global_data.global, &mut changes).await; + if !account_data.is_empty() { + self.handle_account_data(&account_data.global, &mut changes).await; } // FIXME not yet supported by sliding sync. @@ -260,7 +224,7 @@ impl BaseClient { debug!("applied changes"); let device_one_time_keys_count = - device_one_time_keys_count.iter().map(|(k, v)| (k.clone(), (*v).into())).collect(); + e2ee.device_one_time_keys_count.iter().map(|(k, v)| (k.clone(), (*v).into())).collect(); Ok(SyncResponse { rooms: new_rooms, @@ -268,9 +232,9 @@ impl BaseClient { notifications: changes.notifications, // FIXME not yet supported by sliding sync. presence: Default::default(), - account_data: account_data.as_ref().map(|a| a.global.clone()).unwrap_or_default(), + account_data: account_data.global.clone(), to_device_events, - device_lists, + device_lists: e2ee.device_lists.clone(), device_one_time_keys_count, }) } diff --git a/crates/matrix-sdk/src/sliding_sync/builder.rs b/crates/matrix-sdk/src/sliding_sync/builder.rs index 558a762aa..6086cb86f 100644 --- a/crates/matrix-sdk/src/sliding_sync/builder.rs +++ b/crates/matrix-sdk/src/sliding_sync/builder.rs @@ -10,7 +10,6 @@ use ruma::{ self, AccountDataConfig, E2EEConfig, ExtensionsConfig, ReceiptsConfig, ToDeviceConfig, TypingConfig, }, - assign, events::TimelineEventType, OwnedRoomId, }; @@ -85,17 +84,16 @@ impl SlidingSyncBuilder { pub fn with_common_extensions(mut self) -> Self { { let mut cfg = self.extensions.get_or_insert_with(Default::default); - if cfg.to_device.is_none() { - cfg.to_device = Some(assign!(ToDeviceConfig::default(), { enabled: Some(true) })); + if cfg.to_device.enabled.is_none() { + cfg.to_device.enabled = Some(true); } - if cfg.e2ee.is_none() { - cfg.e2ee = Some(assign!(E2EEConfig::default(), { enabled: Some(true) })); + if cfg.e2ee.enabled.is_none() { + cfg.e2ee.enabled = Some(true); } - if cfg.account_data.is_none() { - cfg.account_data = - Some(assign!(AccountDataConfig::default(), { enabled: Some(true) })); + if cfg.account_data.enabled.is_none() { + cfg.account_data.enabled = Some(true); } } self @@ -109,25 +107,24 @@ impl SlidingSyncBuilder { pub fn with_all_extensions(mut self) -> Self { { let mut cfg = self.extensions.get_or_insert_with(Default::default); - if cfg.to_device.is_none() { - cfg.to_device = Some(assign!(ToDeviceConfig::default(), { enabled: Some(true) })); + if cfg.to_device.enabled.is_none() { + cfg.to_device.enabled = Some(true); } - if cfg.e2ee.is_none() { - cfg.e2ee = Some(assign!(E2EEConfig::default(), { enabled: Some(true) })); + if cfg.e2ee.enabled.is_none() { + cfg.e2ee.enabled = Some(true); } - if cfg.account_data.is_none() { - cfg.account_data = - Some(assign!(AccountDataConfig::default(), { enabled: Some(true) })); + if cfg.account_data.enabled.is_none() { + cfg.account_data.enabled = Some(true); } - if cfg.receipts.is_none() { - cfg.receipts = Some(assign!(ReceiptsConfig::default(), { enabled: Some(true) })); + if cfg.receipts.enabled.is_none() { + cfg.receipts.enabled = Some(true); } - if cfg.typing.is_none() { - cfg.typing = Some(assign!(TypingConfig::default(), { enabled: Some(true) })); + if cfg.typing.enabled.is_none() { + cfg.typing.enabled = Some(true); } } self @@ -135,61 +132,62 @@ impl SlidingSyncBuilder { /// Set the E2EE extension configuration. pub fn with_e2ee_extension(mut self, e2ee: E2EEConfig) -> Self { - self.extensions.get_or_insert_with(Default::default).e2ee = Some(e2ee); + self.extensions.get_or_insert_with(Default::default).e2ee = e2ee; self } /// Unset the E2EE extension configuration. pub fn without_e2ee_extension(mut self) -> Self { - self.extensions.get_or_insert_with(Default::default).e2ee = None; + self.extensions.get_or_insert_with(Default::default).e2ee = E2EEConfig::default(); self } /// Set the ToDevice extension configuration. pub fn with_to_device_extension(mut self, to_device: ToDeviceConfig) -> Self { - self.extensions.get_or_insert_with(Default::default).to_device = Some(to_device); + self.extensions.get_or_insert_with(Default::default).to_device = to_device; self } /// Unset the ToDevice extension configuration. pub fn without_to_device_extension(mut self) -> Self { - self.extensions.get_or_insert_with(Default::default).to_device = None; + self.extensions.get_or_insert_with(Default::default).to_device = ToDeviceConfig::default(); self } /// Set the account data extension configuration. pub fn with_account_data_extension(mut self, account_data: AccountDataConfig) -> Self { - self.extensions.get_or_insert_with(Default::default).account_data = Some(account_data); + self.extensions.get_or_insert_with(Default::default).account_data = account_data; self } /// Unset the account data extension configuration. pub fn without_account_data_extension(mut self) -> Self { - self.extensions.get_or_insert_with(Default::default).account_data = None; + self.extensions.get_or_insert_with(Default::default).account_data = + AccountDataConfig::default(); self } /// Set the Typing extension configuration. pub fn with_typing_extension(mut self, typing: TypingConfig) -> Self { - self.extensions.get_or_insert_with(Default::default).typing = Some(typing); + self.extensions.get_or_insert_with(Default::default).typing = typing; self } /// Unset the Typing extension configuration. pub fn without_typing_extension(mut self) -> Self { - self.extensions.get_or_insert_with(Default::default).typing = None; + self.extensions.get_or_insert_with(Default::default).typing = TypingConfig::default(); self } /// Set the Receipt extension configuration. pub fn with_receipt_extension(mut self, receipt: ReceiptsConfig) -> Self { - self.extensions.get_or_insert_with(Default::default).receipts = Some(receipt); + self.extensions.get_or_insert_with(Default::default).receipts = receipt; self } /// Unset the Receipt extension configuration. pub fn without_receipt_extension(mut self) -> Self { - self.extensions.get_or_insert_with(Default::default).receipts = None; + self.extensions.get_or_insert_with(Default::default).receipts = ReceiptsConfig::default(); self } diff --git a/crates/matrix-sdk/src/sliding_sync/cache.rs b/crates/matrix-sdk/src/sliding_sync/cache.rs index 848d360f0..961c56895 100644 --- a/crates/matrix-sdk/src/sliding_sync/cache.rs +++ b/crates/matrix-sdk/src/sliding_sync/cache.rs @@ -174,9 +174,8 @@ pub(super) async fn restore_sliding_sync_state( // Let's update the `SlidingSync`. if let Some(since) = to_device_since { - if let Some(to_device_ext) = - extensions.get_or_insert_with(Default::default).to_device.as_mut() - { + let to_device_ext = &mut extensions.get_or_insert_with(Default::default).to_device; + if to_device_ext.enabled == Some(true) { to_device_ext.since = Some(since); } } diff --git a/crates/matrix-sdk/src/sliding_sync/mod.rs b/crates/matrix-sdk/src/sliding_sync/mod.rs index 2e4ff197c..0d9a96e70 100644 --- a/crates/matrix-sdk/src/sliding_sync/mod.rs +++ b/crates/matrix-sdk/src/sliding_sync/mod.rs @@ -45,9 +45,7 @@ pub use room::*; use ruma::{ api::client::{ error::ErrorKind, - sync::sync_events::v4::{ - self, AccountDataConfig, E2EEConfig, ExtensionsConfig, ToDeviceConfig, - }, + sync::sync_events::v4::{self, ExtensionsConfig}, }, assign, events::TimelineEventType, @@ -156,16 +154,16 @@ impl SlidingSync { let mut lock = self.inner.extensions.lock().unwrap(); let mut cfg = lock.get_or_insert_with(Default::default); - if cfg.to_device.is_none() { - cfg.to_device = Some(assign!(ToDeviceConfig::default(), { enabled: Some(true) })); + if cfg.to_device.enabled.is_none() { + cfg.to_device.enabled = Some(true); } - if cfg.e2ee.is_none() { - cfg.e2ee = Some(assign!(E2EEConfig::default(), { enabled: Some(true) })); + if cfg.e2ee.enabled.is_none() { + cfg.e2ee.enabled = Some(true); } - if cfg.account_data.is_none() { - cfg.account_data = Some(assign!(AccountDataConfig::default(), { enabled: Some(true) })); + if cfg.account_data.enabled.is_none() { + cfg.account_data.enabled = Some(false); } } @@ -189,7 +187,6 @@ impl SlidingSync { .unwrap() .get_or_insert_with(Default::default) .to_device - .get_or_insert_with(Default::default) .since = Some(since); } @@ -257,11 +254,8 @@ impl SlidingSync { // // The token is also loaded from storage in the `SlidingSyncBuilder::build()` // method. - let mut to_device = extensions.to_device.unwrap_or_default(); - to_device.enabled = Some(true); - - extensions.to_device = Some(to_device); - extensions.e2ee = Some(assign!(E2EEConfig::default(), { enabled: Some(true) })); + extensions.to_device.enabled = Some(true); + extensions.e2ee.enabled = Some(true); extensions } else { @@ -273,10 +267,10 @@ impl SlidingSync { .lock() .unwrap() .as_ref() - .and_then(|e| e.to_device.as_ref()?.since.to_owned()); + .and_then(|e| e.to_device.since.clone()); let mut extensions: ExtensionsConfig = Default::default(); - extensions.to_device = Some(assign!(ToDeviceConfig::default(), { since })); + extensions.to_device.since = since; extensions } @@ -642,7 +636,7 @@ impl From<&SlidingSync> for FrozenSlidingSync { .lock() .unwrap() .as_ref() - .and_then(|ext| ext.to_device.as_ref()?.since.clone()), + .and_then(|ext| ext.to_device.since.clone()), } } } @@ -660,6 +654,7 @@ pub struct UpdateSummary { #[cfg(test)] mod test { use assert_matches::assert_matches; + use ruma::api::client::sync::sync_events::v4::{E2EEConfig, ToDeviceConfig}; use wiremock::MockServer; use super::*; @@ -677,9 +672,9 @@ mod test { // e2ee anyways. assert_matches!( extensions.to_device, - Some(ToDeviceConfig { enabled: Some(true), since: None, .. }) + ToDeviceConfig { enabled: Some(true), since: None, .. } ); - assert_matches!(extensions.e2ee, Some(E2EEConfig { enabled: Some(true), .. })); + assert_matches!(extensions.e2ee, E2EEConfig { enabled: Some(true), .. }); let some_since = "some_since".to_owned(); sync.update_to_device_since(some_since.to_owned()); @@ -690,16 +685,16 @@ mod test { // stickyness. assert_matches!( extensions.to_device, - Some(ToDeviceConfig { enabled: None, since: Some(since), .. }) if since == some_since + ToDeviceConfig { enabled: None, since: Some(since), .. } if since == some_since ); - assert_matches!(extensions.e2ee, None); + assert_matches!(extensions.e2ee, E2EEConfig { enabled: None, .. }); let extensions = sync.prepare_extension_config(None); // Even if there isn't a `pos`, if we have a to-device `since` token, we put it // into the request. assert_matches!( extensions.to_device, - Some(ToDeviceConfig { enabled: Some(true), since: Some(since), .. }) if since == some_since + ToDeviceConfig { enabled: Some(true), since: Some(since), .. } if since == some_since ); Ok(()) diff --git a/crates/matrix-sdk/src/sliding_sync/room.rs b/crates/matrix-sdk/src/sliding_sync/room.rs index 879ab74f1..e182f0d5c 100644 --- a/crates/matrix-sdk/src/sliding_sync/room.rs +++ b/crates/matrix-sdk/src/sliding_sync/room.rs @@ -170,7 +170,7 @@ impl SlidingSyncRoom { self.inner.is_dm = is_dm; } - if !invite_state.is_empty() { + if invite_state.is_some() { self.inner.invite_state = invite_state; } From daf611b2901cf68554636568f2629429f9745b50 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 27 Apr 2023 18:50:20 +0200 Subject: [PATCH 20/27] base: Add spans to some medium to large BaseClient methods --- crates/matrix-sdk-base/src/client.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/matrix-sdk-base/src/client.rs b/crates/matrix-sdk-base/src/client.rs index 43ce5a473..3075eda19 100644 --- a/crates/matrix-sdk-base/src/client.rs +++ b/crates/matrix-sdk-base/src/client.rs @@ -54,7 +54,7 @@ use ruma::{ MilliSecondsSinceUnixEpoch, OwnedUserId, RoomId, UInt, UserId, }; use tokio::sync::RwLock; -use tracing::{debug, info, trace, warn}; +use tracing::{debug, info, instrument, trace, warn}; use crate::{ deserialized_responses::{AmbiguityChanges, MembersResponse, SyncTimelineEvent}, @@ -297,6 +297,7 @@ impl BaseClient { } #[allow(clippy::too_many_arguments)] + #[instrument(skip_all, fields(room_id = ?room_info.room_id))] pub(crate) async fn handle_timeline( &self, room: &Room, @@ -438,6 +439,7 @@ impl BaseClient { Ok(timeline) } + #[instrument(skip_all, fields(room_id = ?room_info.room_id))] pub(crate) fn handle_invited_state( &self, events: &[Raw], @@ -467,6 +469,7 @@ impl BaseClient { changes.stripped_state.insert(room_info.room_id().to_owned(), state_events); } + #[instrument(skip_all, fields(room_id = ?room_info.room_id))] pub(crate) async fn handle_state( &self, events: &[Raw], @@ -478,13 +481,11 @@ impl BaseClient { let mut user_ids = BTreeSet::new(); let mut profiles = BTreeMap::new(); - let room_id = room_info.room_id.clone(); - for raw_event in events { let event = match raw_event.deserialize() { - Ok(e) => e, + Ok(ev) => ev, Err(e) => { - warn!(?room_id, "Couldn't deserialize state event: {e:?}"); + warn!("Couldn't deserialize state event: {e}"); continue; } }; @@ -492,7 +493,7 @@ impl BaseClient { room_info.handle_state_event(&event); if let AnySyncStateEvent::RoomMember(member) = &event { - ambiguity_cache.handle_event(changes, &room_id, member).await?; + ambiguity_cache.handle_event(changes, &room_info.room_id, member).await?; match member.membership() { MembershipState::Join | MembershipState::Invite => { @@ -516,12 +517,13 @@ impl BaseClient { .insert(event.state_key().to_owned(), raw_event.clone()); } - changes.profiles.insert((*room_id).to_owned(), profiles); - changes.state.insert((*room_id).to_owned(), state_events); + changes.profiles.insert((*room_info.room_id).to_owned(), profiles); + changes.state.insert((*room_info.room_id).to_owned(), state_events); Ok(user_ids) } + #[instrument(skip_all, fields(?room_id))] pub(crate) async fn handle_room_account_data( &self, room_id: &RoomId, @@ -535,6 +537,7 @@ impl BaseClient { } } + #[instrument(skip_all)] pub(crate) async fn handle_account_data( &self, events: &[Raw], @@ -580,6 +583,7 @@ impl BaseClient { } #[cfg(feature = "e2e-encryption")] + #[instrument(skip_all)] pub(crate) async fn preprocess_to_device_events( &self, to_device_events: Vec>, @@ -656,6 +660,7 @@ impl BaseClient { /// # Arguments /// /// * `response` - The response that we received after a successful sync. + #[instrument(skip_all)] pub async fn receive_sync_response( &self, response: api::sync::sync_events::v3::Response, @@ -907,6 +912,7 @@ impl BaseClient { /// * `room_id` - The room id this response belongs to. /// /// * `response` - The raw response that was received from the server. + #[instrument(skip_all, fields(?room_id))] pub async fn receive_members( &self, room_id: &RoomId, From d7421b3f850c71b778557a7d253199d809a7548d Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 27 Apr 2023 18:51:34 +0200 Subject: [PATCH 21/27] base: Clean up ephemeral event handling Log deserialization failing, and visit all events (though there should never be two receipt events for one room in a single sync response). --- crates/matrix-sdk-base/src/client.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/crates/matrix-sdk-base/src/client.rs b/crates/matrix-sdk-base/src/client.rs index 3075eda19..8a2a512a6 100644 --- a/crates/matrix-sdk-base/src/client.rs +++ b/crates/matrix-sdk-base/src/client.rs @@ -725,13 +725,21 @@ impl BaseClient { ) .await?; - if let Some(event) = - new_info.ephemeral.events.iter().find_map(|e| match e.deserialize() { - Ok(AnySyncEphemeralRoomEvent::Receipt(event)) => Some(event.content), - _ => None, - }) - { - changes.add_receipts(&room_id, event); + for raw in &new_info.ephemeral.events { + match raw.deserialize() { + Ok(AnySyncEphemeralRoomEvent::Receipt(event)) => { + changes.add_receipts(&room_id, event.content); + } + Ok(_) => {} + Err(e) => { + let event_id: Option = raw.get_field("event_id").ok().flatten(); + #[rustfmt::skip] + info!( + ?room_id, event_id, + "Failed to deserialize ephemeral room event: {e}" + ); + } + } } if new_info.timeline.limited { From 7ef6accab8a54af16164803a3c36c6b5930ec78d Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 27 Apr 2023 18:51:53 +0200 Subject: [PATCH 22/27] base: Clean up sliding sync processing a bit --- crates/matrix-sdk-base/src/sliding_sync.rs | 23 +++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/crates/matrix-sdk-base/src/sliding_sync.rs b/crates/matrix-sdk-base/src/sliding_sync.rs index b4282f4f4..ce9abe51b 100644 --- a/crates/matrix-sdk-base/src/sliding_sync.rs +++ b/crates/matrix-sdk-base/src/sliding_sync.rs @@ -66,15 +66,14 @@ impl BaseClient { // the `OlmMachine` assumes empty maps/vecs mean no change in the one-time key // counts. #[cfg(feature = "e2e-encryption")] - let to_device_events = { - self.preprocess_to_device_events( + let to_device_events = self + .preprocess_to_device_events( to_device_events, &e2ee.device_lists, &e2ee.device_one_time_keys_count, e2ee.device_unused_fallback_key_types.as_deref(), ) - .await? - }; + .await?; let store = self.store.clone(); let mut changes = StateChanges::default(); @@ -191,9 +190,19 @@ impl BaseClient { } // Process receipts now we have rooms - for (room_id, receipt_edu) in &receipts.rooms { - if let Ok(receipt_edu) = receipt_edu.deserialize() { - changes.add_receipts(room_id, receipt_edu.content); + for (room_id, raw) in &receipts.rooms { + match raw.deserialize() { + Ok(event) => { + changes.add_receipts(room_id, event.content); + } + Err(e) => { + let event_id: Option = raw.get_field("event_id").ok().flatten(); + #[rustfmt::skip] + info!( + ?room_id, event_id, + "Failed to deserialize ephemeral room event: {e}" + ); + } } } From 396e0a3567c9f2ccddd5bc02bea8e4f390ae1c5a Mon Sep 17 00:00:00 2001 From: Simon Farre Date: Fri, 28 Apr 2023 17:58:41 +0200 Subject: [PATCH 23/27] Add "opaque interface declarations" Using the #[derive(uniffi::Object)] on certain types make them not show up in the .aar file when building for Android. Could not determine why that is, but removing the derive macro, and adding the empty interface declarations inside the UDL, makes them show up. We can still use #[uniffi::export] and #[uniffi::constructor]. Signed-off-by: Simon Farre --- bindings/matrix-sdk-ffi/src/api.udl | 4 ++++ bindings/matrix-sdk-ffi/src/authentication_service.rs | 1 - bindings/matrix-sdk-ffi/src/notification_service.rs | 1 - bindings/matrix-sdk-ffi/src/tracing.rs | 1 - 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/api.udl b/bindings/matrix-sdk-ffi/src/api.udl index dabf4c60d..76e2de280 100644 --- a/bindings/matrix-sdk-ffi/src/api.udl +++ b/bindings/matrix-sdk-ffi/src/api.udl @@ -8,6 +8,10 @@ callback interface NotificationDelegate { void did_receive_notification(NotificationItem notification); }; +interface AuthenticationService {}; +interface Span {}; +interface NotificationService {}; + dictionary NotificationItem { TimelineEvent event; string room_id; diff --git a/bindings/matrix-sdk-ffi/src/authentication_service.rs b/bindings/matrix-sdk-ffi/src/authentication_service.rs index fae7387d8..19aa92383 100644 --- a/bindings/matrix-sdk-ffi/src/authentication_service.rs +++ b/bindings/matrix-sdk-ffi/src/authentication_service.rs @@ -11,7 +11,6 @@ use zeroize::Zeroize; use super::{client::Client, client_builder::ClientBuilder, RUNTIME}; use crate::error::ClientError; -#[derive(uniffi::Object)] pub struct AuthenticationService { base_path: String, passphrase: Option, diff --git a/bindings/matrix-sdk-ffi/src/notification_service.rs b/bindings/matrix-sdk-ffi/src/notification_service.rs index 64f3d8977..16cf23fbf 100644 --- a/bindings/matrix-sdk-ffi/src/notification_service.rs +++ b/bindings/matrix-sdk-ffi/src/notification_service.rs @@ -51,7 +51,6 @@ impl NotificationItem { } #[allow(dead_code)] -#[derive(uniffi::Object)] pub struct NotificationService { base_path: String, user_id: String, diff --git a/bindings/matrix-sdk-ffi/src/tracing.rs b/bindings/matrix-sdk-ffi/src/tracing.rs index c530f33f3..d85ce08ee 100644 --- a/bindings/matrix-sdk-ffi/src/tracing.rs +++ b/bindings/matrix-sdk-ffi/src/tracing.rs @@ -95,7 +95,6 @@ fn span_or_event_enabled(callsite: &'static DefaultCallsite) -> bool { } } -#[derive(uniffi::Object)] pub struct Span(tracing::Span); #[uniffi::export] From 034aa04076c6d482837dbe5b9d4e712c0478b5ff Mon Sep 17 00:00:00 2001 From: Mauro <34335419+Velin92@users.noreply.github.com> Date: Fri, 28 Apr 2023 18:04:42 +0200 Subject: [PATCH 24/27] ffi: Add is_read field to NotificationItem --- bindings/matrix-sdk-ffi/src/api.udl | 1 + bindings/matrix-sdk-ffi/src/notification_service.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/bindings/matrix-sdk-ffi/src/api.udl b/bindings/matrix-sdk-ffi/src/api.udl index 76e2de280..bea96f275 100644 --- a/bindings/matrix-sdk-ffi/src/api.udl +++ b/bindings/matrix-sdk-ffi/src/api.udl @@ -22,6 +22,7 @@ dictionary NotificationItem { boolean is_noisy; boolean is_direct; boolean is_encrypted; + boolean is_read; }; interface TimelineEvent {}; diff --git a/bindings/matrix-sdk-ffi/src/notification_service.rs b/bindings/matrix-sdk-ffi/src/notification_service.rs index 16cf23fbf..caf6ceb6a 100644 --- a/bindings/matrix-sdk-ffi/src/notification_service.rs +++ b/bindings/matrix-sdk-ffi/src/notification_service.rs @@ -18,6 +18,7 @@ pub struct NotificationItem { pub is_noisy: bool, pub is_direct: bool, pub is_encrypted: bool, + pub is_read: bool, } impl NotificationItem { @@ -45,6 +46,7 @@ impl NotificationItem { is_noisy, is_direct: room.is_direct().await?, is_encrypted: room.is_encrypted().await?, + is_read: notification.read, }; Ok(item) } From 87b938b8fe823d9244e1f1d56f3081cab7c26815 Mon Sep 17 00:00:00 2001 From: Mauro <34335419+Velin92@users.noreply.github.com> Date: Tue, 2 May 2023 11:16:43 +0200 Subject: [PATCH 25/27] ffi: Add timestamp field to NotificationItem --- bindings/matrix-sdk-ffi/src/api.udl | 1 + bindings/matrix-sdk-ffi/src/notification_service.rs | 3 +++ crates/matrix-sdk/src/sliding_sync/builder.rs | 4 ++-- crates/matrix-sdk/src/sliding_sync/mod.rs | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/api.udl b/bindings/matrix-sdk-ffi/src/api.udl index bea96f275..38e8fdaa7 100644 --- a/bindings/matrix-sdk-ffi/src/api.udl +++ b/bindings/matrix-sdk-ffi/src/api.udl @@ -23,6 +23,7 @@ dictionary NotificationItem { boolean is_direct; boolean is_encrypted; boolean is_read; + u64 timestamp; }; interface TimelineEvent {}; diff --git a/bindings/matrix-sdk-ffi/src/notification_service.rs b/bindings/matrix-sdk-ffi/src/notification_service.rs index caf6ceb6a..462968682 100644 --- a/bindings/matrix-sdk-ffi/src/notification_service.rs +++ b/bindings/matrix-sdk-ffi/src/notification_service.rs @@ -19,6 +19,8 @@ pub struct NotificationItem { pub is_direct: bool, pub is_encrypted: bool, pub is_read: bool, + + pub timestamp: u64, } impl NotificationItem { @@ -47,6 +49,7 @@ impl NotificationItem { is_direct: room.is_direct().await?, is_encrypted: room.is_encrypted().await?, is_read: notification.read, + timestamp: notification.ts.0.into(), }; Ok(item) } diff --git a/crates/matrix-sdk/src/sliding_sync/builder.rs b/crates/matrix-sdk/src/sliding_sync/builder.rs index 6086cb86f..b263d5e48 100644 --- a/crates/matrix-sdk/src/sliding_sync/builder.rs +++ b/crates/matrix-sdk/src/sliding_sync/builder.rs @@ -83,7 +83,7 @@ impl SlidingSyncBuilder { /// does not matter. pub fn with_common_extensions(mut self) -> Self { { - let mut cfg = self.extensions.get_or_insert_with(Default::default); + let cfg = self.extensions.get_or_insert_with(Default::default); if cfg.to_device.enabled.is_none() { cfg.to_device.enabled = Some(true); } @@ -106,7 +106,7 @@ impl SlidingSyncBuilder { /// does not matter. pub fn with_all_extensions(mut self) -> Self { { - let mut cfg = self.extensions.get_or_insert_with(Default::default); + let cfg = self.extensions.get_or_insert_with(Default::default); if cfg.to_device.enabled.is_none() { cfg.to_device.enabled = Some(true); } diff --git a/crates/matrix-sdk/src/sliding_sync/mod.rs b/crates/matrix-sdk/src/sliding_sync/mod.rs index 0d9a96e70..583f43993 100644 --- a/crates/matrix-sdk/src/sliding_sync/mod.rs +++ b/crates/matrix-sdk/src/sliding_sync/mod.rs @@ -152,7 +152,7 @@ impl SlidingSync { /// Add the common extensions if not already configured. pub fn add_common_extensions(&self) { let mut lock = self.inner.extensions.lock().unwrap(); - let mut cfg = lock.get_or_insert_with(Default::default); + let cfg = lock.get_or_insert_with(Default::default); if cfg.to_device.enabled.is_none() { cfg.to_device.enabled = Some(true); From b9920ab477664bce5e72ad1e1a41bbfda2d5bc71 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Tue, 2 May 2023 11:35:44 +0200 Subject: [PATCH 26/27] bindings: Fix Wasm conversion into base64 --- bindings/matrix-sdk-crypto-js/scripts/build.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bindings/matrix-sdk-crypto-js/scripts/build.sh b/bindings/matrix-sdk-crypto-js/scripts/build.sh index f782a2b2e..2c3caeb5f 100755 --- a/bindings/matrix-sdk-crypto-js/scripts/build.sh +++ b/bindings/matrix-sdk-crypto-js/scripts/build.sh @@ -19,7 +19,11 @@ cd $(dirname "$0")/.. RUSTFLAGS='-C opt-level=z' WASM_BINDGEN_WEAKREF=1 wasm-pack build --target nodejs --scope matrix-org --out-dir pkg "${WASM_PACK_ARGS[@]}" # Convert the Wasm into a JS file that exports the base64'ed Wasm. -echo "module.exports = \`$(base64 pkg/matrix_sdk_crypto_js_bg.wasm)\`;" > pkg/matrix_sdk_crypto_js_bg.wasm.js +{ + printf 'module.exports = `' + base64 < pkg/matrix_sdk_crypto_js_bg.wasm + printf '`;' +} > pkg/matrix_sdk_crypto_js_bg.wasm.js # In the JavaScript: # 1. Strip out the lines that load the WASM, and our new epilogue. From 8f332fddc2f3bf9201db12dae4c5433aa614185f Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Tue, 2 May 2023 10:42:16 +0100 Subject: [PATCH 27/27] crypto-js: Make `importCrossSigningKeys` take strings (#1843) Currently this takes a `CrossSigningKeyExport`, but that's not a class you can construct from the JS side. Instead, let's just pass in the individual keys. --- bindings/matrix-sdk-crypto-js/CHANGELOG.md | 4 ++- bindings/matrix-sdk-crypto-js/src/machine.rs | 26 ++++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/bindings/matrix-sdk-crypto-js/CHANGELOG.md b/bindings/matrix-sdk-crypto-js/CHANGELOG.md index f5563d8e3..c6963648c 100644 --- a/bindings/matrix-sdk-crypto-js/CHANGELOG.md +++ b/bindings/matrix-sdk-crypto-js/CHANGELOG.md @@ -1,6 +1,8 @@ # v0.1.0-alpha.8 -- Make `unused_fallback_keys` as optional in `Machine.receive_sync_changes` +- `importCrossSigningKeys`: change the parameters to be individual keys + rather than a `CrossSigningKeyExport` object. +- Make `unused_fallback_keys` optional in `Machine.receive_sync_changes` # v0.1.0-alpha.7 diff --git a/bindings/matrix-sdk-crypto-js/src/machine.rs b/bindings/matrix-sdk-crypto-js/src/machine.rs index 82f1e290c..a73c87abb 100644 --- a/bindings/matrix-sdk-crypto-js/src/machine.rs +++ b/bindings/matrix-sdk-crypto-js/src/machine.rs @@ -397,11 +397,11 @@ impl OlmMachine { /// Export all the private cross signing keys we have. /// - /// The export will contain the seed for the ed25519 keys as a - /// unpadded base64 encoded string. + /// The export will contain the seeds for the ed25519 keys as + /// unpadded base64 encoded strings. /// - /// This method returns None if we don’t have any private cross - /// signing keys. + /// Returns `null` if we don’t have any private cross signing keys; + /// otherwise returns a `CrossSigningKeyExport`. #[wasm_bindgen(js_name = "exportCrossSigningKeys")] pub fn export_cross_signing_keys(&self) -> Promise { let me = self.inner.clone(); @@ -413,12 +413,22 @@ impl OlmMachine { /// Import our private cross signing keys. /// - /// The export needs to contain the seed for the ed25519 keys as - /// an unpadded base64 encoded string. + /// The keys should be provided as unpadded-base64-encoded strings. + /// + /// Returns a `CrossSigningStatus`. #[wasm_bindgen(js_name = "importCrossSigningKeys")] - pub fn import_cross_signing_keys(&self, export: store::CrossSigningKeyExport) -> Promise { + pub fn import_cross_signing_keys( + &self, + master_key: Option, + self_signing_key: Option, + user_signing_key: Option, + ) -> Promise { let me = self.inner.clone(); - let export = export.inner; + let export = matrix_sdk_crypto::store::CrossSigningKeyExport { + master_key, + self_signing_key, + user_signing_key, + }; future_to_promise(async move { Ok(me.import_cross_signing_keys(export).await.map(olm::CrossSigningStatus::from)?)