Skip to main content

ecksport_rpc/
errors.rs

1//! RPC error types
2
3use std::fmt;
4use std::io::{self, Write};
5
6use thiserror::Error;
7
8use ecksport_codec::CodecError;
9
10use crate::constants::*;
11
12/// Result type returned from `RpcClient` methods.
13pub type ClientResult<T> = Result<T, ClientError>;
14
15#[derive(Debug, Error)]
16pub enum ClientError {
17    #[error("tried to call with un-encodeable argument")]
18    MalformedRequest(CodecError),
19
20    #[error("no response from remote")]
21    NoResponse,
22
23    #[error("malformed response from remote ({0})")]
24    MalformedResponse(CodecError),
25
26    #[error("server rpc: {0}")]
27    ServerRpc(RpcError),
28
29    #[error("unable to parse error code")]
30    ParseErrorCode,
31
32    #[error("eio: {0}")]
33    EcksIo(#[from] ecksport_net::errors::Error),
34}
35
36impl From<RpcError> for ClientError {
37    fn from(value: RpcError) -> Self {
38        Self::ServerRpc(value)
39    }
40}
41
42#[derive(Debug, Error)]
43pub enum ServerError {
44    #[error("ecksio: {0}")]
45    EcksIo(#[from] ecksport_net::errors::Error),
46
47    #[error("io: {0}")]
48    TokioIo(#[from] tokio::io::Error),
49
50    #[error("not yet implemented")]
51    Unimplemented,
52}
53
54#[derive(Debug, Error)]
55pub enum Error {
56    #[error("unable to parse error code")]
57    ParseErrorCode,
58}
59
60/// Result type used in RPC methods and whatnot.
61pub type RpcResult<T> = Result<T, RpcError>;
62
63#[derive(Clone, Debug)]
64pub struct RpcError {
65    code: i16,
66    raw_msg: Option<Vec<u8>>,
67}
68
69impl RpcError {
70    pub fn new_code(code: i16) -> Self {
71        Self {
72            code,
73            raw_msg: None,
74        }
75    }
76
77    /// Constructs a server error by `ToString`ing another type and using a
78    /// specific error code.
79    pub fn server<E: ToString>(code: i16, e: E) -> Self {
80        let buf = e.to_string().into_bytes();
81        Self {
82            code,
83            raw_msg: if buf.len() > 0 { Some(buf) } else { None },
84        }
85    }
86
87    pub fn code(&self) -> i16 {
88        self.code
89    }
90
91    pub fn raw_msg(&self) -> Option<&[u8]> {
92        self.raw_msg.as_ref().map(|b| b.as_slice())
93    }
94
95    /// Returns the error converted to an `RpcErrorKind` which can be matched on
96    /// more easily.
97    pub fn kind(&self) -> RpcErrorKind {
98        match self.code {
99            c if c == ERR_INTERNAL => RpcErrorKind::Internal,
100            c if c == ERR_UNAUTH => RpcErrorKind::Unauthorized,
101            c if c == ERR_UNK_METHOD => RpcErrorKind::UnknownMethod,
102            c if c == ERR_MALFORMED_REQ => RpcErrorKind::MalformedRequest,
103            c if c > 0 => RpcErrorKind::Server(c),
104            _ => RpcErrorKind::Raw(self.code),
105        }
106    }
107
108    /// Returns the error *message* as a string, if there is one and it can be
109    /// parsed as one.
110    pub fn try_parse_msg(&self) -> Option<&str> {
111        self.raw_msg
112            .as_ref()
113            .and_then(|b| std::str::from_utf8(&b).ok())
114    }
115
116    /// Encodes the error into a vec.
117    pub fn to_vec(&self) -> Vec<u8> {
118        let mut buf = Vec::new();
119
120        {
121            let mut cur = io::Cursor::new(&mut buf);
122            cur.write_all(&self.code().to_be_bytes()).unwrap();
123            if let Some(m) = self.raw_msg() {
124                cur.write_all(m).unwrap();
125            }
126        }
127
128        buf
129    }
130
131    /// Decodes an error type from a vector of bytes.  Assumes the buf is
132    /// already appropriately sized.
133    pub fn from_slice(buf: &[u8]) -> Result<Self, Error> {
134        if buf.len() < 2 {
135            return Err(Error::ParseErrorCode);
136        }
137
138        let code = i16::from_be_bytes(<[u8; 2]>::try_from(&buf[..2]).unwrap());
139
140        Ok(Self {
141            code,
142            raw_msg: if buf.len() > 2 {
143                Some(buf[2..].to_vec())
144            } else {
145                None
146            },
147        })
148    }
149}
150
151impl fmt::Display for RpcError {
152    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153        // Write the basic error message first.
154        let k = self.kind();
155        f.write_fmt(format_args!("{k}"))?;
156
157        if let Some(aux) = self.try_parse_msg() {
158            f.write_fmt(format_args!(" ({aux})"))?;
159        } else {
160            f.write_str(" +data")?;
161        }
162
163        Ok(())
164    }
165}
166
167/// Errors related to RPC implementation.
168#[derive(Copy, Clone, Debug, Error)]
169pub enum RpcErrorKind {
170    /// Internal error (probably a panic or something).
171    #[error("internal error")]
172    Internal,
173
174    /// Request required some additional authentication.
175    #[error("unauthorized request")]
176    Unauthorized,
177
178    /// Unknown method.
179    #[error("unknown method")]
180    UnknownMethod,
181
182    /// If the request could not be parsed, for example.
183    #[error("malformed request")]
184    MalformedRequest,
185
186    /// Server error for implementer-defined error codes.
187    #[error("server error {0}")]
188    Server(i16),
189
190    /// If the error is something else.
191    #[error("unknown error {0}")]
192    Raw(i16),
193}