Unverified Commit 14b1b4b5 authored by Niklas Adolfsson's avatar Niklas Adolfsson Committed by GitHub
Browse files

core: remove `Error::Request` variant (#717)

* refactor: get rid off `Error::Request` variant

* fix nit

* to_owned -> to_call_error
parent 3f13274b
Pipeline #186001 passed with stages
in 4 minutes and 11 seconds
......@@ -147,7 +147,7 @@ impl ClientT for HttpClient {
Ok(response) => response,
Err(_) => {
let err: ErrorResponse = serde_json::from_slice(&body).map_err(Error::ParseError)?;
return Err(Error::Request(err.to_string()));
return Err(Error::Call(err.error.to_call_error()));
}
};
......@@ -186,7 +186,7 @@ impl ClientT for HttpClient {
let rps: Vec<Response<_>> =
serde_json::from_slice(&body).map_err(|_| match serde_json::from_slice::<ErrorResponse>(&body) {
Ok(e) => Error::Request(e.to_string()),
Ok(e) => Error::Call(e.error.to_call_error()),
Err(e) => Error::ParseError(e),
})?;
......
......@@ -24,7 +24,7 @@
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
use crate::types::error::{ErrorCode, ErrorObject, ErrorResponse};
use crate::types::error::{ErrorCode, ErrorObject};
use crate::types::ParamsSer;
use crate::HttpClientBuilder;
use jsonrpsee_core::client::{ClientT, IdKind};
......@@ -33,6 +33,7 @@ use jsonrpsee_core::Error;
use jsonrpsee_test_utils::helpers::*;
use jsonrpsee_test_utils::mocks::Id;
use jsonrpsee_test_utils::TimeoutFutureExt;
use jsonrpsee_types::error::CallError;
#[tokio::test]
async fn method_call_works() {
......@@ -97,34 +98,34 @@ async fn response_with_wrong_id() {
async fn response_method_not_found() {
let err =
run_request_with_response(method_not_found(Id::Num(0))).with_default_timeout().await.unwrap().unwrap_err();
assert_jsonrpc_error_response(err, ErrorCode::MethodNotFound.into());
assert_jsonrpc_error_response(err, ErrorObject::from(ErrorCode::MethodNotFound).to_call_error());
}
#[tokio::test]
async fn response_parse_error() {
let err = run_request_with_response(parse_error(Id::Num(0))).with_default_timeout().await.unwrap().unwrap_err();
assert_jsonrpc_error_response(err, ErrorCode::ParseError.into());
assert_jsonrpc_error_response(err, ErrorObject::from(ErrorCode::ParseError).to_call_error());
}
#[tokio::test]
async fn invalid_request_works() {
let err =
run_request_with_response(invalid_request(Id::Num(0_u64))).with_default_timeout().await.unwrap().unwrap_err();
assert_jsonrpc_error_response(err, ErrorCode::InvalidRequest.into());
assert_jsonrpc_error_response(err, ErrorObject::from(ErrorCode::InvalidRequest).to_call_error());
}
#[tokio::test]
async fn invalid_params_works() {
let err =
run_request_with_response(invalid_params(Id::Num(0_u64))).with_default_timeout().await.unwrap().unwrap_err();
assert_jsonrpc_error_response(err, ErrorCode::InvalidParams.into());
assert_jsonrpc_error_response(err, ErrorObject::from(ErrorCode::InvalidParams).to_call_error());
}
#[tokio::test]
async fn internal_error_works() {
let err =
run_request_with_response(internal_error(Id::Num(0_u64))).with_default_timeout().await.unwrap().unwrap_err();
assert_jsonrpc_error_response(err, ErrorCode::InternalError.into());
assert_jsonrpc_error_response(err, ErrorObject::from(ErrorCode::InternalError).to_call_error());
}
#[tokio::test]
......@@ -171,11 +172,10 @@ async fn run_request_with_response(response: String) -> Result<String, Error> {
client.request("say_hello", None).with_default_timeout().await.unwrap()
}
fn assert_jsonrpc_error_response(err: Error, exp: ErrorObject) {
fn assert_jsonrpc_error_response(err: Error, exp: CallError) {
match &err {
Error::Request(e) => {
let this: ErrorResponse = serde_json::from_str(e).unwrap();
assert_eq!(this.error, exp);
Error::Call(e) => {
assert_eq!(e.to_string(), exp.to_string());
}
e => panic!("Expected error: \"{}\", got: {:?}", err, e),
};
......
......@@ -25,7 +25,7 @@
// DEALINGS IN THE SOFTWARE.
#![cfg(test)]
use crate::types::error::{ErrorCode, ErrorObject, ErrorResponse};
use crate::types::error::{ErrorCode, ErrorObject};
use crate::types::ParamsSer;
use crate::WsClientBuilder;
use jsonrpsee_core::client::{ClientT, SubscriptionClientT};
......@@ -35,6 +35,7 @@ use jsonrpsee_core::Error;
use jsonrpsee_test_utils::helpers::*;
use jsonrpsee_test_utils::mocks::{Id, WebSocketTestServer};
use jsonrpsee_test_utils::TimeoutFutureExt;
use jsonrpsee_types::error::CallError;
use serde_json::Value as JsonValue;
#[tokio::test]
......@@ -108,34 +109,34 @@ async fn response_with_wrong_id() {
async fn response_method_not_found() {
let err =
run_request_with_response(method_not_found(Id::Num(0))).with_default_timeout().await.unwrap().unwrap_err();
assert_error_response(err, ErrorCode::MethodNotFound.into());
assert_error_response(err, ErrorObject::from(ErrorCode::MethodNotFound).to_call_error());
}
#[tokio::test]
async fn parse_error_works() {
let err = run_request_with_response(parse_error(Id::Num(0))).with_default_timeout().await.unwrap().unwrap_err();
assert_error_response(err, ErrorCode::ParseError.into());
assert_error_response(err, ErrorObject::from(ErrorCode::ParseError).to_call_error());
}
#[tokio::test]
async fn invalid_request_works() {
let err =
run_request_with_response(invalid_request(Id::Num(0_u64))).with_default_timeout().await.unwrap().unwrap_err();
assert_error_response(err, ErrorCode::InvalidRequest.into());
assert_error_response(err, ErrorObject::from(ErrorCode::InvalidRequest).to_call_error());
}
#[tokio::test]
async fn invalid_params_works() {
let err =
run_request_with_response(invalid_params(Id::Num(0_u64))).with_default_timeout().await.unwrap().unwrap_err();
assert_error_response(err, ErrorCode::InvalidParams.into());
assert_error_response(err, ErrorObject::from(ErrorCode::InvalidParams).to_call_error());
}
#[tokio::test]
async fn internal_error_works() {
let err =
run_request_with_response(internal_error(Id::Num(0_u64))).with_default_timeout().await.unwrap().unwrap_err();
assert_error_response(err, ErrorCode::InternalError.into());
assert_error_response(err, ErrorObject::from(ErrorCode::InternalError).to_call_error());
}
#[tokio::test]
......@@ -282,11 +283,10 @@ async fn run_request_with_response(response: String) -> Result<String, Error> {
client.request("say_hello", None).with_default_timeout().await.unwrap()
}
fn assert_error_response(err: Error, exp: ErrorObject) {
fn assert_error_response(err: Error, exp: CallError) {
match &err {
Error::Request(e) => {
let this: ErrorResponse = serde_json::from_str(e).unwrap();
assert_eq!(this.error, exp);
Error::Call(e) => {
assert_eq!(e.to_string(), exp.to_string());
}
e => panic!("Expected error: \"{}\", got: {:?}", err, e),
};
......
......@@ -208,15 +208,16 @@ pub(crate) fn build_unsubscribe_message(
/// Returns `Err(_)` if the response ID was not found.
pub(crate) fn process_error_response(manager: &mut RequestManager, err: ErrorResponse) -> Result<(), Error> {
let id = err.id.clone().into_owned();
match manager.request_status(&id) {
RequestStatus::PendingMethodCall => {
let send_back = manager.complete_pending_call(id).expect("State checked above; qed");
let _ = send_back.map(|s| s.send(Err(Error::Request(err.to_string()))));
let _ = send_back.map(|s| s.send(Err(Error::Call(err.error.to_call_error()))));
Ok(())
}
RequestStatus::PendingSubscription => {
let (_, send_back, _) = manager.complete_pending_subscription(id).expect("State checked above; qed");
let _ = send_back.send(Err(Error::Request(err.to_string())));
let _ = send_back.send(Err(Error::Call(err.error.to_call_error())));
Ok(())
}
_ => Err(Error::InvalidRequestId),
......
......@@ -56,14 +56,11 @@ impl From<anyhow::Error> for Error {
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Error that occurs when a call failed.
#[error("Server call failed: {0}")]
#[error("JSON-RPC call failed: {0}")]
Call(#[from] CallError),
/// Networking error or error on the low-level protocol layer.
#[error("Networking or low-level protocol error: {0}")]
Transport(#[source] anyhow::Error),
/// JSON-RPC request error.
#[error("JSON-RPC request error: {0:?}")]
Request(String),
/// Frontend/backend channel error.
#[error("Frontend/backend channel error: {0}")]
Internal(#[from] futures_channel::mpsc::SendError),
......
......@@ -41,7 +41,8 @@ use futures_util::pin_mut;
use futures_util::{future::BoxFuture, FutureExt, Stream, StreamExt};
use jsonrpsee_types::error::{ErrorCode, CALL_EXECUTION_FAILED_CODE};
use jsonrpsee_types::{
Id, Params, Request, Response, SubscriptionId as RpcSubscriptionId, SubscriptionPayload, SubscriptionResponse,
ErrorResponse, Id, Params, Request, Response, SubscriptionId as RpcSubscriptionId, SubscriptionPayload,
SubscriptionResponse,
};
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
......@@ -331,10 +332,16 @@ impl Methods {
let req = Request::new(method.into(), Some(&params), Id::Number(0));
tracing::trace!("[Methods::call] Calling method: {:?}, params: {:?}", method, params);
let (resp, _, _) = self.inner_call(req).await;
if let Ok(res) = serde_json::from_str::<Response<T>>(&resp) {
return Ok(res.result);
}
Err(Error::Request(resp))
if let Ok(err) = serde_json::from_str::<ErrorResponse>(&resp) {
return Err(Error::Call(err.error.to_call_error()));
}
unreachable!("Invalid JSON-RPC response is not possible using jsonrpsee; this is bug please file an issue");
}
/// Make a request (JSON-RPC method call or subscription) by using raw JSON.
......
......@@ -32,6 +32,7 @@ use jsonrpsee::core::Error;
use jsonrpsee::http_client::HttpClientBuilder;
use jsonrpsee::http_server::{HttpServerBuilder, HttpServerHandle};
use jsonrpsee::proc_macros::rpc;
use jsonrpsee::types::error::CallError;
use jsonrpsee::ws_client::WsClientBuilder;
use jsonrpsee::ws_server::{WsServerBuilder, WsServerHandle};
use jsonrpsee::RpcModule;
......@@ -117,11 +118,9 @@ async fn http_server(module: RpcModule<()>) -> Result<(SocketAddr, HttpServerHan
fn assert_server_busy(fail: Result<String, Error>) {
match fail {
Err(Error::Request(msg)) => {
let err: serde_json::Value = serde_json::from_str(&msg).unwrap();
assert_eq!(err["error"]["code"], -32604);
assert_eq!(err["error"]["message"], "Server is busy, try again later");
Err(Error::Call(CallError::Custom { code, message, data: _ })) => {
assert_eq!(code, -32604);
assert_eq!(message, "Server is busy, try again later");
}
fail => panic!("Expected error, got: {:?}", fail),
}
......
......@@ -28,6 +28,7 @@ use std::collections::HashMap;
use jsonrpsee::core::error::{Error, SubscriptionClosed, SubscriptionClosedReason};
use jsonrpsee::core::server::rpc_module::*;
use jsonrpsee::types::error::CallError;
use jsonrpsee::types::{EmptyParams, Params};
use serde::{Deserialize, Serialize};
......@@ -103,9 +104,10 @@ async fn calling_method_without_server() {
// Call sync method with bad param
let err = module.call::<_, ()>("foo", (false,)).await.unwrap_err();
assert!(
matches!(err, Error::Request(err) if err == r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"invalid type: boolean `false`, expected u16 at line 1 column 6"},"id":0}"#)
);
assert!(matches!(
err,
Error::Call(CallError::Custom { code, message, data: _}) if code == -32602 && message.as_str() == "invalid type: boolean `false`, expected u16 at line 1 column 6"
));
// Call async method with params and context
struct MyContext;
......@@ -184,9 +186,8 @@ async fn calling_method_without_server_using_proc_macro() {
// Call sync method with bad params
let err = module.call::<_, ()>("rebel", (Gun { shoots: true }, false)).await.unwrap_err();
assert!(matches!(
err,
Error::Request(err) if err == r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"invalid type: boolean `false`, expected a map at line 1 column 5"},"id":0}"#
assert!(matches!(err,
Error::Call(CallError::Custom { code, message, data: _}) if code == -32602 && message.as_str() == "invalid type: boolean `false`, expected a map at line 1 column 5"
));
// Call async method with params and context
......
......@@ -79,6 +79,15 @@ impl<'a> ErrorObject<'a> {
pub fn new(code: ErrorCode, data: Option<&'a RawValue>) -> ErrorObject<'a> {
Self { code, message: code.message().into(), data }
}
/// Create an owned ErrorObject via [`CallError`]
pub fn to_call_error(self) -> CallError {
CallError::Custom {
code: self.code.code(),
data: self.data.map(|d| d.to_owned()),
message: self.message.into_owned(),
}
}
}
impl<'a> From<ErrorCode> for ErrorObject<'a> {
......
......@@ -613,7 +613,7 @@ impl AllowedValue {
if !list.iter().any(|o| o.as_bytes() == value) {
let error = format!("{} denied: {}", header, String::from_utf8_lossy(value));
tracing::warn!("{}", error);
return Err(Error::Request(error));
return Err(Error::Custom(error));
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment