Skip to content

Commit

Permalink
Filter initial membership change message in dm groups from SDK (#1266)
Browse files Browse the repository at this point in the history
* filter membership change message in dm groups

* Update test to show distinction between membership update messages in groups and dms

* metadata conversation type uses new FfiConversationType instead of string

---------

Co-authored-by: cameronvoell <[email protected]>
  • Loading branch information
cameronvoell and cameronvoell authored Nov 14, 2024
1 parent 54d5368 commit 29a955a
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 5 deletions.
120 changes: 115 additions & 5 deletions bindings_ffi/src/mls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1175,13 +1175,19 @@ impl FfiConversation {
) -> Result<Vec<FfiMessage>, GenericError> {
let delivery_status = opts.delivery_status.map(|status| status.into());
let direction = opts.direction.map(|dir| dir.into());
let kind = match self.conversation_type()? {
FfiConversationType::Group => None,
FfiConversationType::Dm => Some(GroupMessageKind::Application),
FfiConversationType::Sync => None,
};

let messages: Vec<FfiMessage> = self
.inner
.find_messages(
&MsgQueryArgs::default()
.maybe_sent_before_ns(opts.sent_before_ns)
.maybe_sent_after_ns(opts.sent_after_ns)
.maybe_kind(kind)
.maybe_delivery_status(delivery_status)
.maybe_limit(opts.limit)
.maybe_direction(direction),
Expand Down Expand Up @@ -1449,6 +1455,12 @@ impl FfiConversation {
pub fn dm_peer_inbox_id(&self) -> Result<String, GenericError> {
self.inner.dm_inbox_id().map_err(Into::into)
}

pub fn conversation_type(&self) -> Result<FfiConversationType, GenericError> {
let provider = self.inner.mls_provider()?;
let conversation_type = self.inner.conversation_type(&provider)?;
Ok(conversation_type.into())
}
}

#[uniffi::export]
Expand All @@ -1458,7 +1470,7 @@ impl FfiConversation {
}
}

#[derive(uniffi::Enum, PartialEq)]
#[derive(uniffi::Enum, PartialEq, Debug)]
pub enum FfiConversationMessageKind {
Application,
MembershipChange,
Expand All @@ -1473,6 +1485,23 @@ impl From<GroupMessageKind> for FfiConversationMessageKind {
}
}

#[derive(uniffi::Enum, PartialEq, Debug)]
pub enum FfiConversationType {
Group,
Dm,
Sync,
}

impl From<ConversationType> for FfiConversationType {
fn from(kind: ConversationType) -> Self {
match kind {
ConversationType::Group => FfiConversationType::Group,
ConversationType::Dm => FfiConversationType::Dm,
ConversationType::Sync => FfiConversationType::Sync,
}
}
}

#[derive(uniffi::Enum, Clone)]
pub enum FfiDeliveryStatus {
Unpublished,
Expand Down Expand Up @@ -1631,11 +1660,11 @@ impl FfiConversationMetadata {
self.inner.creator_inbox_id.clone()
}

pub fn conversation_type(&self) -> String {
pub fn conversation_type(&self) -> FfiConversationType {
match self.inner.conversation_type {
ConversationType::Group => "group".to_string(),
ConversationType::Dm => "dm".to_string(),
ConversationType::Sync => "sync".to_string(),
ConversationType::Group => FfiConversationType::Group,
ConversationType::Dm => FfiConversationType::Dm,
ConversationType::Sync => FfiConversationType::Sync,
}
}
}
Expand Down Expand Up @@ -4049,4 +4078,85 @@ mod tests {
panic!("Error: No member found with the given inbox_id.");
}
}

// Groups contain membership updates, but dms do not
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn test_dm_first_messages() {
let alix = new_test_client().await;
let bo = new_test_client().await;

// Alix creates DM with Bo
let alix_dm = alix
.conversations()
.create_dm(bo.account_address.clone())
.await
.unwrap();

// Alix creates group with Bo
let alix_group = alix
.conversations()
.create_group(
vec![bo.account_address.clone()],
FfiCreateGroupOptions::default(),
)
.await
.unwrap();

// Bo syncs to get both conversations
bo.conversations().sync().await.unwrap();
let bo_dm = bo.conversation(alix_dm.id()).unwrap();
let bo_group = bo.conversation(alix_group.id()).unwrap();

// Alix sends messages in both conversations
alix_dm
.send("Hello in DM".as_bytes().to_vec())
.await
.unwrap();
alix_group
.send("Hello in group".as_bytes().to_vec())
.await
.unwrap();

// Bo syncs the dm and the group
bo_dm.sync().await.unwrap();
bo_group.sync().await.unwrap();

// Get messages for both participants in both conversations
let alix_dm_messages = alix_dm
.find_messages(FfiListMessagesOptions::default())
.unwrap();
let bo_dm_messages = bo_dm
.find_messages(FfiListMessagesOptions::default())
.unwrap();
let alix_group_messages = alix_group
.find_messages(FfiListMessagesOptions::default())
.unwrap();
let bo_group_messages = bo_group
.find_messages(FfiListMessagesOptions::default())
.unwrap();

// Verify DM messages
assert_eq!(alix_dm_messages.len(), 1);
assert_eq!(bo_dm_messages.len(), 1);
assert_eq!(
String::from_utf8_lossy(&alix_dm_messages[0].content),
"Hello in DM"
);
assert_eq!(
String::from_utf8_lossy(&bo_dm_messages[0].content),
"Hello in DM"
);

// Verify group messages
assert_eq!(alix_group_messages.len(), 2);
assert_eq!(bo_group_messages.len(), 1);
assert_eq!(
String::from_utf8_lossy(&alix_group_messages[1].content),
"Hello in group"
);
assert_eq!(
String::from_utf8_lossy(&bo_group_messages[0].content),
"Hello in group"
);
}
}
9 changes: 9 additions & 0 deletions xmtp_mls/src/groups/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,15 @@ impl<ScopedClient: ScopedGroupClient> MlsGroup<ScopedClient> {
Ok(mutable_metadata.super_admin_list.contains(&inbox_id))
}

/// Retrieves the conversation type of the group from the group's metadata extension.
pub fn conversation_type(
&self,
provider: impl OpenMlsProvider,
) -> Result<ConversationType, GroupError> {
let metadata = self.metadata(provider)?;
Ok(metadata.conversation_type)
}

/// Updates the admin list of the group and syncs the changes to the network.
pub async fn update_admin_list(
&self,
Expand Down
5 changes: 5 additions & 0 deletions xmtp_mls/src/storage/encrypted_store/group_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ impl MsgQueryArgs {
self
}

pub fn maybe_kind(mut self, kind: Option<GroupMessageKind>) -> Self {
self.kind = kind;
self
}

pub fn direction(mut self, direction: SortDirection) -> Self {
self.direction = Some(direction);
self
Expand Down

0 comments on commit 29a955a

Please sign in to comment.