1use slim_datapath::errors::{ErrorPayload, MessageContext};
5use slim_datapath::messages::Name;
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 group name in JoinRequest message")]
33 MissingGroupNameInJoinRequest,
34 #[error("ping state not initialized")]
35 PingStateNotInitialized,
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("unexpected error")]
51 UnexpectedError { source: Box<SessionError> },
52
53 #[error("session not found: {0}")]
55 SessionNotFound(u32),
56 #[error("subscription not found: {0}")]
57 SubscriptionNotFound(Name),
58
59 #[error("session builder: not all required fields set")]
61 SessionBuilderIncomplete,
62 #[error("message lost for session id: {0}")]
63 MessageLost(u32),
64 #[error("session closed")]
65 SessionClosed,
66 #[error("receive timeout waiting for message")]
67 ReceiveTimeout,
68 #[error("session id already used: {0}")]
69 SessionIdAlreadyUsed(u32),
70 #[error("invalid session id: {0}")]
71 InvalidSessionId(u32),
72
73 #[error("mls operation error")]
75 MlsOp(#[from] MlsError),
76
77 #[error("auth error")]
79 Auth(#[from] AuthError),
80
81 #[error("error receiving ack for message: {0}")]
83 AckReception(String),
84 #[error("subscription ack failed: {0}")]
85 SubscriptionAckFailed(#[source] SubscriptionAckError),
86 #[error("unknown destination: {0}")]
87 UnknownDestination(Name),
88
89 #[error("participant not found in group: {0}")]
91 ParticipantNotFound(Name),
92 #[error("participant already in group: {0}")]
93 ParticipantAlreadyInGroup(Name),
94 #[error("cannot invite participant to point-to-point session")]
95 CannotInviteToP2P,
96 #[error("cannot remove participant from point-to-point session")]
97 CannotRemoveFromP2P,
98 #[error("only initiator can modify participants")]
99 NotInitiator,
100
101 #[error("error sending session internal message to session controller")]
103 SessionControllerSendFailed,
104 #[error("error sending new session notification to app")]
105 NewSessionSendFailed,
106 #[error("error sending session delete message to session layer")]
107 SessionDeleteMessageSendFailed,
108 #[error("error sending data message to application")]
109 ApplicationMessageSendFailed,
110 #[error("error sending data message to slim")]
111 SlimMessageSendFailed,
112 #[error("send failure reported from slim: {ctx}")]
113 SlimSendFailure { ctx: Box<ErrorPayload> },
114
115 #[error("session is draining - drop message")]
117 SessionDrainingDrop,
118 #[error("session already closed")]
119 SessionAlreadyClosed,
120 #[error("session cleanup failed: {details}")]
121 SessionCleanupFailed { details: String },
122 #[error("message send retries exhausted for id={id}")]
123 MessageSendRetryFailed { id: u32 },
124 #[error("message receive retries exhausted for id={id}")]
125 MessageReceiveRetryFailed { id: u32 },
126 #[error("session sender is shutdown, cannot send messages")]
127 SessionSenderShutdown,
128
129 #[error("missing payload: {context}")]
131 MissingPayload { context: &'static str },
132 #[error("message build failed: {0}")]
133 MessageBuild(MessageError),
134 #[error("message payload extract failed in {context}: {source}")]
135 PayloadExtract {
136 context: &'static str,
137 source: MessageError,
138 },
139
140 #[error("missing mls payload in welcome message")]
142 WelcomeMessageMissingMlsPayload,
143 #[error("invalid join request payload")]
144 InvalidJoinRequestPayload,
145 #[error("participant disconnected: {0}")]
146 ParticipantDisconnected(Name),
147 #[error("missing participant name on disconnection event")]
148 MissingParticipantNameOnDisconnection,
149
150 #[error("no pending requests for the given key: {0}")]
152 TimerNotFound(u32),
153 #[error("phase not supported for task")]
154 ModeratorTaskUnsupportedPhase,
155 #[error("unexpected timer id: {0}")]
156 ModeratorTaskUnexpectedTimerId(u32),
157 #[error("failed to add participant to session")]
158 ModeratorTaskAddFailed { source: Box<SessionError> },
159 #[error("failed to remove participant from session")]
160 ModeratorTaskRemoveFailed { source: Box<SessionError> },
161 #[error("failed to update session")]
162 ModeratorTaskUpdateFailed { source: Box<SessionError> },
163 #[error("failed to close session")]
164 ModeratorTaskCloseFailed { source: Box<SessionError> },
165}
166
167impl SessionError {
168 pub fn build_error(err: MessageError) -> Self {
170 SessionError::MessageBuild(err)
171 }
172 pub fn extract_error(context: &'static str, err: MessageError) -> Self {
173 SessionError::PayloadExtract {
174 context,
175 source: err,
176 }
177 }
178 pub fn cleanup_failed<E: std::fmt::Display>(e: E) -> Self {
179 SessionError::SessionCleanupFailed {
180 details: e.to_string(),
181 }
182 }
183
184 pub fn send_retry_failed(id: u32) -> Self {
186 SessionError::MessageSendRetryFailed { id }
187 }
188
189 pub fn receive_retry_failed(id: u32) -> Self {
190 SessionError::MessageReceiveRetryFailed { id }
191 }
192
193 pub fn session_context(&self) -> Option<&MessageContext> {
196 match self {
197 SessionError::SlimSendFailure { ctx } => ctx.session_context.as_ref(),
198 _ => None,
199 }
200 }
201
202 pub fn is_command_message_error(&self) -> bool {
204 self.session_context()
205 .map(|ctx| ctx.get_session_message_type().is_command_message())
206 .unwrap_or(false)
207 }
208}