pallet_messages_rpc/
lib.rs

1// Strong Documentation Lints
2#![deny(
3	rustdoc::broken_intra_doc_links,
4	rustdoc::missing_crate_level_docs,
5	rustdoc::invalid_codeblock_attributes,
6	missing_docs
7)]
8
9//! Custom APIs for [Messages](../pallet_messages/index.html)
10
11#[cfg(feature = "std")]
12use common_helpers::rpc::map_rpc_result;
13use common_primitives::{messages::*, schema::*};
14use frame_support::{ensure, fail};
15use jsonrpsee::{
16	core::{async_trait, RpcResult},
17	proc_macros::rpc,
18	types::{ErrorObject, ErrorObjectOwned},
19};
20use pallet_messages_runtime_api::MessagesRuntimeApi;
21use pallet_schemas_runtime_api::SchemasRuntimeApi;
22use sp_api::ProvideRuntimeApi;
23use sp_blockchain::HeaderBackend;
24use sp_runtime::traits::Block as BlockT;
25use std::sync::Arc;
26
27#[cfg(test)]
28mod tests;
29
30/// Frequency Messages Custom RPC API
31#[rpc(client, server)]
32pub trait MessagesApi {
33	/// Retrieve paginated messages by schema id
34	#[method(name = "messages_getByIntentId")]
35	fn get_messages_by_intent_id(
36		&self,
37		intent_id: IntentId,
38		pagination: BlockPaginationRequest,
39	) -> RpcResult<BlockPaginationResponse<MessageResponseV2>>;
40}
41
42/// The client handler for the API used by Frequency Service RPC with `jsonrpsee`
43pub struct MessagesHandler<C, M> {
44	client: Arc<C>,
45	_marker: std::marker::PhantomData<M>,
46}
47
48impl<C, M> MessagesHandler<C, M> {
49	/// Create new instance with the given reference to the client.
50	pub fn new(client: Arc<C>) -> Self {
51		Self { client, _marker: Default::default() }
52	}
53}
54
55/// Errors that occur on the client RPC
56#[derive(Debug)]
57pub enum MessageRpcError {
58	/// Pagination request is bad
59	InvalidPaginationRequest,
60	/// Likely passed u32 block count
61	TypeConversionOverflow,
62	/// Schema Id doesn't exist or errored when retrieving from state
63	InvalidSchemaId,
64	/// Intent Id doesn't exist or errored when retrieving from state
65	InvalidIntentId,
66}
67
68impl From<MessageRpcError> for ErrorObjectOwned {
69	fn from(e: MessageRpcError) -> Self {
70		let msg = format!("{e:?}");
71		match e {
72			MessageRpcError::InvalidPaginationRequest => ErrorObject::owned(1, msg, None::<()>),
73			MessageRpcError::TypeConversionOverflow => ErrorObject::owned(2, msg, None::<()>),
74			MessageRpcError::InvalidSchemaId => ErrorObject::owned(3, msg, None::<()>),
75			MessageRpcError::InvalidIntentId => ErrorObject::owned(4, msg, None::<()>),
76		}
77	}
78}
79
80#[async_trait]
81impl<C, Block> MessagesApiServer for MessagesHandler<C, Block>
82where
83	Block: BlockT,
84	C: ProvideRuntimeApi<Block> + HeaderBackend<Block> + 'static,
85	C::Api: MessagesRuntimeApi<Block> + SchemasRuntimeApi<Block>,
86{
87	fn get_messages_by_intent_id(
88		&self,
89		intent_id: IntentId,
90		pagination: BlockPaginationRequest,
91	) -> RpcResult<BlockPaginationResponse<MessageResponseV2>> {
92		// Request Validation
93		ensure!(pagination.validate(), MessageRpcError::InvalidPaginationRequest);
94
95		// Connect to on-chain data
96		let api = self.client.runtime_api();
97		let at = self.client.info().best_hash;
98
99		// Schema Fetch and Check
100		match api.get_intent_by_id(at, intent_id, false) {
101			Ok(Some(s)) => s,
102			_ => fail!(MessageRpcError::InvalidIntentId),
103		};
104
105		let response = api.get_messages_by_intent_id(at, intent_id, pagination).unwrap_or_default();
106		map_rpc_result(Ok(response))
107	}
108}