1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//! Event handler trait for group operations.
//!
//! The [`GroupEventHandler`] trait is the primary integration point between
//! the DE-MLS core and your application. Implement this trait to handle
//! output events from group operations.
use async_trait;
use crateCoreError;
use crateOutboundPacket;
use crateAppMessage;
/// 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
///
/// ```ignore
/// 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}");
/// }
/// }
/// ```