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;
26use crate::schemas::ws::DydxWsMessageType;
27
28/// Result type for dYdX WebSocket operations.
29pub type DydxWsResult<T> = Result<T, DydxWsError>;
30
31/// Errors that can occur during dYdX WebSocket operations.
32#[derive(Debug, Error)]
33pub enum DydxWsError {
34    /// WebSocket client is not connected.
35    #[error("WebSocket client not connected")]
36    NotConnected,
37
38    /// Failed to send a message over the WebSocket connection.
39    #[error("WebSocket send error: {0}")]
40    Send(String),
41
42    /// Underlying transport error from the WebSocket implementation.
43    #[error("WebSocket transport error: {0}")]
44    Transport(String),
45
46    /// Error during JSON serialization/deserialization.
47    #[error("JSON error: {0}")]
48    Json(String),
49
50    /// Failed to parse venue message.
51    #[error("Failed to parse message: {0}")]
52    Parse(String),
53
54    /// Authentication failed.
55    #[error("Authentication error: {0}")]
56    Authentication(String),
57
58    /// Generic client error.
59    #[error("Client error: {0}")]
60    ClientError(String),
61
62    /// Subscription operation failed.
63    #[error("Subscription error: {0}")]
64    Subscription(String),
65
66    /// Error from the dYdX venue.
67    #[error("dYdX error: {0}")]
68    Venue(#[from] DydxWebSocketError),
69}
70
71impl From<SendError> for DydxWsError {
72    fn from(error: SendError) -> Self {
73        Self::Send(error.to_string())
74    }
75}
76
77impl From<tokio_tungstenite::tungstenite::Error> for DydxWsError {
78    fn from(error: tokio_tungstenite::tungstenite::Error) -> Self {
79        Self::Transport(error.to_string())
80    }
81}
82
83impl From<serde_json::Error> for DydxWsError {
84    fn from(error: serde_json::Error) -> Self {
85        Self::Json(error.to_string())
86    }
87}
88
89impl From<anyhow::Error> for DydxWsError {
90    fn from(e: anyhow::Error) -> Self {
91        Self::ClientError(e.to_string())
92    }
93}
94
95/// Error message received from the dYdX WebSocket API.
96///
97/// # References
98///
99/// <https://docs.dydx.trade/developers/indexer/websockets>
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct DydxWebSocketError {
102    /// The type field (typically "error").
103    #[serde(rename = "type")]
104    pub msg_type: DydxWsMessageType,
105    /// The error message from the venue.
106    pub message: String,
107    /// The connection ID.
108    #[serde(default, skip_serializing_if = "Option::is_none")]
109    pub connection_id: Option<String>,
110    /// The message ID.
111    #[serde(default, skip_serializing_if = "Option::is_none")]
112    pub message_id: Option<u64>,
113    /// The channel name.
114    #[serde(default, skip_serializing_if = "Option::is_none")]
115    pub channel: Option<DydxWsChannel>,
116    /// The channel-specific ID.
117    #[serde(default, skip_serializing_if = "Option::is_none")]
118    pub id: Option<String>,
119}
120
121impl DydxWebSocketError {
122    /// Creates a new [`DydxWebSocketError`] from a message.
123    #[must_use]
124    pub fn from_message(message: String) -> Self {
125        Self {
126            msg_type: DydxWsMessageType::Error,
127            message,
128            connection_id: None,
129            message_id: None,
130            channel: None,
131            id: None,
132        }
133    }
134
135    /// Creates a new [`DydxWebSocketError`] from a raw JSON value.
136    pub fn from_value(value: &Value) -> Option<Self> {
137        serde_json::from_value(value.clone()).ok()
138    }
139}
140
141impl Display for DydxWebSocketError {
142    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143        write!(
144            f,
145            "{} (channel: {:?}, id: {:?})",
146            self.message, self.channel, self.id
147        )
148    }
149}
150
151impl std::error::Error for DydxWebSocketError {}