#![deny(
rustdoc::broken_intra_doc_links,
rustdoc::missing_crate_level_docs,
rustdoc::invalid_codeblock_attributes,
missing_docs
)]
#[cfg(feature = "std")]
use common_helpers::rpc::map_rpc_result;
use common_primitives::{messages::*, schema::*};
use frame_support::{ensure, fail};
use jsonrpsee::{
core::{async_trait, RpcResult},
proc_macros::rpc,
types::{ErrorObject, ErrorObjectOwned},
};
use pallet_messages_runtime_api::MessagesRuntimeApi;
use sp_api::ProvideRuntimeApi;
use sp_blockchain::HeaderBackend;
use sp_runtime::traits::Block as BlockT;
use std::sync::Arc;
#[cfg(test)]
mod tests;
#[rpc(client, server)]
pub trait MessagesApi {
#[method(name = "messages_getBySchemaId")]
fn get_messages_by_schema_id(
&self,
schema_id: SchemaId,
pagination: BlockPaginationRequest,
) -> RpcResult<BlockPaginationResponse<MessageResponse>>;
}
pub struct MessagesHandler<C, M> {
client: Arc<C>,
_marker: std::marker::PhantomData<M>,
}
impl<C, M> MessagesHandler<C, M> {
pub fn new(client: Arc<C>) -> Self {
Self { client, _marker: Default::default() }
}
}
#[derive(Debug)]
pub enum MessageRpcError {
InvalidPaginationRequest,
TypeConversionOverflow,
InvalidSchemaId,
}
impl From<MessageRpcError> for ErrorObjectOwned {
fn from(e: MessageRpcError) -> Self {
let msg = format!("{:?}", e);
match e {
MessageRpcError::InvalidPaginationRequest => ErrorObject::owned(1, msg, None::<()>),
MessageRpcError::TypeConversionOverflow => ErrorObject::owned(2, msg, None::<()>),
MessageRpcError::InvalidSchemaId => ErrorObject::owned(3, msg, None::<()>),
}
}
}
#[async_trait]
impl<C, Block> MessagesApiServer for MessagesHandler<C, Block>
where
Block: BlockT,
C: ProvideRuntimeApi<Block> + HeaderBackend<Block> + 'static,
C::Api: MessagesRuntimeApi<Block>,
{
fn get_messages_by_schema_id(
&self,
schema_id: SchemaId,
pagination: BlockPaginationRequest,
) -> RpcResult<BlockPaginationResponse<MessageResponse>> {
ensure!(pagination.validate(), MessageRpcError::InvalidPaginationRequest);
let api = self.client.runtime_api();
let at = self.client.info().best_hash;
let schema: SchemaResponse = match api.get_schema_by_id(at, schema_id) {
Ok(Some(s)) => s,
_ => fail!(MessageRpcError::InvalidSchemaId),
};
let mut response = BlockPaginationResponse::new();
let from: u32 = pagination.from_block;
let to: u32 = pagination.to_block;
let mut from_index = pagination.from_index;
'loops: for block_number in from..to {
let list: Vec<MessageResponse> = api
.get_messages_by_schema_and_block(
at,
schema.schema_id,
schema.payload_location,
block_number,
)
.unwrap_or_default();
let list_size: u32 =
list.len().try_into().map_err(|_| MessageRpcError::TypeConversionOverflow)?;
for i in from_index..list_size {
response.content.push(list[i as usize].clone());
if response.check_end_condition_and_set_next_pagination(
block_number,
i,
list_size,
&pagination,
) {
break 'loops
}
}
from_index = 0;
}
map_rpc_result(Ok(response))
}
}