From dfef64f00e81554e15ead8c9590efe4d1b3c9812 Mon Sep 17 00:00:00 2001 From: cameronvoell Date: Thu, 5 Sep 2024 06:09:06 -0700 Subject: [PATCH 1/8] bindings create_dm function --- bindings_ffi/src/mls.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 8f4a4121b..9df2afff4 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -732,6 +732,26 @@ impl FfiConversations { Ok(out) } + pub async fn create_dm( + &self, + target_inbox_id: String, + ) -> Result, GenericError> { + log::info!( + "creating dm with target inbox id: {}", + target_inbox_id + ); + + let convo = self.inner_client.create_dm(target_inbox_id)?; + + let out = Arc::new(FfiGroup { + inner_client: self.inner_client.clone(), + group_id: convo.group_id, + created_at_ns: convo.created_at_ns, + }); + + Ok(out) + } + pub async fn process_streamed_welcome_message( &self, envelope_bytes: Vec, From fcbe3f0aa99a3665b5caecd2de175b360a667171 Mon Sep 17 00:00:00 2001 From: cameronvoell Date: Tue, 10 Sep 2024 08:32:33 -0700 Subject: [PATCH 2/8] find groups by default does not include dm groups --- bindings_ffi/src/mls.rs | 68 ++++++++++++++----- bindings_node/src/conversations.rs | 13 ++-- examples/cli/cli-client.rs | 3 +- .../down.sql | 3 + .../up.sql | 3 + xmtp_mls/src/client.rs | 63 +++++++++++++---- xmtp_mls/src/groups/group_metadata.rs | 17 +++-- xmtp_mls/src/groups/group_mutable_metadata.rs | 2 +- xmtp_mls/src/groups/group_permissions.rs | 17 +++-- xmtp_mls/src/groups/message_history.rs | 8 +-- xmtp_mls/src/groups/mod.rs | 62 ++++++++++------- xmtp_mls/src/storage/encrypted_store/group.rs | 49 +++++++++++-- .../storage/encrypted_store/group_intent.rs | 1 + xmtp_mls/src/storage/encrypted_store/mod.rs | 2 + .../src/storage/encrypted_store/schema.rs | 1 + xmtp_mls/src/subscriptions.rs | 2 +- 16 files changed, 229 insertions(+), 85 deletions(-) create mode 100644 xmtp_mls/migrations/2024-09-09-231735_create_dm_inbox_id/down.sql create mode 100644 xmtp_mls/migrations/2024-09-09-231735_create_dm_inbox_id/up.sql diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 9df2afff4..080c8295f 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -15,6 +15,7 @@ use xmtp_id::{ }, InboxId, }; +use xmtp_mls::client::FindGroupParams; use xmtp_mls::groups::group_mutable_metadata::MetadataField; use xmtp_mls::groups::group_permissions::BasePolicies; use xmtp_mls::groups::group_permissions::GroupMutablePermissionsError; @@ -732,16 +733,10 @@ impl FfiConversations { Ok(out) } - pub async fn create_dm( - &self, - target_inbox_id: String, - ) -> Result, GenericError> { - log::info!( - "creating dm with target inbox id: {}", - target_inbox_id - ); + pub async fn create_dm(&self, account_address: String) -> Result, GenericError> { + log::info!("creating dm with target address: {}", account_address); - let convo = self.inner_client.create_dm(target_inbox_id)?; + let convo = self.inner_client.create_dm(account_address).await?; let out = Arc::new(FfiGroup { inner_client: self.inner_client.clone(), @@ -776,7 +771,16 @@ impl FfiConversations { pub async fn sync_all_groups(&self) -> Result { let inner = self.inner_client.as_ref(); - let groups = inner.find_groups(None, None, None, None)?; + let groups = inner.find_groups(FindGroupParams { + include_dm_groups: true, + ..FindGroupParams::default() + })?; + + println!( + "groups for client inbox id {:?}: {:?}", + self.inner_client.inbox_id(), + groups.len() + ); let num_groups_synced: usize = inner.sync_all_groups(groups).await?; // Uniffi does not work with usize, so we need to convert to u32 @@ -796,12 +800,12 @@ impl FfiConversations { ) -> Result>, GenericError> { let inner = self.inner_client.as_ref(); let convo_list: Vec> = inner - .find_groups( - None, - opts.created_after_ns, - opts.created_before_ns, - opts.limit, - )? + .find_groups(FindGroupParams { + created_after_ns: opts.created_after_ns, + created_before_ns: opts.created_before_ns, + limit: opts.limit, + ..FindGroupParams::default() + })? .into_iter() .map(|group| { Arc::new(FfiGroup { @@ -3593,4 +3597,36 @@ mod tests { client_1.installation_id() ); } + + #[tokio::test(flavor = "multi_thread", worker_threads = 5)] + #[ignore] + async fn test_dms_sync_but_do_not_list() { + let alix = new_test_client().await; + let bola = new_test_client().await; + + let alix_conversations = alix.conversations(); + let bola_conversations = bola.conversations(); + + let alix_group = alix_conversations + .create_dm(bola.account_address.clone()) + .await + .unwrap(); + let alix_num_sync = alix_conversations.sync_all_groups().await.unwrap(); + bola_conversations.sync().await.unwrap(); + let bola_num_sync = bola_conversations.sync_all_groups().await.unwrap(); + assert_eq!(alix_num_sync, 1); + assert_eq!(bola_num_sync, 1); + + let alix_groups = alix_conversations + .list(FfiListConversationsOptions::default()) + .await + .unwrap(); + assert_eq!(alix_groups.len(), 0); + + let bola_groups = bola_conversations + .list(FfiListConversationsOptions::default()) + .await + .unwrap(); + assert_eq!(bola_groups.len(), 0); + } } diff --git a/bindings_node/src/conversations.rs b/bindings_node/src/conversations.rs index 21a5dae60..c1af59d06 100644 --- a/bindings_node/src/conversations.rs +++ b/bindings_node/src/conversations.rs @@ -6,6 +6,7 @@ use napi::bindgen_prelude::{Error, Result, Uint8Array}; use napi::threadsafe_function::{ErrorStrategy, ThreadsafeFunction, ThreadsafeFunctionCallMode}; use napi::JsFunction; use napi_derive::napi; +use xmtp_mls::client::FindGroupParams; use xmtp_mls::groups::{GroupMetadataOptions, PreconfiguredPolicies}; use crate::messages::NapiMessage; @@ -165,12 +166,12 @@ impl NapiConversations { }; let convo_list: Vec = self .inner_client - .find_groups( - None, - opts.created_after_ns, - opts.created_before_ns, - opts.limit, - ) + .find_groups( FindGroupParams { + created_after_ns: opts.created_after_ns, + created_before_ns: opts.created_before_ns, + limit: opts.limit, + ..FindGroupParams::default() + }) .map_err(|e| Error::from_reason(format!("{}", e)))? .into_iter() .map(|group| { diff --git a/examples/cli/cli-client.rs b/examples/cli/cli-client.rs index 2319916ec..fabbf3302 100755 --- a/examples/cli/cli-client.rs +++ b/examples/cli/cli-client.rs @@ -18,6 +18,7 @@ use ethers::signers::{coins_bip39::English, LocalWallet, MnemonicBuilder}; use kv_log_macro::{error, info}; use prost::Message; use xmtp_id::associations::RecoverableEcdsaSignature; +use xmtp_mls::client::FindGroupParams; use xmtp_mls::groups::message_history::MessageHistoryContent; use xmtp_mls::storage::group_message::GroupMessageKind; @@ -208,7 +209,7 @@ async fn main() { // recv(&client).await.unwrap(); let group_list = client - .find_groups(None, None, None, None) + .find_groups(FindGroupParams::default()) .expect("failed to list groups"); for group in group_list.iter() { group.sync(&client).await.expect("error syncing group"); diff --git a/xmtp_mls/migrations/2024-09-09-231735_create_dm_inbox_id/down.sql b/xmtp_mls/migrations/2024-09-09-231735_create_dm_inbox_id/down.sql new file mode 100644 index 000000000..2dbbf5787 --- /dev/null +++ b/xmtp_mls/migrations/2024-09-09-231735_create_dm_inbox_id/down.sql @@ -0,0 +1,3 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE groups DROP COLUMN dm_inbox_id; +DROP INDEX idx_dm_target; diff --git a/xmtp_mls/migrations/2024-09-09-231735_create_dm_inbox_id/up.sql b/xmtp_mls/migrations/2024-09-09-231735_create_dm_inbox_id/up.sql new file mode 100644 index 000000000..6614f371a --- /dev/null +++ b/xmtp_mls/migrations/2024-09-09-231735_create_dm_inbox_id/up.sql @@ -0,0 +1,3 @@ +-- Your SQL goes here +ALTER TABLE groups ADD COLUMN dm_inbox_id text; +CREATE INDEX idx_dm_target ON groups(dm_inbox_id); diff --git a/xmtp_mls/src/client.rs b/xmtp_mls/src/client.rs index 9e8903aeb..66da7bb7f 100644 --- a/xmtp_mls/src/client.rs +++ b/xmtp_mls/src/client.rs @@ -214,6 +214,15 @@ impl From<&str> for ClientError { } } +#[derive(Debug, Default)] +pub struct FindGroupParams { + pub allowed_states: Option>, + pub created_after_ns: Option, + pub created_before_ns: Option, + pub limit: Option, + pub include_dm_groups: bool, +} + /// Clients manage access to the network, identity, and data store #[derive(Debug)] pub struct Client { @@ -404,15 +413,42 @@ where } /// Create a new Direct Message with the default settings - pub fn create_dm(&self, dm_target_inbox_id: InboxId) -> Result { + pub async fn create_dm(&self, account_address: String) -> Result { + log::info!("creating dm with address: {}", account_address); + + let inbox_id = match self + .find_inbox_id_from_address(account_address.clone()) + .await? + { + Some(id) => id, + None => { + return Err(ClientError::Storage(StorageError::NotFound(format!( + "inbox id for address {} not found", + account_address + )))) + } + }; + + self.create_dm_by_inbox_id(inbox_id).await + } + + /// Create a new Direct Message with the default settings + pub async fn create_dm_by_inbox_id( + &self, + dm_target_inbox_id: InboxId, + ) -> Result { log::info!("creating dm with {}", dm_target_inbox_id); let group = MlsGroup::create_dm_and_insert( self.context.clone(), GroupMembershipState::Allowed, - dm_target_inbox_id, + dm_target_inbox_id.clone(), )?; + group + .add_members_by_inbox_id(self, vec![dm_target_inbox_id]) + .await?; + // notify any streams of the new group let _ = self.local_events.send(LocalEvents::NewGroup(group.clone())); @@ -465,17 +501,17 @@ where /// - created_after_ns: only return groups created after the given timestamp (in nanoseconds) /// - created_before_ns: only return groups created before the given timestamp (in nanoseconds) /// - limit: only return the first `limit` groups - pub fn find_groups( - &self, - allowed_states: Option>, - created_after_ns: Option, - created_before_ns: Option, - limit: Option, - ) -> Result, ClientError> { + pub fn find_groups(&self, params: FindGroupParams) -> Result, ClientError> { Ok(self .store() .conn()? - .find_groups(allowed_states, created_after_ns, created_before_ns, limit)? + .find_groups( + params.allowed_states, + params.created_after_ns, + params.created_before_ns, + params.limit, + params.include_dm_groups, + )? .into_iter() .map(|stored_group| { MlsGroup::new( @@ -768,6 +804,7 @@ mod tests { use crate::{ builder::ClientBuilder, + client::FindGroupParams, groups::GroupMetadataOptions, hpke::{decrypt_welcome, encrypt_welcome}, }; @@ -835,7 +872,7 @@ mod tests { .create_group(None, GroupMetadataOptions::default()) .unwrap(); - let groups = client.find_groups(None, None, None, None).unwrap(); + let groups = client.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(groups.len(), 2); assert_eq!(groups[0].group_id, group_1.group_id); assert_eq!(groups[1].group_id, group_2.group_id); @@ -901,7 +938,7 @@ mod tests { let bob_received_groups = bo.sync_welcomes().await.unwrap(); assert_eq!(bob_received_groups.len(), 2); - let bo_groups = bo.find_groups(None, None, None, None).unwrap(); + let bo_groups = bo.find_groups(FindGroupParams::default()).unwrap(); let bo_group1 = bo.group(alix_bo_group1.clone().group_id).unwrap(); let bo_messages1 = bo_group1 .find_messages(None, None, None, None, None) @@ -1006,7 +1043,7 @@ mod tests { log::info!("Syncing bolas welcomes"); // See if Bola can see that they were added to the group bola.sync_welcomes().await.unwrap(); - let bola_groups = bola.find_groups(None, None, None, None).unwrap(); + let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); let bola_group = bola_groups.first().unwrap(); log::info!("Syncing bolas messages"); diff --git a/xmtp_mls/src/groups/group_metadata.rs b/xmtp_mls/src/groups/group_metadata.rs index 781ab0f49..4cf7cbea1 100644 --- a/xmtp_mls/src/groups/group_metadata.rs +++ b/xmtp_mls/src/groups/group_metadata.rs @@ -17,6 +17,8 @@ pub enum GroupMetadataError { InvalidConversationType, #[error("missing extension")] MissingExtension, + #[error("invalid dm members")] + InvalidDmMembers, } #[derive(Debug, Clone, PartialEq)] @@ -72,11 +74,12 @@ impl TryFrom for GroupMetadata { type Error = GroupMetadataError; fn try_from(value: GroupMetadataProto) -> Result { - let dm_members = if value.dm_members.is_some() { - Some(DmMembers::try_from(value.dm_members.unwrap())?) + let dm_members = if let Some(dm_members) = value.dm_members { + Some(DmMembers::try_from(dm_members)?) } else { None }; + Ok(Self::new( value.conversation_type.try_into()?, value.creator_inbox_id.clone(), @@ -150,8 +153,14 @@ impl TryFrom for DmMembers { fn try_from(value: DmMembersProto) -> Result { Ok(Self { - member_one_inbox_id: value.dm_member_one.unwrap().inbox_id.clone(), - member_two_inbox_id: value.dm_member_two.unwrap().inbox_id.clone(), + member_one_inbox_id: value + .dm_member_one + .ok_or(GroupMetadataError::InvalidDmMembers)? + .inbox_id, + member_two_inbox_id: value + .dm_member_two + .ok_or(GroupMetadataError::InvalidDmMembers)? + .inbox_id, }) } } diff --git a/xmtp_mls/src/groups/group_mutable_metadata.rs b/xmtp_mls/src/groups/group_mutable_metadata.rs index b97c14c0e..13a91aa42 100644 --- a/xmtp_mls/src/groups/group_mutable_metadata.rs +++ b/xmtp_mls/src/groups/group_mutable_metadata.rs @@ -114,7 +114,7 @@ impl GroupMutableMetadata { } // Admin / super admin is not needed for a DM - pub fn new_dm_default(_creator_inbox_id: String, _dm_target_inbox_id: String) -> Self { + pub fn new_dm_default(_creator_inbox_id: String, _dm_target_inbox_id: &str) -> Self { let mut attributes = HashMap::new(); // TODO: would it be helpful to incorporate the dm inbox ids in the name or description? attributes.insert( diff --git a/xmtp_mls/src/groups/group_permissions.rs b/xmtp_mls/src/groups/group_permissions.rs index 43c331ba4..0f8dd1d42 100644 --- a/xmtp_mls/src/groups/group_permissions.rs +++ b/xmtp_mls/src/groups/group_permissions.rs @@ -863,15 +863,14 @@ impl PolicySet { ); // We can always add DM member's inboxId to a DM - if commit.dm_members.is_some() - && commit.added_inboxes.len() == 1 - && (commit.added_inboxes[0].inbox_id - == commit.dm_members.as_ref().unwrap().member_one_inbox_id - || commit.added_inboxes[0].inbox_id - == commit.dm_members.as_ref().unwrap().member_two_inbox_id) - && commit.added_inboxes[0].inbox_id != commit.actor_inbox_id() - { - added_inboxes_valid = true; + if let Some(dm_members) = &commit.dm_members { + if commit.added_inboxes.len() == 1 + && (commit.added_inboxes[0].inbox_id == dm_members.member_one_inbox_id + || commit.added_inboxes[0].inbox_id == dm_members.member_two_inbox_id) + && commit.added_inboxes[0].inbox_id != commit.actor_inbox_id() + { + added_inboxes_valid = true; + } } // Verify remove member policy was not violated diff --git a/xmtp_mls/src/groups/message_history.rs b/xmtp_mls/src/groups/message_history.rs index 0f0768397..86aaca7ba 100644 --- a/xmtp_mls/src/groups/message_history.rs +++ b/xmtp_mls/src/groups/message_history.rs @@ -135,7 +135,7 @@ where pub async fn ensure_member_of_all_groups(&self, inbox_id: String) -> Result<(), GroupError> { let conn = self.store().conn()?; - let groups = conn.find_groups(None, None, None, None)?; + let groups = conn.find_groups(None, None, None, None, false)?; for group in groups { let group = self.group(group.id)?; Box::pin(group.add_members_by_inbox_id(self, vec![inbox_id.clone()])).await?; @@ -384,7 +384,7 @@ where self.sync_welcomes().await?; let conn = self.store().conn()?; - let groups = conn.find_groups(None, None, None, None)?; + let groups = conn.find_groups(None, None, None, None, false)?; for crate::storage::group::StoredGroup { id, .. } in groups.into_iter() { let group = self.group(id)?; Box::pin(group.sync(self)).await?; @@ -502,14 +502,14 @@ where async fn prepare_groups_to_sync(&self) -> Result, MessageHistoryError> { let conn = self.store().conn()?; - Ok(conn.find_groups(None, None, None, None)?) + Ok(conn.find_groups(None, None, None, None, false)?) } async fn prepare_messages_to_sync( &self, ) -> Result, MessageHistoryError> { let conn = self.store().conn()?; - let groups = conn.find_groups(None, None, None, None)?; + let groups = conn.find_groups(None, None, None, None, false)?; let mut all_messages: Vec = vec![]; for StoredGroup { id, .. } in groups.into_iter() { diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index f7727a49c..4a013582b 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -319,6 +319,7 @@ impl MlsGroup { now_ns(), membership_state, context.inbox_id(), + None, ); stored_group.store(provider.conn_ref())?; @@ -340,7 +341,7 @@ impl MlsGroup { let protected_metadata = build_dm_protected_metadata_extension(&context.identity, dm_target_inbox_id.clone())?; let mutable_metadata = - build_dm_mutable_metadata_extension_default(context.inbox_id(), dm_target_inbox_id)?; + build_dm_mutable_metadata_extension_default(context.inbox_id(), &dm_target_inbox_id)?; let group_membership = build_starting_group_membership_extension(context.inbox_id(), 0); let mutable_permissions = PolicySet::new_dm(); let mutable_permission_extension = @@ -368,6 +369,7 @@ impl MlsGroup { now_ns(), membership_state, context.inbox_id(), + Some(dm_target_inbox_id), ); stored_group.store(provider.conn_ref())?; @@ -393,6 +395,16 @@ impl MlsGroup { let mls_group = mls_welcome.into_group(provider)?; let group_id = mls_group.group_id().to_vec(); let metadata = extract_group_metadata(&mls_group)?; + let dm_members = metadata.dm_members; + let dm_inbox_id = if let Some(dm_members) = &dm_members { + if dm_members.member_one_inbox_id == client.inbox_id() { + Some(dm_members.member_two_inbox_id.clone()) + } else { + Some(dm_members.member_one_inbox_id.clone()) + } + } else { + None + }; let group_type = metadata.conversation_type; let to_store = match group_type { @@ -403,6 +415,7 @@ impl MlsGroup { added_by_inbox, welcome_id, Purpose::Conversation, + dm_inbox_id, ), ConversationType::Sync => StoredGroup::new_from_welcome( group_id.clone(), @@ -411,6 +424,7 @@ impl MlsGroup { added_by_inbox, welcome_id, Purpose::Sync, + dm_inbox_id, ), }; @@ -1111,7 +1125,7 @@ pub fn build_mutable_metadata_extension_default( pub fn build_dm_mutable_metadata_extension_default( creator_inbox_id: String, - dm_target_inbox_id: String, + dm_target_inbox_id: &str, ) -> Result { let mutable_metadata: Vec = GroupMutableMetadata::new_dm_default(creator_inbox_id, dm_target_inbox_id).try_into()?; @@ -1371,7 +1385,7 @@ mod tests { use crate::{ assert_err, assert_logged, builder::ClientBuilder, - client::MessageProcessingError, + client::{FindGroupParams, MessageProcessingError}, codecs::{group_updated::GroupUpdatedCodec, ContentCodec}, groups::{ build_group_membership_extension, @@ -1400,7 +1414,7 @@ mod tests { ApiClient: XmtpApi, { client.sync_welcomes().await.unwrap(); - let mut groups = client.find_groups(None, None, None, None).unwrap(); + let mut groups = client.find_groups(FindGroupParams::default()).unwrap(); groups.remove(0) } @@ -1712,7 +1726,7 @@ mod tests { // Bo should not be able to actually read this group bo.sync_welcomes().await.unwrap(); - let groups = bo.find_groups(None, None, None, None).unwrap(); + let groups = bo.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(groups.len(), 0); assert_logged!("failed to create group from welcome", 1); } @@ -1840,7 +1854,7 @@ mod tests { .expect("send message"); bola_client.sync_welcomes().await.unwrap(); - let bola_groups = bola_client.find_groups(None, None, None, None).unwrap(); + let bola_groups = bola_client.find_groups(FindGroupParams::default()).unwrap(); let bola_group = bola_groups.first().unwrap(); bola_group.sync(&bola_client).await.unwrap(); let bola_messages = bola_group @@ -2191,7 +2205,7 @@ mod tests { .await .unwrap(); bola.sync_welcomes().await.unwrap(); - let bola_groups = bola.find_groups(None, None, None, None).unwrap(); + let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); let bola_group = bola_groups.first().unwrap(); bola_group.sync(&bola).await.unwrap(); @@ -2359,7 +2373,7 @@ mod tests { .await .unwrap(); bola.sync_welcomes().await.unwrap(); - let bola_groups = bola.find_groups(None, None, None, None).unwrap(); + let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); let bola_group = bola_groups.first().unwrap(); bola_group.sync(&bola).await.unwrap(); @@ -2438,7 +2452,7 @@ mod tests { .await .unwrap(); bola.sync_welcomes().await.unwrap(); - let bola_groups = bola.find_groups(None, None, None, None).unwrap(); + let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); let bola_group = bola_groups.first().unwrap(); bola_group.sync(&bola).await.unwrap(); @@ -2454,7 +2468,7 @@ mod tests { // Verify that bola can not add caro because they are not an admin bola.sync_welcomes().await.unwrap(); - let bola_groups = bola.find_groups(None, None, None, None).unwrap(); + let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); let bola_group: &MlsGroup = bola_groups.first().unwrap(); bola_group.sync(&bola).await.unwrap(); @@ -2518,7 +2532,7 @@ mod tests { // Verify that bola can not add charlie because they are not an admin bola.sync_welcomes().await.unwrap(); - let bola_groups = bola.find_groups(None, None, None, None).unwrap(); + let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); let bola_group: &MlsGroup = bola_groups.first().unwrap(); bola_group.sync(&bola).await.unwrap(); @@ -2546,7 +2560,7 @@ mod tests { .await .unwrap(); bola.sync_welcomes().await.unwrap(); - let bola_groups = bola.find_groups(None, None, None, None).unwrap(); + let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); let bola_group = bola_groups.first().unwrap(); bola_group.sync(&bola).await.unwrap(); @@ -2562,7 +2576,7 @@ mod tests { // Verify that bola can not add caro as an admin because they are not a super admin bola.sync_welcomes().await.unwrap(); - let bola_groups = bola.find_groups(None, None, None, None).unwrap(); + let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); assert_eq!(bola_groups.len(), 1); let bola_group: &MlsGroup = bola_groups.first().unwrap(); bola_group.sync(&bola).await.unwrap(); @@ -2809,7 +2823,7 @@ mod tests { // Step 3: Verify that Bola can update the group name, and amal sees the update bola.sync_welcomes().await.unwrap(); - let bola_groups = bola.find_groups(None, None, None, None).unwrap(); + let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); let bola_group: &MlsGroup = bola_groups.first().unwrap(); bola_group.sync(&bola).await.unwrap(); bola_group @@ -2874,7 +2888,7 @@ mod tests { // Step 3: Bola attemps to add Caro, but fails because group is admin only let caro = ClientBuilder::new_test_client(&generate_local_wallet()).await; bola.sync_welcomes().await.unwrap(); - let bola_groups = bola.find_groups(None, None, None, None).unwrap(); + let bola_groups = bola.find_groups(FindGroupParams::default()).unwrap(); let bola_group: &MlsGroup = bola_groups.first().unwrap(); bola_group.sync(&bola).await.unwrap(); let result = bola_group @@ -3018,7 +3032,7 @@ mod tests { let caro = ClientBuilder::new_test_client(&generate_local_wallet()).await; // Amal creates a dm group targetting bola - let amal_dm: MlsGroup = amal.create_dm(bola.inbox_id()).unwrap(); + let amal_dm: MlsGroup = amal.create_dm_by_inbox_id(bola.inbox_id()).await.unwrap(); // Amal can not add caro to the dm group let result = amal_dm @@ -3029,22 +3043,20 @@ mod tests { .add_members_by_inbox_id(&amal, vec![caro.inbox_id()]) .await; assert!(result.is_err()); - amal_dm.sync(&amal).await.unwrap(); - let members = amal_dm.members().unwrap(); - assert_eq!(members.len(), 1); - // Amal can add bola - amal_dm - .add_members_by_inbox_id(&amal, vec![bola.inbox_id()]) - .await - .unwrap(); + // Bola is already a member amal_dm.sync(&amal).await.unwrap(); let members = amal_dm.members().unwrap(); assert_eq!(members.len(), 2); // Bola can message amal let _ = bola.sync_welcomes().await; - let bola_groups = bola.find_groups(None, None, None, None).unwrap(); + let bola_groups = bola + .find_groups(FindGroupParams { + include_dm_groups: true, + ..FindGroupParams::default() + }) + .unwrap(); let bola_dm: &MlsGroup = bola_groups.first().unwrap(); bola_dm.send_message(b"test one", &bola).await.unwrap(); diff --git a/xmtp_mls/src/storage/encrypted_store/group.rs b/xmtp_mls/src/storage/encrypted_store/group.rs index d5516e7ec..b68e61e11 100644 --- a/xmtp_mls/src/storage/encrypted_store/group.rs +++ b/xmtp_mls/src/storage/encrypted_store/group.rs @@ -39,6 +39,8 @@ pub struct StoredGroup { pub added_by_inbox_id: String, /// The sequence id of the welcome message pub welcome_id: Option, + /// The inbox_id of the DM target + pub dm_inbox_id: Option, } impl_fetch!(StoredGroup, groups, Vec); @@ -53,6 +55,7 @@ impl StoredGroup { added_by_inbox_id: String, welcome_id: i64, purpose: Purpose, + dm_inbox_id: Option, ) -> Self { Self { id, @@ -62,6 +65,7 @@ impl StoredGroup { purpose, added_by_inbox_id, welcome_id: Some(welcome_id), + dm_inbox_id, } } @@ -71,6 +75,7 @@ impl StoredGroup { created_at_ns: i64, membership_state: GroupMembershipState, added_by_inbox_id: String, + dm_inbox_id: Option, ) -> Self { Self { id, @@ -80,6 +85,7 @@ impl StoredGroup { purpose: Purpose::Conversation, added_by_inbox_id, welcome_id: None, + dm_inbox_id, } } @@ -98,6 +104,7 @@ impl StoredGroup { purpose: Purpose::Sync, added_by_inbox_id: "".into(), welcome_id: None, + dm_inbox_id: None, } } } @@ -110,6 +117,7 @@ impl DbConnection { created_after_ns: Option, created_before_ns: Option, limit: Option, + include_dm_groups: bool, ) -> Result, StorageError> { let mut query = dsl::groups.order(dsl::created_at_ns.asc()).into_boxed(); @@ -129,6 +137,10 @@ impl DbConnection { query = query.limit(limit); } + if !include_dm_groups { + query = query.filter(dsl::dm_inbox_id.is_null()); + } + query = query.filter(dsl::purpose.eq(Purpose::Conversation)); Ok(self.raw_query(|conn| query.load(conn))?) @@ -331,6 +343,22 @@ pub(crate) mod tests { created_at_ns, membership_state, "placeholder_address".to_string(), + None, + ) + } + + /// Generate a test dm group + pub fn generate_dm(state: Option) -> StoredGroup { + let id = rand_vec(); + let created_at_ns = now_ns(); + let membership_state = state.unwrap_or(GroupMembershipState::Allowed); + let dm_inbox_id = Some("placeholder_inbox_id".to_string()); + StoredGroup::new( + id, + created_at_ns, + membership_state, + "placeholder_address".to_string(), + dm_inbox_id, ) } @@ -392,23 +420,31 @@ pub(crate) mod tests { test_group_1.store(conn).unwrap(); let test_group_2 = generate_group(Some(GroupMembershipState::Allowed)); test_group_2.store(conn).unwrap(); + let test_group_3 = generate_dm(Some(GroupMembershipState::Allowed)); + test_group_3.store(conn).unwrap(); - let all_results = conn.find_groups(None, None, None, None).unwrap(); + let all_results = conn.find_groups(None, None, None, None, false).unwrap(); assert_eq!(all_results.len(), 2); let pending_results = conn - .find_groups(Some(vec![GroupMembershipState::Pending]), None, None, None) + .find_groups( + Some(vec![GroupMembershipState::Pending]), + None, + None, + None, + false, + ) .unwrap(); assert_eq!(pending_results[0].id, test_group_1.id); assert_eq!(pending_results.len(), 1); // Offset and limit - let results_with_limit = conn.find_groups(None, None, None, Some(1)).unwrap(); + let results_with_limit = conn.find_groups(None, None, None, Some(1), false).unwrap(); assert_eq!(results_with_limit.len(), 1); assert_eq!(results_with_limit[0].id, test_group_1.id); let results_with_created_at_ns_after = conn - .find_groups(None, Some(test_group_1.created_at_ns), None, Some(1)) + .find_groups(None, Some(test_group_1.created_at_ns), None, Some(1), false) .unwrap(); assert_eq!(results_with_created_at_ns_after.len(), 1); assert_eq!(results_with_created_at_ns_after[0].id, test_group_2.id); @@ -417,7 +453,10 @@ pub(crate) mod tests { let synced_groups = conn.find_sync_groups().unwrap(); assert_eq!(synced_groups.len(), 0); - // test that ONLY normal groups show up. + // test that dm groups are included + let dm_results = conn.find_groups(None, None, None, None, true).unwrap(); + assert_eq!(dm_results.len(), 3); + assert_eq!(dm_results[2].id, test_group_3.id); }) } diff --git a/xmtp_mls/src/storage/encrypted_store/group_intent.rs b/xmtp_mls/src/storage/encrypted_store/group_intent.rs index 4ff7615e7..b5104f9ac 100644 --- a/xmtp_mls/src/storage/encrypted_store/group_intent.rs +++ b/xmtp_mls/src/storage/encrypted_store/group_intent.rs @@ -404,6 +404,7 @@ mod tests { 100, GroupMembershipState::Allowed, "placeholder_address".to_string(), + None, ); group.store(conn).unwrap(); } diff --git a/xmtp_mls/src/storage/encrypted_store/mod.rs b/xmtp_mls/src/storage/encrypted_store/mod.rs index f5d2f843d..4f338899e 100644 --- a/xmtp_mls/src/storage/encrypted_store/mod.rs +++ b/xmtp_mls/src/storage/encrypted_store/mod.rs @@ -688,6 +688,7 @@ mod tests { 0, GroupMembershipState::Allowed, "goodbye".to_string(), + None, ); group.store(connection)?; Ok(()) @@ -739,6 +740,7 @@ mod tests { 0, GroupMembershipState::Allowed, "goodbye".to_string(), + None, ); group.store(conn1).unwrap(); diff --git a/xmtp_mls/src/storage/encrypted_store/schema.rs b/xmtp_mls/src/storage/encrypted_store/schema.rs index 84d3c69ec..81b97dcfe 100644 --- a/xmtp_mls/src/storage/encrypted_store/schema.rs +++ b/xmtp_mls/src/storage/encrypted_store/schema.rs @@ -45,6 +45,7 @@ diesel::table! { purpose -> Integer, added_by_inbox_id -> Text, welcome_id -> Nullable, + dm_inbox_id -> Nullable, } } diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index 6c3fd03e1..fb7242c65 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -281,7 +281,7 @@ where let mut group_id_to_info = client .store() .conn()? - .find_groups(None, None, None, None)? + .find_groups(None, None, None, None, false)? .into_iter() .map(Into::into) .collect::, MessagesStreamInfo>>(); From f4fd05e079b6fdeef2c39f53f0a0d4787e953650 Mon Sep 17 00:00:00 2001 From: cameronvoell Date: Wed, 18 Sep 2024 23:01:16 -0700 Subject: [PATCH 3/8] fmt fix --- bindings_node/src/conversations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings_node/src/conversations.rs b/bindings_node/src/conversations.rs index fd1c8087f..003371eaa 100644 --- a/bindings_node/src/conversations.rs +++ b/bindings_node/src/conversations.rs @@ -172,7 +172,7 @@ impl NapiConversations { }; let convo_list: Vec = self .inner_client - .find_groups( FindGroupParams { + .find_groups(FindGroupParams { created_after_ns: opts.created_after_ns, created_before_ns: opts.created_before_ns, limit: opts.limit, From b81ebf00c68e91cbd22ade88932d5f2d45cca21a Mon Sep 17 00:00:00 2001 From: cameronvoell Date: Wed, 18 Sep 2024 23:36:59 -0700 Subject: [PATCH 4/8] dont execute callbacks when dm group welcomes are streamed --- bindings_ffi/src/mls.rs | 9 ++-- bindings_node/src/conversations.rs | 9 ++-- xmtp_mls/src/subscriptions.rs | 82 ++++++++++++++++++++++++++++-- 3 files changed, 89 insertions(+), 11 deletions(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 2661d53a0..b4b4b168f 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -855,14 +855,17 @@ impl FfiConversations { pub async fn stream(&self, callback: Box) -> FfiStreamCloser { let client = self.inner_client.clone(); - let handle = - RustXmtpClient::stream_conversations_with_callback(client.clone(), move |convo| { + let handle = RustXmtpClient::stream_conversations_with_callback( + client.clone(), + move |convo| { callback.on_conversation(Arc::new(FfiGroup { inner_client: client.clone(), group_id: convo.group_id, created_at_ns: convo.created_at_ns, })) - }); + }, + false, + ); FfiStreamCloser::new(handle) } diff --git a/bindings_node/src/conversations.rs b/bindings_node/src/conversations.rs index 003371eaa..ed39f37fa 100644 --- a/bindings_node/src/conversations.rs +++ b/bindings_node/src/conversations.rs @@ -197,8 +197,9 @@ impl NapiConversations { let tsfn: ThreadsafeFunction = callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value]))?; let client = self.inner_client.clone(); - let stream_closer = - RustXmtpClient::stream_conversations_with_callback(client.clone(), move |convo| { + let stream_closer = RustXmtpClient::stream_conversations_with_callback( + client.clone(), + move |convo| { tsfn.call( Ok(NapiGroup::new( client.clone(), @@ -207,7 +208,9 @@ impl NapiConversations { )), ThreadsafeFunctionCallMode::Blocking, ); - }); + }, + false, + ); Ok(NapiStreamCloser::new(stream_closer)) } diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index aee1aaf49..f02c657ed 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -9,7 +9,7 @@ use xmtp_proto::xmtp::mls::api::v1::WelcomeMessage; use crate::{ api::GroupFilter, client::{extract_welcome_message, ClientError}, - groups::{extract_group_id, GroupError, MlsGroup}, + groups::{extract_group_id, group_metadata::ConversationType, GroupError, MlsGroup}, retry::Retry, retry_async, storage::{group::StoredGroup, group_message::StoredGroupMessage}, @@ -234,6 +234,7 @@ where pub fn stream_conversations_with_callback( client: Arc>, mut convo_callback: impl FnMut(MlsGroup) + Send + 'static, + include_dm: bool, ) -> StreamHandle> { let (tx, rx) = oneshot::channel(); @@ -242,7 +243,12 @@ where futures::pin_mut!(stream); let _ = tx.send(()); while let Some(convo) = stream.next().await { - convo_callback(convo) + let provider = client.context.mls_provider()?; + // Don't execute callback for dms unless include_dm is true + if include_dm || convo.metadata(provider)?.conversation_type != ConversationType::Dm + { + convo_callback(convo) + } } log::debug!("`stream_conversations` stream ended, dropping stream"); Ok(()) @@ -726,12 +732,15 @@ mod tests { let notify = Delivery::new(None); let (notify_pointer, groups_pointer) = (notify.clone(), groups.clone()); - let closer = - Client::::stream_conversations_with_callback(alix.clone(), move |g| { + let closer = Client::::stream_conversations_with_callback( + alix.clone(), + move |g| { let mut groups = groups_pointer.lock(); groups.push(g); notify_pointer.notify_one(); - }); + }, + false, + ); alix.create_group(None, GroupMetadataOptions::default()) .unwrap(); @@ -763,4 +772,67 @@ mod tests { closer.handle.abort(); } + + #[tokio::test(flavor = "multi_thread")] + async fn test_dm_creation() { + let alix = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); + let bo = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); + + let groups = Arc::new(Mutex::new(Vec::new())); + // Wait for 2 seconds for the group creation to be streamed + let notify = Delivery::new(Some(std::time::Duration::from_secs(1))); + let (notify_pointer, groups_pointer) = (notify.clone(), groups.clone()); + + // Start a stream with enableDm set to false + let closer = Client::::stream_conversations_with_callback( + alix.clone(), + move |g| { + let mut groups = groups_pointer.lock(); + groups.push(g); + notify_pointer.notify_one(); + }, + false, + ); + + alix.create_dm_by_inbox_id(bo.inbox_id()).await.unwrap(); + + let result = notify.wait_for_delivery().await; + assert!(result.is_err(), "Stream unexpectedly received a DM group"); + + closer.handle.abort(); + + // Start a stream with enableDm set to true + let groups = Arc::new(Mutex::new(Vec::new())); + // Wait for 2 seconds for the group creation to be streamed + let notify = Delivery::new(Some(std::time::Duration::from_secs(1))); + let (notify_pointer, groups_pointer) = (notify.clone(), groups.clone()); + let closer = Client::::stream_conversations_with_callback( + alix.clone(), + move |g| { + let mut groups = groups_pointer.lock(); + groups.push(g); + notify_pointer.notify_one(); + }, + true, + ); + + alix.create_dm_by_inbox_id(bo.inbox_id()).await.unwrap(); + notify.wait_for_delivery().await.unwrap(); + { + let grps = groups.lock(); + assert_eq!(grps.len(), 1); + } + + let dm = bo.create_dm_by_inbox_id(alix.inbox_id()).await.unwrap(); + dm.add_members_by_inbox_id(&bo, vec![alix.inbox_id()]) + .await + .unwrap(); + notify.wait_for_delivery().await.unwrap(); + { + let grps = groups.lock(); + assert_eq!(grps.len(), 2); + } + + closer.handle.abort(); + } } From 3ce9809eb0235a787642746bf9622d6bf72957ad Mon Sep 17 00:00:00 2001 From: Cameron Voell <1103838+cameronvoell@users.noreply.github.com> Date: Fri, 20 Sep 2024 16:13:03 -0700 Subject: [PATCH 5/8] Update bindings_ffi/src/mls.rs Co-authored-by: Andrew Plaza --- bindings_ffi/src/mls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index b4b4b168f..b067bccc1 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -810,7 +810,7 @@ impl FfiConversations { ..FindGroupParams::default() })?; - println!( + log::info!( "groups for client inbox id {:?}: {:?}", self.inner_client.inbox_id(), groups.len() From 6fb038579ad63d7d4cf30ee4e2bce0a88be5bc33 Mon Sep 17 00:00:00 2001 From: cameronvoell Date: Fri, 20 Sep 2024 17:14:33 -0700 Subject: [PATCH 6/8] fixed bad merge --- xmtp_mls/src/groups/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/xmtp_mls/src/groups/mod.rs b/xmtp_mls/src/groups/mod.rs index 66c094368..782a92e0b 100644 --- a/xmtp_mls/src/groups/mod.rs +++ b/xmtp_mls/src/groups/mod.rs @@ -431,6 +431,7 @@ impl MlsGroup { added_by_inbox, welcome_id, Purpose::Conversation, + dm_inbox_id, ) } ConversationType::Sync => StoredGroup::new_from_welcome( @@ -1110,11 +1111,8 @@ impl MlsGroup { .unwrap() }); let mutable_metadata = custom_mutable_metadata.unwrap_or_else(|| { - build_dm_mutable_metadata_extension_default( - context.inbox_id(), - dm_target_inbox_id.clone(), - ) - .unwrap() + build_dm_mutable_metadata_extension_default(context.inbox_id(), &dm_target_inbox_id) + .unwrap() }); let group_membership = custom_group_membership .unwrap_or_else(|| build_starting_group_membership_extension(context.inbox_id(), 0)); @@ -1145,6 +1143,7 @@ impl MlsGroup { now_ns(), GroupMembershipState::Allowed, // Use Allowed as default for tests context.inbox_id(), + Some(dm_target_inbox_id), ); stored_group.store(provider.conn_ref())?; From fc02806f7e7f47b402bb019c56379112d4fda97e Mon Sep 17 00:00:00 2001 From: cameronvoell Date: Fri, 20 Sep 2024 22:13:45 -0700 Subject: [PATCH 7/8] filter dms in stream_conversations --- xmtp_mls/src/subscriptions.rs | 69 ++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/xmtp_mls/src/subscriptions.rs b/xmtp_mls/src/subscriptions.rs index f02c657ed..c69bfdaac 100644 --- a/xmtp_mls/src/subscriptions.rs +++ b/xmtp_mls/src/subscriptions.rs @@ -1,5 +1,6 @@ use std::{collections::HashMap, sync::Arc}; +use crate::xmtp_openmls_provider::XmtpOpenMlsProvider; use futures::{FutureExt, Stream, StreamExt}; use prost::Message; use tokio::{sync::oneshot, task::JoinHandle}; @@ -130,18 +131,42 @@ where pub async fn stream_conversations( &self, + include_dm: bool, ) -> Result + '_, ClientError> { + let provider = Arc::new(self.context.mls_provider()?); + let event_queue = tokio_stream::wrappers::BroadcastStream::new(self.local_events.subscribe()); - let event_queue = event_queue.filter_map(|event| async move { - match event { - Ok(LocalEvents::NewGroup(g)) => Some(g), - Err(BroadcastStreamRecvError::Lagged(missed)) => { - log::warn!("Missed {missed} messages due to local event queue lagging"); + // Helper function for filtering Dm groups + let filter_group = move |group: MlsGroup, provider: Arc| async move { + match group.metadata(provider.as_ref()) { + Ok(metadata) => { + if include_dm || metadata.conversation_type != ConversationType::Dm { + Some(group) + } else { + None + } + } + Err(err) => { + log::error!("Error processing group metadata: {:?}", err); None } } + }; + + let event_provider = Arc::clone(&provider); + let event_queue = event_queue.filter_map(move |event| { + let provider = Arc::clone(&event_provider); + async move { + match event { + Ok(LocalEvents::NewGroup(group)) => filter_group(group, provider).await, + Err(BroadcastStreamRecvError::Lagged(missed)) => { + log::warn!("Missed {missed} messages due to local event queue lagging"); + None + } + } + } }); let installation_key = self.installation_public_key(); @@ -152,17 +177,24 @@ where .subscribe_welcome_messages(installation_key, Some(id_cursor)) .await?; + let stream_provider = Arc::clone(&provider); let stream = subscription .map(|welcome| async { log::info!("Received conversation streaming payload"); self.process_streamed_welcome(welcome?).await }) - .filter_map(|res| async { - match res.await { - Ok(group) => Some(group), - Err(err) => { - log::error!("Error processing stream entry for conversation: {:?}", err); - None + .filter_map(move |res| { + let provider = Arc::clone(&stream_provider); + async move { + match res.await { + Ok(group) => filter_group(group, provider).await, + Err(err) => { + log::error!( + "Error processing stream entry for conversation: {:?}", + err + ); + None + } } } }); @@ -239,16 +271,11 @@ where let (tx, rx) = oneshot::channel(); let handle = tokio::spawn(async move { - let stream = client.stream_conversations().await?; + let stream = client.stream_conversations(include_dm).await?; futures::pin_mut!(stream); let _ = tx.send(()); while let Some(convo) = stream.next().await { - let provider = client.context.mls_provider()?; - // Don't execute callback for dms unless include_dm is true - if include_dm || convo.metadata(provider)?.conversation_type != ConversationType::Dm - { - convo_callback(convo) - } + convo_callback(convo) } log::debug!("`stream_conversations` stream ended, dropping stream"); Ok(()) @@ -304,7 +331,7 @@ where .await?; futures::pin_mut!(messages_stream); - let convo_stream = self.stream_conversations().await?; + let convo_stream = self.stream_conversations(true).await?; futures::pin_mut!(convo_stream); let mut extra_messages = Vec::new(); @@ -422,7 +449,7 @@ mod tests { let mut stream = tokio_stream::wrappers::UnboundedReceiverStream::new(rx); let bob_ptr = bob.clone(); tokio::spawn(async move { - let bob_stream = bob_ptr.stream_conversations().await.unwrap(); + let bob_stream = bob_ptr.stream_conversations(true).await.unwrap(); futures::pin_mut!(bob_stream); while let Some(item) = bob_stream.next().await { let _ = tx.send(item); @@ -774,7 +801,7 @@ mod tests { } #[tokio::test(flavor = "multi_thread")] - async fn test_dm_creation() { + async fn test_dm_streaming() { let alix = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); let bo = Arc::new(ClientBuilder::new_test_client(&generate_local_wallet()).await); From eb506f4e982cf3d07c42c51b049511e9911869cf Mon Sep 17 00:00:00 2001 From: cameronvoell Date: Fri, 20 Sep 2024 23:32:16 -0700 Subject: [PATCH 8/8] surface include_dm_groups in bindings list function more clearly --- bindings_ffi/src/mls.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index c178b487e..53c8e1297 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -832,10 +832,11 @@ impl FfiConversations { let inner = self.inner_client.as_ref(); let convo_list: Vec> = inner .find_groups(FindGroupParams { + allowed_states: None, created_after_ns: opts.created_after_ns, created_before_ns: opts.created_before_ns, limit: opts.limit, - ..FindGroupParams::default() + include_dm_groups: false, })? .into_iter() .map(|group| {