nautilus_dydx/websocket/
error.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Error types for dYdX WebSocket operations.
17
18use std::fmt::{self, Display};
19
20use nautilus_network::error::SendError;
21use serde::{Deserialize, Serialize};
22use serde_json::Value;
23use thiserror::Error;
24
25use super::enums::{DydxWsChannel, DydxWsMessageType};
26
27/// Result type for dYdX WebSocket operations.
28pub type DydxWsResult<T> = Result<T, DydxWsError>;
29
30/// Errors that can occur during dYdX WebSocket operations.
31#[derive(Debug, Error)]
32pub enum DydxWsError {
33    /// WebSocket client is not connected.
34    #[error("WebSocket client not connected")]
35    NotConnected,
36
37    /// Failed to send a message over the WebSocket connection.
38    #[error("WebSocket send error: {0}")]
39    Send(String),
40
41    /// Underlying transport error from the WebSocket implementation.
42    #[error("WebSocket transport error: {0}")]
43    Transport(String),
44
45    /// Error during JSON serialization/deserialization.
46    #[error("JSON error: {0}")]
47    Json(String),
48
49    /// Failed to parse venue message.
50    #[error("Failed to parse message: {0}")]
51    Parse(String),
52
53    /// Authentication failed.
54    #[error("Authentication error: {0}")]
55    Authentication(String),
56
57    /// Generic client error.
58    #[error("Client error: {0}")]
59    ClientError(String),
60
61    /// Subscription operation failed.
62    #[error("Subscription error: {0}")]
63    Subscription(String),
64
65    /// Error from the dYdX venue.
66    #[error("dYdX error: {0}")]
67    Venue(#[from] DydxWebSocketError),
68}
69
70impl From<SendError> for DydxWsError {
71    fn from(error: SendError) -> Self {
72        Self::Send(error.to_string())
73    }
74}
75
76impl From<tokio_tungstenite::tungstenite::Error> for DydxWsError {
77    fn from(error: tokio_tungstenite::tungstenite::Error) -> Self {
78        Self::Transport(error.to_string())
79    }
80}
81
82impl From<serde_json::Error> for DydxWsError {
83    fn from(error: serde_json::Error) -> Self {
84        Self::Json(error.to_string())
85    }
86}
87
88impl From<anyhow::Error> for DydxWsError {
89    fn from(e: anyhow::Error) -> Self {
90        Self::ClientError(e.to_string())
91    }
92}
93
94/// Error message received from the dYdX WebSocket API.
95///
96/// # References
97///
98/// <https://docs.dydx.trade/developers/indexer/websockets>
99#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct DydxWebSocketError {
101    /// The type field (typically "error").
102    #[serde(rename = "type")]
103    pub msg_type: DydxWsMessageType,
104    /// The error message from the venue.
105    pub message: String,
106    /// The connection ID.
107    #[serde(default, skip_serializing_if = "Option::is_none")]
108    pub connection_id: Option<String>,
109    /// The message ID.
110    #[serde(default, skip_serializing_if = "Option::is_none")]
111    pub message_id: Option<u64>,
112    /// The channel name.
113    #[serde(default, skip_serializing_if = "Option::is_none")]
114    pub channel: Option<DydxWsChannel>,
115    /// The channel-specific ID.
116    #[serde(default, skip_serializing_if = "Option::is_none")]
117    pub id: Option<String>,
118}
119
120impl DydxWebSocketError {
121    /// Creates a new [`DydxWebSocketError`] from a message.
122    #[must_use]
123    pub fn from_message(message: String) -> Self {
124        Self {
125            msg_type: DydxWsMessageType::Error,
126            message,
127            connection_id: None,
128            message_id: None,
129            channel: None,
130            id: None,
131        }
132    }
133
134    /// Creates a new [`DydxWebSocketError`] from a raw JSON value.
135    pub fn from_value(value: &Value) -> Option<Self> {
136        serde_json::from_value(value.clone()).ok()
137    }
138}
139
140impl Display for DydxWebSocketError {
141    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142        write!(
143            f,
144            "{} (channel: {:?}, id: {:?})",
145            self.message, self.channel, self.id
146        )
147    }
148}
149
150impl std::error::Error for DydxWebSocketError {}