1use thiserror::Error;
4
5pub type Result<T> = std::result::Result<T, RealtimeError>;
7
8#[derive(Error, Debug)]
10pub enum RealtimeError {
11 #[error("WebSocket connection error: {0}")]
13 ConnectionError(String),
14
15 #[error("WebSocket message error: {0}")]
17 MessageError(String),
18
19 #[error("Authentication error: {0}")]
21 AuthError(String),
22
23 #[error("Session not connected")]
25 NotConnected,
26
27 #[error("Session already closed")]
29 SessionClosed,
30
31 #[error("Invalid configuration: {0}")]
33 ConfigError(String),
34
35 #[error("Audio format error: {0}")]
37 AudioFormatError(String),
38
39 #[error("Tool execution error: {0}")]
41 ToolError(String),
42
43 #[error("Server error: {code} - {message}")]
45 ServerError {
46 code: String,
48 message: String,
50 },
51
52 #[error("Timeout: {0}")]
54 Timeout(String),
55
56 #[error("Serialization error: {0}")]
58 SerializationError(#[from] serde_json::Error),
59
60 #[error("Provider error: {0}")]
62 ProviderError(String),
63
64 #[error("IO error: {0}")]
66 IoError(#[from] std::io::Error),
67
68 #[error("Opus codec error: {0}")]
70 OpusCodecError(String),
71
72 #[error("WebRTC error: {0}")]
74 WebRTCError(String),
75
76 #[error("LiveKit error: {0}")]
78 LiveKitError(String),
79
80 #[cfg(feature = "livekit")]
82 #[error(transparent)]
83 LiveKitNativeError(Box<crate::livekit::LiveKitError>),
84}
85
86#[cfg(feature = "livekit")]
87impl From<crate::livekit::LiveKitError> for RealtimeError {
89 fn from(err: crate::livekit::LiveKitError) -> Self {
90 RealtimeError::LiveKitNativeError(Box::new(err))
91 }
92}
93
94impl RealtimeError {
95 pub fn connection<S: Into<String>>(msg: S) -> Self {
97 Self::ConnectionError(msg.into())
98 }
99
100 pub fn server<S: Into<String>>(code: S, message: S) -> Self {
102 Self::ServerError { code: code.into(), message: message.into() }
103 }
104
105 pub fn provider<S: Into<String>>(msg: S) -> Self {
107 Self::ProviderError(msg.into())
108 }
109
110 #[cfg(feature = "video-avatar")]
115 pub fn avatar<S: Into<String>>(msg: S) -> Self {
116 Self::ProviderError(format!("avatar: {}", msg.into()))
117 }
118
119 pub fn config<S: Into<String>>(msg: S) -> Self {
121 Self::ConfigError(msg.into())
122 }
123
124 pub fn protocol<S: Into<String>>(msg: S) -> Self {
126 Self::MessageError(msg.into())
127 }
128
129 pub fn audio<S: Into<String>>(msg: S) -> Self {
131 Self::AudioFormatError(msg.into())
132 }
133
134 pub fn opus(msg: impl Into<String>) -> Self {
136 Self::OpusCodecError(msg.into())
137 }
138
139 pub fn webrtc(msg: impl Into<String>) -> Self {
141 Self::WebRTCError(msg.into())
142 }
143
144 pub fn livekit(msg: impl Into<String>) -> Self {
146 Self::LiveKitError(msg.into())
147 }
148}
149
150#[cfg(test)]
151mod tests {
152
153 #[cfg(feature = "livekit")]
154 #[test]
155 fn test_livekit_native_error_conversion() {
156 let inner = crate::livekit::LiveKitError::ConfigError("test config error".to_string());
158
159 let realtime_err: crate::error::RealtimeError = inner.into();
161
162 match realtime_err {
164 crate::error::RealtimeError::LiveKitNativeError(boxed_err) => {
165 assert!(matches!(*boxed_err, crate::livekit::LiveKitError::ConfigError(_)));
166 assert_eq!(
167 format!("{}", boxed_err),
168 "LiveKit configuration error: test config error"
169 );
170 }
171 _ => panic!("Expected LiveKitNativeError variant"),
172 }
173 }
174}