1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Strong Documentation Lints
#![deny(
	rustdoc::broken_intra_doc_links,
	rustdoc::missing_crate_level_docs,
	rustdoc::invalid_codeblock_attributes,
	missing_docs
)]

//! Custom APIs for [User-Handles](../pallet_handles/index.html)

use common_helpers::rpc::map_rpc_result;
use common_primitives::{
	handles::{
		BaseHandle, DisplayHandle, HandleResponse, PresumptiveSuffixesResponse,
		DEFAULT_SUFFIX_COUNT, MAX_SUFFIXES_COUNT,
	},
	msa::MessageSourceId,
};
use jsonrpsee::{
	core::{async_trait, RpcResult},
	proc_macros::rpc,
	types::{error::ErrorObjectOwned, ErrorObject},
};
use pallet_handles_runtime_api::HandlesRuntimeApi;
use sp_api::ProvideRuntimeApi;
use sp_blockchain::HeaderBackend;
use sp_runtime::traits::Block as BlockT;
use std::sync::Arc;

#[cfg(test)]
mod tests;

/// Frequency Handles Custom RPC API
#[rpc(client, server)]
pub trait HandlesApi<BlockHash> {
	/// retrieve `HandleResponse` for a given `MessageSourceId`
	#[method(name = "handles_getHandleForMsa")]
	fn get_handle_for_msa(&self, msa_id: MessageSourceId) -> RpcResult<Option<HandleResponse>>;

	/// retrieve next `n` suffixes for a given handle
	#[method(name = "handles_getNextSuffixes")]
	fn get_next_suffixes(
		&self,
		base_handle: String,
		count: Option<u16>,
	) -> RpcResult<PresumptiveSuffixesResponse>;

	/// retrieve `MessageSourceId` for a given handle
	#[method(name = "handles_getMsaForHandle")]
	fn get_msa_for_handle(&self, display_handle: String) -> RpcResult<Option<MessageSourceId>>;

	/// validate a handle
	#[method(name = "handles_validateHandle")]
	fn validate_handle(&self, base_handle: String) -> RpcResult<bool>;
}

/// The client handler for the API used by Frequency Service RPC with `jsonrpsee`
pub struct HandlesHandler<C, M> {
	client: Arc<C>,
	_marker: std::marker::PhantomData<M>,
}

impl<C, M> HandlesHandler<C, M> {
	/// Create new instance with the given reference to the client.
	pub fn new(client: Arc<C>) -> Self {
		Self { client, _marker: Default::default() }
	}
}

/// Errors that occur on the client RPC
#[derive(Debug)]
pub enum HandlesRpcError {
	/// InvalidHandle
	InvalidHandle,
}

impl From<HandlesRpcError> for ErrorObjectOwned {
	fn from(e: HandlesRpcError) -> Self {
		let msg = format!("{:?}", e);

		match e {
			HandlesRpcError::InvalidHandle => ErrorObject::owned(1, msg, None::<()>),
		}
	}
}

#[async_trait]
impl<C, Block> HandlesApiServer<<Block as BlockT>::Hash> for HandlesHandler<C, Block>
where
	Block: BlockT,
	C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
	C::Api: HandlesRuntimeApi<Block>,
{
	fn get_handle_for_msa(&self, msa_id: MessageSourceId) -> RpcResult<Option<HandleResponse>> {
		let api = self.client.runtime_api();
		let at = self.client.info().best_hash;
		let result = api.get_handle_for_msa(at, msa_id);
		map_rpc_result(result)
	}

	fn get_next_suffixes(
		&self,
		base_handle: String,
		count: Option<u16>,
	) -> RpcResult<PresumptiveSuffixesResponse> {
		let api = self.client.runtime_api();
		let at = self.client.info().best_hash;
		let base_handle: BaseHandle = base_handle
			.into_bytes()
			.try_into()
			.map_err(|_| HandlesRpcError::InvalidHandle)?;
		let max_count = MAX_SUFFIXES_COUNT;
		let count = count.unwrap_or(DEFAULT_SUFFIX_COUNT).min(max_count);
		let suffixes_result = api.get_next_suffixes(at, base_handle, count);
		map_rpc_result(suffixes_result)
	}

	fn get_msa_for_handle(&self, display_handle: String) -> RpcResult<Option<MessageSourceId>> {
		let api = self.client.runtime_api();
		let at = self.client.info().best_hash;
		let handle: DisplayHandle = display_handle
			.into_bytes()
			.try_into()
			.map_err(|_| HandlesRpcError::InvalidHandle)?;
		let result = api.get_msa_for_handle(at, handle);
		map_rpc_result(result)
	}

	fn validate_handle(&self, base_handle: String) -> RpcResult<bool> {
		let api = self.client.runtime_api();
		let at = self.client.info().best_hash;
		let base_handle: BaseHandle = base_handle.into_bytes().try_into().unwrap_or_default();
		let result = api.validate_handle(at, base_handle);
		map_rpc_result(result)
	}
}