canic_core/ops/rpc/
mod.rs

1pub(crate) mod methods;
2mod request;
3mod response;
4
5pub use request::*;
6pub use response::*;
7
8use crate::{
9    Error, ThisError,
10    cdk::candid::CandidType,
11    ops::{OpsError, ic::call::Call, storage::env::EnvOps},
12};
13use serde::de::DeserializeOwned;
14
15///
16/// Rpc
17/// Typed RPC command binding a request variant to its response payload.
18///
19
20pub trait Rpc {
21    type Response: CandidType + DeserializeOwned;
22
23    fn into_request(self) -> Request;
24    fn try_from_response(resp: Response) -> Result<Self::Response, RequestOpsError>;
25}
26
27///
28/// RpcOpsError
29///
30
31#[derive(Debug, ThisError)]
32pub enum RpcOpsError {
33    #[error(transparent)]
34    RequestOpsError(#[from] request::RequestOpsError),
35}
36
37impl From<RpcOpsError> for Error {
38    fn from(err: RpcOpsError) -> Self {
39        OpsError::from(err).into()
40    }
41}
42
43// execute_rpc
44async fn execute_rpc<R: Rpc>(rpc: R) -> Result<R::Response, Error> {
45    let root_pid = EnvOps::root_pid();
46
47    let call_response = Call::unbounded_wait(root_pid, methods::CANIC_RESPONSE)
48        .with_arg(rpc.into_request())
49        .await?;
50
51    let response = call_response.candid::<Result<Response, Error>>()??;
52
53    R::try_from_response(response)
54        .map_err(RpcOpsError::from)
55        .map_err(Error::from)
56}