// Copyright 2019-2023 Parity Technologies (UK) Ltd. // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. use serde::Deserialize; use serde_json::value::RawValue; /// The RPC response from the light-client. /// This can either be a response of a method, or a notification from a subscription. #[derive(Debug, Clone)] pub enum RpcResponse { Method { /// Response ID. id: String, /// The result of the method call. result: Box, }, MethodError { /// Response ID. id: String, /// Error. error: Box, }, Notification { /// RPC method that generated the notification. method: String, /// Subscription ID. subscription_id: String, /// Result. result: Box, }, NotificationError { /// RPC method that generated the notification. method: String, /// Subscription ID. subscription_id: String, /// Result. error: Box, }, } impl std::str::FromStr for RpcResponse { type Err = (); fn from_str(response: &str) -> Result { // Valid response #[derive(Deserialize, Debug)] struct Response { #[allow(unused)] jsonrpc: String, id: String, result: Box, } // Error response #[derive(Deserialize)] struct ResponseError { #[allow(unused)] jsonrpc: String, id: String, error: Box, } // Valid notification (subscription) response #[derive(Deserialize)] struct Notification { #[allow(unused)] jsonrpc: String, method: String, params: NotificationResultParams, } #[derive(Deserialize)] struct NotificationResultParams { subscription: String, result: Box, } // Error notification (subscription) response #[derive(Deserialize)] struct NotificationError { #[allow(unused)] jsonrpc: String, method: String, params: NotificationErrorParams, } #[derive(Deserialize)] struct NotificationErrorParams { /// The ID of the subscription. subscription: String, error: Box, } // Try deserializing the response payload to one of the above. We can // do this more efficiently eg how jsonrpsee_types does. let result: Result = serde_json::from_str(response); if let Ok(response) = result { return Ok(RpcResponse::Method { id: response.id, result: response.result, }); } let result: Result = serde_json::from_str(response); if let Ok(response) = result { return Ok(RpcResponse::Notification { subscription_id: response.params.subscription, method: response.method, result: response.params.result, }); } let result: Result = serde_json::from_str(response); if let Ok(response) = result { return Ok(RpcResponse::MethodError { id: response.id, error: response.error, }); } let result: Result = serde_json::from_str(response); if let Ok(response) = result { return Ok(RpcResponse::NotificationError { method: response.method, subscription_id: response.params.subscription, error: response.params.error, }); } // We couldn't decode into any of the above. We could pick one of the above` // errors to return, but there's no real point since the string is obviously // different from any of them. Err(()) } }