1use slim_datapath::api::ProtoName;
5use slim_datapath::errors::{ErrorPayload, MessageContext};
6use thiserror::Error;
8
9use slim_auth::errors::AuthError;
11use slim_datapath::api::{ProtoMessage, ProtoSessionMessageType, ProtoSessionType};
12use slim_datapath::messages::utils::MessageError;
13use slim_mls::errors::MlsError;
14use tonic::Status;
15
16use crate::SessionMessage;
17use crate::subscription_manager::SubscriptionAckError;
18
19#[derive(Error, Debug)]
20pub enum SessionError {
21 #[error("SLIM channel closed")]
23 SlimChannelClosed,
24 #[error("error receiving message from SLIM")]
25 SlimReception(#[from] Status),
26
27 #[error("message error")]
29 MessageError(#[from] MessageError),
30 #[error("missing removed participant in GroupRemove message")]
31 MissingRemovedParticipantInGroupRemove,
32 #[error("missing new participant in GroupAdd message")]
33 MissingNewParticipantInGroupAdd,
34 #[error("missing group name in JoinRequest message")]
35 MissingGroupNameInJoinRequest,
36 #[error("missing channel name for group session")]
37 MissingChannelName,
38 #[error("session type unknown: {0:?}")]
39 SessionTypeUnknown(ProtoSessionType),
40 #[error("session message type unexpected: {0:?}")]
41 SessionMessageInternalUnexpected(Box<SessionMessage>),
42 #[error("session message type unknown: {0:?}")]
43 SessionMessageTypeUnknown(ProtoSessionMessageType),
44 #[error("message type unexpected: {0:?}")]
45 MessageTypeUnexpected(Box<ProtoMessage>),
46 #[error("session message type unexpected: {0:?}")]
47 SessionMessageTypeUnexpected(ProtoSessionMessageType),
48 #[error("error getting the participants list")]
49 ParticipantsListQueryFailed,
50 #[error("malformed participant settings")]
51 MalformedParticipant,
52 #[error("missing participant settings")]
53 MissingParticipantSettings,
54 #[error("identity key is empty")]
55 SignatureKeyIsEmpty,
56 #[error("identity key collection failed with auth error: {0:?}")]
57 SignatureKeyCollectionFailedWithAuthErr(AuthError),
58 #[error("unexpected error")]
59 UnexpectedError { source: Box<SessionError> },
60
61 #[error("session not found: {0}")]
63 SessionNotFound(u32),
64 #[error("subscription not found: {0}")]
65 SubscriptionNotFound(ProtoName),
66
67 #[error("session builder: not all required fields set")]
69 SessionBuilderIncomplete,
70 #[error("message lost for session id: {0}")]
71 MessageLost(u32),
72 #[error("session closed")]
73 SessionClosed,
74 #[error("receive timeout waiting for message")]
75 ReceiveTimeout,
76 #[error("session id already used: {0}")]
77 SessionIdAlreadyUsed(u32),
78 #[error("invalid session id: {0}")]
79 InvalidSessionId(u32),
80
81 #[error("mls operation error")]
83 MlsOp(#[from] MlsError),
84
85 #[error("auth error: {0}")]
87 Auth(#[from] AuthError),
88 #[error("duplicate control message replay: message_id={message_id}")]
89 ControlMessageReplay { message_id: u32 },
90
91 #[error("error receiving ack for message: {0}")]
93 AckReception(String),
94 #[error("subscription ack failed: {0}")]
95 SubscriptionAckFailed(#[source] SubscriptionAckError),
96 #[error("unknown destination: {0}")]
97 UnknownDestination(ProtoName),
98
99 #[error("participant not found in group: {0}")]
101 ParticipantNotFound(ProtoName),
102 #[error("participant already in group: {0}")]
103 ParticipantAlreadyInGroup(ProtoName),
104 #[error("cannot invite participant to point-to-point session")]
105 CannotInviteToP2P,
106 #[error("cannot remove participant from point-to-point session")]
107 CannotRemoveFromP2P,
108 #[error("cannot close a point-to-point session")]
109 CannotCloseP2P,
110 #[error("cannot rejoin a point-to-point session")]
111 CannotRejoinP2P,
112 #[error("only initiator can modify participants")]
113 NotInitiator,
114
115 #[error("error sending session internal message to session controller")]
117 SessionControllerSendFailed,
118 #[error("error sending new session notification to app")]
119 NewSessionSendFailed,
120 #[error("error sending session delete message to session layer")]
121 SessionDeleteMessageSendFailed,
122 #[error("error sending data message to application")]
123 ApplicationMessageSendFailed,
124 #[error("error sending data message to slim")]
125 SlimMessageSendFailed,
126 #[error("send failure reported from slim: {ctx}")]
127 SlimSendFailure { ctx: Box<ErrorPayload> },
128
129 #[error("session is draining - drop message")]
131 SessionDrainingDrop,
132 #[error("session already closed")]
133 SessionAlreadyClosed,
134 #[error("participant is offline")]
135 ParticipantOffLine,
136 #[error("rejoin failed: epoch mismatch")]
137 RejoinFailed,
138 #[error("another status change is already in progress")]
139 StatusChangeInProgress,
140 #[error("session cleanup failed: {details}")]
141 SessionCleanupFailed { details: String },
142 #[error("message send retries exhausted for id={id}")]
143 MessageSendRetryFailed { id: u32 },
144 #[error("message receive retries exhausted for id={id}")]
145 MessageReceiveRetryFailed { id: u32 },
146 #[error("session sender is shutdown, cannot send messages")]
147 SessionSenderShutdown,
148 #[error("session receiver is shutdown, cannot receive messages")]
149 SessionReceiverShutdown,
150 #[error("missing participant name on timer")]
151 MissingParticipantNameOnTimer,
152
153 #[error("missing payload: {context}")]
155 MissingPayload { context: &'static str },
156 #[error("message build failed: {0}")]
157 MessageBuild(MessageError),
158 #[error("message payload extract failed in {context}: {source}")]
159 PayloadExtract {
160 context: &'static str,
161 source: MessageError,
162 },
163
164 #[error("missing mls payload in welcome message")]
166 WelcomeMessageMissingMlsPayload,
167 #[error("invalid join request payload")]
168 InvalidJoinRequestPayload,
169 #[error("participant disconnected: {0}")]
170 ParticipantDisconnected(ProtoName),
171 #[error("missing participant name on disconnection event")]
172 MissingParticipantNameOnDisconnection,
173
174 #[error("no pending requests for the given key: {0}")]
176 TimerNotFound(u32),
177 #[error("phase not supported for task")]
178 ModeratorTaskUnsupportedPhase,
179 #[error("unexpected timer id: {0}")]
180 ModeratorTaskUnexpectedTimerId(u32),
181 #[error("failed to add participant to session: {source}")]
182 ModeratorTaskAddFailed { source: Box<SessionError> },
183 #[error("failed to remove participant from session: {source}")]
184 ModeratorTaskRemoveFailed { source: Box<SessionError> },
185 #[error("failed to update session: {source}")]
186 ModeratorTaskUpdateFailed { source: Box<SessionError> },
187 #[error("failed to close session: {source}")]
188 ModeratorTaskCloseFailed { source: Box<SessionError> },
189}
190
191impl SessionError {
192 pub fn build_error(err: MessageError) -> Self {
194 SessionError::MessageBuild(err)
195 }
196 pub fn extract_error(context: &'static str, err: MessageError) -> Self {
197 SessionError::PayloadExtract {
198 context,
199 source: err,
200 }
201 }
202 pub fn cleanup_failed<E: std::fmt::Display>(e: E) -> Self {
203 SessionError::SessionCleanupFailed {
204 details: e.to_string(),
205 }
206 }
207
208 pub fn send_retry_failed(id: u32) -> Self {
210 SessionError::MessageSendRetryFailed { id }
211 }
212
213 pub fn receive_retry_failed(id: u32) -> Self {
214 SessionError::MessageReceiveRetryFailed { id }
215 }
216
217 pub fn session_context(&self) -> Option<&MessageContext> {
220 match self {
221 SessionError::SlimSendFailure { ctx } => ctx.session_context.as_ref(),
222 _ => None,
223 }
224 }
225
226 pub fn is_command_message_error(&self) -> bool {
228 self.session_context()
229 .map(|ctx| ctx.get_session_message_type().is_command_message())
230 .unwrap_or(false)
231 }
232}