use candid::utils::ArgumentEncoder;
use candid::{CandidType, Principal};
use serde::de::DeserializeOwned;
use crate::client::CanisterClient;
use crate::{CanisterClientError, CanisterClientResult};
#[derive(Debug, Clone)]
pub struct IcCanisterClient {
pub canister_id: Principal,
timeout_seconds: Option<u32>,
}
impl IcCanisterClient {
pub fn new(canister: Principal, timeout_seconds: Option<u32>) -> Self {
Self {
canister_id: canister,
timeout_seconds,
}
}
async fn call<T, R>(&self, method: &str, args: T) -> CanisterClientResult<R>
where
T: ArgumentEncoder + Send,
R: DeserializeOwned + CandidType,
{
let call = if let Some(timeout_seconds) = self.timeout_seconds {
ic_cdk::call::Call::bounded_wait(self.canister_id, method)
.change_timeout(timeout_seconds)
.with_args(&args)
} else {
ic_cdk::call::Call::unbounded_wait(self.canister_id, method).with_args(&args)
};
let call_result = call
.await
.map_err(|e| CanisterClientError::CanisterError(e.into()))?
.into_bytes();
use candid::Decode;
Decode!(&call_result, R).map_err(CanisterClientError::CandidError)
}
}
impl CanisterClient for IcCanisterClient {
async fn update<T, R>(&self, method: &str, args: T) -> CanisterClientResult<R>
where
T: ArgumentEncoder + Send + Sync,
R: DeserializeOwned + CandidType + Send,
{
self.call(method, args).await
}
async fn query<T, R>(&self, method: &str, args: T) -> CanisterClientResult<R>
where
T: ArgumentEncoder + Send + Sync,
R: DeserializeOwned + CandidType + Send,
{
self.call(method, args).await
}
}