use std::error::Error as StdError;
use std::sync::Arc;
use openmls::credentials::CredentialWithKey;
use openmls::prelude::Ciphersuite;
use openmls_traits::signatures::Signer;
use openmls_traits::{OpenMlsProvider, storage::StorageProvider};
use hashgraph_like_consensus::events::ConsensusEventBus;
use crate::{
ConsensusPlugin, ConsensusServiceFor, Conversation, ConversationConfig, ConversationError,
ConversationEvent, ConversationQueues, ConversationServices, ConversationStateMachine,
PeerScoringPlugin, StewardListPlugin,
mls_crypto::{MlsService, OpenMlsService},
};
impl<C, Sc, St> Conversation<C, Sc, St>
where
C: ConsensusPlugin,
Sc: PeerScoringPlugin,
St: StewardListPlugin,
{
#[allow(clippy::too_many_arguments)]
pub fn create<Pr>(
conversation_id: &str,
provider: &Pr,
credential: CredentialWithKey,
ciphersuite: Ciphersuite,
signer: &impl Signer,
scoring: Sc,
steward: St,
consensus: ConsensusServiceFor<C>,
app_id: Arc<[u8]>,
config: ConversationConfig,
member_id: &[u8],
) -> Result<Self, ConversationError>
where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
{
let mls = OpenMlsService::new_as_creator(
conversation_id.to_string(),
provider,
credential,
ciphersuite,
signer,
)?;
Self::assemble(
conversation_id,
mls,
scoring,
steward,
consensus,
app_id,
config,
true,
member_id,
)
}
#[allow(clippy::too_many_arguments)]
pub fn join<Pr>(
provider: &Pr,
welcome_bytes: &[u8],
conversation_sync_bytes: &[u8],
scoring: Sc,
steward: St,
consensus: ConsensusServiceFor<C>,
app_id: Arc<[u8]>,
config: ConversationConfig,
member_id: &[u8],
signer: &impl Signer,
) -> Result<Option<Self>, ConversationError>
where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
{
let Some(mls) = OpenMlsService::new_from_welcome(provider, welcome_bytes)? else {
return Ok(None);
};
let conversation_id = mls.conversation_id().to_string();
let mut conversation = Self::assemble(
&conversation_id,
mls,
scoring,
steward,
consensus,
app_id,
config,
false,
member_id,
)?;
conversation.on_joined(provider, signer)?;
conversation.apply_welcome_sync(provider, conversation_sync_bytes, signer)?;
Ok(Some(conversation))
}
#[allow(clippy::too_many_arguments)]
fn assemble(
conversation_id: &str,
mls: OpenMlsService,
mut scoring: Sc,
mut steward_list: St,
consensus: ConsensusServiceFor<C>,
app_id: Arc<[u8]>,
config: ConversationConfig,
is_creation: bool,
member_id: &[u8],
) -> Result<Self, ConversationError> {
let self_member_id_bytes = member_id.to_vec();
let queues = ConversationQueues::new(conversation_id);
steward_list.set_conversation_id(conversation_id.as_bytes());
steward_list.set_max_retries(config.max_reelection_attempts);
if is_creation {
steward_list.install_list(0, std::slice::from_ref(&self_member_id_bytes), 1, 0)?;
let _ = scoring.add_member(&self_member_id_bytes);
}
let state_machine = ConversationStateMachine::new_as_member();
let initial_state = state_machine.current_state();
let consensus_rx = consensus.event_bus().subscribe();
let services = ConversationServices {
mls,
scoring,
steward_list,
consensus,
consensus_rx,
};
let conversation = Conversation::new(
conversation_id.to_string(),
queues,
services,
state_machine,
config,
Arc::from(member_id),
app_id,
);
conversation.emit_event(ConversationEvent::PhaseChange(initial_state));
Ok(conversation)
}
}