1use std::error::Error as StdError;
11use std::sync::Arc;
12
13use openmls::credentials::CredentialWithKey;
14use openmls::prelude::Ciphersuite;
15use openmls_traits::signatures::Signer;
16use openmls_traits::{OpenMlsProvider, storage::StorageProvider};
17
18use hashgraph_like_consensus::events::ConsensusEventBus;
19
20use crate::{
21 ConsensusPlugin, ConsensusServiceFor, Conversation, ConversationConfig, ConversationError,
22 ConversationEvent, ConversationQueues, ConversationServices, ConversationStateMachine,
23 PeerScoringPlugin, StewardListPlugin,
24 mls_crypto::{MlsService, OpenMlsService},
25};
26
27impl<C, Sc, St> Conversation<C, Sc, St>
28where
29 C: ConsensusPlugin,
30 Sc: PeerScoringPlugin,
31 St: StewardListPlugin,
32{
33 #[allow(clippy::too_many_arguments)]
39 pub fn create<Pr>(
40 conversation_id: &str,
41 provider: &Pr,
42 credential: CredentialWithKey,
43 ciphersuite: Ciphersuite,
44 signer: &impl Signer,
45 scoring: Sc,
46 steward: St,
47 consensus: ConsensusServiceFor<C>,
48 app_id: Arc<[u8]>,
49 config: ConversationConfig,
50 member_id: &[u8],
51 ) -> Result<Self, ConversationError>
52 where
53 Pr: OpenMlsProvider,
54 <Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
55 {
56 let mls = OpenMlsService::new_as_creator(
57 conversation_id.to_string(),
58 provider,
59 credential,
60 ciphersuite,
61 signer,
62 )?;
63 Self::assemble(
64 conversation_id,
65 mls,
66 scoring,
67 steward,
68 consensus,
69 app_id,
70 config,
71 true,
72 member_id,
73 )
74 }
75
76 #[allow(clippy::too_many_arguments)]
88 pub fn join<Pr>(
89 provider: &Pr,
90 welcome_bytes: &[u8],
91 conversation_sync_bytes: &[u8],
92 scoring: Sc,
93 steward: St,
94 consensus: ConsensusServiceFor<C>,
95 app_id: Arc<[u8]>,
96 config: ConversationConfig,
97 member_id: &[u8],
98 signer: &impl Signer,
99 ) -> Result<Option<Self>, ConversationError>
100 where
101 Pr: OpenMlsProvider,
102 <Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
103 {
104 let Some(mls) = OpenMlsService::new_from_welcome(provider, welcome_bytes)? else {
105 return Ok(None);
106 };
107 let conversation_id = mls.conversation_id().to_string();
108 let mut conversation = Self::assemble(
109 &conversation_id,
110 mls,
111 scoring,
112 steward,
113 consensus,
114 app_id,
115 config,
116 false,
117 member_id,
118 )?;
119 conversation.on_joined(provider, signer)?;
120 conversation.apply_welcome_sync(provider, conversation_sync_bytes, signer)?;
121 Ok(Some(conversation))
122 }
123
124 #[allow(clippy::too_many_arguments)]
131 fn assemble(
132 conversation_id: &str,
133 mls: OpenMlsService,
134 mut scoring: Sc,
135 mut steward_list: St,
136 consensus: ConsensusServiceFor<C>,
137 app_id: Arc<[u8]>,
138 config: ConversationConfig,
139 is_creation: bool,
140 member_id: &[u8],
141 ) -> Result<Self, ConversationError> {
142 let self_member_id_bytes = member_id.to_vec();
143 let queues = ConversationQueues::new(conversation_id);
144
145 steward_list.set_conversation_id(conversation_id.as_bytes());
149 steward_list.set_max_retries(config.max_reelection_attempts);
150 if is_creation {
153 steward_list.install_list(0, std::slice::from_ref(&self_member_id_bytes), 1, 0)?;
154 let _ = scoring.add_member(&self_member_id_bytes);
157 }
158
159 let state_machine = ConversationStateMachine::new_as_member();
160 let initial_state = state_machine.current_state();
161
162 let consensus_rx = consensus.event_bus().subscribe();
163 let services = ConversationServices {
164 mls,
165 scoring,
166 steward_list,
167 consensus,
168 consensus_rx,
169 };
170 let conversation = Conversation::new(
171 conversation_id.to_string(),
172 queues,
173 services,
174 state_machine,
175 config,
176 Arc::from(member_id),
177 app_id,
178 );
179 conversation.emit_event(ConversationEvent::PhaseChange(initial_state));
182 Ok(conversation)
183 }
184}