core_crypto/transaction_context/conversation/
mod.rs1pub mod external_commit;
4mod external_proposal;
5pub(crate) mod proposal;
6pub mod welcome;
7
8use core_crypto_keystore::{entities::PersistedMlsPendingGroup, traits::FetchFromDatabase as _};
9
10use super::{Error, Result, TransactionContext};
11use crate::{
12 CredentialRef, KeystoreError, LeafError, MlsConversation, MlsConversationConfiguration, RecursiveError,
13 mls::conversation::{ConversationGuard, ConversationIdRef, pending_conversation::PendingConversation},
14};
15
16impl TransactionContext {
17 pub async fn conversation(&self, id: &ConversationIdRef) -> Result<ConversationGuard> {
21 let keystore = self.database().await?;
22 let inner = self
23 .mls_groups()
24 .await?
25 .get_fetch(id, &keystore, None)
26 .await
27 .map_err(RecursiveError::root("fetching conversation from mls groups by id"))?;
28
29 if let Some(inner) = inner {
30 return Ok(ConversationGuard::new(inner, self.clone()));
31 }
32 let pending = self.pending_conversation(id).await.map(Error::PendingConversation)?;
35 Err(pending)
36 }
37
38 pub(crate) async fn pending_conversation(&self, id: &ConversationIdRef) -> Result<PendingConversation> {
39 let keystore = self.database().await?;
40 let Some(pending_group) = keystore
41 .get_borrowed::<PersistedMlsPendingGroup>(id.as_ref())
42 .await
43 .map_err(KeystoreError::wrap("finding persisted mls pending group"))?
44 else {
45 return Err(LeafError::ConversationNotFound(id.to_owned()).into());
46 };
47 Ok(PendingConversation::new(pending_group, self.clone()))
48 }
49
50 #[cfg_attr(test, crate::dispotent)]
61 pub async fn new_conversation(
62 &self,
63 id: &ConversationIdRef,
64 credential_ref: &CredentialRef,
65 config: MlsConversationConfiguration,
66 ) -> Result<()> {
67 let database = &self.database().await?;
68 let provider = &self.mls_provider().await?;
69 if self.conversation_exists(id).await? || self.pending_conversation_exists(id).await? {
70 return Err(LeafError::ConversationAlreadyExists(id.to_owned()).into());
71 }
72 let conversation = MlsConversation::create(id.to_owned(), provider, database, credential_ref, config)
73 .await
74 .map_err(RecursiveError::mls_conversation("creating conversation"))?;
75
76 self.mls_groups().await?.insert(id, conversation);
77
78 Ok(())
79 }
80
81 pub async fn conversation_exists(&self, id: &ConversationIdRef) -> Result<bool> {
83 self.mls_groups()
84 .await?
85 .get_fetch(id, &self.database().await?, None)
86 .await
87 .map(|option| option.is_some())
88 .map_err(RecursiveError::root("fetching conversation from mls groups by id"))
89 .map_err(Into::into)
90 }
91}