pub struct Conversation<C: ConsensusPlugin, Sc: PeerScoringPlugin, St: StewardListPlugin> { /* private fields */ }Implementations§
Source§impl<C, Sc, St> Conversation<C, Sc, St>
impl<C, Sc, St> Conversation<C, Sc, St>
Sourcepub 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,
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,
Create a brand-new conversation we steward. Starts in Working with the
local member installed as sole steward at epoch 0. The library seeds a
fresh MLS group into provider (which it does not retain) from
credential and ciphersuite. member_id names the local member — the
opaque id bytes the protocol matches on.
Sourcepub 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,
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,
Build a fully-joined conversation from a welcome: the library opens the
joiner-side MLS group from welcome_bytes using provider (which must
hold the joiner’s key-package private keys), runs the joiner-side join
side-effects, and replays the bundled ConversationSync (steward list,
timing, peer scores).
Returns Ok(None) when the welcome doesn’t address one of our key
packages — the “not for us” branch, not an error.
The conversation id comes from the MLS group, so the caller needs no prior knowledge of the conversation.
Source§impl<C, Sc, St> Conversation<C, Sc, St>
impl<C, Sc, St> Conversation<C, Sc, St>
pub fn is_in_recovery_mode(&self) -> bool
pub fn enter_recovery_mode(&mut self)
pub fn exit_recovery_mode(&mut self)
pub fn current_state(&self) -> ConversationState
Sourcepub fn drain_events(&self) -> Vec<ConversationEvent>
pub fn drain_events(&self) -> Vec<ConversationEvent>
Drain every pending ConversationEvent accumulated since the last
call. Returns events in insertion order. Callers (UI fanout,
audit log) invoke this once per polling cycle.
Sourcepub fn next_wakeup_in(&self) -> Option<Duration>
pub fn next_wakeup_in(&self) -> Option<Duration>
Smallest pending deadline relative to now, or None when nothing
is scheduled. Returns Some(Duration::ZERO) for an already-elapsed
deadline. Covers consensus-session timeouts, auto-vote timers, and
state-machine phase deadlines (Freezing window, steward / recovery
inactivity). Forward to an external scheduler that calls poll() on
fire; extra/early wakeups are no-ops.
Sourcepub fn drain_outbound(&self) -> Vec<Outbound>
pub fn drain_outbound(&self) -> Vec<Outbound>
Drain every buffered Outbound accumulated since the last call,
in insertion order. The integrator invokes this once per cycle (after
poll / handle_inbound / an intent) and maps each item onto its
own transport.
Sourcepub fn leave<Pr>(
&mut self,
provider: &Pr,
signer: &impl Signer,
) -> Result<LeaveOutcome, ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
pub fn leave<Pr>(
&mut self,
provider: &Pr,
signer: &impl Signer,
) -> Result<LeaveOutcome, ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
Leave this conversation. Opens a self-leave consensus round and returns
LeaveOutcome::LeaveInitiated; the leave completes when the next
steward commit merges the removal. signer is the local member’s MLS
signer, used to authenticate the self-leave proposal.
Source§impl<C, Sc, St> Conversation<C, Sc, St>
impl<C, Sc, St> Conversation<C, Sc, St>
Sourcepub fn process_inbound<Pr>(
&mut self,
provider: &Pr,
sender: &[u8],
payload: &[u8],
signer: &impl Signer,
) -> Result<DispatchOutcome, ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
pub fn process_inbound<Pr>(
&mut self,
provider: &Pr,
sender: &[u8],
payload: &[u8],
signer: &impl Signer,
) -> Result<DispatchOutcome, ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
Decrypt and dispatch an inbound conversation payload. Drops self-echoes.
Runs the full dispatch chain internally. Returns
DispatchOutcome::LeaveRequested when the conversation has completed
its protocol-side teardown; the integrator must then remove the registry
entry and clean up the consensus scope.
pub fn apply_welcome_sync<Pr>(
&mut self,
provider: &Pr,
sync_bytes: &[u8],
signer: &impl Signer,
) -> Result<(), ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
Source§impl<C, Sc, St> Conversation<C, Sc, St>
impl<C, Sc, St> Conversation<C, Sc, St>
Sourcepub fn send_message<Pr>(
&mut self,
provider: &Pr,
message: Vec<u8>,
signer: &impl Signer,
) -> Result<(), ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
pub fn send_message<Pr>(
&mut self,
provider: &Pr,
message: Vec<u8>,
signer: &impl Signer,
) -> Result<(), ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
Buffer a chat message for broadcast. The conversation never sends — the
message is enqueued and the integrator drains it via
Conversation::drain_outbound. Blocked in Freezing and Selection
(epoch rotation in flight — the message might not decrypt on peers who
already merged the next commit). Governance traffic has its own gate
(check_proposal_allowed). signer is the local member’s MLS signer,
used to authenticate the outbound message.
Sourcepub fn add_member<Pr>(
&mut self,
provider: &Pr,
key_package_bytes: &[u8],
signer: &impl Signer,
) -> Result<(), ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
pub fn add_member<Pr>(
&mut self,
provider: &Pr,
key_package_bytes: &[u8],
signer: &impl Signer,
) -> Result<(), ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
Invite a joiner whose key package the caller supplies out of band,
endorsing the add by bundling a YES vote at submit. Any member may call.
Errors unless the conversation is Working.
See Self::sponsor_member for the non-endorsing steward relay.
Sourcepub fn sponsor_member<Pr>(
&mut self,
provider: &Pr,
key_package_bytes: &[u8],
signer: &impl Signer,
) -> Result<(), ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
pub fn sponsor_member<Pr>(
&mut self,
provider: &Pr,
key_package_bytes: &[u8],
signer: &impl Signer,
) -> Result<(), ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
Relay a joiner that announced its own key package, without endorsing it:
the proposal is submitted unbundled (CreatorVote::Deferred) and this
member votes on it like any other. Only the primary epoch steward relays
immediately, so a single Add proposal is opened per joiner. Every other
member records the announcement in the pending-update buffer instead —
a backup proposes it from there if the epoch steward stays silent past
the recovery window (drained by poll), so an offline epoch steward
doesn’t strand the join. No-op outside Working.
See Self::add_member for the endorsing out-of-band invite.
Sourcepub fn remove_member<Pr>(
&mut self,
provider: &Pr,
member_id: &[u8],
signer: &impl Signer,
) -> Result<(), ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
pub fn remove_member<Pr>(
&mut self,
provider: &Pr,
member_id: &[u8],
signer: &impl Signer,
) -> Result<(), ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
Start a RemoveMember consensus round targeting member_id. The
requester’s intent is the removal → the creator’s vote is bundled as
YES at submit; no vote request is shown to the requester.
Source§impl<C, Sc, St> Conversation<C, Sc, St>
impl<C, Sc, St> Conversation<C, Sc, St>
Sourcepub fn poll<Pr>(&mut self, provider: &Pr, signer: &impl Signer) -> PollOutcomewhere
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
pub fn poll<Pr>(&mut self, provider: &Pr, signer: &impl Signer) -> PollOutcomewhere
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
Drive one polling cycle: tick consensus deadlines, advance freeze state, and check steward inactivity.
Best-effort: each step runs regardless of whether the previous one failed; step errors are transient (a step that can’t act this cycle retries on the next) and are logged rather than surfaced.
Returns PollOutcome::leave_requested when the conversation is ready
to be torn down; the integrator finalizes the leave.
signer is the local member’s MLS signer, threaded into the
steward commit-candidate build and any auto-vote casts that fire
this cycle.
Source§impl<C, Sc, St> Conversation<C, Sc, St>
impl<C, Sc, St> Conversation<C, Sc, St>
Sourcepub fn state(&self) -> ConversationState
pub fn state(&self) -> ConversationState
Current state of the conversation’s state machine.
Sourcepub fn id(&self) -> &str
pub fn id(&self) -> &str
Name of this conversation. Identifies it in the integrator’s
registry and on every crate::Outbound it produces.
Sourcepub fn member_id_bytes(&self) -> &[u8] ⓘ
pub fn member_id_bytes(&self) -> &[u8] ⓘ
Identity bytes of the local member in this conversation.
Sourcepub fn app_id(&self) -> &[u8] ⓘ
pub fn app_id(&self) -> &[u8] ⓘ
App id this conversation tags on outbound packets and uses for self-echo
filtering in Conversation::process_inbound.
Sourcepub fn epoch_and_retry(&self) -> Result<(u64, u32), ConversationError>
pub fn epoch_and_retry(&self) -> Result<(u64, u32), ConversationError>
Current MLS epoch + reelection retry round. Intended for UI status display.
Sourcepub fn pending_update_count(&self) -> usize
pub fn pending_update_count(&self) -> usize
Count of buffered pending membership updates. Used by tests and the UI to verify buffer hygiene (e.g., that a joiner’s buffer is empty right after they receive the welcome).
Sourcepub fn freeze_candidate_count(&self) -> (usize, usize)
pub fn freeze_candidate_count(&self) -> (usize, usize)
Freeze round progress: (received, expected). Returns (0, 0) if not
in freeze or no steward list is known.
pub fn is_steward(&self) -> bool
Sourcepub fn is_epoch_steward(&self) -> Result<bool, ConversationError>
pub fn is_epoch_steward(&self) -> Result<bool, ConversationError>
true if the local member is the primary steward designated for the
current epoch — the one that should commit and sponsor joiners first.
Unlike Self::is_steward (true for any member on the list, backups
included), this is true for exactly one member per epoch, so it gates the
single-actor paths: backups defer to the primary and only step in after
the recovery window. Eligibility is the same live rotation
Self::member_roles uses, so all members agree on who it is.
Sourcepub fn members(&self) -> Result<Vec<Vec<u8>>, ConversationError>
pub fn members(&self) -> Result<Vec<Vec<u8>>, ConversationError>
Identity bytes of every current member of this conversation, as reported by MLS.
pub fn member_scores(&self) -> Vec<(Vec<u8>, i64)>
pub fn member_score(&self, member_id: &[u8]) -> Option<i64>
Sourcepub fn pending_leave_member_ids(
&self,
) -> Result<Vec<Vec<u8>>, ConversationError>
pub fn pending_leave_member_ids( &self, ) -> Result<Vec<Vec<u8>>, ConversationError>
Identities that have an in-flight self-leave request. Used by the UI to render a “pending leave” indicator.
Sourcepub fn member_roles(
&self,
) -> Result<Vec<(Vec<u8>, MemberRole)>, ConversationError>
pub fn member_roles( &self, ) -> Result<Vec<(Vec<u8>, MemberRole)>, ConversationError>
Steward role for each member. Uses live rotation so removed or pending-leave stewards are skipped in role display.
pub fn approved_proposals_for_current_epoch( &self, ) -> Vec<ConversationUpdateRequest>
Source§impl<C, Sc, St> Conversation<C, Sc, St>
impl<C, Sc, St> Conversation<C, Sc, St>
Sourcepub fn initiate_proposal<Pr>(
&mut self,
provider: &Pr,
request: ConversationUpdateRequest,
creator_vote: CreatorVote,
signer: &impl Signer,
) -> Result<(), ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
pub fn initiate_proposal<Pr>(
&mut self,
provider: &Pr,
request: ConversationUpdateRequest,
creator_vote: CreatorVote,
signer: &impl Signer,
) -> Result<(), ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
Open a consensus vote for request; CreatorVote picks the wire
shape and the integrator event.
Errors when the state machine forbids new proposals (freeze phases,
partial freeze during an active emergency). On success the proposal
is on the wire and a consensus-timeout deadline is armed for
tick_deadlines to fire.
Local ownership is recorded before any vote is cast: with a single expected voter the bundled YES resolves the session synchronously, and the outcome handler must already see us as the owner by then.
Sourcepub fn vote<Pr>(
&mut self,
provider: &Pr,
proposal_id: u32,
vote: bool,
signer: &impl Signer,
) -> Result<(), ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
pub fn vote<Pr>(
&mut self,
provider: &Pr,
proposal_id: u32,
vote: bool,
signer: &impl Signer,
) -> Result<(), ConversationError>where
Pr: OpenMlsProvider,
<Pr::StorageProvider as StorageProvider<1>>::Error: StdError + Send + Sync + 'static,
Cast the local member’s vote. Cancels the pending auto-vote so the
manual choice wins. Blocked while an epoch rotation is in flight
(Freezing/Selection) — the encrypted vote might not decrypt on
peers that already merged the next commit.
Auto Trait Implementations§
impl<C, Sc, St> !Freeze for Conversation<C, Sc, St>
impl<C, Sc, St> RefUnwindSafe for Conversation<C, Sc, St>where
Sc: RefUnwindSafe,
St: RefUnwindSafe,
<<C as ConsensusPlugin>::EventBus as ConsensusEventBus<<C as ConsensusPlugin>::Scope>>::Receiver: RefUnwindSafe,
<C as ConsensusPlugin>::ConsensusStorage: RefUnwindSafe,
<C as ConsensusPlugin>::EventBus: RefUnwindSafe,
<C as ConsensusPlugin>::Signer: RefUnwindSafe,
<C as ConsensusPlugin>::Scope: RefUnwindSafe,
impl<C, Sc, St> Send for Conversation<C, Sc, St>
impl<C, Sc, St> Sync for Conversation<C, Sc, St>where
Sc: Sync,
St: Sync,
<<C as ConsensusPlugin>::EventBus as ConsensusEventBus<<C as ConsensusPlugin>::Scope>>::Receiver: Sync,
impl<C, Sc, St> Unpin for Conversation<C, Sc, St>where
Sc: Unpin,
St: Unpin,
<<C as ConsensusPlugin>::EventBus as ConsensusEventBus<<C as ConsensusPlugin>::Scope>>::Receiver: Unpin,
<C as ConsensusPlugin>::ConsensusStorage: Unpin,
<C as ConsensusPlugin>::EventBus: Unpin,
<C as ConsensusPlugin>::Signer: Unpin,
<C as ConsensusPlugin>::Scope: Unpin,
impl<C, Sc, St> UnsafeUnpin for Conversation<C, Sc, St>where
Sc: UnsafeUnpin,
St: UnsafeUnpin,
<<C as ConsensusPlugin>::EventBus as ConsensusEventBus<<C as ConsensusPlugin>::Scope>>::Receiver: UnsafeUnpin,
<C as ConsensusPlugin>::ConsensusStorage: UnsafeUnpin,
<C as ConsensusPlugin>::EventBus: UnsafeUnpin,
<C as ConsensusPlugin>::Signer: UnsafeUnpin,
impl<C, Sc, St> UnwindSafe for Conversation<C, Sc, St>where
Sc: UnwindSafe,
St: UnwindSafe,
<<C as ConsensusPlugin>::EventBus as ConsensusEventBus<<C as ConsensusPlugin>::Scope>>::Receiver: UnwindSafe,
<C as ConsensusPlugin>::ConsensusStorage: UnwindSafe,
<C as ConsensusPlugin>::EventBus: UnwindSafe,
<C as ConsensusPlugin>::Signer: UnwindSafe,
<C as ConsensusPlugin>::Scope: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more