canic_core/ops/rpc/
mod.rs

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