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