linkrs_server/session/
error.rs1use std::error::Error;
11
12use linkrs_core::error::codes::{ErrorCode, PublicError, ToPublicError};
13
14type BoxedError = Box<dyn Error + Send + Sync>;
16
17pub type SessionResult<T> = Result<T, SessionError>;
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub enum SessionErrorKind {
23 SessionNotFound,
24 SessionExpired,
25 MaxConnectionsExceeded,
26 QueryNotFound,
27 KillSessionFailed,
28 ManagerError,
29 InsufficientPermission,
30}
31
32impl SessionErrorKind {
33 pub fn as_str(&self) -> &'static str {
34 match self {
35 SessionErrorKind::SessionNotFound => "session_not_found",
36 SessionErrorKind::SessionExpired => "session_expired",
37 SessionErrorKind::MaxConnectionsExceeded => "max_connections_exceeded",
38 SessionErrorKind::QueryNotFound => "query_not_found",
39 SessionErrorKind::KillSessionFailed => "kill_session_failed",
40 SessionErrorKind::ManagerError => "manager_error",
41 SessionErrorKind::InsufficientPermission => "insufficient_permission",
42 }
43 }
44}
45
46#[derive(Debug)]
53pub struct SessionError {
54 kind: SessionErrorKind,
55 message: String,
56 source: Option<BoxedError>,
57}
58
59impl SessionError {
60 pub fn new(kind: SessionErrorKind, message: impl Into<String>) -> Self {
61 Self {
62 kind,
63 message: message.into(),
64 source: None,
65 }
66 }
67
68 pub fn with_source(mut self, source: BoxedError) -> Self {
69 self.source = Some(source);
70 self
71 }
72
73 pub fn kind(&self) -> SessionErrorKind {
74 self.kind
75 }
76
77 pub fn message(&self) -> &str {
78 &self.message
79 }
80
81 pub fn session_not_found(session_id: i64) -> Self {
83 Self::new(
84 SessionErrorKind::SessionNotFound,
85 format!("Session not found: {}", session_id),
86 )
87 }
88
89 pub fn session_expired() -> Self {
90 Self::new(SessionErrorKind::SessionExpired, "Session expired")
91 }
92
93 pub fn max_connections_exceeded() -> Self {
94 Self::new(
95 SessionErrorKind::MaxConnectionsExceeded,
96 "Maximum connections exceeded",
97 )
98 }
99
100 pub fn query_not_found(query_id: u32) -> Self {
101 Self::new(
102 SessionErrorKind::QueryNotFound,
103 format!("Query not found: {}", query_id),
104 )
105 }
106
107 pub fn kill_session_failed(message: impl Into<String>) -> Self {
108 Self::new(SessionErrorKind::KillSessionFailed, message)
109 }
110
111 pub fn manager_error(message: impl Into<String>) -> Self {
112 Self::new(SessionErrorKind::ManagerError, message)
113 }
114
115 pub fn insufficient_permission() -> Self {
116 Self::new(
117 SessionErrorKind::InsufficientPermission,
118 "Insufficient permission to perform this operation",
119 )
120 }
121}
122
123impl std::fmt::Display for SessionError {
124 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125 write!(f, "[{}] {}", self.kind.as_str(), self.message)?;
126 if let Some(ref source) = self.source {
127 write!(f, "\n Caused by: {}", source)?;
128 }
129 Ok(())
130 }
131}
132
133impl Clone for SessionError {
134 fn clone(&self) -> Self {
135 Self {
136 kind: self.kind,
137 message: self.message.clone(),
138 source: None,
139 }
140 }
141}
142
143impl std::error::Error for SessionError {
144 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
145 self.source
146 .as_ref()
147 .map(|e| e.as_ref() as &(dyn std::error::Error + 'static))
148 }
149}
150
151impl ToPublicError for SessionError {
152 fn to_public_error(&self) -> PublicError {
153 PublicError::new(self.to_error_code(), self.to_public_message())
154 }
155
156 fn to_error_code(&self) -> ErrorCode {
157 match self.kind {
158 SessionErrorKind::SessionNotFound => ErrorCode::ResourceNotFound,
159 SessionErrorKind::SessionExpired => ErrorCode::Unauthorized,
160 SessionErrorKind::MaxConnectionsExceeded => ErrorCode::ResourceExhausted,
161 SessionErrorKind::QueryNotFound => ErrorCode::ResourceNotFound,
162 SessionErrorKind::KillSessionFailed => ErrorCode::InternalError,
163 SessionErrorKind::ManagerError => ErrorCode::InternalError,
164 SessionErrorKind::InsufficientPermission => ErrorCode::PermissionDenied,
165 }
166 }
167
168 fn to_public_message(&self) -> String {
169 self.message.clone()
170 }
171}
172
173impl From<SessionError> for linkrs_core::error::DBError {
174 fn from(e: SessionError) -> Self {
175 let msg = e.to_string();
176 linkrs_core::error::DBError::session(msg).with_source(Box::new(e))
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183
184 #[test]
185 fn test_session_error_size() {
186 assert!(
187 std::mem::size_of::<SessionError>() <= 64,
188 "SessionError should be small, got {} bytes",
189 std::mem::size_of::<SessionError>()
190 );
191 }
192
193 #[test]
194 fn test_session_error_creation() {
195 let err = SessionError::session_not_found(123);
196 assert_eq!(err.kind(), SessionErrorKind::SessionNotFound);
197 assert!(err.message().contains("123"));
198 }
199}