Skip to content

Commit

Permalink
Extend the TransportError type.
Browse files Browse the repository at this point in the history
  • Loading branch information
marmistrz committed Jan 24, 2022
1 parent ff4ba6e commit 8b51457
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 47 deletions.
22 changes: 16 additions & 6 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ use std::io::Error as IoError;
/// Web3 `Result` type.
pub type Result<T = ()> = std::result::Result<T, Error>;

/// Transport-depended error.
#[derive(Display, Debug, Clone, PartialEq)]
pub enum TransportError {
/// Transport-specific error code.
#[display(fmt = "code {}", _0)]
Code(u16),
/// Arbitrary, developer-readable description of the occurred error.
#[display(fmt = "{}", _0)]
Message(String),
}

/// Errors which can occur when attempting to generate resource uri.
#[derive(Debug, Display, From)]
pub enum Error {
Expand All @@ -21,9 +32,9 @@ pub enum Error {
#[from(ignore)]
InvalidResponse(String),
/// transport error
#[display(fmt = "Transport error: {}", _0)]
#[display(fmt = "Transport error: {}" _0)]
#[from(ignore)]
Transport(String),
Transport(TransportError),
/// rpc error
#[display(fmt = "RPC error: {:?}", _0)]
Rpc(RPCError),
Expand All @@ -42,7 +53,7 @@ impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Error::*;
match *self {
Unreachable | Decoder(_) | InvalidResponse(_) | Transport(_) | Internal => None,
Unreachable | Decoder(_) | InvalidResponse(_) | Transport { .. } | Internal => None,
Rpc(ref e) => Some(e),
Io(ref e) => Some(e),
Recovery(ref e) => Some(e),
Expand Down Expand Up @@ -78,9 +89,8 @@ impl PartialEq for Error {
use self::Error::*;
match (self, other) {
(Unreachable, Unreachable) | (Internal, Internal) => true,
(Decoder(a), Decoder(b)) | (InvalidResponse(a), InvalidResponse(b)) | (Transport(a), Transport(b)) => {
a == b
}
(Decoder(a), Decoder(b)) | (InvalidResponse(a), InvalidResponse(b)) => a == b,
(Transport(a), Transport(b)) => a == b,
(Rpc(a), Rpc(b)) => a == b,
(Io(a), Io(b)) => a.kind() == b.kind(),
(Recovery(a), Recovery(b)) => a == b,
Expand Down
40 changes: 18 additions & 22 deletions src/transports/http.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
//! HTTP Transport

use crate::{
error::{Error, Result},
helpers,
rpc::error::Error as RPCError,
BatchTransport, RequestId, Transport,
error::{Error, Result, TransportError},
helpers, BatchTransport, RequestId, Transport,
};
#[cfg(not(feature = "wasm"))]
use futures::future::BoxFuture;
#[cfg(feature = "wasm")]
use futures::future::LocalBoxFuture as BoxFuture;
use jsonrpc_core::{
types::{Call, Output, Request, Value},
ErrorCode,
};
use jsonrpc_core::types::{Call, Output, Request, Value};
use reqwest::{Client, Url};
use serde::de::DeserializeOwned;
use std::{
Expand Down Expand Up @@ -53,7 +48,7 @@ impl Http {
}
let client = builder
.build()
.map_err(|err| Error::Transport(format!("failed to build client: {}", err)))?;
.map_err(|err| Error::Transport(TransportError::Message(format!("failed to build client: {}", err))))?;
Ok(Self::with_client(client, url.parse()?))
}

Expand Down Expand Up @@ -85,24 +80,25 @@ async fn execute_rpc<T: DeserializeOwned>(client: &Client, url: Url, request: &R
.json(request)
.send()
.await
.map_err(|err| Error::Transport(format!("failed to send request: {}", err)))?;
.map_err(|err| Error::Transport(TransportError::Message(format!("failed to send request: {}", err))))?;
let status = response.status();
let response = response
.bytes()
.await
.map_err(|err| Error::Transport(format!("failed to read response bytes: {}", err)))?;
let response = response.bytes().await.map_err(|err| {
Error::Transport(TransportError::Message(format!(
"failed to read response bytes: {}",
err
)))
})?;
let decoded_response = String::from_utf8_lossy(&response);
log::debug!("[id:{}] received response: {:?}", id, decoded_response.as_ref());
if !status.is_success() {
let code = ErrorCode::from(i64::from(status.as_u16()));
return Err(Error::Rpc(RPCError {
code,
message: decoded_response.to_string(),
data: None,
}));
return Err(Error::Transport(TransportError::Code(status.as_u16())));
}
helpers::arbitrary_precision_deserialize_workaround(&response)
.map_err(|err| Error::Transport(format!("failed to deserialize response: {}", err)))
helpers::arbitrary_precision_deserialize_workaround(&response).map_err(|err| {
Error::Transport(TransportError::Message(format!(
"failed to deserialize response: {}",
err
)))
})
}

type RpcResult = Result<Value>;
Expand Down
9 changes: 6 additions & 3 deletions src/transports/ipc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! IPC transport

use crate::{api::SubscriptionId, helpers, BatchTransport, DuplexTransport, Error, RequestId, Result, Transport};
use crate::{
api::SubscriptionId, error::TransportError, helpers, BatchTransport, DuplexTransport, Error, RequestId, Result,
Transport,
};
use futures::{
future::{join_all, JoinAll},
stream::StreamExt,
Expand Down Expand Up @@ -324,13 +327,13 @@ fn respond_output(

impl From<mpsc::error::SendError<TransportMessage>> for Error {
fn from(err: mpsc::error::SendError<TransportMessage>) -> Self {
Error::Transport(format!("Send Error: {:?}", err))
Error::Transport(TransportError::Message(format!("Send Error: {:?}", err)))
}
}

impl From<oneshot::error::RecvError> for Error {
fn from(err: oneshot::error::RecvError) -> Self {
Error::Transport(format!("Recv Error: {:?}", err))
Error::Transport(TransportError::Message(format!("Recv Error: {:?}", err)))
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/transports/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Supported Ethereum JSON-RPC transports.

pub mod batch;
use crate::error::TransportError;

pub use self::batch::Batch;
pub mod either;
pub use self::either::Either;
Expand All @@ -26,14 +28,14 @@ pub mod test;
#[cfg(feature = "url")]
impl From<url::ParseError> for crate::Error {
fn from(err: url::ParseError) -> Self {
crate::Error::Transport(format!("failed to parse url: {}", err))
crate::Error::Transport(TransportError::Message(format!("failed to parse url: {}", err)))
}
}

#[cfg(feature = "async-native-tls")]
impl From<async_native_tls::Error> for crate::Error {
fn from(err: async_native_tls::Error) -> Self {
crate::Error::Transport(format!("{:?}", err))
crate::Error::Transport(TransportError::Message(format!("{:?}", err)))
}
}

Expand Down
37 changes: 23 additions & 14 deletions src/transports/ws.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
//! WebSocket Transport

use self::compat::{TcpStream, TlsStream};
use crate::{api::SubscriptionId, error, helpers, rpc, BatchTransport, DuplexTransport, Error, RequestId, Transport};
use crate::{
api::SubscriptionId,
error::{self, TransportError},
helpers, rpc, BatchTransport, DuplexTransport, Error, RequestId, Transport,
};
use futures::{
channel::{mpsc, oneshot},
task::{Context, Poll},
Expand All @@ -22,13 +26,13 @@ use url::Url;

impl From<soketto::handshake::Error> for Error {
fn from(err: soketto::handshake::Error) -> Self {
Error::Transport(format!("Handshake Error: {:?}", err))
Error::Transport(TransportError::Message(format!("Handshake Error: {:?}", err)))
}
}

impl From<connection::Error> for Error {
fn from(err: connection::Error) -> Self {
Error::Transport(format!("Connection Error: {:?}", err))
Error::Transport(TransportError::Message(format!("Connection Error: {:?}", err)))
}
}

Expand Down Expand Up @@ -100,12 +104,21 @@ impl WsServerTask {

let scheme = match url.scheme() {
s if s == "ws" || s == "wss" => s,
s => return Err(error::Error::Transport(format!("Wrong scheme: {}", s))),
s => {
return Err(error::Error::Transport(TransportError::Message(format!(
"Wrong scheme: {}",
s
))))
}
};

let host = match url.host_str() {
Some(s) => s,
None => return Err(error::Error::Transport("Wrong host name".to_string())),
None => {
return Err(error::Error::Transport(TransportError::Message(
"Wrong host name".to_string(),
)))
}
};

let port = url.port().unwrap_or(if scheme == "ws" { 80 } else { 443 });
Expand Down Expand Up @@ -143,16 +156,10 @@ impl WsServerTask {
let (sender, receiver) = match handshake.await? {
ServerResponse::Accepted { .. } => client.into_builder().finish(),
ServerResponse::Redirect { status_code, location } => {
return Err(error::Error::Transport(format!(
"(code: {}) Unable to follow redirects: {}",
status_code, location
)))
return Err(error::Error::Transport(TransportError::Code(status_code)))
}
ServerResponse::Rejected { status_code } => {
return Err(error::Error::Transport(format!(
"(code: {}) Connection rejected.",
status_code
)))
return Err(error::Error::Transport(TransportError::Code(status_code)))
}
};

Expand Down Expand Up @@ -342,7 +349,9 @@ impl WebSocket {
}

fn dropped_err<T>(_: T) -> error::Error {
Error::Transport("Cannot send request. Internal task finished.".into())
Error::Transport(TransportError::Message(
"Cannot send request. Internal task finished.".into(),
))
}

fn batch_to_single(response: BatchResult) -> SingleResult {
Expand Down

0 comments on commit 8b51457

Please sign in to comment.