pezkuwi-subxt-lightclient 0.44.0

Light Client for chain interaction
Documentation
// Copyright 2019-2025 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<RawValue>,
	},
	MethodError {
		/// Response ID.
		id: String,
		/// Error.
		error: Box<RawValue>,
	},
	Notification {
		/// RPC method that generated the notification.
		method: String,
		/// Subscription ID.
		subscription_id: String,
		/// Result.
		result: Box<RawValue>,
	},
	NotificationError {
		/// RPC method that generated the notification.
		method: String,
		/// Subscription ID.
		subscription_id: String,
		/// Result.
		error: Box<RawValue>,
	},
}

impl std::str::FromStr for RpcResponse {
	type Err = ();

	fn from_str(response: &str) -> Result<Self, Self::Err> {
		// Valid response
		#[derive(Deserialize, Debug)]
		struct Response {
			#[allow(unused)]
			jsonrpc: String,
			id: String,
			result: Box<RawValue>,
		}

		// Error response
		#[derive(Deserialize)]
		struct ResponseError {
			#[allow(unused)]
			jsonrpc: String,
			id: String,
			error: Box<RawValue>,
		}

		// Valid notification (subscription) response
		#[derive(Deserialize)]
		struct Notification {
			#[allow(unused)]
			jsonrpc: String,
			method: String,
			params: NotificationResultParams,
		}
		#[derive(Deserialize)]
		struct NotificationResultParams {
			subscription: String,
			result: Box<RawValue>,
		}

		// 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<RawValue>,
		}

		// Try deserializing the response payload to one of the above. We can
		// do this more efficiently eg how jsonrpsee_types does.

		let result: Result<Response, _> = serde_json::from_str(response);
		if let Ok(response) = result {
			return Ok(RpcResponse::Method { id: response.id, result: response.result });
		}
		let result: Result<Notification, _> = 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<ResponseError, _> = serde_json::from_str(response);
		if let Ok(response) = result {
			return Ok(RpcResponse::MethodError { id: response.id, error: response.error });
		}
		let result: Result<NotificationError, _> = 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(())
	}
}