ic_agent_canister_runtime/
lib.rs1use async_trait::async_trait;
7use candid::{decode_one, encode_args, utils::ArgumentEncoder, CandidType, Principal};
8use ic_agent::{Agent, AgentError};
9use ic_canister_runtime::{IcError, Runtime};
10use ic_error_types::RejectCode;
11use serde::de::DeserializeOwned;
12
13#[derive(Clone, Debug)]
46pub struct AgentRuntime<'a> {
47 agent: &'a Agent,
48}
49
50impl<'a> AgentRuntime<'a> {
51 pub fn new(agent: &'a Agent) -> Self {
53 Self { agent }
54 }
55}
56
57#[async_trait]
58impl Runtime for AgentRuntime<'_> {
59 async fn update_call<In, Out>(
60 &self,
61 id: Principal,
62 method: &str,
63 args: In,
64 _cycles: u128,
65 ) -> Result<Out, IcError>
66 where
67 In: ArgumentEncoder + Send,
68 Out: CandidType + DeserializeOwned,
69 {
70 self.agent
71 .update(&id, method)
72 .with_arg(encode_args(args).unwrap_or_else(panic_when_encode_fails))
73 .call_and_wait()
74 .await
75 .map_err(convert_agent_error)
76 .and_then(decode_agent_response)
77 }
78
79 async fn query_call<In, Out>(
80 &self,
81 id: Principal,
82 method: &str,
83 args: In,
84 ) -> Result<Out, IcError>
85 where
86 In: ArgumentEncoder + Send,
87 Out: CandidType + DeserializeOwned,
88 {
89 self.agent
90 .query(&id, method)
91 .with_arg(encode_args(args).unwrap_or_else(panic_when_encode_fails))
92 .call()
93 .await
94 .map_err(convert_agent_error)
95 .and_then(decode_agent_response)
96 }
97}
98
99fn decode_agent_response<Out>(result: Vec<u8>) -> Result<Out, IcError>
100where
101 Out: CandidType + DeserializeOwned,
102{
103 decode_one::<Out>(&result).map_err(|e| IcError::CandidDecodeFailed {
104 message: e.to_string(),
105 })
106}
107
108fn convert_agent_error(e: AgentError) -> IcError {
109 if let AgentError::CertifiedReject { ref reject, .. } = e {
110 if let Ok(code) = RejectCode::try_from(reject.reject_code as u64) {
111 return IcError::CallRejected {
112 code,
113 message: reject.reject_message.clone(),
114 };
115 }
116 }
117 IcError::CallRejected {
118 code: RejectCode::SysFatal,
119 message: e.to_string(),
120 }
121}
122
123fn panic_when_encode_fails(err: candid::error::Error) -> Vec<u8> {
124 panic!("failed to encode args: {err}")
125}