From 4c293a498c428253cfa04e3669f6f91c157f8663 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 1 May 2023 14:07:10 +0200 Subject: [PATCH 01/22] split client and server error --- benches/helpers.rs | 4 +- client/http-client/src/client.rs | 7 +- client/http-client/src/tests.rs | 18 ++-- client/ws-client/src/lib.rs | 4 +- client/ws-client/src/tests.rs | 5 +- core/src/client/async_client/helpers.rs | 5 +- core/src/client/async_client/manager.rs | 15 ++- core/src/client/async_client/mod.rs | 18 ++-- core/src/client/mod.rs | 15 +-- core/src/error.rs | 104 +++------------------ core/src/lib.rs | 6 +- core/src/params.rs | 15 ++- core/src/server/error.rs | 15 +++ core/src/server/host_filtering/host.rs | 9 +- core/src/server/rpc_module.rs | 49 ++++++---- core/src/server/subscription.rs | 8 +- core/src/traits.rs | 16 ++-- examples/examples/core_client.rs | 2 +- examples/examples/cors_server.rs | 2 +- examples/examples/http.rs | 2 +- examples/examples/http_proxy_middleware.rs | 2 +- examples/examples/logger.rs | 2 +- examples/examples/middleware.rs | 2 +- examples/examples/multi_logger.rs | 2 +- examples/examples/proc_macro.rs | 2 +- examples/examples/proc_macro_bounds.rs | 2 +- examples/examples/tokio_console.rs | 2 +- examples/examples/ws.rs | 2 +- examples/examples/ws_pubsub_broadcast.rs | 2 +- examples/examples/ws_pubsub_with_params.rs | 2 +- proc-macros/src/render_client.rs | 9 +- server/Cargo.toml | 1 + server/src/future.rs | 5 +- server/src/lib.rs | 1 + server/src/middleware/proxy_get_request.rs | 14 ++- server/src/server.rs | 14 +-- server/src/tests/helpers.rs | 6 +- server/src/tests/http.rs | 19 ++-- server/src/tests/shared.rs | 7 +- server/src/tests/ws.rs | 26 +++--- server/src/transport/ws.rs | 6 +- tests/tests/helpers.rs | 11 +-- tests/tests/integration_tests.rs | 20 ++-- tests/tests/metrics.rs | 11 ++- tests/tests/proc_macros.rs | 9 +- tests/tests/rpc_module.rs | 15 +-- 46 files changed, 235 insertions(+), 278 deletions(-) diff --git a/benches/helpers.rs b/benches/helpers.rs index ec633ad536..58cba6e445 100644 --- a/benches/helpers.rs +++ b/benches/helpers.rs @@ -125,7 +125,7 @@ pub async fn http_server(handle: tokio::runtime::Handle) -> (String, jsonrpsee:: let module = gen_rpc_module(); let addr = server.local_addr().unwrap(); - let handle = server.start(module).unwrap(); + let handle = server.start(module); (format!("http://{}", addr), handle) } @@ -161,7 +161,7 @@ pub async fn ws_server(handle: tokio::runtime::Handle) -> (String, jsonrpsee::se .unwrap(); let addr = format!("ws://{}", server.local_addr().unwrap()); - let handle = server.start(module).unwrap(); + let handle = server.start(module); (addr, handle) } diff --git a/client/http-client/src/client.rs b/client/http-client/src/client.rs index c75827079f..b36d23dab1 100644 --- a/client/http-client/src/client.rs +++ b/client/http-client/src/client.rs @@ -37,12 +37,12 @@ use hyper::body::HttpBody; use hyper::http::HeaderMap; use hyper::Body; use jsonrpsee_core::client::{ - generate_batch_id_range, BatchResponse, CertificateStore, ClientT, IdKind, RequestIdManager, Subscription, + generate_batch_id_range, BatchResponse, CertificateStore, ClientT, Error, IdKind, RequestIdManager, Subscription, SubscriptionClientT, }; use jsonrpsee_core::params::BatchRequestBuilder; use jsonrpsee_core::traits::ToRpcParams; -use jsonrpsee_core::{Error, JsonRawValue, TEN_MB_SIZE_BYTES}; +use jsonrpsee_core::{JsonRawValue, TEN_MB_SIZE_BYTES}; use jsonrpsee_types::{ErrorObject, ResponseSuccess, TwoPointZero}; use serde::de::DeserializeOwned; use tower::layer::util::Identity; @@ -315,7 +315,8 @@ where where R: DeserializeOwned + fmt::Debug + 'a, { - let batch = batch.build()?; + // TODO fix unwrap. + let batch = batch.build().unwrap(); let guard = self.id_manager.next_request_id()?; let id_range = generate_batch_id_range(&guard, batch.len() as u64)?; diff --git a/client/http-client/src/tests.rs b/client/http-client/src/tests.rs index 5474e658d1..ccdfe1280f 100644 --- a/client/http-client/src/tests.rs +++ b/client/http-client/src/tests.rs @@ -29,7 +29,7 @@ use crate::types::error::{ErrorCode, ErrorObject}; use crate::HttpClientBuilder; use jsonrpsee_core::client::{BatchResponse, ClientT, IdKind}; use jsonrpsee_core::params::BatchRequestBuilder; -use jsonrpsee_core::Error; +use jsonrpsee_core::ClientError; use jsonrpsee_core::{rpc_params, DeserializeOwned}; use jsonrpsee_test_utils::helpers::*; use jsonrpsee_test_utils::mocks::Id; @@ -59,8 +59,8 @@ async fn method_call_with_wrong_id_kind() { http_server_with_hardcoded_response(ok_response(exp.into(), Id::Num(0))).with_default_timeout().await.unwrap(); let uri = format!("http://{server_addr}"); let client = HttpClientBuilder::default().id_format(IdKind::String).build(&uri).unwrap(); - let res: Result = client.request("o", rpc_params![]).with_default_timeout().await.unwrap(); - assert!(matches!(res, Err(Error::InvalidRequestId))); + let res: Result = client.request("o", rpc_params![]).with_default_timeout().await.unwrap(); + assert!(matches!(res, Err(ClientError::InvalidRequestId))); } #[tokio::test] @@ -96,7 +96,7 @@ async fn response_with_wrong_id() { .await .unwrap() .unwrap_err(); - assert!(matches!(err, Error::InvalidRequestId)); + assert!(matches!(err, ClientError::InvalidRequestId)); } #[tokio::test] @@ -137,7 +137,7 @@ async fn internal_error_works() { async fn subscription_response_to_request() { let req = r#"{"jsonrpc":"2.0","method":"subscribe_hello","params":{"subscription":"3px4FrtxSYQ1zBKW154NoVnrDhrq764yQNCXEgZyM6Mu","result":"hello my friend"}}"#.to_string(); let err = run_request_with_response(req).with_default_timeout().await.unwrap().unwrap_err(); - assert!(matches!(err, Error::ParseError(_))); + assert!(matches!(err, ClientError::ParseError(_))); } #[tokio::test] @@ -261,23 +261,23 @@ async fn batch_request_out_of_order_response() { async fn run_batch_request_with_response( batch: BatchRequestBuilder<'_>, response: String, -) -> Result, Error> { +) -> Result, ClientError> { let server_addr = http_server_with_hardcoded_response(response).with_default_timeout().await.unwrap(); let uri = format!("http://{server_addr}"); let client = HttpClientBuilder::default().build(&uri).unwrap(); client.batch_request(batch).with_default_timeout().await.unwrap() } -async fn run_request_with_response(response: String) -> Result { +async fn run_request_with_response(response: String) -> Result { let server_addr = http_server_with_hardcoded_response(response).with_default_timeout().await.unwrap(); let uri = format!("http://{server_addr}"); let client = HttpClientBuilder::default().build(&uri).unwrap(); client.request("say_hello", rpc_params![]).with_default_timeout().await.unwrap() } -fn assert_jsonrpc_error_response(err: Error, exp: ErrorObjectOwned) { +fn assert_jsonrpc_error_response(err: ClientError, exp: ErrorObjectOwned) { match &err { - Error::Call(err) => { + ClientError::Call(err) => { assert_eq!(err, &exp); } e => panic!("Expected error: \"{err}\", got: {e:?}"), diff --git a/client/ws-client/src/lib.rs b/client/ws-client/src/lib.rs index 0f1c032a51..051fcb476c 100644 --- a/client/ws-client/src/lib.rs +++ b/client/ws-client/src/lib.rs @@ -45,8 +45,8 @@ pub use http::{HeaderMap, HeaderValue}; use std::time::Duration; use jsonrpsee_client_transport::ws::{InvalidUri, Uri, WsTransportClientBuilder}; -use jsonrpsee_core::client::{CertificateStore, ClientBuilder, IdKind}; -use jsonrpsee_core::{Error, TEN_MB_SIZE_BYTES}; +use jsonrpsee_core::client::{CertificateStore, ClientBuilder, Error, IdKind}; +use jsonrpsee_core::TEN_MB_SIZE_BYTES; /// Builder for [`WsClient`]. /// diff --git a/client/ws-client/src/tests.rs b/client/ws-client/src/tests.rs index b4b94d080f..aeec3bbe5d 100644 --- a/client/ws-client/src/tests.rs +++ b/client/ws-client/src/tests.rs @@ -28,10 +28,9 @@ use crate::types::error::{ErrorCode, ErrorObject}; use crate::WsClientBuilder; -use jsonrpsee_core::client::{BatchResponse, ClientT, SubscriptionClientT}; -use jsonrpsee_core::client::{IdKind, Subscription}; +use jsonrpsee_core::client::{BatchResponse, ClientT, Error, IdKind, Subscription, SubscriptionClientT}; use jsonrpsee_core::params::BatchRequestBuilder; -use jsonrpsee_core::{rpc_params, DeserializeOwned, Error}; +use jsonrpsee_core::{rpc_params, DeserializeOwned}; use jsonrpsee_test_utils::helpers::*; use jsonrpsee_test_utils::mocks::{Id, WebSocketTestServer}; use jsonrpsee_test_utils::TimeoutFutureExt; diff --git a/core/src/client/async_client/helpers.rs b/core/src/client/async_client/helpers.rs index d5b965fb5a..2b9b533e2f 100644 --- a/core/src/client/async_client/helpers.rs +++ b/core/src/client/async_client/helpers.rs @@ -25,10 +25,9 @@ // DEALINGS IN THE SOFTWARE. use crate::client::async_client::manager::{RequestManager, RequestStatus}; -use crate::client::{RequestMessage, TransportSenderT}; +use crate::client::{Error, RequestMessage, TransportSenderT}; use crate::params::ArrayParams; use crate::traits::ToRpcParams; -use crate::Error; use futures_timer::Delay; use futures_util::future::{self, Either}; @@ -153,7 +152,7 @@ pub(crate) fn process_notification(manager: &mut RequestManager, notif: Notifica Ok(()) => Ok(()), Err(err) => { tracing::error!("Error sending notification, dropping handler for {:?} error: {:?}", notif.method, err); - let _ = manager.remove_notification_handler(notif.method.into_owned()); + let _ = manager.remove_notification_handler(¬if.method); Err(Error::Custom(err.to_string())) } }, diff --git a/core/src/client/async_client/manager.rs b/core/src/client/async_client/manager.rs index 3fe01fbfcd..c67c720d55 100644 --- a/core/src/client/async_client/manager.rs +++ b/core/src/client/async_client/manager.rs @@ -37,7 +37,10 @@ use std::{ ops::Range, }; -use crate::{client::BatchEntry, Error}; +use crate::{ + client::BatchEntry, + client::{error::RegisterMethodError, Error}, +}; use jsonrpsee_types::{Id, SubscriptionId}; use rustc_hash::FxHashMap; use serde_json::value::Value as JsonValue; @@ -187,17 +190,13 @@ impl RequestManager { handle.insert(send_back); Ok(()) } else { - Err(Error::MethodAlreadyRegistered(method.to_owned())) + Err(Error::RegisterMethod(RegisterMethodError::AlreadyRegistered(method.to_owned()))) } } /// Removes a notification handler. - pub(crate) fn remove_notification_handler(&mut self, method: String) -> Result<(), Error> { - if self.notification_handlers.remove(&method).is_some() { - Ok(()) - } else { - Err(Error::UnregisteredNotification(method)) - } + pub(crate) fn remove_notification_handler<'a>(&mut self, method: &'a str) -> Option { + self.notification_handlers.remove(method) } /// Tries to complete a pending subscription. diff --git a/core/src/client/async_client/mod.rs b/core/src/client/async_client/mod.rs index dbc4740864..834fc908a4 100644 --- a/core/src/client/async_client/mod.rs +++ b/core/src/client/async_client/mod.rs @@ -5,10 +5,9 @@ mod manager; use crate::client::async_client::helpers::{process_subscription_close_response, InnerBatchResponse}; use crate::client::{ - BatchMessage, BatchResponse, ClientT, ReceivedMessage, RegisterNotificationMessage, RequestMessage, Subscription, - SubscriptionClientT, SubscriptionKind, SubscriptionMessage, TransportReceiverT, TransportSenderT, + BatchMessage, BatchResponse, ClientT, Error, ReceivedMessage, RegisterNotificationMessage, RequestMessage, + Subscription, SubscriptionClientT, SubscriptionKind, SubscriptionMessage, TransportReceiverT, TransportSenderT, }; -use crate::error::Error; use crate::params::BatchRequestBuilder; use crate::tracing::{rx_log_from_json, tx_log_from_str}; use crate::traits::ToRpcParams; @@ -35,6 +34,7 @@ use serde::de::DeserializeOwned; use tokio::sync::{mpsc, oneshot}; use tracing::instrument; +use super::error::RegisterMethodError; use super::{generate_batch_id_range, FrontToBack, IdKind, RequestIdManager}; /// Wrapper over a [`oneshot::Receiver`](tokio::sync::oneshot::Receiver) that reads @@ -349,7 +349,8 @@ impl ClientT for Client { where R: DeserializeOwned, { - let batch = batch.build()?; + // TODO: remove unwrap + let batch = batch.build().unwrap(); let guard = self.id_manager.next_request_id()?; let id_range = generate_batch_id_range(&guard, batch.len() as u64)?; @@ -428,7 +429,9 @@ impl SubscriptionClientT for Client { Notif: DeserializeOwned, { if subscribe_method == unsubscribe_method { - return Err(Error::SubscriptionNameConflict(unsubscribe_method.to_owned())); + return Err(Error::RegisterMethod(RegisterMethodError::SubscriptionNameConflict( + unsubscribe_method.to_owned(), + ))); } let guard = self.id_manager.next_request_two_ids()?; @@ -682,12 +685,13 @@ async fn handle_frontend_messages( if manager.insert_notification_handler(®.method, subscribe_tx).is_ok() { let _ = reg.send_back.send(Ok((subscribe_rx, reg.method))); } else { - let _ = reg.send_back.send(Err(Error::MethodAlreadyRegistered(reg.method))); + let _ = + reg.send_back.send(Err(Error::RegisterMethod(RegisterMethodError::AlreadyRegistered(reg.method)))); } } // User dropped the NotificationHandler for this method FrontToBack::UnregisterNotification(method) => { - let _ = manager.remove_notification_handler(method); + let _ = manager.remove_notification_handler(&method); } } } diff --git a/core/src/client/mod.rs b/core/src/client/mod.rs index a31ce200b6..dcb6729b50 100644 --- a/core/src/client/mod.rs +++ b/core/src/client/mod.rs @@ -26,6 +26,13 @@ //! Shared utilities for `jsonrpsee` clients. +mod error; + +cfg_async_client! { + pub mod async_client; + pub use async_client::{Client, ClientBuilder}; +} + use std::fmt; use std::ops::Range; use std::pin::Pin; @@ -33,7 +40,6 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; use std::task; -use crate::error::Error; use crate::params::BatchRequestBuilder; use crate::traits::ToRpcParams; use async_trait::async_trait; @@ -44,6 +50,8 @@ use serde::de::DeserializeOwned; use serde_json::Value as JsonValue; use tokio::sync::{mpsc, oneshot}; +pub use error::{Error, RegisterMethodError}; + // Re-exports for the `rpc_params` macro. #[doc(hidden)] pub mod __reexports { @@ -53,11 +61,6 @@ pub mod __reexports { pub use crate::params::ArrayParams; } -cfg_async_client! { - pub mod async_client; - pub use async_client::{Client, ClientBuilder}; -} - /// [JSON-RPC](https://www.jsonrpc.org/specification) client interface that can make requests and notifications. #[async_trait] pub trait ClientT { diff --git a/core/src/error.rs b/core/src/error.rs index 4fba255efe..9937760396 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -26,8 +26,6 @@ use std::fmt; -use jsonrpsee_types::error::ErrorObjectOwned; - /// Convenience type for displaying errors. #[derive(Clone, Debug, PartialEq, Eq)] pub struct Mismatch { @@ -43,71 +41,6 @@ impl fmt::Display for Mismatch { } } -/// Error type. -#[derive(Debug, thiserror::Error)] -pub enum Error { - /// JSON-RPC error which can occur when a JSON-RPC call fails. - #[error("{0}")] - Call(#[from] ErrorObjectOwned), - /// Networking error or error on the low-level protocol layer. - #[error("Networking or low-level protocol error: {0}")] - Transport(#[source] anyhow::Error), - /// Invalid response, - #[error("Invalid response: {0}")] - InvalidResponse(Mismatch), - /// The background task has been terminated. - #[error("The background task been terminated because: {0}; restart required")] - RestartNeeded(String), - /// Failed to parse the data. - #[error("Parse error: {0}")] - ParseError(#[from] serde_json::Error), - /// Invalid subscription ID. - #[error("Invalid subscription ID")] - InvalidSubscriptionId, - /// Invalid request ID. - #[error("Invalid request ID")] - InvalidRequestId, - /// Client received a notification with an unregistered method - #[error("Unregistered notification method")] - UnregisteredNotification(String), - /// A request with the same request ID has already been registered. - #[error("A request with the same request ID has already been registered")] - DuplicateRequestId, - /// Method was already registered. - #[error("Method: {0} was already registered")] - MethodAlreadyRegistered(String), - /// Method with that name has not yet been registered. - #[error("Method: {0} has not yet been registered")] - MethodNotFound(String), - /// Subscribe and unsubscribe method names are the same. - #[error("Cannot use the same method name for subscribe and unsubscribe, used: {0}")] - SubscriptionNameConflict(String), - /// Request timeout - #[error("Request timeout")] - RequestTimeout, - /// Configured max number of request slots exceeded. - #[error("Configured max number of request slots exceeded")] - MaxSlotsExceeded, - /// Attempted to stop server that is already stopped. - #[error("Attempted to stop server that is already stopped")] - AlreadyStopped, - /// List passed into access control based on HTTP header verification. - #[error("Must set at least one allowed value for the {0} header")] - EmptyAllowList(&'static str), - /// Access control verification of HTTP headers failed. - #[error("HTTP header: `{0}` value: `{1}` verification failed")] - HttpHeaderRejected(&'static str, String), - /// Custom error. - #[error("Custom error: {0}")] - Custom(String), - /// Not implemented for HTTP clients. - #[error("Not implemented")] - HttpNotImplemented, - /// Empty batch request. - #[error("Empty batch request is not allowed")] - EmptyBatchRequest, -} - /// Generic transport error. #[derive(Debug, thiserror::Error)] pub enum GenericTransportError { @@ -132,29 +65,16 @@ impl From for StringError { } } -impl From for Error { - fn from(io_err: std::io::Error) -> Error { - Error::Transport(io_err.into()) - } -} - -#[cfg(feature = "soketto")] -impl From for Error { - fn from(handshake_err: soketto::handshake::Error) -> Error { - Error::Transport(handshake_err.into()) - } -} - -#[cfg(feature = "soketto")] -impl From for Error { - fn from(conn_err: soketto::connection::Error) -> Error { - Error::Transport(conn_err.into()) - } -} - -#[cfg(feature = "hyper")] -impl From for Error { - fn from(hyper_err: hyper::Error) -> Error { - Error::Transport(hyper_err.into()) - } +/// The error returned when registering a method or subscription failed. +#[derive(Debug, Clone, thiserror::Error)] +pub enum RegisterMethodError { + /// Method was already registered. + #[error("Method: {0} was already registered")] + AlreadyRegistered(String), + /// Subscribe and unsubscribe method names are the same. + #[error("Cannot use the same method name for subscribe and unsubscribe, used: {0}")] + SubscriptionNameConflict(String), + /// Method with that name has not yet been registered. + #[error("Method: {0} has not yet been registered")] + MethodNotFound(String), } diff --git a/core/src/lib.rs b/core/src/lib.rs index bff45dfec0..e16d2387a8 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -54,12 +54,14 @@ cfg_server! { cfg_client! { pub mod client; + + pub use client::Error as ClientError; } /// Shared tracing helpers to trace RPC calls. pub mod tracing; pub use async_trait::async_trait; -pub use error::{Error, GenericTransportError, StringError}; +//pub use error::{Error, GenericTransportError, StringError}; /// JSON-RPC result. pub type RpcResult = std::result::Result; @@ -87,4 +89,4 @@ pub use serde_json::{ pub const TEN_MB_SIZE_BYTES: u32 = 10 * 1024 * 1024; /// The return type if the subscription wants to return `Result`. -pub type SubscriptionResult = Result<(), StringError>; +pub type SubscriptionResult = Result<(), error::StringError>; diff --git a/core/src/params.rs b/core/src/params.rs index a9f4600e4b..be9ad9f78f 100644 --- a/core/src/params.rs +++ b/core/src/params.rs @@ -27,7 +27,6 @@ //! RPC parameters. use crate::traits::ToRpcParams; -use crate::Error; use serde::Serialize; use serde_json::value::RawValue; @@ -164,9 +163,9 @@ impl Default for ObjectParams { } impl ToRpcParams for ObjectParams { - fn to_rpc_params(self) -> Result>, Error> { + fn to_rpc_params(self) -> Result>, serde_json::Error> { if let Some(json) = self.0.build() { - RawValue::from_string(json).map(Some).map_err(Error::ParseError) + RawValue::from_string(json).map(Some) } else { Ok(None) } @@ -210,9 +209,9 @@ impl Default for ArrayParams { } impl ToRpcParams for ArrayParams { - fn to_rpc_params(self) -> Result>, Error> { + fn to_rpc_params(self) -> Result>, serde_json::Error> { if let Some(json) = self.0.build() { - RawValue::from_string(json).map(Some).map_err(Error::ParseError) + RawValue::from_string(json).map(Some) } else { Ok(None) } @@ -234,16 +233,16 @@ impl<'a> BatchRequestBuilder<'a> { } /// Inserts the RPC method with provided parameters into the builder. - pub fn insert(&mut self, method: &'a str, value: Params) -> Result<(), Error> { + pub fn insert(&mut self, method: &'a str, value: Params) -> Result<(), serde_json::Error> { self.0.push((method, value.to_rpc_params()?)); Ok(()) } /// Finish the building process and return a valid batch parameter. #[allow(clippy::type_complexity)] - pub fn build(self) -> Result>)>, Error> { + pub fn build(self) -> Result>)>, ()> { if self.0.is_empty() { - Err(Error::EmptyBatchRequest) + Err(()) } else { Ok(self.0) } diff --git a/core/src/server/error.rs b/core/src/server/error.rs index e92a29e112..48d5355e29 100644 --- a/core/src/server/error.rs +++ b/core/src/server/error.rs @@ -25,6 +25,7 @@ // DEALINGS IN THE SOFTWARE. use crate::server::SubscriptionMessage; +use jsonrpsee_types::ErrorObjectOwned; use tokio::sync::mpsc; /// Error that may occur during [`crate::server::MethodSink::try_send`] or [`crate::server::SubscriptionSink::try_send`]. @@ -83,3 +84,17 @@ impl From> for SendTimeoutError { } } } + +/// The error that can occur when [`RpcModule::call`] or [`RpcModule::subscribe`] is invoked. +#[derive(thiserror::Error, Debug)] +pub enum CallError { + /// Failed to parse the call as valid JSON-RPC. + #[error("{0}")] + Parse(#[from] serde_json::Error), + /// Specific JSON-RPC error. + #[error("{0}")] + JsonRpc(#[from] ErrorObjectOwned), + #[error("Invalid subscription ID: `{0}`")] + /// Invalid subscription ID. + InvalidSubscriptionId(String), +} diff --git a/core/src/server/host_filtering/host.rs b/core/src/server/host_filtering/host.rs index 893dddc169..299fb5eef7 100644 --- a/core/src/server/host_filtering/host.rs +++ b/core/src/server/host_filtering/host.rs @@ -27,7 +27,6 @@ //! Host header validation. use crate::server::host_filtering::matcher::{Matcher, Pattern}; -use crate::Error; const SPLIT_PROOF: &str = "split always returns non-empty iterator."; @@ -149,12 +148,16 @@ pub enum AllowHosts { Only(Vec), } +#[derive(Debug, thiserror::Error)] +#[error("host `{0}` rejected because it's not whitelisted")] +pub struct AllowHostError(String); + impl AllowHosts { /// Verify a host. - pub fn verify(&self, value: &str) -> Result<(), Error> { + pub fn verify(&self, value: &str) -> Result<(), AllowHostError> { if let AllowHosts::Only(list) = self { if !list.iter().any(|o| o.matches(value)) { - return Err(Error::HttpHeaderRejected("host", value.into())); + return Err(AllowHostError(value.to_string())); } } diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 7db5bc6330..337b720ece 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -30,7 +30,7 @@ use std::future::Future; use std::ops::{Deref, DerefMut}; use std::sync::Arc; -use crate::error::Error; +use crate::error::RegisterMethodError; use crate::id_providers::RandomIntegerIdProvider; use crate::server::helpers::{MethodResponse, MethodSink}; use crate::server::subscription::{ @@ -48,7 +48,7 @@ use rustc_hash::FxHashMap; use serde::de::DeserializeOwned; use tokio::sync::{mpsc, oneshot}; -use super::IntoResponse; +use super::{CallError, IntoResponse}; /// A `MethodCallback` is an RPC endpoint, callable with a standard JSON-RPC request, /// implemented as a function pointer to a `Fn` function taking four arguments: @@ -164,9 +164,9 @@ impl Methods { } /// Verifies that the method name is not already taken, and returns an error if it is. - pub fn verify_method_name(&mut self, name: &'static str) -> Result<(), Error> { + pub fn verify_method_name(&mut self, name: &'static str) -> Result<(), RegisterMethodError> { if self.callbacks.contains_key(name) { - return Err(Error::MethodAlreadyRegistered(name.into())); + return Err(RegisterMethodError::AlreadyRegistered(name.into())); } Ok(()) @@ -178,9 +178,9 @@ impl Methods { &mut self, name: &'static str, callback: MethodCallback, - ) -> Result<&mut MethodCallback, Error> { + ) -> Result<&mut MethodCallback, RegisterMethodError> { match self.mut_callbacks().entry(name) { - Entry::Occupied(_) => Err(Error::MethodAlreadyRegistered(name.into())), + Entry::Occupied(_) => Err(RegisterMethodError::AlreadyRegistered(name.into())), Entry::Vacant(vacant) => Ok(vacant.insert(callback)), } } @@ -192,7 +192,7 @@ impl Methods { /// Merge two [`Methods`]'s by adding all [`MethodCallback`]s from `other` into `self`. /// Fails if any of the methods in `other` is present already. - pub fn merge(&mut self, other: impl Into) -> Result<(), Error> { + pub fn merge(&mut self, other: impl Into) -> Result<(), RegisterMethodError> { let mut other = other.into(); for name in other.callbacks.keys() { @@ -246,13 +246,13 @@ impl Methods { &self, method: &str, params: Params, - ) -> Result { + ) -> Result { let params = params.to_rpc_params()?; let req = Request::new(method.into(), params.as_ref().map(|p| p.as_ref()), Id::Number(0)); tracing::trace!("[Methods::call] Method: {:?}, params: {:?}", method, params); let (resp, _) = self.inner_call(req, 1, mock_subscription_permit()).await; let rp = serde_json::from_str::>(&resp.result)?; - ResponseSuccess::try_from(rp).map(|s| s.result).map_err(Error::Call) + ResponseSuccess::try_from(rp).map(|s| s.result).map_err(|e| CallError::JsonRpc(e.into_owned())) } /// Make a request (JSON-RPC method call or subscription) by using raw JSON. @@ -290,7 +290,7 @@ impl Methods { &self, request: &str, buf_size: usize, - ) -> Result<(MethodResponse, mpsc::Receiver), Error> { + ) -> Result<(MethodResponse, mpsc::Receiver), serde_json::Error> { tracing::trace!("[Methods::raw_json_request] Request: {:?}", request); let req: Request = serde_json::from_str(request)?; let (resp, rx) = self.inner_call(req, buf_size, mock_subscription_permit()).await; @@ -364,18 +364,23 @@ impl Methods { /// assert_eq!(&sub_resp, "one answer"); /// } /// ``` - pub async fn subscribe_unbounded(&self, sub_method: &str, params: impl ToRpcParams) -> Result { + pub async fn subscribe_unbounded( + &self, + sub_method: &str, + params: impl ToRpcParams, + ) -> Result { self.subscribe(sub_method, params, u32::MAX as usize).await } /// Similar to [`Methods::subscribe_unbounded`] but it's using a bounded channel and the buffer capacity must be /// provided. + /// pub async fn subscribe( &self, sub_method: &str, params: impl ToRpcParams, buf_size: usize, - ) -> Result { + ) -> Result { let params = params.to_rpc_params()?; let req = Request::new(sub_method.into(), params.as_ref().map(|p| p.as_ref()), Id::Number(0)); @@ -387,7 +392,7 @@ impl Methods { let as_success: ResponseSuccess = serde_json::from_str::>(&resp.result)?.try_into()?; - let sub_id = as_success.result.try_into().map_err(|_| Error::InvalidSubscriptionId)?; + let sub_id = as_success.result.try_into().map_err(|_| CallError::InvalidSubscriptionId(resp.result.clone()))?; Ok(Subscription { sub_id, rx }) } @@ -447,7 +452,7 @@ impl RpcModule { &mut self, method_name: &'static str, callback: F, - ) -> Result<&mut MethodCallback, Error> + ) -> Result<&mut MethodCallback, RegisterMethodError> where Context: Send + Sync + 'static, R: IntoResponse + 'static, @@ -468,7 +473,7 @@ impl RpcModule { &mut self, method_name: &'static str, callback: Fun, - ) -> Result<&mut MethodCallback, Error> + ) -> Result<&mut MethodCallback, RegisterMethodError> where R: IntoResponse + 'static, Fut: Future + Send, @@ -497,7 +502,7 @@ impl RpcModule { &mut self, method_name: &'static str, callback: F, - ) -> Result<&mut MethodCallback, Error> + ) -> Result<&mut MethodCallback, RegisterMethodError> where Context: Send + Sync + 'static, R: IntoResponse + 'static, @@ -628,7 +633,7 @@ impl RpcModule { notif_method_name: &'static str, unsubscribe_method_name: &'static str, callback: F, - ) -> Result<&mut MethodCallback, Error> + ) -> Result<&mut MethodCallback, RegisterMethodError> where Context: Send + Sync + 'static, F: (Fn(Params<'static>, PendingSubscriptionSink, Arc) -> Fut) + Send + Sync + Clone + 'static, @@ -636,7 +641,7 @@ impl RpcModule { R: IntoSubscriptionCloseResponse + Send, { if subscribe_method_name == unsubscribe_method_name { - return Err(Error::SubscriptionNameConflict(subscribe_method_name.into())); + return Err(RegisterMethodError::SubscriptionNameConflict(subscribe_method_name.into())); } self.methods.verify_method_name(subscribe_method_name)?; @@ -755,12 +760,16 @@ impl RpcModule { } /// Register an alias for an existing_method. Alias uniqueness is enforced. - pub fn register_alias(&mut self, alias: &'static str, existing_method: &'static str) -> Result<(), Error> { + pub fn register_alias( + &mut self, + alias: &'static str, + existing_method: &'static str, + ) -> Result<(), RegisterMethodError> { self.methods.verify_method_name(alias)?; let callback = match self.methods.callbacks.get(existing_method) { Some(callback) => callback.clone(), - None => return Err(Error::MethodNotFound(existing_method.into())), + None => return Err(RegisterMethodError::MethodNotFound(existing_method.into())), }; self.methods.mut_callbacks().insert(alias, callback); diff --git a/core/src/server/subscription.rs b/core/src/server/subscription.rs index 7e150f6a4f..e382a34bd5 100644 --- a/core/src/server/subscription.rs +++ b/core/src/server/subscription.rs @@ -29,7 +29,7 @@ use super::helpers::{MethodResponse, MethodSink}; use crate::server::error::{DisconnectError, PendingSubscriptionAcceptError, SendTimeoutError, TrySendError}; use crate::server::rpc_module::ConnectionId; -use crate::{traits::IdProvider, Error, StringError}; +use crate::{error::StringError, traits::IdProvider}; use jsonrpsee_types::{ response::SubscriptionError, ErrorObjectOwned, Id, ResponsePayload, SubscriptionId, SubscriptionResponse, }; @@ -411,7 +411,9 @@ impl Subscription { } /// Receives the next value on the subscription if value could be decoded as T. - pub async fn next(&mut self) -> Option), Error>> { + /// + // todo fix error type. + pub async fn next(&mut self) -> Option), String>> { let raw = self.rx.recv().await?; tracing::debug!("[Subscription::next]: rx {}", raw); @@ -419,7 +421,7 @@ impl Subscription { Ok(r) => Some(Ok((r.params.result, r.params.subscription.into_owned()))), Err(e) => match serde_json::from_str::>(&raw) { Ok(_) => None, - Err(_) => Some(Err(e.into())), + Err(_) => Some(Err(e.to_string())), }, }; res diff --git a/core/src/traits.rs b/core/src/traits.rs index bf95913f31..16cdb12aef 100644 --- a/core/src/traits.rs +++ b/core/src/traits.rs @@ -24,7 +24,6 @@ // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use crate::Error; use jsonrpsee_types::SubscriptionId; use serde::Serialize; use serde_json::value::RawValue; @@ -50,9 +49,9 @@ use serde_json::value::RawValue; /// struct ManualParam; /// /// impl ToRpcParams for ManualParam { -/// fn to_rpc_params(self) -> Result>, Error> { +/// fn to_rpc_params(self) -> Result>, serde_json::Error> { /// // Manually define a valid JSONRPC parameter. -/// RawValue::from_string("[1, \"2\", 3]".to_string()).map(Some).map_err(Error::ParseError) +/// RawValue::from_string("[1, \"2\", 3]".to_string()).map(Some) /// } /// } /// ``` @@ -63,7 +62,6 @@ use serde_json::value::RawValue; /// use jsonrpsee_core::traits::ToRpcParams; /// use serde_json::value::RawValue; /// use serde::Serialize; -/// use jsonrpsee_core::Error; /// /// #[derive(Serialize)] /// struct SerParam { @@ -72,7 +70,7 @@ use serde_json::value::RawValue; /// }; /// /// impl ToRpcParams for SerParam { -/// fn to_rpc_params(self) -> Result>, Error> { +/// fn to_rpc_params(self) -> Result>, serde_json::Error> { /// let s = String::from_utf8(serde_json::to_vec(&self)?).expect("Valid UTF8 format"); /// RawValue::from_string(s).map(Some).map_err(Error::ParseError) /// } @@ -80,16 +78,16 @@ use serde_json::value::RawValue; /// ``` pub trait ToRpcParams { /// Consume and serialize the type as a JSON raw value. - fn to_rpc_params(self) -> Result>, Error>; + fn to_rpc_params(self) -> Result>, serde_json::Error>; } // To not bound the `ToRpcParams: Serialize` define a custom implementation // for types which are serializable. macro_rules! to_rpc_params_impl { () => { - fn to_rpc_params(self) -> Result>, Error> { - let json = serde_json::to_string(&self).map_err(Error::ParseError)?; - RawValue::from_string(json).map(Some).map_err(Error::ParseError) + fn to_rpc_params(self) -> Result>, serde_json::Error> { + let json = serde_json::to_string(&self)?; + RawValue::from_string(json).map(Some) } }; } diff --git a/examples/examples/core_client.rs b/examples/examples/core_client.rs index 67d4e73810..35acbf69c7 100644 --- a/examples/examples/core_client.rs +++ b/examples/examples/core_client.rs @@ -55,7 +55,7 @@ async fn run_server() -> anyhow::Result { module.register_method("say_hello", |_, _| "lo")?; let addr = server.local_addr()?; - let handle = server.start(module)?; + let handle = server.start(module); // In this example we don't care about doing shutdown so let's it run forever. // You may use the `ServerHandle` to shut it down or manage it yourself. diff --git a/examples/examples/cors_server.rs b/examples/examples/cors_server.rs index 5bf58273a6..5e6c436a9e 100644 --- a/examples/examples/cors_server.rs +++ b/examples/examples/cors_server.rs @@ -99,7 +99,7 @@ async fn run_server() -> anyhow::Result { })?; let addr = server.local_addr()?; - let handle = server.start(module)?; + let handle = server.start(module); // In this example we don't care about doing shutdown so let's it run forever. // You may use the `ServerHandle` to shut it down or manage it yourself. diff --git a/examples/examples/http.rs b/examples/examples/http.rs index e6f7d4fc5b..7c0ebabccd 100644 --- a/examples/examples/http.rs +++ b/examples/examples/http.rs @@ -72,7 +72,7 @@ async fn run_server() -> anyhow::Result { module.register_method("say_hello", |_, _| "lo")?; let addr = server.local_addr()?; - let handle = server.start(module)?; + let handle = server.start(module); // In this example we don't care about doing shutdown so let's it run forever. // You may use the `ServerHandle` to shut it down or manage it yourself. diff --git a/examples/examples/http_proxy_middleware.rs b/examples/examples/http_proxy_middleware.rs index fb9cf40d35..6b1f61404c 100644 --- a/examples/examples/http_proxy_middleware.rs +++ b/examples/examples/http_proxy_middleware.rs @@ -96,7 +96,7 @@ async fn run_server() -> anyhow::Result { module.register_method("say_hello", |_, _| "lo").unwrap(); module.register_method("system_health", |_, _| serde_json::json!({ "health": true })).unwrap(); - let handle = server.start(module)?; + let handle = server.start(module); // In this example we don't care about doing shutdown so let's it run forever. // You may use the `ServerHandle` to shut it down or manage it yourself. diff --git a/examples/examples/logger.rs b/examples/examples/logger.rs index 8c5595a093..9b5886ab49 100644 --- a/examples/examples/logger.rs +++ b/examples/examples/logger.rs @@ -90,7 +90,7 @@ async fn run_server() -> anyhow::Result { module.register_method("say_hello", |_, _| "lo")?; let addr = server.local_addr()?; - let handle = server.start(module)?; + let handle = server.start(module); // In this example we don't care about doing shutdown so let's it run forever. // You may use the `ServerHandle` to shut it down or manage it yourself. diff --git a/examples/examples/middleware.rs b/examples/examples/middleware.rs index 757d294257..0a0f7e49a4 100644 --- a/examples/examples/middleware.rs +++ b/examples/examples/middleware.rs @@ -112,7 +112,7 @@ async fn run_server() -> anyhow::Result { let mut module = RpcModule::new(()); module.register_method("say_hello", |_, _| "lo").unwrap(); - let handle = server.start(module)?; + let handle = server.start(module); // In this example we don't care about doing shutdown so let's it run forever. // You may use the `ServerHandle` to shut it down or manage it yourself. diff --git a/examples/examples/multi_logger.rs b/examples/examples/multi_logger.rs index 95b21eaf45..a63199c317 100644 --- a/examples/examples/multi_logger.rs +++ b/examples/examples/multi_logger.rs @@ -153,7 +153,7 @@ async fn run_server() -> anyhow::Result { "" })?; let addr = server.local_addr()?; - let handle = server.start(module)?; + let handle = server.start(module); // In this example we don't care about doing shutdown so let's it run forever. // You may use the `ServerHandle` to shut it down or manage it yourself. diff --git a/examples/examples/proc_macro.rs b/examples/examples/proc_macro.rs index 86c70cec32..8f8b6fb31c 100644 --- a/examples/examples/proc_macro.rs +++ b/examples/examples/proc_macro.rs @@ -102,7 +102,7 @@ async fn run_server() -> anyhow::Result { let server = ServerBuilder::default().build("127.0.0.1:0").await?; let addr = server.local_addr()?; - let handle = server.start(RpcServerImpl.into_rpc())?; + let handle = server.start(RpcServerImpl.into_rpc()); // In this example we don't care about doing shutdown so let's it run forever. // You may use the `ServerHandle` to shut it down or manage it yourself. diff --git a/examples/examples/proc_macro_bounds.rs b/examples/examples/proc_macro_bounds.rs index 352a52ac20..b09c46491a 100644 --- a/examples/examples/proc_macro_bounds.rs +++ b/examples/examples/proc_macro_bounds.rs @@ -86,7 +86,7 @@ async fn run_server() -> anyhow::Result { let server = ServerBuilder::default().build("127.0.0.1:0").await?; let addr = server.local_addr()?; - let handle = server.start(RpcServerImpl.into_rpc())?; + let handle = server.start(RpcServerImpl.into_rpc()); // In this example we don't care about doing shutdown so let's it run forever. // You may use the `ServerHandle` to shut it down or manage it yourself. diff --git a/examples/examples/tokio_console.rs b/examples/examples/tokio_console.rs index 9c7b560869..288de43de1 100644 --- a/examples/examples/tokio_console.rs +++ b/examples/examples/tokio_console.rs @@ -59,7 +59,7 @@ async fn run_server() -> anyhow::Result { })?; let addr = server.local_addr()?; - let handle = server.start(module)?; + let handle = server.start(module); // In this example we don't care about doing a stopping the server so let it run forever. // You may use the `ServerHandle` to shut it down or manage it yourself. diff --git a/examples/examples/ws.rs b/examples/examples/ws.rs index 54f5d6fbff..8c2470aa22 100644 --- a/examples/examples/ws.rs +++ b/examples/examples/ws.rs @@ -54,7 +54,7 @@ async fn run_server() -> anyhow::Result { let mut module = RpcModule::new(()); module.register_method("say_hello", |_, _| "lo")?; let addr = server.local_addr()?; - let handle = server.start(module)?; + let handle = server.start(module); // In this example we don't care about doing shutdown so let's it run forever. // You may use the `ServerHandle` to shut it down or manage it yourself. diff --git a/examples/examples/ws_pubsub_broadcast.rs b/examples/examples/ws_pubsub_broadcast.rs index f7b50bba91..d092d693c7 100644 --- a/examples/examples/ws_pubsub_broadcast.rs +++ b/examples/examples/ws_pubsub_broadcast.rs @@ -82,7 +82,7 @@ async fn run_server() -> anyhow::Result { }) .unwrap(); let addr = server.local_addr()?; - let handle = server.start(module)?; + let handle = server.start(module); // In this example we don't care about doing shutdown so let's it run forever. // You may use the `ServerHandle` to shut it down or manage it yourself. diff --git a/examples/examples/ws_pubsub_with_params.rs b/examples/examples/ws_pubsub_with_params.rs index 7920c713e9..033dc49877 100644 --- a/examples/examples/ws_pubsub_with_params.rs +++ b/examples/examples/ws_pubsub_with_params.rs @@ -96,7 +96,7 @@ async fn run_server() -> anyhow::Result { .unwrap(); let addr = server.local_addr()?; - let handle = server.start(module)?; + let handle = server.start(module); // In this example we don't care about doing shutdown so let's it run forever. // You may use the `ServerHandle` to shut it down or manage it yourself. diff --git a/proc-macros/src/render_client.rs b/proc-macros/src/render_client.rs index cc366ab73f..439e8f2372 100644 --- a/proc-macros/src/render_client.rs +++ b/proc-macros/src/render_client.rs @@ -94,7 +94,8 @@ impl RpcDescription { // Force the last argument to be `jsonrpsee::core::Error`: let error_arg = args.last_mut().unwrap(); - *error_arg = syn::GenericArgument::Type(syn::Type::Verbatim(self.jrps_client_item(quote! { core::Error }))); + *error_arg = + syn::GenericArgument::Type(syn::Type::Verbatim(self.jrps_client_item(quote! { core::client::Error }))); quote!(#ty) } else if type_name.ident == "RpcResult" { @@ -105,7 +106,7 @@ impl RpcDescription { // The type alias `RpcResult` is modified to `Result`. let ret_ty = args.last_mut().unwrap(); - let err_ty = self.jrps_client_item(quote! { core::Error }); + let err_ty = self.jrps_client_item(quote! { core::client::Error }); quote! { core::result::Result<#ret_ty, #err_ty> } } else { @@ -116,7 +117,7 @@ impl RpcDescription { fn render_method(&self, method: &RpcMethod) -> Result { // `jsonrpsee::Error` - let jrps_error = self.jrps_client_item(quote! { core::Error }); + let jrps_error = self.jrps_client_item(quote! { core::client::Error }); // Rust method to invoke (e.g. `self.(...)`). let rust_method_name = &method.signature.sig.ident; // List of inputs to put into `Params` (e.g. `self.foo(<12, "baz">)`). @@ -160,7 +161,7 @@ impl RpcDescription { fn render_sub(&self, sub: &RpcSubscription) -> Result { // `jsonrpsee::core::Error` - let jrps_error = self.jrps_client_item(quote! { core::Error }); + let jrps_error = self.jrps_client_item(quote! { core::client::Error }); // Rust method to invoke (e.g. `self.(...)`). let rust_method_name = &sub.signature.sig.ident; // List of inputs to put into `Params` (e.g. `self.foo(<12, "baz">)`). diff --git a/server/Cargo.toml b/server/Cargo.toml index c6209292c7..fda02e00f1 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -26,6 +26,7 @@ tokio-util = { version = "0.7", features = ["compat"] } tokio-stream = "0.1.7" hyper = { version = "0.14", features = ["server", "http1", "http2"] } tower = "0.4.13" +thiserror = "1" [dev-dependencies] anyhow = "1" diff --git a/server/src/future.rs b/server/src/future.rs index beb69b0f19..b06a0521e5 100644 --- a/server/src/future.rs +++ b/server/src/future.rs @@ -26,7 +26,6 @@ //! Utilities for handling async code. -use jsonrpsee_core::Error; use std::sync::Arc; use tokio::sync::{watch, OwnedSemaphorePermit, Semaphore, TryAcquireError}; @@ -61,8 +60,8 @@ impl ServerHandle { } /// Tell the server to stop without waiting for the server to stop. - pub fn stop(&self) -> Result<(), Error> { - self.0.send(()).map_err(|_| Error::AlreadyStopped) + pub fn stop(&self) -> Result<(), ()> { + self.0.send(()).map_err(|_| ()) } /// Wait for the server to stop. diff --git a/server/src/lib.rs b/server/src/lib.rs index d5306b56aa..71fb96a73c 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -42,6 +42,7 @@ pub mod middleware; mod tests; pub use future::ServerHandle; +pub use jsonrpsee_core::error::RegisterMethodError; pub use jsonrpsee_core::server::*; pub use jsonrpsee_core::{id_providers::*, traits::IdProvider}; pub use jsonrpsee_types as types; diff --git a/server/src/middleware/proxy_get_request.rs b/server/src/middleware/proxy_get_request.rs index 1a46e7e76b..3520b0a053 100644 --- a/server/src/middleware/proxy_get_request.rs +++ b/server/src/middleware/proxy_get_request.rs @@ -5,7 +5,6 @@ use crate::transport::http; use hyper::header::{ACCEPT, CONTENT_TYPE}; use hyper::http::HeaderValue; use hyper::{Body, Method, Request, Response, Uri}; -use jsonrpsee_core::error::Error as RpcError; use jsonrpsee_types::{Id, RequestSer}; use std::error::Error; use std::future::Future; @@ -14,6 +13,11 @@ use std::sync::Arc; use std::task::{Context, Poll}; use tower::{Layer, Service}; +/// Error that occur if the specified path doesn't start with `/` +#[derive(Debug, thiserror::Error)] +#[error("ProxyGetRequestLayer path must start with `/`, got `{0}`")] +pub struct InvalidPath(String); + /// Layer that applies [`ProxyGetRequest`] which proxies the `GET /path` requests to /// specific RPC method calls and that strips the response. /// @@ -28,10 +32,10 @@ impl ProxyGetRequestLayer { /// Creates a new [`ProxyGetRequestLayer`]. /// /// See [`ProxyGetRequest`] for more details. - pub fn new(path: impl Into, method: impl Into) -> Result { + pub fn new(path: impl Into, method: impl Into) -> Result { let path = path.into(); if !path.starts_with('/') { - return Err(RpcError::Custom("ProxyGetRequestLayer path must start with `/`".to_string())); + return Err(InvalidPath(path)); } Ok(Self { path, method: method.into() }) @@ -70,9 +74,9 @@ impl ProxyGetRequest { /// /// The request `GET /path` is redirected to the provided method. /// Fails if the path does not start with `/`. - pub fn new(inner: S, path: &str, method: &str) -> Result { + pub fn new(inner: S, path: &str, method: &str) -> Result { if !path.starts_with('/') { - return Err(RpcError::Custom(format!("ProxyGetRequest path must start with `/`, got: {path}"))); + return Err(InvalidPath(path.to_string())); } Ok(Self { inner, path: Arc::from(path), method: Arc::from(method) }) diff --git a/server/src/server.rs b/server/src/server.rs index 6ad323fc77..b48622afd1 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -45,7 +45,7 @@ use jsonrpsee_core::id_providers::RandomIntegerIdProvider; use jsonrpsee_core::server::{AllowHosts, Methods}; use jsonrpsee_core::traits::IdProvider; -use jsonrpsee_core::{http_helpers, Error, TEN_MB_SIZE_BYTES}; +use jsonrpsee_core::{http_helpers, TEN_MB_SIZE_BYTES}; use soketto::handshake::http::is_upgrade_request; use tokio::net::{TcpListener, TcpStream, ToSocketAddrs}; @@ -79,8 +79,8 @@ impl std::fmt::Debug for Server { impl Server { /// Returns socket address to which the server is bound. - pub fn local_addr(&self) -> Result { - self.listener.local_addr().map_err(Into::into) + pub fn local_addr(&self) -> std::io::Result { + self.listener.local_addr() } } @@ -102,7 +102,7 @@ where /// Start responding to connections requests. /// /// This will run on the tokio runtime until the server is stopped or the `ServerHandle` is dropped. - pub fn start(mut self, methods: impl Into) -> Result { + pub fn start(mut self, methods: impl Into) -> ServerHandle { let methods = methods.into(); let (stop_tx, stop_rx) = watch::channel(()); @@ -113,7 +113,7 @@ where None => tokio::spawn(self.start_inner(methods, stop_handle)), }; - Ok(ServerHandle::new(stop_tx)) + ServerHandle::new(stop_tx) } async fn start_inner(self, methods: Methods, stop_handle: StopHandle) { @@ -501,7 +501,7 @@ impl Builder { /// } /// ``` /// - pub async fn build(self, addrs: impl ToSocketAddrs) -> Result, Error> { + pub async fn build(self, addrs: impl ToSocketAddrs) -> std::io::Result> { let listener = TcpListener::bind(addrs).await?; Ok(Server { @@ -536,7 +536,7 @@ impl Builder { /// let server = ServerBuilder::new().build_from_tcp(socket).unwrap(); /// } /// ``` - pub fn build_from_tcp(self, listener: impl Into) -> Result, Error> { + pub fn build_from_tcp(self, listener: impl Into) -> std::io::Result> { let listener = TcpListener::from_std(listener.into())?; Ok(Server { diff --git a/server/src/tests/helpers.rs b/server/src/tests/helpers.rs index 46c2144c8d..bb733359fd 100644 --- a/server/src/tests/helpers.rs +++ b/server/src/tests/helpers.rs @@ -3,7 +3,7 @@ use std::net::SocketAddr; use crate::{RpcModule, ServerBuilder, ServerHandle}; -use jsonrpsee_core::{DeserializeOwned, RpcResult, StringError}; +use jsonrpsee_core::{error::StringError, DeserializeOwned, RpcResult}; use jsonrpsee_test_utils::TimeoutFutureExt; use jsonrpsee_types::{error::ErrorCode, ErrorObject, ErrorObjectOwned, Response, ResponseSuccess}; use tracing_subscriber::{EnvFilter, FmtSubscriber}; @@ -118,7 +118,7 @@ pub(crate) async fn server_with_handles() -> (SocketAddr, ServerHandle) { let addr = server.local_addr().unwrap(); - let server_handle = server.start(module).unwrap(); + let server_handle = server.start(module); (addr, server_handle) } @@ -160,7 +160,7 @@ pub(crate) async fn server_with_context() -> SocketAddr { .unwrap(); let addr = server.local_addr().unwrap(); - let handle = server.start(rpc_module).unwrap(); + let handle = server.start(rpc_module); tokio::spawn(handle.stopped()); addr diff --git a/server/src/tests/http.rs b/server/src/tests/http.rs index bfb3cd6904..34b5e5ee00 100644 --- a/server/src/tests/http.rs +++ b/server/src/tests/http.rs @@ -26,9 +26,8 @@ use std::net::SocketAddr; -use crate::server::BatchRequestConfig; -use crate::{RpcModule, ServerBuilder, ServerHandle}; -use jsonrpsee_core::{Error, RpcResult}; +use crate::{BatchRequestConfig, RegisterMethodError, RpcModule, ServerBuilder, ServerHandle}; +use jsonrpsee_core::RpcResult; use jsonrpsee_test_utils::helpers::*; use jsonrpsee_test_utils::mocks::{Id, StatusCode}; use jsonrpsee_test_utils::TimeoutFutureExt; @@ -85,7 +84,7 @@ async fn server() -> (SocketAddr, ServerHandle) { }) .unwrap(); - let server_handle = server.start(module).unwrap(); + let server_handle = server.start(module); (addr, server_handle) } @@ -447,7 +446,7 @@ async fn can_register_modules() { let err = mod1.merge(mod2).unwrap_err(); - let expected_err = Error::MethodAlreadyRegistered(String::from("bla")); + let expected_err = RegisterMethodError::AlreadyRegistered(String::from("bla")); assert_eq!(err.to_string(), expected_err.to_string()); assert_eq!(mod1.method_names().count(), 2); } @@ -461,7 +460,7 @@ async fn can_set_the_max_request_body_size() { module.register_method("anything", |_p, _cx| "a".repeat(100)).unwrap(); let addr = server.local_addr().unwrap(); let uri = to_http_uri(addr); - let handle = server.start(module).unwrap(); + let handle = server.start(module); // Invalid: too long let req = format!(r#"{{"jsonrpc":"2.0", "method":{}, "id":1}}"#, "a".repeat(100)); @@ -486,7 +485,7 @@ async fn can_set_the_max_response_size() { module.register_method("anything", |_p, _cx| "a".repeat(101)).unwrap(); let addr = server.local_addr().unwrap(); let uri = to_http_uri(addr); - let handle = server.start(module).unwrap(); + let handle = server.start(module); // Oversized response. let req = r#"{"jsonrpc":"2.0", "method":"anything", "id":1}"#; @@ -506,7 +505,7 @@ async fn can_set_the_max_response_size_to_batch() { module.register_method("anything", |_p, _cx| "a".repeat(51)).unwrap(); let addr = server.local_addr().unwrap(); let uri = to_http_uri(addr); - let handle = server.start(module).unwrap(); + let handle = server.start(module); // Two response will end up in a response of 102 bytes which is too big. let req = r#"[{"jsonrpc":"2.0", "method":"anything", "id":1},{"jsonrpc":"2.0", "method":"anything", "id":2}]"#; @@ -527,7 +526,7 @@ async fn disabled_batches() { module.register_method("should_ok", |_, _ctx| "ok").unwrap(); let addr = server.local_addr().unwrap(); let uri = to_http_uri(addr); - let handle = server.start(module).unwrap(); + let handle = server.start(module); // Send a valid batch. let req = r#"[ @@ -551,7 +550,7 @@ async fn batch_limit_works() { module.register_method("should_ok", |_, _ctx| "ok").unwrap(); let addr = server.local_addr().unwrap(); let uri = to_http_uri(addr); - let handle = server.start(module).unwrap(); + let handle = server.start(module); // Send a valid batch. let req = r#"[ diff --git a/server/src/tests/shared.rs b/server/src/tests/shared.rs index 3d5e5dc6ac..17f112e555 100644 --- a/server/src/tests/shared.rs +++ b/server/src/tests/shared.rs @@ -1,6 +1,5 @@ use crate::tests::helpers::{init_logger, server_with_handles}; use hyper::StatusCode; -use jsonrpsee_core::Error; use jsonrpsee_test_utils::helpers::{http_request, ok_response, to_http_uri}; use jsonrpsee_test_utils::mocks::{Id, WebSocketTestClient, WebSocketTestError}; use jsonrpsee_test_utils::TimeoutFutureExt; @@ -19,7 +18,7 @@ async fn stop_works() { // First `unwrap` is timeout, second is `JoinHandle`'s one. // After server was stopped, attempt to stop it again should result in an error. - assert!(matches!(server_handle.stop(), Err(Error::AlreadyStopped))); + assert!(matches!(server_handle.stop(), Err(()))); } #[tokio::test] @@ -54,7 +53,7 @@ async fn http_only_works() { .unwrap(); let addr = server.local_addr().unwrap(); - let _server_handle = server.start(module).unwrap(); + let _server_handle = server.start(module); let req = r#"{"jsonrpc":"2.0","method":"say_hello","id":1}"#; let response = http_request(req.into(), to_http_uri(addr)).with_default_timeout().await.unwrap().unwrap(); @@ -79,7 +78,7 @@ async fn ws_only_works() { .unwrap(); let addr = server.local_addr().unwrap(); - let _server_handle = server.start(module).unwrap(); + let _server_handle = server.start(module); let req = r#"{"jsonrpc":"2.0","method":"say_hello","id":1}"#; let response = http_request(req.into(), to_http_uri(addr)).with_default_timeout().await.unwrap().unwrap(); diff --git a/server/src/tests/ws.rs b/server/src/tests/ws.rs index c3ca417532..08fd42aced 100644 --- a/server/src/tests/ws.rs +++ b/server/src/tests/ws.rs @@ -26,12 +26,12 @@ use std::time::Duration; -use crate::server::BatchRequestConfig; use crate::tests::helpers::{deser_call, init_logger, server_with_context}; use crate::types::SubscriptionId; +use crate::{BatchRequestConfig, RegisterMethodError}; use crate::{RpcModule, ServerBuilder}; use jsonrpsee_core::server::{SendTimeoutError, SubscriptionMessage}; -use jsonrpsee_core::{traits::IdProvider, Error}; +use jsonrpsee_core::traits::IdProvider; use jsonrpsee_test_utils::helpers::*; use jsonrpsee_test_utils::mocks::{Id, WebSocketTestClient, WebSocketTestError}; use jsonrpsee_test_utils::TimeoutFutureExt; @@ -50,7 +50,7 @@ async fn can_set_the_max_request_body_size() { let mut module = RpcModule::new(()); module.register_method("anything", |_p, _cx| "a".repeat(100)).unwrap(); let addr = server.local_addr().unwrap(); - let handle = server.start(module).unwrap(); + let handle = server.start(module); let mut client = WebSocketTestClient::new(addr).await.unwrap(); @@ -78,7 +78,7 @@ async fn can_set_the_max_response_body_size() { let mut module = RpcModule::new(()); module.register_method("anything", |_p, _cx| "a".repeat(101)).unwrap(); let addr = server.local_addr().unwrap(); - let server_handle = server.start(module).unwrap(); + let server_handle = server.start(module); let mut client = WebSocketTestClient::new(addr).await.unwrap(); @@ -101,7 +101,7 @@ async fn can_set_the_max_response_size_to_batch() { let mut module = RpcModule::new(()); module.register_method("anything", |_p, _cx| "a".repeat(51)).unwrap(); let addr = server.local_addr().unwrap(); - let server_handle = server.start(module).unwrap(); + let server_handle = server.start(module); let mut client = WebSocketTestClient::new(addr).await.unwrap(); @@ -125,7 +125,7 @@ async fn can_set_max_connections() { module.register_method("anything", |_p, _cx| ()).unwrap(); let addr = server.local_addr().unwrap(); - let server_handle = server.start(module).unwrap(); + let server_handle = server.start(module); let conn1 = WebSocketTestClient::new(addr).await; let conn2 = WebSocketTestClient::new(addr).await; @@ -438,7 +438,7 @@ async fn register_same_subscribe_unsubscribe_is_err() { assert!(matches!( module .register_subscription("subscribe_hello", "subscribe_hello", "subscribe_hello", |_, _, _| async { Ok(()) }), - Err(Error::SubscriptionNameConflict(_)) + Err(RegisterMethodError::SubscriptionNameConflict(_)) )); } @@ -508,7 +508,7 @@ async fn can_register_modules() { assert_eq!(mod1.method_names().count(), 2); let err = mod1.merge(mod2).unwrap_err(); - assert!(matches!(err, Error::MethodAlreadyRegistered(err) if err == "bla")); + assert!(matches!(err, RegisterMethodError::AlreadyRegistered(err) if err == "bla")); assert_eq!(mod1.method_names().count(), 2); } @@ -575,7 +575,7 @@ async fn custom_subscription_id_works() { } }) .unwrap(); - let _handle = server.start(module).unwrap(); + let _handle = server.start(module); let mut client = WebSocketTestClient::new(addr).with_default_timeout().await.unwrap().unwrap(); @@ -600,7 +600,7 @@ async fn disabled_batches() { module.register_method("should_ok", |_, _ctx| "ok").unwrap(); let addr = server.local_addr().unwrap(); - let server_handle = server.start(module).unwrap(); + let server_handle = server.start(module); // Send a valid batch. let mut client = WebSocketTestClient::new(addr).with_default_timeout().await.unwrap().unwrap(); @@ -630,7 +630,7 @@ async fn batch_limit_works() { module.register_method("should_ok", |_, _ctx| "ok").unwrap(); let addr = server.local_addr().unwrap(); - let server_handle = server.start(module).unwrap(); + let server_handle = server.start(module); // Send a valid batch. let mut client = WebSocketTestClient::new(addr).with_default_timeout().await.unwrap().unwrap(); @@ -767,7 +767,7 @@ async fn ws_server_backpressure_works() { .unwrap(); let addr = server.local_addr().unwrap(); - let _server_handle = server.start(module).unwrap(); + let _server_handle = server.start(module); // Send a valid batch. let mut client = WebSocketTestClient::new(addr).with_default_timeout().await.unwrap().unwrap(); @@ -899,5 +899,5 @@ async fn server_with_infinite_call( .unwrap(); let addr = server.local_addr().unwrap(); - (server.start(module).unwrap(), addr) + (server.start(module), addr) } diff --git a/server/src/transport/ws.rs b/server/src/transport/ws.rs index 63ef8faea2..0208a35042 100644 --- a/server/src/transport/ws.rs +++ b/server/src/transport/ws.rs @@ -17,7 +17,7 @@ use jsonrpsee_core::server::{ }; use jsonrpsee_core::tracing::{rx_log_from_json, tx_log_from_str}; use jsonrpsee_core::traits::IdProvider; -use jsonrpsee_core::{Error, JsonRawValue}; +use jsonrpsee_core::JsonRawValue; use jsonrpsee_types::error::{ reject_too_big_batch_request, reject_too_big_request, reject_too_many_subscriptions, ErrorCode, BATCHES_NOT_SUPPORTED_CODE, BATCHES_NOT_SUPPORTED_MSG, @@ -36,12 +36,12 @@ pub(crate) type Receiver = soketto::Receiver = Notification<'a, Option<&'a JsonRawValue>>; -pub(crate) async fn send_message(sender: &mut Sender, response: String) -> Result<(), Error> { +pub(crate) async fn send_message(sender: &mut Sender, response: String) -> Result<(), SokettoError> { sender.send_text_owned(response).await?; sender.flush().await.map_err(Into::into) } -pub(crate) async fn send_ping(sender: &mut Sender) -> Result<(), Error> { +pub(crate) async fn send_ping(sender: &mut Sender) -> Result<(), SokettoError> { tracing::debug!("Send ping"); // Submit empty slice as "optional" parameter. let slice: &[u8] = &[]; diff --git a/tests/tests/helpers.rs b/tests/tests/helpers.rs index 5a09d912b9..6c9c2978d0 100644 --- a/tests/tests/helpers.rs +++ b/tests/tests/helpers.rs @@ -30,7 +30,6 @@ use std::net::SocketAddr; use std::time::Duration; use futures::{SinkExt, Stream, StreamExt}; -use jsonrpsee::core::Error; use jsonrpsee::server::middleware::proxy_get_request::ProxyGetRequestLayer; use jsonrpsee::server::{ AllowHosts, PendingSubscriptionSink, RpcModule, ServerBuilder, ServerHandle, SubscriptionMessage, TrySendError, @@ -91,7 +90,7 @@ pub async fn server_with_subscription_and_handle() -> (SocketAddr, ServerHandle) .register_subscription("subscribe_noop", "subscribe_noop", "unsubscribe_noop", |_, pending, _| async { let _sink = pending.accept().await?; tokio::time::sleep(Duration::from_secs(1)).await; - Err(Error::Custom("Server closed the stream because it was lazy".to_string()).into()) + Err("Server closed the stream because it was lazy".to_string().into()) }) .unwrap(); @@ -119,7 +118,7 @@ pub async fn server_with_subscription_and_handle() -> (SocketAddr, ServerHandle) .unwrap(); let addr = server.local_addr().unwrap(); - let server_handle = server.start(module).unwrap(); + let server_handle = server.start(module); (addr, server_handle) } @@ -158,7 +157,7 @@ pub async fn server() -> SocketAddr { let addr = server.local_addr().unwrap(); - let server_handle = server.start(module).unwrap(); + let server_handle = server.start(module); tokio::spawn(server_handle.stopped()); @@ -186,7 +185,7 @@ pub async fn server_with_sleeping_subscription(tx: futures::channel::mpsc::Sende res.map_err(Into::into) }) .unwrap(); - let handle = server.start(module).unwrap(); + let handle = server.start(module); tokio::spawn(handle.stopped()); @@ -218,7 +217,7 @@ pub async fn server_with_access_control(allowed_hosts: AllowHosts, cors: CorsLay module.register_method("system_health", |_, _| serde_json::json!({ "health": true })).unwrap(); - let handle = server.start(module).unwrap(); + let handle = server.start(module); (addr, handle) } diff --git a/tests/tests/integration_tests.rs b/tests/tests/integration_tests.rs index c7d0b0828a..7cf75a8314 100644 --- a/tests/tests/integration_tests.rs +++ b/tests/tests/integration_tests.rs @@ -40,10 +40,10 @@ use helpers::{ server_with_subscription, server_with_subscription_and_handle, }; use hyper::http::HeaderValue; -use jsonrpsee::core::client::{ClientT, IdKind, Subscription, SubscriptionClientT}; +use jsonrpsee::core::client::{ClientT, Error, IdKind, Subscription, SubscriptionClientT}; use jsonrpsee::core::params::{ArrayParams, BatchRequestBuilder}; use jsonrpsee::core::server::SubscriptionMessage; -use jsonrpsee::core::{Error, JsonValue}; +use jsonrpsee::core::JsonValue; use jsonrpsee::http_client::HttpClientBuilder; use jsonrpsee::server::{ServerBuilder, ServerHandle}; use jsonrpsee::types::error::{ErrorObject, UNKNOWN_ERROR_CODE}; @@ -458,7 +458,7 @@ async fn ws_server_should_stop_subscription_after_client_drop() { ) .unwrap(); - let _handle = server.start(module).unwrap(); + let _handle = server.start(module); let client = WsClientBuilder::default().build(&server_url).await.unwrap(); @@ -490,7 +490,7 @@ async fn ws_server_stop_subscription_when_dropped() { .register_subscription("subscribe_nop", "h", "unsubscribe_nop", |_params, _pending, _ctx| async { Ok(()) }) .unwrap(); - let _handle = server.start(module).unwrap(); + let _handle = server.start(module); let client = WsClientBuilder::default().build(&server_url).await.unwrap(); assert!(client.subscribe::("subscribe_nop", rpc_params![], "unsubscribe_nop").await.is_err()); @@ -754,7 +754,7 @@ async fn ws_server_limit_subs_per_conn_works() { pipe_from_stream_and_drop(pending, stream).await.map_err(Into::into) }) .unwrap(); - let _handle = server.start(module).unwrap(); + let _handle = server.start(module); let c1 = WsClientBuilder::default().build(&server_url).await.unwrap(); let c2 = WsClientBuilder::default().build(&server_url).await.unwrap(); @@ -809,7 +809,7 @@ async fn ws_server_unsub_methods_should_ignore_sub_limit() { pipe_from_stream_and_drop(pending, stream).await.map_err(Into::into) }) .unwrap(); - let _handle = server.start(module).unwrap(); + let _handle = server.start(module); let client = WsClientBuilder::default().build(&server_url).await.unwrap(); @@ -1031,7 +1031,7 @@ async fn ws_host_filtering_wildcard_works() { let addr = server.local_addr().unwrap(); module.register_method("say_hello", |_, _| "hello").unwrap(); - let _handle = server.start(module).unwrap(); + let _handle = server.start(module); let server_url = format!("ws://{}", addr); let client = WsClientBuilder::default().build(&server_url).await.unwrap(); @@ -1052,7 +1052,7 @@ async fn http_host_filtering_wildcard_works() { let addr = server.local_addr().unwrap(); module.register_method("say_hello", |_, _| "hello").unwrap(); - let _handle = server.start(module).unwrap(); + let _handle = server.start(module); let server_url = format!("http://{}", addr); let client = HttpClientBuilder::default().build(&server_url).unwrap(); @@ -1073,7 +1073,7 @@ async fn deny_invalid_host() { let addr = server.local_addr().unwrap(); module.register_method("say_hello", |_, _| "hello").unwrap(); - let _handle = server.start(module).unwrap(); + let _handle = server.start(module); // HTTP { @@ -1233,7 +1233,7 @@ async fn run_shutdown_test(transport: &str) { .unwrap(); let addr = server.local_addr().unwrap(); - (server.start(module).unwrap(), addr) + (server.start(module), addr) }; match transport { diff --git a/tests/tests/metrics.rs b/tests/tests/metrics.rs index a07a1d69b1..bc9ca2d459 100644 --- a/tests/tests/metrics.rs +++ b/tests/tests/metrics.rs @@ -27,12 +27,13 @@ mod helpers; use std::collections::HashMap; +use std::io; use std::net::SocketAddr; use std::sync::{Arc, Mutex}; use std::time::Duration; use helpers::init_logger; -use jsonrpsee::core::{client::ClientT, Error}; +use jsonrpsee::core::client::{ClientT, Error}; use jsonrpsee::http_client::HttpClientBuilder; use jsonrpsee::proc_macros::rpc; use jsonrpsee::rpc_params; @@ -112,20 +113,20 @@ fn test_module() -> RpcModule<()> { ().into_rpc() } -async fn websocket_server(module: RpcModule<()>, counter: Counter) -> Result<(SocketAddr, ServerHandle), Error> { +async fn websocket_server(module: RpcModule<()>, counter: Counter) -> io::Result<(SocketAddr, ServerHandle)> { let server = ServerBuilder::default().set_logger(counter).build("127.0.0.1:0").await?; let addr = server.local_addr()?; - let handle = server.start(module)?; + let handle = server.start(module); Ok((addr, handle)) } -async fn http_server(module: RpcModule<()>, counter: Counter) -> Result<(SocketAddr, ServerHandle), Error> { +async fn http_server(module: RpcModule<()>, counter: Counter) -> io::Result<(SocketAddr, ServerHandle)> { let server = ServerBuilder::default().set_logger(counter).build("127.0.0.1:0").await?; let addr = server.local_addr()?; - let handle = server.start(module)?; + let handle = server.start(module); Ok((addr, handle)) } diff --git a/tests/tests/proc_macros.rs b/tests/tests/proc_macros.rs index 362bf43149..993cad9bf2 100644 --- a/tests/tests/proc_macros.rs +++ b/tests/tests/proc_macros.rs @@ -31,8 +31,7 @@ mod helpers; use std::net::SocketAddr; use helpers::init_logger; -use jsonrpsee::core::client::ClientT; -use jsonrpsee::core::{client::SubscriptionClientT, Error}; +use jsonrpsee::core::client::{ClientT, Error, SubscriptionClientT}; use jsonrpsee::http_client::HttpClientBuilder; use jsonrpsee::rpc_params; use jsonrpsee::server::ServerBuilder; @@ -195,7 +194,7 @@ use rpc_impl::{RpcClient, RpcServer, RpcServerImpl}; pub async fn server() -> SocketAddr { let server = ServerBuilder::default().build("127.0.0.1:0").await.unwrap(); let addr = server.local_addr().unwrap(); - let handle = server.start(RpcServerImpl.into_rpc()).unwrap(); + let handle = server.start(RpcServerImpl.into_rpc()); tokio::spawn(handle.stopped()); @@ -318,7 +317,7 @@ async fn subscriptions_do_not_work_for_http_servers() { let htserver = ServerBuilder::default().build("127.0.0.1:0").await.unwrap(); let addr = htserver.local_addr().unwrap(); let htserver_url = format!("http://{}", addr); - let _handle = htserver.start(RpcServerImpl.into_rpc()).unwrap(); + let _handle = htserver.start(RpcServerImpl.into_rpc()); let htclient = HttpClientBuilder::default().build(&htserver_url).unwrap(); @@ -385,7 +384,7 @@ async fn calls_with_object_params_works() { let server = ServerBuilder::default().build("127.0.0.1:0").await.unwrap(); let addr = server.local_addr().unwrap(); let server_url = format!("ws://{}", addr); - let _handle = server.start(RpcServerImpl.into_rpc()).unwrap(); + let _handle = server.start(RpcServerImpl.into_rpc()); let client = WsClientBuilder::default().build(&server_url).await.unwrap(); // snake_case params diff --git a/tests/tests/rpc_module.rs b/tests/tests/rpc_module.rs index bbd8428801..23bde1aee9 100644 --- a/tests/tests/rpc_module.rs +++ b/tests/tests/rpc_module.rs @@ -31,7 +31,6 @@ use std::time::Duration; use futures::StreamExt; use helpers::{init_logger, pipe_from_stream_and_drop}; -use jsonrpsee::core::error::Error; use jsonrpsee::core::EmptyServerParams; use jsonrpsee::core::{server::*, RpcResult}; use jsonrpsee::types::error::{ErrorCode, ErrorObject, INVALID_PARAMS_MSG, PARSE_ERROR_CODE}; @@ -115,7 +114,7 @@ async fn calling_method_without_server() { let err = module.call::<_, EmptyServerParams>("foo", (false,)).await.unwrap_err(); assert!(matches!( err, - Error::Call(err) if err.code() == ErrorCode::InvalidParams.code() && err.message() == INVALID_PARAMS_MSG && err.data().unwrap().get().contains("invalid type: boolean `false`, expected u16 at line 1 column 6") + CallError::JsonRpc(err) if err.code() == ErrorCode::InvalidParams.code() && err.message() == INVALID_PARAMS_MSG && err.data().unwrap().get().contains("invalid type: boolean `false`, expected u16 at line 1 column 6") )); // Call async method with params and context @@ -209,7 +208,7 @@ async fn calling_method_without_server_using_proc_macro() { let err = module.call::<_, EmptyServerParams>("rebel", (Gun { shoots: true }, false)).await.unwrap_err(); assert!(matches!(err, - Error::Call(err) if err.data().unwrap().get().contains("invalid type: boolean `false`, expected a map at line 1 column 5") && + CallError::JsonRpc(err) if err.data().unwrap().get().contains("invalid type: boolean `false`, expected a map at line 1 column 5") && err.code() == ErrorCode::InvalidParams.code() && err.message() == INVALID_PARAMS_MSG )); @@ -228,7 +227,7 @@ async fn calling_method_without_server_using_proc_macro() { // Call async method with option which should `Err`. let err = module.call::<_, Option>("can_have_options", vec![2]).await.unwrap_err(); assert!(matches!(err, - Error::Call(err) if err.message() == "too big number" + CallError::JsonRpc(err) if err.message() == "too big number" )); } @@ -250,7 +249,7 @@ async fn subscribing_without_server() { tokio::time::sleep(std::time::Duration::from_millis(500)).await; } - Err(Error::Custom("closed successfully".into()).into()) + Err("closed successfully".into()) }) .unwrap(); @@ -334,7 +333,7 @@ async fn subscribing_without_server_bad_params() { let sub = module.subscribe_unbounded("my_sub", EmptyServerParams::new()).await.unwrap_err(); assert!( - matches!(sub, Error::Call(e) if e.data().unwrap().get().contains("invalid length 0, expected an array of length 1 at line 1 column 2") && e.code() == ErrorCode::InvalidParams.code() + matches!(sub, CallError::JsonRpc(e) if e.data().unwrap().get().contains("invalid length 0, expected an array of length 1 at line 1 column 2") && e.code() == ErrorCode::InvalidParams.code() && e.message() == INVALID_PARAMS_MSG ) ); @@ -410,7 +409,9 @@ async fn rejected_subscription_without_server() { .unwrap(); let sub_err = module.subscribe_unbounded("my_sub", EmptyServerParams::new()).await.unwrap_err(); - assert!(matches!(sub_err, Error::Call(e) if e.message().contains("rejected") && e.code() == PARSE_ERROR_CODE)); + assert!( + matches!(sub_err, CallError::JsonRpc(e) if e.message().contains("rejected") && e.code() == PARSE_ERROR_CODE) + ); } #[tokio::test] From 5524eba9bfadd663577f1ce13b026e0556523409 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 1 Dec 2023 18:02:34 +0100 Subject: [PATCH 02/22] cargo fmt --- client/ws-client/src/lib.rs | 2 +- client/ws-client/src/tests.rs | 2 +- server/src/lib.rs | 2 +- server/src/server.rs | 5 ++++- server/src/transport/http.rs | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/client/ws-client/src/lib.rs b/client/ws-client/src/lib.rs index 48e1ba2d97..4a22118c74 100644 --- a/client/ws-client/src/lib.rs +++ b/client/ws-client/src/lib.rs @@ -47,7 +47,7 @@ use url::Url; use jsonrpsee_client_transport::ws::{AsyncRead, AsyncWrite, WsTransportClientBuilder}; use jsonrpsee_core::client::{ - CertificateStore, ClientBuilder, IdKind, MaybeSend, TransportReceiverT, TransportSenderT, Error + CertificateStore, ClientBuilder, Error, IdKind, MaybeSend, TransportReceiverT, TransportSenderT, }; use jsonrpsee_core::TEN_MB_SIZE_BYTES; diff --git a/client/ws-client/src/tests.rs b/client/ws-client/src/tests.rs index b8b7ae3ccd..565e650bf0 100644 --- a/client/ws-client/src/tests.rs +++ b/client/ws-client/src/tests.rs @@ -29,7 +29,7 @@ use crate::types::error::{ErrorCode, ErrorObject}; use crate::WsClientBuilder; -use jsonrpsee_core::client::{BatchResponse, ClientT, SubscriptionClientT, Error, IdKind, Subscription}; +use jsonrpsee_core::client::{BatchResponse, ClientT, Error, IdKind, Subscription, SubscriptionClientT}; use jsonrpsee_core::params::BatchRequestBuilder; use jsonrpsee_core::{rpc_params, DeserializeOwned}; use jsonrpsee_test_utils::helpers::*; diff --git a/server/src/lib.rs b/server/src/lib.rs index d542e70037..fe4029de11 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -40,8 +40,8 @@ pub mod middleware; #[cfg(test)] mod tests; -pub use jsonrpsee_core::error::RegisterMethodError; pub use future::{stop_channel, ConnectionGuard, ConnectionPermit, ServerHandle, StopHandle}; +pub use jsonrpsee_core::error::RegisterMethodError; pub use jsonrpsee_core::server::*; pub use jsonrpsee_core::{id_providers::*, traits::IdProvider}; pub use jsonrpsee_types as types; diff --git a/server/src/server.rs b/server/src/server.rs index 99fb52f1a5..4c3beed8ee 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -891,7 +891,10 @@ impl Builder { /// let server = Server::builder().build_from_tcp(socket).unwrap(); /// } /// ``` - pub fn build_from_tcp(self, listener: impl Into) -> std::io::Result> { + pub fn build_from_tcp( + self, + listener: impl Into, + ) -> std::io::Result> { let listener = TcpListener::from_std(listener.into())?; Ok(Server { diff --git a/server/src/transport/http.rs b/server/src/transport/http.rs index e9b61b80be..beb1be9cc9 100644 --- a/server/src/transport/http.rs +++ b/server/src/transport/http.rs @@ -1,5 +1,5 @@ use http::Method; -use jsonrpsee_core::{http_helpers::read_body, server::Methods, error::GenericTransportError}; +use jsonrpsee_core::{error::GenericTransportError, http_helpers::read_body, server::Methods}; use crate::{ middleware::rpc::{RpcService, RpcServiceBuilder, RpcServiceCfg, RpcServiceT}, From 4562b211e6425cf13361cae7f1e71394aa3fb1b6 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 1 Dec 2023 18:13:12 +0100 Subject: [PATCH 03/22] remove old code --- core/src/server/host_filtering/host.rs | 210 ------------------------- 1 file changed, 210 deletions(-) delete mode 100644 core/src/server/host_filtering/host.rs diff --git a/core/src/server/host_filtering/host.rs b/core/src/server/host_filtering/host.rs deleted file mode 100644 index 299fb5eef7..0000000000 --- a/core/src/server/host_filtering/host.rs +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any -// person obtaining a copy of this software and associated -// documentation files (the "Software"), to deal in the -// Software without restriction, including without -// limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice -// shall be included in all copies or substantial portions -// of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -//! Host header validation. - -use crate::server::host_filtering::matcher::{Matcher, Pattern}; - -const SPLIT_PROOF: &str = "split always returns non-empty iterator."; - -/// Port pattern -#[derive(Clone, Hash, PartialEq, Eq, Debug)] -pub enum Port { - /// No port specified (default port) - None, - /// Port specified as a wildcard pattern - Pattern(String), - /// Fixed numeric port - Fixed(u16), -} - -impl From> for Port { - fn from(opt: Option) -> Self { - match opt { - Some(port) => Port::Fixed(port), - None => Port::None, - } - } -} - -impl From for Port { - fn from(port: u16) -> Port { - Port::Fixed(port) - } -} - -/// Host type -#[derive(Clone, Hash, PartialEq, Eq, Debug)] -pub struct Host { - hostname: String, - port: Port, - host_with_port: String, - matcher: Matcher, -} - -impl> From for Host { - fn from(string: T) -> Self { - Host::parse(string.as_ref()) - } -} - -impl Host { - /// Creates a new `Host` given hostname and port number. - pub fn new>(hostname: &str, port: T) -> Self { - let port = port.into(); - let hostname = Self::pre_process(hostname); - let host_with_port = Self::from_str(&hostname, &port); - let matcher = Matcher::new(&host_with_port); - - Host { hostname, port, host_with_port, matcher } - } - - /// Attempts to parse given string as a `Host`. - /// NOTE: This method always succeeds and falls back to sensible defaults. - pub fn parse(hostname: &str) -> Self { - let hostname = Self::pre_process(hostname); - let mut hostname = hostname.split(':'); - let host = hostname.next().expect(SPLIT_PROOF); - let port = match hostname.next() { - None => Port::None, - Some(port) => match port.parse::().ok() { - Some(num) => Port::Fixed(num), - None => Port::Pattern(port.into()), - }, - }; - - Host::new(host, port) - } - - fn pre_process(host: &str) -> String { - // Remove possible protocol definition - let mut it = host.split("://"); - let protocol = it.next().expect(SPLIT_PROOF); - let host = match it.next() { - Some(data) => data, - None => protocol, - }; - - let mut it = host.split('/'); - it.next().expect(SPLIT_PROOF).to_lowercase() - } - - fn from_str(hostname: &str, port: &Port) -> String { - format!( - "{}{}", - hostname, - match *port { - Port::Fixed(port) => format!(":{port}"), - Port::Pattern(ref port) => format!(":{port}"), - Port::None => "".into(), - }, - ) - } -} - -impl Pattern for Host { - fn matches>(&self, other: T) -> bool { - self.matcher.matches(other) - } -} - -impl std::ops::Deref for Host { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.host_with_port - } -} - -/// Policy for validating the `HTTP host header`. -#[derive(Debug, Clone)] -pub enum AllowHosts { - /// Allow all hosts (no filter). - Any, - /// Allow only specified hosts. - Only(Vec), -} - -#[derive(Debug, thiserror::Error)] -#[error("host `{0}` rejected because it's not whitelisted")] -pub struct AllowHostError(String); - -impl AllowHosts { - /// Verify a host. - pub fn verify(&self, value: &str) -> Result<(), AllowHostError> { - if let AllowHosts::Only(list) = self { - if !list.iter().any(|o| o.matches(value)) { - return Err(AllowHostError(value.to_string())); - } - } - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::{AllowHosts, Host, Port}; - - #[test] - fn should_parse_host() { - assert_eq!(Host::parse("http://parity.io"), Host::new("parity.io", None)); - assert_eq!(Host::parse("https://parity.io:8443"), Host::new("parity.io", Some(8443))); - assert_eq!(Host::parse("chrome-extension://124.0.0.1"), Host::new("124.0.0.1", None)); - assert_eq!(Host::parse("parity.io/somepath"), Host::new("parity.io", None)); - assert_eq!(Host::parse("127.0.0.1:8545/somepath"), Host::new("127.0.0.1", Some(8545))); - - let host = Host::parse("*.domain:*/somepath"); - assert_eq!(host.port, Port::Pattern("*".into())); - assert_eq!(host.hostname.as_str(), "*.domain"); - } - - #[test] - fn should_allow_when_validation_is_disabled() { - assert!((AllowHosts::Any).verify("any").is_ok()); - } - - #[test] - fn should_reject_if_header_not_on_the_list() { - assert!((AllowHosts::Only(vec![])).verify("parity.io").is_err()); - } - - #[test] - fn should_accept_if_on_the_list() { - assert!((AllowHosts::Only(vec!["parity.io".into()])).verify("parity.io").is_ok()); - } - - #[test] - fn should_accept_if_on_the_list_with_port() { - assert!((AllowHosts::Only(vec!["parity.io:443".into()])).verify("parity.io:443").is_ok()); - assert!((AllowHosts::Only(vec!["parity.io".into()])).verify("parity.io:443").is_err()); - } - - #[test] - fn should_support_wildcards() { - assert!((AllowHosts::Only(vec!["*.web3.site:*".into()])).verify("parity.web3.site:8180").is_ok()); - } -} From 2181ed0e4fab42c99d0a93670c862af22e7f12bb Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Dec 2023 10:43:27 +0100 Subject: [PATCH 04/22] fix tests --- client/wasm-client/src/lib.rs | 3 +-- core/src/server/rpc_module.rs | 2 +- core/src/traits.rs | 3 +-- proc-macros/src/render_client.rs | 6 +++--- proc-macros/tests/ui/correct/custom_ret_types.rs | 12 ++++++------ 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/client/wasm-client/src/lib.rs b/client/wasm-client/src/lib.rs index 5d4f4d6a1e..8eda472719 100644 --- a/client/wasm-client/src/lib.rs +++ b/client/wasm-client/src/lib.rs @@ -36,8 +36,7 @@ pub use jsonrpsee_types as types; use std::time::Duration; use jsonrpsee_client_transport::web; -use jsonrpsee_core::client::{ClientBuilder, IdKind}; -use jsonrpsee_core::Error; +use jsonrpsee_core::client::{ClientBuilder, IdKind, Error}; /// Builder for [`Client`]. /// diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 794fe26371..042cda40f5 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -372,7 +372,7 @@ impl Methods { /// #[tokio::main] /// async fn main() { /// use jsonrpsee::{RpcModule, SubscriptionMessage}; - /// use jsonrpsee::core::{Error, EmptyServerParams, RpcResult}; + /// use jsonrpsee::core::{EmptyServerParams, RpcResult}; /// /// let mut module = RpcModule::new(()); /// module.register_subscription("hi", "hi", "goodbye", |_, pending, _| async move { diff --git a/core/src/traits.rs b/core/src/traits.rs index 16cdb12aef..64e158c913 100644 --- a/core/src/traits.rs +++ b/core/src/traits.rs @@ -44,7 +44,6 @@ use serde_json::value::RawValue; /// ```rust /// use jsonrpsee_core::traits::ToRpcParams; /// use serde_json::value::RawValue; -/// use jsonrpsee_core::Error; /// /// struct ManualParam; /// @@ -72,7 +71,7 @@ use serde_json::value::RawValue; /// impl ToRpcParams for SerParam { /// fn to_rpc_params(self) -> Result>, serde_json::Error> { /// let s = String::from_utf8(serde_json::to_vec(&self)?).expect("Valid UTF8 format"); -/// RawValue::from_string(s).map(Some).map_err(Error::ParseError) +/// RawValue::from_string(s).map(Some) /// } /// } /// ``` diff --git a/proc-macros/src/render_client.rs b/proc-macros/src/render_client.rs index 66be627a5b..4f2f6c39d5 100644 --- a/proc-macros/src/render_client.rs +++ b/proc-macros/src/render_client.rs @@ -93,7 +93,7 @@ impl RpcDescription { return quote_spanned!(args.span() => compile_error!("Result must be have two arguments")); } - // Force the last argument to be `jsonrpsee::core::Error`: + // Force the last argument to be `jsonrpsee::core::ClientError`: let error_arg = args.last_mut().unwrap(); *error_arg = syn::GenericArgument::Type(syn::Type::Verbatim(self.jrps_client_item(quote! { core::client::Error }))); @@ -128,7 +128,7 @@ impl RpcDescription { let rpc_method_name = self.rpc_identifier(&method.name); // Called method is either `request` or `notification`. - // `returns` represent the return type of the *rust method* (`Result< <..>, jsonrpsee::core::Error`). + // `returns` represent the return type of the *rust method* (`Result`). let (called_method, returns) = if let Some(returns) = &method.returns { let called_method = quote::format_ident!("request"); let returns = self.return_result_type(returns.clone()); @@ -161,7 +161,7 @@ impl RpcDescription { } fn render_sub(&self, sub: &RpcSubscription) -> Result { - // `jsonrpsee::core::Error` + // `jsonrpsee::core::ClientError` let jrps_error = self.jrps_client_item(quote! { core::client::Error }); // Rust method to invoke (e.g. `self.(...)`). let rust_method_name = &sub.signature.sig.ident; diff --git a/proc-macros/tests/ui/correct/custom_ret_types.rs b/proc-macros/tests/ui/correct/custom_ret_types.rs index 011fe9f845..8f89b55392 100644 --- a/proc-macros/tests/ui/correct/custom_ret_types.rs +++ b/proc-macros/tests/ui/correct/custom_ret_types.rs @@ -2,7 +2,7 @@ use std::net::SocketAddr; -use jsonrpsee::core::{async_trait, Error, Serialize}; +use jsonrpsee::core::{async_trait, ClientError, Serialize}; use jsonrpsee::proc_macros::rpc; use jsonrpsee::server::{IntoResponse, ServerBuilder}; use jsonrpsee::types::ResponsePayload; @@ -87,7 +87,7 @@ impl RpcServer for RpcServerImpl { // TODO: https://github.com/paritytech/jsonrpsee/issues/1067 // -// The client accepts only return types that are `Result`. +// The client accepts only return types that are `Result`. #[rpc(client, namespace = "foo")] pub trait RpcClient { #[method(name = "async_method1")] @@ -144,9 +144,9 @@ async fn main() { assert_method2(error); } -fn assert_method1(error: Error) { +fn assert_method1(error: ClientError) { let get_error_object = |err| match err { - jsonrpsee::core::Error::Call(object) => object, + ClientError::Call(object) => object, _ => panic!("wrong error kind: {:?}", err), }; @@ -156,9 +156,9 @@ fn assert_method1(error: Error) { assert!(error_object.data().is_none()); } -fn assert_method2(error: Error) { +fn assert_method2(error: ClientError) { let get_error_object = |err| match err { - jsonrpsee::core::Error::Call(object) => object, + ClientError::Call(object) => object, _ => panic!("wrong error kind: {:?}", err), }; From 46fdececfa10cb790aa8ede9491f600401841857 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Dec 2023 10:47:02 +0100 Subject: [PATCH 05/22] cargo fmt --- client/wasm-client/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/wasm-client/src/lib.rs b/client/wasm-client/src/lib.rs index 8eda472719..943adf51ae 100644 --- a/client/wasm-client/src/lib.rs +++ b/client/wasm-client/src/lib.rs @@ -36,7 +36,7 @@ pub use jsonrpsee_types as types; use std::time::Duration; use jsonrpsee_client_transport::web; -use jsonrpsee_core::client::{ClientBuilder, IdKind, Error}; +use jsonrpsee_core::client::{ClientBuilder, Error, IdKind}; /// Builder for [`Client`]. /// From 2bf937aa709ae5f9b82f7d260396503a12e51efe Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Dec 2023 10:55:58 +0100 Subject: [PATCH 06/22] fix rustdoc links --- core/src/server/error.rs | 15 --------------- core/src/server/rpc_module.rs | 29 ++++++++++++++++++++++------- tests/tests/rpc_module.rs | 10 +++++----- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/core/src/server/error.rs b/core/src/server/error.rs index 48d5355e29..e92a29e112 100644 --- a/core/src/server/error.rs +++ b/core/src/server/error.rs @@ -25,7 +25,6 @@ // DEALINGS IN THE SOFTWARE. use crate::server::SubscriptionMessage; -use jsonrpsee_types::ErrorObjectOwned; use tokio::sync::mpsc; /// Error that may occur during [`crate::server::MethodSink::try_send`] or [`crate::server::SubscriptionSink::try_send`]. @@ -84,17 +83,3 @@ impl From> for SendTimeoutError { } } } - -/// The error that can occur when [`RpcModule::call`] or [`RpcModule::subscribe`] is invoked. -#[derive(thiserror::Error, Debug)] -pub enum CallError { - /// Failed to parse the call as valid JSON-RPC. - #[error("{0}")] - Parse(#[from] serde_json::Error), - /// Specific JSON-RPC error. - #[error("{0}")] - JsonRpc(#[from] ErrorObjectOwned), - #[error("Invalid subscription ID: `{0}`")] - /// Invalid subscription ID. - InvalidSubscriptionId(String), -} diff --git a/core/src/server/rpc_module.rs b/core/src/server/rpc_module.rs index 042cda40f5..abceec27d8 100644 --- a/core/src/server/rpc_module.rs +++ b/core/src/server/rpc_module.rs @@ -43,13 +43,13 @@ use crate::traits::ToRpcParams; use futures_util::{future::BoxFuture, FutureExt}; use jsonrpsee_types::error::{ErrorCode, ErrorObject}; use jsonrpsee_types::{ - Id, Params, Request, Response, ResponsePayload, ResponseSuccess, SubscriptionId as RpcSubscriptionId, + Id, Params, Request, Response, ResponsePayload, ResponseSuccess, SubscriptionId as RpcSubscriptionId, ErrorObjectOwned, }; use rustc_hash::FxHashMap; use serde::de::DeserializeOwned; use tokio::sync::{mpsc, oneshot}; -use super::{CallError, IntoResponse}; +use super::IntoResponse; /// A `MethodCallback` is an RPC endpoint, callable with a standard JSON-RPC request, /// implemented as a function pointer to a `Fn` function taking four arguments: @@ -78,6 +78,21 @@ pub type MaxResponseSize = usize; /// - a [`mpsc::UnboundedReceiver`] to receive future subscription results pub type RawRpcResponse = (MethodResponse, mpsc::Receiver); + +/// The error that can occur when [`Methods::call`] or [`Methods::subscribe`] is invoked. +#[derive(thiserror::Error, Debug)] +pub enum MethodsError { + /// Failed to parse the call as valid JSON-RPC. + #[error("{0}")] + Parse(#[from] serde_json::Error), + /// Specific JSON-RPC error. + #[error("{0}")] + JsonRpc(#[from] ErrorObjectOwned), + #[error("Invalid subscription ID: `{0}`")] + /// Invalid subscription ID. + InvalidSubscriptionId(String), +} + /// This represent a response to a RPC call /// and `Subscribe` calls are handled differently /// because we want to prevent subscriptions to start @@ -272,13 +287,13 @@ impl Methods { &self, method: &str, params: Params, - ) -> Result { + ) -> Result { let params = params.to_rpc_params()?; let req = Request::new(method.into(), params.as_ref().map(|p| p.as_ref()), Id::Number(0)); tracing::trace!(target: LOG_TARGET, "[Methods::call] Method: {:?}, params: {:?}", method, params); let (resp, _) = self.inner_call(req, 1, mock_subscription_permit()).await; let rp = serde_json::from_str::>(&resp.result)?; - ResponseSuccess::try_from(rp).map(|s| s.result).map_err(|e| CallError::JsonRpc(e.into_owned())) + ResponseSuccess::try_from(rp).map(|s| s.result).map_err(|e| MethodsError::JsonRpc(e.into_owned())) } /// Make a request (JSON-RPC method call or subscription) by using raw JSON. @@ -391,7 +406,7 @@ impl Methods { &self, sub_method: &str, params: impl ToRpcParams, - ) -> Result { + ) -> Result { self.subscribe(sub_method, params, u32::MAX as usize).await } @@ -403,7 +418,7 @@ impl Methods { sub_method: &str, params: impl ToRpcParams, buf_size: usize, - ) -> Result { + ) -> Result { let params = params.to_rpc_params()?; let req = Request::new(sub_method.into(), params.as_ref().map(|p| p.as_ref()), Id::Number(0)); @@ -415,7 +430,7 @@ impl Methods { let as_success: ResponseSuccess = serde_json::from_str::>(&resp.result)?.try_into()?; - let sub_id = as_success.result.try_into().map_err(|_| CallError::InvalidSubscriptionId(resp.result.clone()))?; + let sub_id = as_success.result.try_into().map_err(|_| MethodsError::InvalidSubscriptionId(resp.result.clone()))?; Ok(Subscription { sub_id, rx }) } diff --git a/tests/tests/rpc_module.rs b/tests/tests/rpc_module.rs index cbf7d5dce3..65ba98424b 100644 --- a/tests/tests/rpc_module.rs +++ b/tests/tests/rpc_module.rs @@ -116,7 +116,7 @@ async fn calling_method_without_server() { let err = module.call::<_, EmptyServerParams>("foo", (false,)).await.unwrap_err(); assert!(matches!( err, - CallError::JsonRpc(err) if err.code() == ErrorCode::InvalidParams.code() && err.message() == INVALID_PARAMS_MSG && err.data().unwrap().get().contains("invalid type: boolean `false`, expected u16 at line 1 column 6") + MethodsError::JsonRpc(err) if err.code() == ErrorCode::InvalidParams.code() && err.message() == INVALID_PARAMS_MSG && err.data().unwrap().get().contains("invalid type: boolean `false`, expected u16 at line 1 column 6") )); // Call async method with params and context @@ -210,7 +210,7 @@ async fn calling_method_without_server_using_proc_macro() { let err = module.call::<_, EmptyServerParams>("rebel", (Gun { shoots: true }, false)).await.unwrap_err(); assert!(matches!(err, - CallError::JsonRpc(err) if err.data().unwrap().get().contains("invalid type: boolean `false`, expected a map at line 1 column 5") && + MethodsError::JsonRpc(err) if err.data().unwrap().get().contains("invalid type: boolean `false`, expected a map at line 1 column 5") && err.code() == ErrorCode::InvalidParams.code() && err.message() == INVALID_PARAMS_MSG )); @@ -229,7 +229,7 @@ async fn calling_method_without_server_using_proc_macro() { // Call async method with option which should `Err`. let err = module.call::<_, Option>("can_have_options", vec![2]).await.unwrap_err(); assert!(matches!(err, - CallError::JsonRpc(err) if err.message() == "too big number" + MethodsError::JsonRpc(err) if err.message() == "too big number" )); } @@ -335,7 +335,7 @@ async fn subscribing_without_server_bad_params() { let sub = module.subscribe_unbounded("my_sub", EmptyServerParams::new()).await.unwrap_err(); assert!( - matches!(sub, CallError::JsonRpc(e) if e.data().unwrap().get().contains("invalid length 0, expected an array of length 1 at line 1 column 2") && e.code() == ErrorCode::InvalidParams.code() + matches!(sub, MethodsError::JsonRpc(e) if e.data().unwrap().get().contains("invalid length 0, expected an array of length 1 at line 1 column 2") && e.code() == ErrorCode::InvalidParams.code() && e.message() == INVALID_PARAMS_MSG ) ); @@ -412,7 +412,7 @@ async fn rejected_subscription_without_server() { let sub_err = module.subscribe_unbounded("my_sub", EmptyServerParams::new()).await.unwrap_err(); assert!( - matches!(sub_err, CallError::JsonRpc(e) if e.message().contains("rejected") && e.code() == PARSE_ERROR_CODE) + matches!(sub_err, MethodsError::JsonRpc(e) if e.message().contains("rejected") && e.code() == PARSE_ERROR_CODE) ); } From 7c6f9e3ba21c4c8a52b36aca7f31c7d5bc36153f Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Dec 2023 11:18:09 +0100 Subject: [PATCH 07/22] make clippy happy --- core/src/client/async_client/helpers.rs | 8 ++++---- core/src/client/async_client/manager.rs | 2 +- core/src/client/async_client/mod.rs | 4 ++-- core/src/client/mod.rs | 10 +++++----- core/src/params.rs | 9 +++++++-- server/src/future.rs | 9 +++++++-- server/src/tests/shared.rs | 2 +- 7 files changed, 27 insertions(+), 17 deletions(-) diff --git a/core/src/client/async_client/helpers.rs b/core/src/client/async_client/helpers.rs index e817819067..d9d55f3869 100644 --- a/core/src/client/async_client/helpers.rs +++ b/core/src/client/async_client/helpers.rs @@ -64,7 +64,7 @@ pub(crate) fn process_batch_response( Some(state) => state, None => { tracing::warn!(target: LOG_TARGET, "Received unknown batch response"); - return Err(InvalidRequestId::NotPendingRequest(format!("{:?}", range)).into()); + return Err(InvalidRequestId::NotPendingRequest(format!("{:?}", range))); } }; @@ -80,7 +80,7 @@ pub(crate) fn process_batch_response( if let Some(elem) = maybe_elem { *elem = rp.result; } else { - return Err(InvalidRequestId::NotPendingRequest(rp.id.to_string()).into()); + return Err(InvalidRequestId::NotPendingRequest(rp.id.to_string())); } } @@ -181,7 +181,7 @@ pub(crate) fn process_single_response( let send_back_oneshot = match manager.complete_pending_call(response_id.clone()) { Some(Some(send)) => send, Some(None) => return Ok(None), - None => return Err(InvalidRequestId::NotPendingRequest(response_id.to_string()).into()), + None => return Err(InvalidRequestId::NotPendingRequest(response_id.to_string())), }; let _ = send_back_oneshot.send(result); @@ -222,7 +222,7 @@ pub(crate) fn process_single_response( } RequestStatus::Subscription | RequestStatus::Invalid => { - Err(InvalidRequestId::NotPendingRequest(response_id.to_string()).into()) + Err(InvalidRequestId::NotPendingRequest(response_id.to_string())) } } } diff --git a/core/src/client/async_client/manager.rs b/core/src/client/async_client/manager.rs index ae20476c6e..3ac657cbcf 100644 --- a/core/src/client/async_client/manager.rs +++ b/core/src/client/async_client/manager.rs @@ -196,7 +196,7 @@ impl RequestManager { } /// Removes a notification handler. - pub(crate) fn remove_notification_handler<'a>(&mut self, method: &'a str) -> Option { + pub(crate) fn remove_notification_handler(&mut self, method: &str) -> Option { self.notification_handlers.remove(method) } diff --git a/core/src/client/async_client/mod.rs b/core/src/client/async_client/mod.rs index 30b979ee91..90a0e262ef 100644 --- a/core/src/client/async_client/mod.rs +++ b/core/src/client/async_client/mod.rs @@ -9,7 +9,7 @@ use crate::client::{ Subscription, SubscriptionClientT, SubscriptionKind, SubscriptionMessage, TransportReceiverT, TransportSenderT, Error }; use crate::error::RegisterMethodError; -use crate::params::BatchRequestBuilder; +use crate::params::{BatchRequestBuilder, EmptyBatchRequest}; use crate::tracing::client::{rx_log_from_json, tx_log_from_str}; use crate::traits::ToRpcParams; use crate::JsonRawValue; @@ -657,7 +657,7 @@ fn handle_backend_messages( range.end += 1; process_batch_response(&mut manager.lock(), batch, range)?; } else { - return Err(Error::EmptyBatchRequest); + return Err(EmptyBatchRequest.into()); } } else { return Err(unparse_error(raw)); diff --git a/core/src/client/mod.rs b/core/src/client/mod.rs index b0ddfe5d5e..22d1843f40 100644 --- a/core/src/client/mod.rs +++ b/core/src/client/mod.rs @@ -38,8 +38,8 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; use std::task; -use crate::error::{RegisterMethodError}; -use crate::params::BatchRequestBuilder; +use crate::error::RegisterMethodError; +use crate::params::{BatchRequestBuilder, EmptyBatchRequest}; use crate::traits::ToRpcParams; use async_trait::async_trait; use core::marker::PhantomData; @@ -95,9 +95,9 @@ pub enum Error { #[error("Not implemented")] HttpNotImplemented, /// Empty batch request. - #[error("Empty batch request is not allowed")] - EmptyBatchRequest, - /// The error returned when registering a method or subscription failed. + #[error("{0}")] + EmptyBatchRequest(#[from] EmptyBatchRequest), + /// The error returned w hen registering a method or subscription failed. #[error("{0}")] RegisterMethod(#[from] RegisterMethodError), } diff --git a/core/src/params.rs b/core/src/params.rs index be9ad9f78f..3521097037 100644 --- a/core/src/params.rs +++ b/core/src/params.rs @@ -221,6 +221,11 @@ impl ToRpcParams for ArrayParams { /// Initial number of parameters in a batch request. const BATCH_PARAMS_NUM_CAPACITY: usize = 4; +/// Error representing an empty batch request. +#[derive(Debug, Clone, Copy, thiserror::Error)] +#[error("Empty batch request is not allowed")] +pub struct EmptyBatchRequest; + /// Request builder that serializes RPC parameters to construct a valid batch parameter. /// This is the equivalent of chaining multiple RPC requests. #[derive(Clone, Debug, Default)] @@ -240,9 +245,9 @@ impl<'a> BatchRequestBuilder<'a> { /// Finish the building process and return a valid batch parameter. #[allow(clippy::type_complexity)] - pub fn build(self) -> Result>)>, ()> { + pub fn build(self) -> Result>)>, EmptyBatchRequest> { if self.0.is_empty() { - Err(()) + Err(EmptyBatchRequest) } else { Ok(self.0) } diff --git a/server/src/future.rs b/server/src/future.rs index 88c1f2a52c..8bcd7abf20 100644 --- a/server/src/future.rs +++ b/server/src/future.rs @@ -60,6 +60,11 @@ impl StopHandle { } } +#[derive(Debug, Copy, Clone, thiserror::Error)] +#[error("The server is already stopped")] +pub struct AlreadyStoppedError; + + /// Server handle. /// /// When all [`StopHandle`]'s have been `dropped` or `stop` has been called @@ -74,8 +79,8 @@ impl ServerHandle { } /// Tell the server to stop without waiting for the server to stop. - pub fn stop(&self) -> Result<(), ()> { - self.0.send(()).map_err(|_| ()) + pub fn stop(&self) -> Result<(), AlreadyStoppedError> { + self.0.send(()).map_err(|_| AlreadyStoppedError) } /// Wait for the server to stop. diff --git a/server/src/tests/shared.rs b/server/src/tests/shared.rs index 17f112e555..9e37f3a8fb 100644 --- a/server/src/tests/shared.rs +++ b/server/src/tests/shared.rs @@ -18,7 +18,7 @@ async fn stop_works() { // First `unwrap` is timeout, second is `JoinHandle`'s one. // After server was stopped, attempt to stop it again should result in an error. - assert!(matches!(server_handle.stop(), Err(()))); + assert!(matches!(server_handle.stop(), Err(_))); } #[tokio::test] From 439552060edc5f7255283175413aec158f1dab76 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Dec 2023 11:20:28 +0100 Subject: [PATCH 08/22] Update server/src/future.rs --- server/src/future.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/server/src/future.rs b/server/src/future.rs index 8bcd7abf20..d187ef58e2 100644 --- a/server/src/future.rs +++ b/server/src/future.rs @@ -64,7 +64,6 @@ impl StopHandle { #[error("The server is already stopped")] pub struct AlreadyStoppedError; - /// Server handle. /// /// When all [`StopHandle`]'s have been `dropped` or `stop` has been called From e2383516359ec1b8b2b4f3652e30f0799a640f76 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Dec 2023 11:21:05 +0100 Subject: [PATCH 09/22] Update client/http-client/src/client.rs --- client/http-client/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/http-client/src/client.rs b/client/http-client/src/client.rs index c51ad4abfb..0d6cd727c2 100644 --- a/client/http-client/src/client.rs +++ b/client/http-client/src/client.rs @@ -328,7 +328,7 @@ where R: DeserializeOwned + fmt::Debug + 'a, { // TODO fix unwrap. - let batch = batch.build().unwrap(); + let batch = batch.build()?; let guard = self.id_manager.next_request_id()?; let id_range = generate_batch_id_range(&guard, batch.len() as u64)?; From 04173042281990fd09a68c9a27f6b6d6759066dd Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Dec 2023 11:21:20 +0100 Subject: [PATCH 10/22] Update client/http-client/src/client.rs --- client/http-client/src/client.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/client/http-client/src/client.rs b/client/http-client/src/client.rs index 0d6cd727c2..6ee886b884 100644 --- a/client/http-client/src/client.rs +++ b/client/http-client/src/client.rs @@ -327,7 +327,6 @@ where where R: DeserializeOwned + fmt::Debug + 'a, { - // TODO fix unwrap. let batch = batch.build()?; let guard = self.id_manager.next_request_id()?; let id_range = generate_batch_id_range(&guard, batch.len() as u64)?; From 5704689e1b572a79303aefefd2cce9641d743388 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Dec 2023 11:22:34 +0100 Subject: [PATCH 11/22] Update core/src/client/async_client/helpers.rs --- core/src/client/async_client/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/client/async_client/helpers.rs b/core/src/client/async_client/helpers.rs index d9d55f3869..5eec7e6ffc 100644 --- a/core/src/client/async_client/helpers.rs +++ b/core/src/client/async_client/helpers.rs @@ -197,7 +197,7 @@ pub(crate) fn process_single_response( let sub_id = match sub_id { Ok(Some(sub_id)) => sub_id, Ok(None) => { - let _ = send_back_oneshot.send(Err(Error::InvalidRequestId(InvalidRequestId::Invalid("Invalid subscription ID".into())))); + let _ = send_back_oneshot.send(Err(Error::InvalidSubscriptionId)); return Ok(None); } Err(e) => { From 5de5c0a53ffad1154777d78598d86fa943032a79 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Dec 2023 11:23:26 +0100 Subject: [PATCH 12/22] Update core/src/client/async_client/helpers.rs --- core/src/client/async_client/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/client/async_client/helpers.rs b/core/src/client/async_client/helpers.rs index 5eec7e6ffc..eb42e851e2 100644 --- a/core/src/client/async_client/helpers.rs +++ b/core/src/client/async_client/helpers.rs @@ -216,7 +216,7 @@ pub(crate) fn process_single_response( Err(_) => Ok(build_unsubscribe_message(manager, response_id, sub_id)), } } else { - let _ = send_back_oneshot.send(Err(Error::InvalidRequestId(InvalidRequestId::Invalid("Invalid subscription ID".into())))); + let _ = send_back_oneshot.send(Err(Error::InvalidSubscriptionId)); Ok(None) } } From cc85b30b8eafc1d2dbde6118add153278b82d5f9 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Dec 2023 11:23:59 +0100 Subject: [PATCH 13/22] Update core/src/client/async_client/mod.rs --- core/src/client/async_client/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/client/async_client/mod.rs b/core/src/client/async_client/mod.rs index 90a0e262ef..b7a0037bc0 100644 --- a/core/src/client/async_client/mod.rs +++ b/core/src/client/async_client/mod.rs @@ -428,7 +428,7 @@ impl ClientT for Client { R: DeserializeOwned, { // TODO: remove unwrap - let batch = batch.build().unwrap(); + let batch = batch.build()?; let guard = self.id_manager.next_request_id()?; let id_range = generate_batch_id_range(&guard, batch.len() as u64)?; From 570be497fb8b16d33648909a2441559f26e28505 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Dec 2023 11:24:31 +0100 Subject: [PATCH 14/22] Update core/src/client/async_client/mod.rs --- core/src/client/async_client/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/client/async_client/mod.rs b/core/src/client/async_client/mod.rs index b7a0037bc0..8f7e37820d 100644 --- a/core/src/client/async_client/mod.rs +++ b/core/src/client/async_client/mod.rs @@ -427,7 +427,6 @@ impl ClientT for Client { where R: DeserializeOwned, { - // TODO: remove unwrap let batch = batch.build()?; let guard = self.id_manager.next_request_id()?; let id_range = generate_batch_id_range(&guard, batch.len() as u64)?; From 6f9995572a7a3b3bfe4b5c5f9783019d6b2d6bf3 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Dec 2023 11:30:35 +0100 Subject: [PATCH 15/22] fix more todos --- core/src/client/mod.rs | 2 +- core/src/server/subscription.rs | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core/src/client/mod.rs b/core/src/client/mod.rs index 22d1843f40..46a57c78e8 100644 --- a/core/src/client/mod.rs +++ b/core/src/client/mod.rs @@ -85,7 +85,7 @@ pub enum Error { /// Request timeout #[error("Request timeout")] RequestTimeout, - /// Configured max number of request slots exceeded. + /// Max number of request slots exceeded. #[error("Configured max number of request slots exceeded")] MaxSlotsExceeded, /// Custom error. diff --git a/core/src/server/subscription.rs b/core/src/server/subscription.rs index 3f0920bf03..2685c8968e 100644 --- a/core/src/server/subscription.rs +++ b/core/src/server/subscription.rs @@ -26,6 +26,7 @@ //! Subscription related types and traits for server implementations. +use super::MethodsError; use super::helpers::{MethodResponse, MethodSink}; use crate::server::LOG_TARGET; use crate::server::error::{DisconnectError, PendingSubscriptionAcceptError, SendTimeoutError, TrySendError}; @@ -434,10 +435,8 @@ impl Subscription { &self.sub_id } - /// Receives the next value on the subscription if value could be decoded as T. - /// - // todo fix error type. - pub async fn next(&mut self) -> Option), String>> { + /// Receives the next value on the subscription if the value could be decoded as T. + pub async fn next(&mut self) -> Option), MethodsError>> { let raw = self.rx.recv().await?; tracing::debug!(target: LOG_TARGET, "[Subscription::next]: rx {}", raw); @@ -448,7 +447,7 @@ impl Subscription { Ok(r) => Some(Ok((r.params.result, r.params.subscription.into_owned()))), Err(e) => match serde_json::from_str::>(&raw) { Ok(_) => None, - Err(_) => Some(Err(e.to_string())), + Err(_) => Some(Err(e.into())), }, }; res From bebaa3b213f2e2edb843f047b491c7bd8acc42ff Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Dec 2023 11:39:47 +0100 Subject: [PATCH 16/22] unused dep: soketto --- core/Cargo.toml | 2 -- server/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index 84ee12c693..edb3a5aa3e 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -29,13 +29,11 @@ futures-util = { version = "0.3.14", default-features = false, optional = true } hyper = { version = "0.14.10", default-features = false, features = ["stream"], optional = true } rustc-hash = { version = "1", optional = true } rand = { version = "0.8", optional = true } -soketto = { version = "0.7.1", optional = true } parking_lot = { version = "0.12", optional = true } tokio = { version = "1.16", optional = true } wasm-bindgen-futures = { version = "0.4.19", optional = true } futures-timer = { version = "3", optional = true } - [features] default = [] http-helpers = ["hyper", "futures-util"] diff --git a/server/Cargo.toml b/server/Cargo.toml index fee68ad941..266497c840 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -16,7 +16,7 @@ publish = true [dependencies] futures-util = { version = "0.3.14", default-features = false, features = ["io", "async-await-macro"] } jsonrpsee-types = { workspace = true } -jsonrpsee-core = { workspace = true, features = ["server", "soketto", "http-helpers"] } +jsonrpsee-core = { workspace = true, features = ["server", "http-helpers"] } tracing = "0.1.34" serde = "1" serde_json = { version = "1", features = ["raw_value"] } From e013884793d2215e19ad5d0c1bc461f4a90c4bc2 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 4 Dec 2023 11:46:29 +0100 Subject: [PATCH 17/22] remove unused error variant --- core/src/client/async_client/mod.rs | 6 +++--- core/src/client/mod.rs | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/core/src/client/async_client/mod.rs b/core/src/client/async_client/mod.rs index 8f7e37820d..769ed99db5 100644 --- a/core/src/client/async_client/mod.rs +++ b/core/src/client/async_client/mod.rs @@ -506,9 +506,9 @@ impl SubscriptionClientT for Client { Notif: DeserializeOwned, { if subscribe_method == unsubscribe_method { - return Err(Error::RegisterMethod(RegisterMethodError::SubscriptionNameConflict( + return Err(RegisterMethodError::SubscriptionNameConflict( unsubscribe_method.to_owned(), - ))); + ).into()); } let guard = self.id_manager.next_request_two_ids()?; @@ -765,7 +765,7 @@ async fn handle_frontend_messages( let _ = reg.send_back.send(Ok((subscribe_rx, reg.method))); } else { let _ = - reg.send_back.send(Err(Error::RegisterMethod(RegisterMethodError::AlreadyRegistered(reg.method)))); + reg.send_back.send(Err(RegisterMethodError::AlreadyRegistered(reg.method).into())); } } // User dropped the NotificationHandler for this method diff --git a/core/src/client/mod.rs b/core/src/client/mod.rs index 46a57c78e8..dbb556555d 100644 --- a/core/src/client/mod.rs +++ b/core/src/client/mod.rs @@ -79,9 +79,6 @@ pub enum Error { /// Invalid request ID. #[error("{0}")] InvalidRequestId(#[from] InvalidRequestId), - /// A request with the same request ID has already been registered. - #[error("A request with the same request ID has already been registered")] - DuplicateRequestId, /// Request timeout #[error("Request timeout")] RequestTimeout, From a16ee716249c90d1a1514f5164ffa75016821fd2 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 5 Dec 2023 13:28:10 +0100 Subject: [PATCH 18/22] Update core/src/lib.rs --- core/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index a25e315f2b..f0b686c70b 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -60,7 +60,7 @@ cfg_client! { /// Shared tracing helpers to trace RPC calls. pub mod tracing; pub use async_trait::async_trait; -//pub use error::{Error, GenericTransportError, StringError}; +pub use error::{GenericTransportError, StringError, RegisterMethodError}; /// JSON-RPC result. pub type RpcResult = std::result::Result; From 86b29a918c2036d450852e17a6d74bddc8c6fed4 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 5 Dec 2023 14:58:40 +0100 Subject: [PATCH 19/22] cargo fmt --- client/ws-client/src/lib.rs | 6 +++--- core/src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/ws-client/src/lib.rs b/client/ws-client/src/lib.rs index 8335d35c71..c354ff7992 100644 --- a/client/ws-client/src/lib.rs +++ b/client/ws-client/src/lib.rs @@ -38,17 +38,17 @@ #[cfg(test)] mod tests; +pub use http::{HeaderMap, HeaderValue}; pub use jsonrpsee_core::client::Client as WsClient; pub use jsonrpsee_types as types; -pub use http::{HeaderMap, HeaderValue}; -use std::time::Duration; -use url::Url; use jsonrpsee_client_transport::ws::{AsyncRead, AsyncWrite, WsTransportClientBuilder}; use jsonrpsee_core::client::{ CertificateStore, ClientBuilder, Error, IdKind, MaybeSend, TransportReceiverT, TransportSenderT, }; use jsonrpsee_core::TEN_MB_SIZE_BYTES; +use std::time::Duration; +use url::Url; /// Builder for [`WsClient`]. /// diff --git a/core/src/lib.rs b/core/src/lib.rs index f0b686c70b..9c3e5aac0e 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -60,7 +60,7 @@ cfg_client! { /// Shared tracing helpers to trace RPC calls. pub mod tracing; pub use async_trait::async_trait; -pub use error::{GenericTransportError, StringError, RegisterMethodError}; +pub use error::{GenericTransportError, RegisterMethodError, StringError}; /// JSON-RPC result. pub type RpcResult = std::result::Result; From 71ca1dcf89ff1ff91af5c5fcab2a9fb849bf4dbe Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 6 Dec 2023 09:45:33 +0100 Subject: [PATCH 20/22] fix grumbles: move client error to own mod --- core/src/client/error.rs | 72 ++++++++++++++++++++++++++++++++++++++++ core/src/client/mod.rs | 49 +++------------------------ 2 files changed, 77 insertions(+), 44 deletions(-) create mode 100644 core/src/client/error.rs diff --git a/core/src/client/error.rs b/core/src/client/error.rs new file mode 100644 index 0000000000..b0514d86a7 --- /dev/null +++ b/core/src/client/error.rs @@ -0,0 +1,72 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// +// Permission is hereby granted, free of charge, to any +// person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the +// Software without restriction, including without +// limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice +// shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +//! Error type for client(s). + +use std::sync::Arc; +use crate::{params::EmptyBatchRequest, RegisterMethodError}; +use jsonrpsee_types::{ErrorObjectOwned, InvalidRequestId}; + +/// Error type. +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// JSON-RPC error which can occur when a JSON-RPC call fails. + #[error("{0}")] + Call(#[from] ErrorObjectOwned), + /// Networking error or error on the low-level protocol layer. + #[error("Networking or low-level protocol error: {0}")] + Transport(#[source] anyhow::Error), + /// The background task has been terminated. + #[error("The background task been terminated because: {0}; restart required")] + RestartNeeded(Arc), + /// Failed to parse the data. + #[error("Parse error: {0}")] + ParseError(#[from] serde_json::Error), + /// Invalid subscription ID. + #[error("Invalid subscription ID")] + InvalidSubscriptionId, + /// Invalid request ID. + #[error("{0}")] + InvalidRequestId(#[from] InvalidRequestId), + /// Request timeout + #[error("Request timeout")] + RequestTimeout, + /// Max number of request slots exceeded. + #[error("Configured max number of request slots exceeded")] + MaxSlotsExceeded, + /// Custom error. + #[error("Custom error: {0}")] + Custom(String), + /// Not implemented for HTTP clients. + #[error("Not implemented")] + HttpNotImplemented, + /// Empty batch request. + #[error("{0}")] + EmptyBatchRequest(#[from] EmptyBatchRequest), + /// The error returned w hen registering a method or subscription failed. + #[error("{0}")] + RegisterMethod(#[from] RegisterMethodError), +} \ No newline at end of file diff --git a/core/src/client/mod.rs b/core/src/client/mod.rs index dbb556555d..6b91774fe9 100644 --- a/core/src/client/mod.rs +++ b/core/src/client/mod.rs @@ -31,6 +31,9 @@ cfg_async_client! { pub use async_client::{Client, ClientBuilder}; } +pub mod error; +pub use error::Error; + use std::fmt; use std::ops::Range; use std::pin::Pin; @@ -38,13 +41,12 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; use std::task; -use crate::error::RegisterMethodError; -use crate::params::{BatchRequestBuilder, EmptyBatchRequest}; +use crate::params::BatchRequestBuilder; use crate::traits::ToRpcParams; use async_trait::async_trait; use core::marker::PhantomData; use futures_util::stream::{Stream, StreamExt}; -use jsonrpsee_types::{ErrorObject, Id, SubscriptionId, InvalidRequestId, ErrorObjectOwned}; +use jsonrpsee_types::{ErrorObject, Id, SubscriptionId}; use serde::de::DeserializeOwned; use serde_json::Value as JsonValue; use tokio::sync::{mpsc, oneshot}; @@ -58,47 +60,6 @@ pub mod __reexports { pub use crate::params::ArrayParams; } -/// Error type. -#[derive(Debug, thiserror::Error)] -pub enum Error { - /// JSON-RPC error which can occur when a JSON-RPC call fails. - #[error("{0}")] - Call(#[from] ErrorObjectOwned), - /// Networking error or error on the low-level protocol layer. - #[error("Networking or low-level protocol error: {0}")] - Transport(#[source] anyhow::Error), - /// The background task has been terminated. - #[error("The background task been terminated because: {0}; restart required")] - RestartNeeded(Arc), - /// Failed to parse the data. - #[error("Parse error: {0}")] - ParseError(#[from] serde_json::Error), - /// Invalid subscription ID. - #[error("Invalid subscription ID")] - InvalidSubscriptionId, - /// Invalid request ID. - #[error("{0}")] - InvalidRequestId(#[from] InvalidRequestId), - /// Request timeout - #[error("Request timeout")] - RequestTimeout, - /// Max number of request slots exceeded. - #[error("Configured max number of request slots exceeded")] - MaxSlotsExceeded, - /// Custom error. - #[error("Custom error: {0}")] - Custom(String), - /// Not implemented for HTTP clients. - #[error("Not implemented")] - HttpNotImplemented, - /// Empty batch request. - #[error("{0}")] - EmptyBatchRequest(#[from] EmptyBatchRequest), - /// The error returned w hen registering a method or subscription failed. - #[error("{0}")] - RegisterMethod(#[from] RegisterMethodError), -} - /// [JSON-RPC](https://www.jsonrpc.org/specification) client interface that can make requests and notifications. #[async_trait] pub trait ClientT { From dd75d00838dd0b0710315e59c4d57e6ddd73e1dc Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 6 Dec 2023 09:54:53 +0100 Subject: [PATCH 21/22] simplify imports --- client/http-client/src/transport.rs | 3 +-- core/src/lib.rs | 2 +- server/src/tests/helpers.rs | 2 +- server/src/transport/http.rs | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/client/http-client/src/transport.rs b/client/http-client/src/transport.rs index 852248f434..741f53e3d1 100644 --- a/client/http-client/src/transport.rs +++ b/client/http-client/src/transport.rs @@ -10,9 +10,8 @@ use hyper::body::{Body, HttpBody}; use hyper::client::{Client, HttpConnector}; use hyper::http::{HeaderMap, HeaderValue}; use jsonrpsee_core::client::CertificateStore; -use jsonrpsee_core::error::GenericTransportError; -use jsonrpsee_core::http_helpers; use jsonrpsee_core::tracing::client::{rx_log_from_bytes, tx_log_from_str}; +use jsonrpsee_core::{http_helpers, GenericTransportError}; use std::error::Error as StdError; use std::future::Future; use std::pin::Pin; diff --git a/core/src/lib.rs b/core/src/lib.rs index 9c3e5aac0e..a4cf37bcef 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -88,4 +88,4 @@ pub use serde_json::{ pub const TEN_MB_SIZE_BYTES: u32 = 10 * 1024 * 1024; /// The return type if the subscription wants to return `Result`. -pub type SubscriptionResult = Result<(), error::StringError>; +pub type SubscriptionResult = Result<(), StringError>; diff --git a/server/src/tests/helpers.rs b/server/src/tests/helpers.rs index bb733359fd..413aa7bd0d 100644 --- a/server/src/tests/helpers.rs +++ b/server/src/tests/helpers.rs @@ -3,7 +3,7 @@ use std::net::SocketAddr; use crate::{RpcModule, ServerBuilder, ServerHandle}; -use jsonrpsee_core::{error::StringError, DeserializeOwned, RpcResult}; +use jsonrpsee_core::{DeserializeOwned, RpcResult, StringError}; use jsonrpsee_test_utils::TimeoutFutureExt; use jsonrpsee_types::{error::ErrorCode, ErrorObject, ErrorObjectOwned, Response, ResponseSuccess}; use tracing_subscriber::{EnvFilter, FmtSubscriber}; diff --git a/server/src/transport/http.rs b/server/src/transport/http.rs index beb1be9cc9..3b7bec07e7 100644 --- a/server/src/transport/http.rs +++ b/server/src/transport/http.rs @@ -1,5 +1,5 @@ use http::Method; -use jsonrpsee_core::{error::GenericTransportError, http_helpers::read_body, server::Methods}; +use jsonrpsee_core::{http_helpers::read_body, server::Methods, GenericTransportError}; use crate::{ middleware::rpc::{RpcService, RpcServiceBuilder, RpcServiceCfg, RpcServiceT}, From b628df6e321264bd41803a7b441e89960d6501cd Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Wed, 6 Dec 2023 10:10:02 +0100 Subject: [PATCH 22/22] Update core/src/client/error.rs --- core/src/client/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/client/error.rs b/core/src/client/error.rs index b0514d86a7..13a435a998 100644 --- a/core/src/client/error.rs +++ b/core/src/client/error.rs @@ -66,7 +66,7 @@ pub enum Error { /// Empty batch request. #[error("{0}")] EmptyBatchRequest(#[from] EmptyBatchRequest), - /// The error returned w hen registering a method or subscription failed. + /// The error returned when registering a method or subscription failed. #[error("{0}")] RegisterMethod(#[from] RegisterMethodError), } \ No newline at end of file