canic_core/api/ic/
mod.rs

1pub mod http;
2pub mod signature;
3
4use crate::{
5    Error, PublicError,
6    cdk::{candid::CandidType, types::Principal},
7    dto::canister::CanisterStatusView,
8    log::Topic,
9    ops::ic::{call::CallOps, mgmt::MgmtOps},
10};
11use serde::de::DeserializeOwned;
12
13///
14/// CallWait
15///
16
17pub enum CallWait {
18    Bounded,
19    Unbounded,
20}
21
22///
23/// CallBuilder
24///
25
26pub struct CallBuilder {
27    pid: Principal,
28    method: String,
29    wait: CallWait,
30}
31
32impl CallBuilder {
33    #[must_use]
34    pub const fn bounded(mut self) -> Self {
35        self.wait = CallWait::Bounded;
36        self
37    }
38
39    #[must_use]
40    pub const fn unbounded(mut self) -> Self {
41        self.wait = CallWait::Unbounded;
42        self
43    }
44
45    pub async fn with_arg<R, A>(self, arg: A) -> Result<R, PublicError>
46    where
47        R: CandidType + DeserializeOwned,
48        A: CandidType,
49    {
50        let call = match self.wait {
51            CallWait::Bounded => CallOps::bounded_wait(self.pid, &self.method),
52            CallWait::Unbounded => CallOps::unbounded_wait(self.pid, &self.method),
53        };
54
55        let response = call
56            .try_with_arg(arg)
57            .map_err(|e| map_internal_error(Error::from(e)))?
58            .execute()
59            .await
60            .map_err(|e| map_internal_error(Error::from(e)))?;
61
62        response
63            .candid::<R>()
64            .map_err(|e| map_internal_error(Error::from(e)))
65    }
66}
67
68pub async fn canister_status(pid: Principal) -> Result<CanisterStatusView, PublicError> {
69    MgmtOps::canister_status(pid)
70        .await
71        .map_err(map_internal_error)
72}
73
74fn map_internal_error(err: Error) -> PublicError {
75    // Log the internal error for operators, but return a stable PublicError contract.
76    crate::log!(Topic::Rpc, Error, "api.ic failed: {err:?}");
77    PublicError::from(err)
78}