canic_core/ops/rpc/
request.rs1use crate::{
2 Error, ThisError,
3 ids::CanisterRole,
4 ops::{
5 prelude::*,
6 rpc::{
7 CreateCanisterResponse, CyclesResponse, Response, Rpc, RpcOpsError,
8 UpgradeCanisterResponse, execute_rpc,
9 },
10 },
11};
12use candid::encode_one;
13
14#[derive(Debug, ThisError)]
20pub enum RequestOpsError {
21 #[error("canister type {0} not found")]
22 CanisterRoleNotFound(CanisterRole),
23
24 #[error("child canister {0} not found")]
25 ChildNotFound(Principal),
26
27 #[error("canister {0} is not a child of caller {1}")]
28 NotChildOfCaller(Principal, Principal),
29
30 #[error("canister {0}'s parent was not found")]
31 ParentNotFound(Principal),
32
33 #[error("invalid response type")]
34 InvalidResponseType,
35
36 #[error("create_canister: missing new pid")]
37 MissingNewCanisterPid,
38}
39
40impl From<RequestOpsError> for Error {
41 fn from(err: RequestOpsError) -> Self {
42 RpcOpsError::from(err).into()
43 }
44}
45
46#[derive(CandidType, Clone, Debug, Deserialize)]
52pub enum Request {
53 CreateCanister(CreateCanisterRequest),
54 UpgradeCanister(UpgradeCanisterRequest),
55 Cycles(CyclesRequest),
56}
57
58#[derive(CandidType, Clone, Debug, Deserialize)]
64pub struct CreateCanisterRequest {
65 pub canister_role: CanisterRole,
66 pub parent: CreateCanisterParent,
67 pub extra_arg: Option<Vec<u8>>,
68}
69
70#[derive(CandidType, Clone, Debug, Deserialize)]
76pub enum CreateCanisterParent {
77 Root,
78 ThisCanister,
80 Parent,
82 Canister(Principal),
83 Directory(CanisterRole),
84}
85
86#[derive(CandidType, Clone, Debug, Deserialize)]
92pub struct UpgradeCanisterRequest {
93 pub canister_pid: Principal,
94}
95
96#[derive(CandidType, Clone, Debug, Deserialize)]
102pub struct CyclesRequest {
103 pub cycles: u128,
104}
105
106pub async fn create_canister_request<A>(
111 canister_role: &CanisterRole,
112 parent: CreateCanisterParent,
113 extra: Option<A>,
114) -> Result<CreateCanisterResponse, Error>
115where
116 A: CandidType + Send + Sync,
117{
118 let extra_arg = extra.map(encode_one).transpose()?;
119
120 execute_rpc(CreateCanisterRpc {
121 canister_role: canister_role.clone(),
122 parent,
123 extra_arg,
124 })
125 .await
126}
127
128pub struct CreateCanisterRpc {
129 pub canister_role: CanisterRole,
130 pub parent: CreateCanisterParent,
131 pub extra_arg: Option<Vec<u8>>,
132}
133
134impl Rpc for CreateCanisterRpc {
135 type Response = CreateCanisterResponse;
136
137 fn into_request(self) -> Request {
138 Request::CreateCanister(CreateCanisterRequest {
139 canister_role: self.canister_role,
140 parent: self.parent,
141 extra_arg: self.extra_arg,
142 })
143 }
144
145 fn try_from_response(resp: Response) -> Result<Self::Response, RequestOpsError> {
146 match resp {
147 Response::CreateCanister(r) => Ok(r),
148 _ => Err(RequestOpsError::InvalidResponseType),
149 }
150 }
151}
152
153pub async fn upgrade_canister_request(
159 canister_pid: Principal,
160) -> Result<UpgradeCanisterResponse, Error> {
161 execute_rpc(UpgradeCanisterRpc { canister_pid }).await
162}
163
164pub struct UpgradeCanisterRpc {
165 pub canister_pid: Principal,
166}
167
168impl Rpc for UpgradeCanisterRpc {
169 type Response = UpgradeCanisterResponse;
170
171 fn into_request(self) -> Request {
172 Request::UpgradeCanister(UpgradeCanisterRequest {
173 canister_pid: self.canister_pid,
174 })
175 }
176
177 fn try_from_response(resp: Response) -> Result<Self::Response, RequestOpsError> {
178 match resp {
179 Response::UpgradeCanister(r) => Ok(r),
180 _ => Err(RequestOpsError::InvalidResponseType),
181 }
182 }
183}
184
185pub async fn cycles_request(cycles: u128) -> Result<CyclesResponse, Error> {
191 OpsError::deny_root()?;
192
193 execute_rpc(CyclesRpc { cycles }).await
194}
195
196pub struct CyclesRpc {
197 pub cycles: u128,
198}
199
200impl Rpc for CyclesRpc {
201 type Response = CyclesResponse;
202
203 fn into_request(self) -> Request {
204 Request::Cycles(CyclesRequest {
205 cycles: self.cycles,
206 })
207 }
208
209 fn try_from_response(resp: Response) -> Result<Self::Response, RequestOpsError> {
210 match resp {
211 Response::Cycles(r) => Ok(r),
212 _ => Err(RequestOpsError::InvalidResponseType),
213 }
214 }
215}