Skip to main content

GroupEventHandler

Trait GroupEventHandler 

Source
pub trait GroupEventHandler: Send + Sync {
    // Required methods
    fn on_outbound<'life0, 'life1, 'async_trait>(
        &'life0 self,
        group_name: &'life1 str,
        packet: OutboundPacket,
    ) -> Pin<Box<dyn Future<Output = Result<String, CoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn on_app_message<'life0, 'life1, 'async_trait>(
        &'life0 self,
        group_name: &'life1 str,
        message: AppMessage,
    ) -> Pin<Box<dyn Future<Output = Result<(), CoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn on_leave_group<'life0, 'life1, 'async_trait>(
        &'life0 self,
        group_name: &'life1 str,
    ) -> Pin<Box<dyn Future<Output = Result<(), CoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn on_joined_group<'life0, 'life1, 'async_trait>(
        &'life0 self,
        group_name: &'life1 str,
    ) -> Pin<Box<dyn Future<Output = Result<(), CoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn on_error<'life0, 'life1, 'life2, 'life3, 'async_trait>(
        &'life0 self,
        group_name: &'life1 str,
        operation: &'life2 str,
        error: &'life3 str,
    ) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait,
             'life3: 'async_trait;
}
Expand description

Trait for handling output events from group operations.

This is the main trait you need to implement to integrate DE-MLS with your application. It receives callbacks for all significant output events:

  • Network packets that need to be sent
  • Application messages for UI display
  • Group membership changes (join/leave)
  • Background operation errors

§Thread Safety

This trait requires Send + Sync because callbacks may be invoked from async contexts and multiple groups may be processed concurrently.

§Example

use async_trait::async_trait;
use de_mls::core::{GroupEventHandler, CoreError};
use de_mls::protos::de_mls::messages::v1::AppMessage;
use ds::transport::OutboundPacket;

struct MyHandler {
    transport: MyTransport,
    ui_sender: mpsc::Sender<UiEvent>,
}

#[async_trait]
impl GroupEventHandler for MyHandler {
    async fn on_outbound(
        &self,
        group_name: &str,
        packet: OutboundPacket,
    ) -> Result<String, CoreError> {
        self.transport.send(packet).await
            .map_err(|e| CoreError::DeliveryError(e.to_string()))
    }

    async fn on_app_message(
        &self,
        group_name: &str,
        message: AppMessage,
    ) -> Result<(), CoreError> {
        self.ui_sender.send(UiEvent::Message { group_name, message }).await
            .map_err(|e| CoreError::HandlerError(e.to_string()))
    }

    async fn on_leave_group(&self, group_name: &str) -> Result<(), CoreError> {
        self.ui_sender.send(UiEvent::GroupRemoved(group_name.to_string())).await
            .map_err(|e| CoreError::HandlerError(e.to_string()))
    }

    async fn on_joined_group(&self, group_name: &str) -> Result<(), CoreError> {
        self.ui_sender.send(UiEvent::GroupJoined(group_name.to_string())).await
            .map_err(|e| CoreError::HandlerError(e.to_string()))
    }

    async fn on_error(&self, group_name: &str, operation: &str, error: &str) {
        tracing::error!("Error in {operation} for group {group_name}: {error}");
    }
}

Required Methods§

Source

fn on_outbound<'life0, 'life1, 'async_trait>( &'life0 self, group_name: &'life1 str, packet: OutboundPacket, ) -> Pin<Box<dyn Future<Output = Result<String, CoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Called when a packet needs to be sent to the network.

This is the primary output for MLS-encrypted messages. The packet contains the encrypted payload, subtopic, group name, and app ID.

§Arguments
  • group_name - The name of the group this packet is for
  • packet - The outbound packet to send
§Returns

A message ID or identifier from the transport layer (if available).

§Implementation Notes
  • This should send the packet via your transport layer (Waku, libp2p, etc.)
  • The packet’s subtopic determines the message type (welcome vs app)
  • Failures should be returned as CoreError::DeliveryError
Source

fn on_app_message<'life0, 'life1, 'async_trait>( &'life0 self, group_name: &'life1 str, message: AppMessage, ) -> Pin<Box<dyn Future<Output = Result<(), CoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Called when an application message should be delivered to the UI.

This includes:

  • Chat messages (ConversationMessage)
  • Vote requests (VotePayload)
  • Proposal notifications (ProposalAdded)
  • Ban requests (BanRequest)
§Arguments
  • group_name - The name of the group this message is from
  • message - The application message (see app_message::Payload variants)
§Implementation Notes
  • Dispatch based on message.payload variant
  • VotePayload should trigger UI for user to approve/reject
  • ConversationMessage should be displayed in chat
Source

fn on_leave_group<'life0, 'life1, 'async_trait>( &'life0 self, group_name: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<(), CoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Called when the user has been removed from a group.

This is called for both:

  • Voluntary leave (after the removal commit is processed)
  • Forced removal (when another member removes you)
§Arguments
  • group_name - The name of the group to leave
§Implementation Notes
  • Remove the group from your registry
  • Stop any background tasks for this group
  • Notify the UI that the group was removed
Source

fn on_joined_group<'life0, 'life1, 'async_trait>( &'life0 self, group_name: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<(), CoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Called when the user successfully joined a group.

This is called after a welcome message is processed and the MLS state is initialized.

§Arguments
  • group_name - The name of the group joined
§Implementation Notes
  • Update UI to show the user is now a member
  • Start any background tasks for this group (epoch timer, etc.)
Source

fn on_error<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, group_name: &'life1 str, operation: &'life2 str, error: &'life3 str, ) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Called when a background operation fails.

This is used for operations that run in spawned tasks, such as voting requests, where errors can’t be returned directly.

§Arguments
  • group_name - The name of the group
  • operation - Description of the failed operation (e.g., “start_voting”)
  • error - The error message
§Implementation Notes
  • Log the error
  • Optionally notify the UI

Implementors§