core_crypto/transaction_context/conversation/
mod.rs1pub mod external_commit;
4mod external_proposal;
5pub mod external_sender;
6pub(crate) mod proposal;
7pub mod welcome;
8
9use core_crypto_keystore::connection::FetchFromDatabase as _;
10use core_crypto_keystore::entities::PersistedMlsPendingGroup;
11
12use crate::mls::conversation::ConversationGuard;
13use crate::mls::conversation::pending_conversation::PendingConversation;
14use crate::prelude::{ConversationId, MlsConversation, MlsConversationConfiguration, MlsCredentialType};
15use crate::{KeystoreError, LeafError, RecursiveError};
16
17use super::TransactionContext;
18use super::{Error, Result};
19
20impl TransactionContext {
21 pub async fn conversation(&self, id: &ConversationId) -> Result<ConversationGuard> {
25 let keystore = self.mls_provider().await?.keystore();
26 let inner = self
27 .mls_groups()
28 .await?
29 .get_fetch(id, &keystore, None)
30 .await
31 .map_err(RecursiveError::root("fetching conversation from mls groups by id"))?;
32
33 if let Some(inner) = inner {
34 return Ok(ConversationGuard::new(inner, self.clone()));
35 }
36 let pending = self.pending_conversation(id).await.map(Error::PendingConversation)?;
39 Err(pending)
40 }
41
42 pub(crate) async fn pending_conversation(&self, id: &ConversationId) -> Result<PendingConversation> {
43 let keystore = self.keystore().await?;
44 let Some(pending_group) = keystore
45 .find::<PersistedMlsPendingGroup>(id)
46 .await
47 .map_err(KeystoreError::wrap("finding persisted mls pending group"))?
48 else {
49 return Err(LeafError::ConversationNotFound(id.clone()).into());
50 };
51 Ok(PendingConversation::new(pending_group, self.clone()))
52 }
53
54 #[cfg_attr(test, crate::dispotent)]
66 pub async fn new_conversation(
67 &self,
68 id: &ConversationId,
69 creator_credential_type: MlsCredentialType,
70 config: MlsConversationConfiguration,
71 ) -> Result<()> {
72 if self.conversation_exists(id).await? || self.pending_conversation_exists(id).await? {
73 return Err(LeafError::ConversationAlreadyExists(id.clone()).into());
74 }
75 let conversation = MlsConversation::create(
76 id.clone(),
77 &self.session().await?,
78 creator_credential_type,
79 config,
80 &self.mls_provider().await?,
81 )
82 .await
83 .map_err(RecursiveError::mls_conversation("creating conversation"))?;
84
85 self.mls_groups().await?.insert(id.clone(), conversation);
86
87 Ok(())
88 }
89
90 pub async fn conversation_exists(&self, id: &ConversationId) -> Result<bool> {
92 self.mls_groups()
93 .await?
94 .get_fetch(id, &self.mls_provider().await?.keystore(), None)
95 .await
96 .map(|option| option.is_some())
97 .map_err(RecursiveError::root("fetching conversation from mls groups by id"))
98 .map_err(Into::into)
99 }
100}