canic_core/ops/request/
request.rs1use crate::{
2 Error,
3 cdk::call::Call,
4 ids::CanisterRole,
5 ops::{
6 model::memory::{EnvOps, topology::SubnetCanisterChildrenOps},
7 prelude::*,
8 request::{
9 CreateCanisterResponse, CyclesResponse, RequestOpsError, Response,
10 UpgradeCanisterResponse,
11 },
12 },
13};
14use candid::encode_one;
15
16#[derive(CandidType, Clone, Debug, Deserialize)]
22pub enum Request {
23 CreateCanister(CreateCanisterRequest),
24 UpgradeCanister(UpgradeCanisterRequest),
25 Cycles(CyclesRequest),
26}
27
28#[derive(CandidType, Clone, Debug, Deserialize)]
34pub struct CreateCanisterRequest {
35 pub canister_role: CanisterRole,
36 pub parent: CreateCanisterParent,
37 pub extra_arg: Option<Vec<u8>>,
38}
39
40#[derive(CandidType, Clone, Debug, Deserialize)]
46pub enum CreateCanisterParent {
47 Root,
48 ThisCanister,
50 Parent,
52 Canister(Principal),
53 Directory(CanisterRole),
54}
55
56#[derive(CandidType, Clone, Debug, Deserialize)]
62pub struct UpgradeCanisterRequest {
63 pub canister_pid: Principal,
64 pub canister_type: CanisterRole,
65}
66
67#[derive(CandidType, Clone, Debug, Deserialize)]
73pub struct CyclesRequest {
74 pub cycles: u128,
75}
76
77async fn request(request: Request) -> Result<Response, Error> {
79 let root_pid = EnvOps::try_get_root_pid().map_err(|_| RequestOpsError::RootNotFound)?;
80
81 let call_response = Call::unbounded_wait(root_pid, "canic_response")
82 .with_arg(&request)
83 .await?;
84
85 call_response.candid::<Result<Response, Error>>()?
86}
87
88pub async fn create_canister_request<A>(
90 canister_role: &CanisterRole,
91 parent: CreateCanisterParent,
92 extra: Option<A>,
93) -> Result<CreateCanisterResponse, Error>
94where
95 A: CandidType + Send + Sync,
96{
97 let encoded = extra.map(|v| encode_one(v)).transpose()?;
98
99 let q = Request::CreateCanister(CreateCanisterRequest {
101 canister_role: canister_role.clone(),
102 parent,
103 extra_arg: encoded,
104 });
105
106 match request(q).await? {
107 Response::CreateCanister(res) => Ok(res),
108 _ => Err(RequestOpsError::InvalidResponseType.into()),
109 }
110}
111
112pub async fn upgrade_canister_request(
114 canister_pid: Principal,
115) -> Result<UpgradeCanisterResponse, Error> {
116 let canister = SubnetCanisterChildrenOps::find_by_pid(&canister_pid)
118 .ok_or(RequestOpsError::ChildNotFound(canister_pid))?;
119
120 let q = Request::UpgradeCanister(UpgradeCanisterRequest {
122 canister_pid: canister.pid,
123 canister_type: canister.ty,
124 });
125
126 match request(q).await? {
127 Response::UpgradeCanister(res) => Ok(res),
128 _ => Err(RequestOpsError::InvalidResponseType.into()),
129 }
130}
131
132pub async fn cycles_request(cycles: u128) -> Result<CyclesResponse, Error> {
134 OpsError::deny_root()?;
135
136 let q = Request::Cycles(CyclesRequest { cycles });
137
138 match request(q).await? {
139 Response::Cycles(res) => Ok(res),
140 _ => Err(RequestOpsError::InvalidResponseType.into()),
141 }
142}