pub struct SessionRunner<P: ConsensusPlugin, CP: ConversationPluginsFactory> {
pub consensus: PluginConsensus<P>,
/* private fields */
}Fields§
§consensus: PluginConsensus<P>Per-conversation consensus service. Owns this conversation’s scope
in the shared storage and a private event bus. Constructed at
conversation creation by User::build_consensus_service and held
here so consensus calls hit the local service directly without
User-level lookup. pub so integrators can reach
session.consensus.event_bus().subscribe() for per-conv consensus
event forwarding.
Implementations§
Source§impl<P: ConsensusPlugin, CP: ConversationPluginsFactory> SessionRunner<P, CP>
impl<P: ConsensusPlugin, CP: ConversationPluginsFactory> SessionRunner<P, CP>
Sourcepub async fn initiate_proposal(
arc: &Arc<RwLock<Self>>,
request: ConversationUpdateRequest,
creator_vote: CreatorVote,
) -> Result<(), UserError>
pub async fn initiate_proposal( arc: &Arc<RwLock<Self>>, request: ConversationUpdateRequest, creator_vote: CreatorVote, ) -> Result<(), UserError>
Start a consensus vote for request.
Gates against the session’s state machine (no proposals during
Freezing/Selection, partial-freeze rules during Reelection,
MLS must be attached), opens the consensus session inline, casts
the creator’s vote (bundled YES) or registers an auto-vote
(Deferred), and records a consensus_timeout deadline. The
caller’s polling loop fires handle_consensus_timeout via
Self::tick_deadlines once the deadline elapses.
creator_vote — see CreatorVote for wire shape and local UI behavior.
Sourcepub async fn handle_incoming_update_request(
arc: &Arc<RwLock<Self>>,
request: ConversationUpdateRequest,
) -> Result<(), UserError>
pub async fn handle_incoming_update_request( arc: &Arc<RwLock<Self>>, request: ConversationUpdateRequest, ) -> Result<(), UserError>
Handle an incoming membership update (KP-derived InviteMember or
RemoveMember): buffer it so every member has a durable record, then
promote it to a voting proposal if this node is the current epoch
steward and the conversation accepts new proposals.
Sourcepub async fn process_user_vote(
arc: &Arc<RwLock<Self>>,
proposal_id: u32,
vote: bool,
) -> Result<(), UserError>
pub async fn process_user_vote( arc: &Arc<RwLock<Self>>, proposal_id: u32, vote: bool, ) -> Result<(), UserError>
Cast a manual vote on behalf of the local member. Blocked in
Freezing and Selection; cancels any pending auto-vote so the
manual choice wins.
Sourcepub async fn tick_deadlines(arc: &Arc<RwLock<Self>>) -> Result<(), UserError>
pub async fn tick_deadlines(arc: &Arc<RwLock<Self>>) -> Result<(), UserError>
Walk pending deadlines and fire any whose fire_at has elapsed.
Call from the caller’s polling loop. Drains entries synchronously
under a brief write guard, then awaits the async fire (consensus
call or vote cast + publish) without holding the lock.
Source§impl<P: ConsensusPlugin, CP: ConversationPluginsFactory> SessionRunner<P, CP>
impl<P: ConsensusPlugin, CP: ConversationPluginsFactory> SessionRunner<P, CP>
Sourcepub async fn apply_consensus_outcome(
arc: &Arc<RwLock<Self>>,
event: ConsensusEvent,
) -> Result<(), UserError>
pub async fn apply_consensus_outcome( arc: &Arc<RwLock<Self>>, event: ConsensusEvent, ) -> Result<(), UserError>
Entry point from the consensus event bus: decode the proposal, apply the result to the conversation, and dispatch to the correct follow-up handler (election-accepted / election-rejected / emergency-scored).
Source§impl<P: ConsensusPlugin, CP: ConversationPluginsFactory> SessionRunner<P, CP>
impl<P: ConsensusPlugin, CP: ConversationPluginsFactory> SessionRunner<P, CP>
Sourcepub fn check_pending_join(
arc: &Arc<RwLock<Self>>,
) -> Result<PendingJoinTick, UserError>
pub fn check_pending_join( arc: &Arc<RwLock<Self>>, ) -> Result<PendingJoinTick, UserError>
Polling check for PendingJoin. Returns PendingJoinTick::Expired
after emitting SessionEvent::Leaving once the pending-join window
elapses; the caller handles registry-side cleanup.
Sourcepub async fn poll_freeze_status(
arc: &Arc<RwLock<Self>>,
) -> Result<(FreezeTimeoutStatus, DispatchOutcome), UserError>
pub async fn poll_freeze_status( arc: &Arc<RwLock<Self>>, ) -> Result<(FreezeTimeoutStatus, DispatchOutcome), UserError>
Poll tick for Freezing: drives Freezing → Selection once candidates
are all in or the freeze window elapses, then finalises, dispatches
the resulting crate::core::ProcessResult, and returns the
freeze status. The DispatchOutcome is LeaveRequested if the
applied commit ejected the local member — the caller drives the
User-side registry teardown.
Sourcepub async fn check_member_freeze(
arc: &Arc<RwLock<Self>>,
) -> Result<bool, UserError>
pub async fn check_member_freeze( arc: &Arc<RwLock<Self>>, ) -> Result<bool, UserError>
Drive the steward-inactivity check. Returns true exactly on the
tick that transitions into Freezing; false while still waiting,
outside Working, or when there’s no approved work. Stewards build
their own commit candidate under the same lock; candidate-build
failure is logged and the freeze transition proceeds (peers’
candidates still get processed).
Takes &Arc<RwLock<Self>> so the runner lock is released before
awaiting on the transport for the steward’s own candidate send.
Source§impl<P: ConsensusPlugin, CP: ConversationPluginsFactory> SessionRunner<P, CP>
impl<P: ConsensusPlugin, CP: ConversationPluginsFactory> SessionRunner<P, CP>
Sourcepub async fn send_kp_message(
arc: &Arc<RwLock<Self>>,
key_package: KeyPackageBytes,
) -> Result<(), UserError>
pub async fn send_kp_message( arc: &Arc<RwLock<Self>>, key_package: KeyPackageBytes, ) -> Result<(), UserError>
Broadcast key_package on this conversation’s welcome subtopic so
the steward can invite us. The caller (typically the integrator)
generates the key package via crate::app::User::generate_key_package —
KP minting is identity-bound, not conversation-bound, so it stays
at the User layer.
Takes &Arc<RwLock<Self>> so the runner lock is released before
awaiting on the transport.
Sourcepub async fn send_app_message(
arc: &Arc<RwLock<Self>>,
message: Vec<u8>,
) -> Result<(), UserError>
pub async fn send_app_message( arc: &Arc<RwLock<Self>>, message: Vec<u8>, ) -> Result<(), UserError>
Send a chat message. Blocked in PendingJoin (no keys yet),
Freezing, and Selection (epoch rotation in flight — the message
might not decrypt on peers who have already merged the next commit).
Governance traffic has its own gate (check_proposal_allowed).
Takes &Arc<RwLock<Self>> so the runner lock is released before
awaiting on the transport.
Sourcepub async fn process_ban_request(
arc: &Arc<RwLock<Self>>,
ban_request: BanRequest,
) -> Result<(), UserError>
pub async fn process_ban_request( arc: &Arc<RwLock<Self>>, ban_request: BanRequest, ) -> Result<(), UserError>
Start a RemoveMember consensus round targeting ban_request.user_to_ban.
The requester’s click means “I want this person removed” → the
creator’s vote is bundled as YES at submit; no banner is shown to
the requester.
Source§impl<P: ConsensusPlugin, CP: ConversationPluginsFactory> SessionRunner<P, CP>
impl<P: ConsensusPlugin, CP: ConversationPluginsFactory> SessionRunner<P, CP>
pub fn get_conversation_state(&self) -> ConversationState
Sourcepub fn get_epoch_and_retry(&self) -> Result<(u64, u32), UserError>
pub fn get_epoch_and_retry(&self) -> Result<(u64, u32), UserError>
Current MLS epoch + reelection retry round. (0, 0) when the
conversation has no MLS state yet (pending join). Intended for UI
status display.
Sourcepub fn get_pending_update_count(&self) -> usize
pub fn get_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 get_freeze_candidate_count(&self) -> (usize, usize)
pub fn get_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_for_self(&self) -> bool
Sourcepub fn get_conversation_members(&self) -> Result<Vec<Vec<u8>>, UserError>
pub fn get_conversation_members(&self) -> Result<Vec<Vec<u8>>, UserError>
Identity bytes of every current member of this conversation, as reported by MLS. Returns an empty vec when the local user has no MLS state yet (pending join).
pub fn get_member_scores(&self) -> Vec<(Vec<u8>, i64)>
pub fn get_member_score(&self, member_id: &[u8]) -> Option<i64>
Sourcepub fn get_pending_leave_identities(&self) -> Result<Vec<Vec<u8>>, UserError>
pub fn get_pending_leave_identities(&self) -> Result<Vec<Vec<u8>>, UserError>
Identities that have an in-flight self-leave request. Used by the UI to render a “pending leave” indicator.
Sourcepub fn get_member_roles(&self) -> Result<Vec<(Vec<u8>, MemberRole)>, UserError>
pub fn get_member_roles(&self) -> Result<Vec<(Vec<u8>, MemberRole)>, UserError>
Steward role for each member. Uses live rotation so removed or pending-leave stewards are skipped in role display.
pub fn get_approved_proposal_for_current_epoch( &self, ) -> Vec<ConversationUpdateRequest>
Source§impl<P: ConsensusPlugin, CP: ConversationPluginsFactory> SessionRunner<P, CP>
impl<P: ConsensusPlugin, CP: ConversationPluginsFactory> SessionRunner<P, CP>
Sourcepub fn drain_events(&self) -> Vec<SessionEvent>
pub fn drain_events(&self) -> Vec<SessionEvent>
Drain every pending SessionEvent accumulated since the last
call. Returns events in insertion order. Callers (UI fanout,
audit log) invoke this once per polling cycle.
Source§impl<P: ConsensusPlugin, CP: ConversationPluginsFactory> SessionRunner<P, CP>
impl<P: ConsensusPlugin, CP: ConversationPluginsFactory> SessionRunner<P, CP>
Sourcepub fn sync_scoring_members(&mut self, mls_members: &[Vec<u8>])
pub fn sync_scoring_members(&mut self, mls_members: &[Vec<u8>])
Add any MLS members not yet tracked in scoring, and drop scored
entries for identities no longer in MLS. Diffing is delegated to
scoring_member_diff; this method only applies the diff.
Sourcepub async fn steward_list_housekeeping(
arc: &Arc<RwLock<Self>>,
) -> Result<(), UserError>
pub async fn steward_list_housekeeping( arc: &Arc<RwLock<Self>>, ) -> Result<(), UserError>
Post-epoch-advance sequence: (1) auto-fill if membership dropped
below sn_min, (2) kick off an election if the list is exhausted.
Election-initiate failures are logged, not surfaced — conversation
state may legitimately reject a new proposal right now.
Sourcepub fn regenerate_steward_list(&mut self) -> Result<(), UserError>
pub fn regenerate_steward_list(&mut self) -> Result<(), UserError>
Regenerate the steward list at the current epoch against the current MLS member set — same effect as a successful election. Intended for tests and administrative tooling.
Sourcepub fn prune_pending_updates_after_commit(&mut self) -> Result<(), UserError>
pub fn prune_pending_updates_after_commit(&mut self) -> Result<(), UserError>
Drop Add entries whose target is now a member and Remove entries
whose target is now gone, then expire entries older than
pending_update_max_epochs.
Sourcepub async fn process_buffered_updates(
arc: &Arc<RwLock<Self>>,
) -> Result<(), UserError>
pub async fn process_buffered_updates( arc: &Arc<RwLock<Self>>, ) -> Result<(), UserError>
On epoch advance, the new live epoch steward drains the pending-update buffer into voting proposals. Skips entries already covered by the current voting/approved queues so we don’t double-propose.
Sourcepub async fn send_conversation_sync(
arc: &Arc<RwLock<Self>>,
) -> Result<(), UserError>
pub async fn send_conversation_sync( arc: &Arc<RwLock<Self>>, ) -> Result<(), UserError>
Broadcast steward list + protocol config + peer scores + timing as
an encrypted ConversationSync. Steward calls this after an Add-bearing
commit so new joiners can fully participate. Idempotent for members
who already have a steward list.
Takes &Arc<RwLock<Self>> so the runner lock is released before
awaiting on the transport.
Auto Trait Implementations§
impl<P, CP> !Freeze for SessionRunner<P, CP>
impl<P, CP> RefUnwindSafe for SessionRunner<P, CP>where
<CP as ConversationPluginsFactory>::Scoring: RefUnwindSafe,
<CP as ConversationPluginsFactory>::StewardList: RefUnwindSafe,
<P as ConsensusPlugin>::ConsensusStorage: RefUnwindSafe,
<P as ConsensusPlugin>::EventBus: RefUnwindSafe,
<P as ConsensusPlugin>::Signer: RefUnwindSafe,
<CP as ConversationPluginsFactory>::Mls: RefUnwindSafe,
<P as ConsensusPlugin>::Scope: RefUnwindSafe,
impl<P, CP> Send for SessionRunner<P, CP>where
<CP as ConversationPluginsFactory>::Scoring: Send,
<CP as ConversationPluginsFactory>::StewardList: Send,
<CP as ConversationPluginsFactory>::Mls: Send,
impl<P, CP> Sync for SessionRunner<P, CP>where
<CP as ConversationPluginsFactory>::Scoring: Sync,
<CP as ConversationPluginsFactory>::StewardList: Sync,
<CP as ConversationPluginsFactory>::Mls: Sync,
impl<P, CP> Unpin for SessionRunner<P, CP>where
<CP as ConversationPluginsFactory>::Scoring: Unpin,
<CP as ConversationPluginsFactory>::StewardList: Unpin,
<P as ConsensusPlugin>::ConsensusStorage: Unpin,
<P as ConsensusPlugin>::EventBus: Unpin,
<P as ConsensusPlugin>::Signer: Unpin,
<CP as ConversationPluginsFactory>::Mls: Unpin,
<P as ConsensusPlugin>::Scope: Unpin,
impl<P, CP> UnsafeUnpin for SessionRunner<P, CP>where
<CP as ConversationPluginsFactory>::Scoring: UnsafeUnpin,
<CP as ConversationPluginsFactory>::StewardList: UnsafeUnpin,
<P as ConsensusPlugin>::ConsensusStorage: UnsafeUnpin,
<P as ConsensusPlugin>::EventBus: UnsafeUnpin,
<P as ConsensusPlugin>::Signer: UnsafeUnpin,
<CP as ConversationPluginsFactory>::Mls: UnsafeUnpin,
impl<P, CP> UnwindSafe for SessionRunner<P, CP>where
<CP as ConversationPluginsFactory>::Scoring: UnwindSafe,
<CP as ConversationPluginsFactory>::StewardList: UnwindSafe,
<P as ConsensusPlugin>::ConsensusStorage: UnwindSafe,
<P as ConsensusPlugin>::EventBus: UnwindSafe,
<P as ConsensusPlugin>::Signer: UnwindSafe,
<CP as ConversationPluginsFactory>::Mls: UnwindSafe,
<P 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
Source§impl<T> Declassify for T
impl<T> Declassify for T
type Declassified = T
fn declassify(self) -> T
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