modbus_relay/errors/
relay.rs

1use thiserror::Error;
2
3use super::{
4    BackoffError, ClientErrorKind, ConfigValidationError, ConnectionError, FrameError,
5    FrameErrorKind, FrameFormatKind, FrameSizeKind, InitializationError, ProtocolErrorKind,
6    RtsError, TransportError,
7};
8
9#[derive(Error, Debug)]
10pub enum RelayError {
11    #[error("Transport error: {0}")]
12    Transport(#[from] TransportError),
13
14    #[error("Protocol error: {kind} - {details}")]
15    Protocol {
16        kind: ProtocolErrorKind,
17        details: String,
18        source: Option<Box<dyn std::error::Error + Send + Sync>>,
19    },
20
21    #[error("Configuration error: {0}")]
22    Config(#[from] ConfigValidationError),
23
24    #[error("Frame error: {0}")]
25    Frame(#[from] FrameError),
26
27    #[error("Connection error: {0}")]
28    Connection(#[from] ConnectionError),
29
30    #[error("Client error: {kind} from {client_addr} - {details}")]
31    Client {
32        kind: ClientErrorKind,
33        client_addr: std::net::SocketAddr,
34        details: String,
35    },
36
37    #[error("Initialization error: {0}")]
38    Init(#[from] InitializationError),
39}
40
41impl RelayError {
42    pub fn protocol(kind: ProtocolErrorKind, details: impl Into<String>) -> Self {
43        RelayError::Protocol {
44            kind,
45            details: details.into(),
46            source: None,
47        }
48    }
49
50    pub fn protocol_with_source(
51        kind: ProtocolErrorKind,
52        details: impl Into<String>,
53        source: impl Into<Box<dyn std::error::Error + Send + Sync>>,
54    ) -> Self {
55        RelayError::Protocol {
56            kind,
57            details: details.into(),
58            source: Some(source.into()),
59        }
60    }
61
62    pub fn connection(kind: ConnectionError) -> Self {
63        RelayError::Connection(kind)
64    }
65
66    pub fn config(kind: ConfigValidationError) -> Self {
67        RelayError::Config(kind)
68    }
69
70    pub fn frame(
71        kind: FrameErrorKind,
72        details: impl Into<String>,
73        frame_data: Option<Vec<u8>>,
74    ) -> Self {
75        let details = details.into();
76        match kind {
77            FrameErrorKind::TooShort | FrameErrorKind::TooLong => {
78                RelayError::Frame(FrameError::Size {
79                    kind: match kind {
80                        FrameErrorKind::TooShort => FrameSizeKind::TooShort,
81                        FrameErrorKind::TooLong => FrameSizeKind::TooLong,
82                        _ => unreachable!(),
83                    },
84                    details,
85                    frame_data,
86                })
87            }
88            FrameErrorKind::InvalidFormat
89            | FrameErrorKind::InvalidUnitId
90            | FrameErrorKind::InvalidHeader
91            | FrameErrorKind::UnexpectedResponse => RelayError::Frame(FrameError::Format {
92                kind: match kind {
93                    FrameErrorKind::InvalidFormat => FrameFormatKind::InvalidFormat,
94                    FrameErrorKind::InvalidHeader => FrameFormatKind::InvalidHeader,
95                    FrameErrorKind::UnexpectedResponse => FrameFormatKind::UnexpectedResponse,
96                    _ => unreachable!(),
97                },
98                details,
99                frame_data,
100            }),
101            FrameErrorKind::InvalidCrc => {
102                if let Some(frame_data) = frame_data {
103                    let frame_hex = hex::encode(&frame_data);
104                    RelayError::Frame(FrameError::Crc {
105                        calculated: 0, // TODO(aljen): pass actual values
106                        received: 0,   // TODO(aljen): pass actual values
107                        frame_hex,
108                    })
109                } else {
110                    RelayError::Frame(FrameError::Format {
111                        kind: FrameFormatKind::InvalidFormat,
112                        details,
113                        frame_data: None,
114                    })
115                }
116            }
117        }
118    }
119
120    pub fn client(
121        kind: ClientErrorKind,
122        client_addr: std::net::SocketAddr,
123        details: impl Into<String>,
124    ) -> Self {
125        RelayError::Client {
126            kind,
127            client_addr,
128            details: details.into(),
129        }
130    }
131}
132
133impl From<BackoffError> for RelayError {
134    fn from(err: BackoffError) -> Self {
135        RelayError::Connection(ConnectionError::Backoff(err))
136    }
137}
138
139impl From<RtsError> for RelayError {
140    fn from(err: RtsError) -> Self {
141        RelayError::Transport(TransportError::Rts(err))
142    }
143}
144
145impl From<config::ConfigError> for RelayError {
146    fn from(err: config::ConfigError) -> Self {
147        Self::Config(ConfigValidationError::config(err.to_string()))
148    }
149}