1use crate::{
6 call::{AsyncCall, SyncCall},
7 Canister,
8};
9use ic_agent::{export::Principal, Agent};
10use ic_management_canister_types::{
11 CanisterIdRecord, DeleteCanisterSnapshotArgs, LoadCanisterSnapshotArgs,
12 ProvisionalTopUpCanisterArgs, ReadCanisterSnapshotDataArgs, ReadCanisterSnapshotMetadataArgs,
13 TakeCanisterSnapshotArgs, UploadCanisterSnapshotDataArgs, UploadCanisterSnapshotMetadataArgs,
14 UploadChunkArgs,
15};
16pub use ic_management_canister_types::{
18 CanisterLogRecord, CanisterStatusResult, CanisterStatusType, CanisterTimer, ChunkHash,
19 DefiniteCanisterSettings, FetchCanisterLogsResult, LogVisibility, OnLowWasmMemoryHookStatus,
20 QueryStats, ReadCanisterSnapshotDataResult, ReadCanisterSnapshotMetadataResult, Snapshot,
21 SnapshotDataKind, SnapshotDataOffset, SnapshotMetadataGlobal, SnapshotSource,
22 StoredChunksResult, UploadCanisterSnapshotMetadataResult, UploadChunkResult,
23};
24use std::{convert::AsRef, ops::Deref};
25use strum_macros::{AsRefStr, Display, EnumString};
26
27pub mod attributes;
28pub mod builders;
29
30#[doc(inline)]
31pub use builders::{
32 CreateCanisterBuilder, InstallBuilder, InstallChunkedCodeBuilder, InstallCodeBuilder,
33 UpdateCanisterBuilder,
34};
35
36#[derive(Debug, Clone)]
38pub struct ManagementCanister<'agent>(Canister<'agent>);
39
40impl<'agent> Deref for ManagementCanister<'agent> {
41 type Target = Canister<'agent>;
42 fn deref(&self) -> &Self::Target {
43 &self.0
44 }
45}
46
47#[derive(AsRefStr, Debug, EnumString, Display)]
49#[strum(serialize_all = "snake_case")]
50pub enum MgmtMethod {
51 CreateCanister,
53 InstallCode,
55 StartCanister,
57 StopCanister,
59 CanisterStatus,
61 DeleteCanister,
63 DepositCycles,
65 RawRand,
67 ProvisionalCreateCanisterWithCycles,
69 ProvisionalTopUpCanister,
71 UninstallCode,
73 UpdateSettings,
75 UploadChunk,
77 ClearChunkStore,
79 StoredChunks,
81 InstallChunkedCode,
83 FetchCanisterLogs,
85 TakeCanisterSnapshot,
87 LoadCanisterSnapshot,
89 ListCanisterSnapshots,
91 DeleteCanisterSnapshot,
93 ReadCanisterSnapshotMetadata,
95 ReadCanisterSnapshotData,
97 UploadCanisterSnapshotMetadata,
99 UploadCanisterSnapshotData,
101 EcdsaPublicKey,
103 SignWithEcdsa,
105 BitcoinGetBalance,
107 BitcoinGetUtxos,
109 BitcoinSendTransaction,
111 BitcoinGetCurrentFeePercentiles,
113 BitcoinGetBlockHeaders,
115 NodeMetricsHistory,
117 CanisterInfo,
119}
120
121impl<'agent> ManagementCanister<'agent> {
122 pub fn create(agent: &'agent Agent) -> Self {
124 Self(
125 Canister::builder()
126 .with_agent(agent)
127 .with_canister_id(Principal::management_canister())
128 .build()
129 .unwrap(),
130 )
131 }
132
133 pub fn from_canister(canister: Canister<'agent>) -> Self {
135 Self(canister)
136 }
137}
138
139#[doc(hidden)]
140#[deprecated(since = "0.42.0", note = "Please use CanisterStatusResult instead")]
141pub type StatusCallResult = CanisterStatusResult;
142
143#[doc(hidden)]
144#[deprecated(since = "0.42.0", note = "Please use CanisterStatusType instead")]
145pub type CanisterStatus = CanisterStatusType;
146
147#[doc(hidden)]
148#[deprecated(since = "0.42.0", note = "Please use FetchCanisterLogsResult instead")]
149pub type FetchCanisterLogsResponse = FetchCanisterLogsResult;
150
151#[doc(hidden)]
152#[deprecated(since = "0.42.0", note = "Please use StoredChunksResult instead")]
153pub type StoreChunksResult = StoredChunksResult;
154
155#[doc(hidden)]
156#[deprecated(
157 since = "0.42.0",
158 note = "Please use ReadCanisterSnapshotMetadataResult instead"
159)]
160pub type SnapshotMetadata = ReadCanisterSnapshotMetadataResult;
161
162#[doc(hidden)]
163#[deprecated(
164 since = "0.42.0",
165 note = "Please use ReadCanisterSnapshotDataResult instead"
166)]
167pub type SnapshotDataResult = ReadCanisterSnapshotDataResult;
168
169#[doc(hidden)]
170#[deprecated(
171 since = "0.42.0",
172 note = "Please use UploadCanisterSnapshotMetadataResult instead"
173)]
174pub type CanisterSnapshotId = UploadCanisterSnapshotMetadataResult;
175
176impl<'agent> ManagementCanister<'agent> {
177 pub fn canister_status(
179 &self,
180 canister_id: &Principal,
181 ) -> impl 'agent + AsyncCall<Value = (CanisterStatusResult,)> {
182 self.update(MgmtMethod::CanisterStatus.as_ref())
183 .with_arg(CanisterIdRecord {
184 canister_id: *canister_id,
185 })
186 .with_effective_canister_id(canister_id.to_owned())
187 .build()
188 .map(|result: (CanisterStatusResult,)| (result.0,))
189 }
190
191 pub fn create_canister<'canister>(&'canister self) -> CreateCanisterBuilder<'agent, 'canister> {
193 CreateCanisterBuilder::builder(self)
194 }
195
196 pub fn deposit_cycles(&self, canister_id: &Principal) -> impl 'agent + AsyncCall<Value = ()> {
199 self.update(MgmtMethod::DepositCycles.as_ref())
200 .with_arg(CanisterIdRecord {
201 canister_id: *canister_id,
202 })
203 .with_effective_canister_id(canister_id.to_owned())
204 .build()
205 }
206
207 pub fn delete_canister(&self, canister_id: &Principal) -> impl 'agent + AsyncCall<Value = ()> {
209 self.update(MgmtMethod::DeleteCanister.as_ref())
210 .with_arg(CanisterIdRecord {
211 canister_id: *canister_id,
212 })
213 .with_effective_canister_id(canister_id.to_owned())
214 .build()
215 }
216
217 pub fn provisional_top_up_canister(
222 &self,
223 canister_id: &Principal,
224 top_up_args: &ProvisionalTopUpCanisterArgs,
225 ) -> impl 'agent + AsyncCall<Value = ()> {
226 self.update(MgmtMethod::ProvisionalTopUpCanister.as_ref())
227 .with_arg(top_up_args)
228 .with_effective_canister_id(canister_id.to_owned())
229 .build()
230 }
231
232 pub fn raw_rand(&self) -> impl 'agent + AsyncCall<Value = (Vec<u8>,)> {
236 self.update(MgmtMethod::RawRand.as_ref())
237 .build()
238 .map(|result: (Vec<u8>,)| (result.0,))
239 }
240
241 pub fn start_canister(&self, canister_id: &Principal) -> impl 'agent + AsyncCall<Value = ()> {
243 self.update(MgmtMethod::StartCanister.as_ref())
244 .with_arg(CanisterIdRecord {
245 canister_id: *canister_id,
246 })
247 .with_effective_canister_id(canister_id.to_owned())
248 .build()
249 }
250
251 pub fn stop_canister(&self, canister_id: &Principal) -> impl 'agent + AsyncCall<Value = ()> {
253 self.update(MgmtMethod::StopCanister.as_ref())
254 .with_arg(CanisterIdRecord {
255 canister_id: *canister_id,
256 })
257 .with_effective_canister_id(canister_id.to_owned())
258 .build()
259 }
260
261 pub fn uninstall_code(&self, canister_id: &Principal) -> impl 'agent + AsyncCall<Value = ()> {
269 self.update(MgmtMethod::UninstallCode.as_ref())
270 .with_arg(CanisterIdRecord {
271 canister_id: *canister_id,
272 })
273 .with_effective_canister_id(canister_id.to_owned())
274 .build()
275 }
276
277 pub fn install_code<'canister>(
279 &'canister self,
280 canister_id: &Principal,
281 wasm: &'canister [u8],
282 ) -> InstallCodeBuilder<'agent, 'canister> {
283 InstallCodeBuilder::builder(self, canister_id, wasm)
284 }
285
286 pub fn update_settings<'canister>(
288 &'canister self,
289 canister_id: &Principal,
290 ) -> UpdateCanisterBuilder<'agent, 'canister> {
291 UpdateCanisterBuilder::builder(self, canister_id)
292 }
293
294 pub fn upload_chunk(
296 &self,
297 canister_id: &Principal,
298 upload_chunk_args: &UploadChunkArgs,
299 ) -> impl 'agent + AsyncCall<Value = (UploadChunkResult,)> {
300 self.update(MgmtMethod::UploadChunk.as_ref())
301 .with_arg(upload_chunk_args)
302 .with_effective_canister_id(*canister_id)
303 .build()
304 }
305
306 pub fn clear_chunk_store(
308 &self,
309 canister_id: &Principal,
310 ) -> impl 'agent + AsyncCall<Value = ()> {
311 self.update(MgmtMethod::ClearChunkStore.as_ref())
312 .with_arg(CanisterIdRecord {
313 canister_id: *canister_id,
314 })
315 .with_effective_canister_id(*canister_id)
316 .build()
317 }
318
319 pub fn stored_chunks(
321 &self,
322 canister_id: &Principal,
323 ) -> impl 'agent + AsyncCall<Value = (StoredChunksResult,)> {
324 self.update(MgmtMethod::StoredChunks.as_ref())
325 .with_arg(CanisterIdRecord {
326 canister_id: *canister_id,
327 })
328 .with_effective_canister_id(*canister_id)
329 .build()
330 }
331
332 pub fn install_chunked_code<'canister>(
334 &'canister self,
335 canister_id: &Principal,
336 wasm_module_hash: &[u8],
337 ) -> InstallChunkedCodeBuilder<'agent, 'canister> {
338 InstallChunkedCodeBuilder::builder(self, *canister_id, wasm_module_hash)
339 }
340
341 pub fn install<'canister: 'builder, 'builder>(
347 &'canister self,
348 canister_id: &Principal,
349 wasm: &'builder [u8],
350 ) -> InstallBuilder<'agent, 'canister, 'builder> {
351 InstallBuilder::builder(self, canister_id, wasm)
352 }
353
354 pub fn fetch_canister_logs(
356 &self,
357 canister_id: &Principal,
358 ) -> impl 'agent + SyncCall<Value = (FetchCanisterLogsResult,)> {
359 self.query(MgmtMethod::FetchCanisterLogs.as_ref())
361 .with_arg(CanisterIdRecord {
362 canister_id: *canister_id,
363 })
364 .with_effective_canister_id(*canister_id)
365 .build()
366 }
367
368 pub fn take_canister_snapshot(
372 &self,
373 canister_id: &Principal,
374 take_args: &TakeCanisterSnapshotArgs,
375 ) -> impl 'agent + AsyncCall<Value = (Snapshot,)> {
376 self.update(MgmtMethod::TakeCanisterSnapshot.as_ref())
377 .with_arg(take_args)
378 .with_effective_canister_id(*canister_id)
379 .build()
380 }
381
382 pub fn load_canister_snapshot(
386 &self,
387 canister_id: &Principal,
388 load_args: &LoadCanisterSnapshotArgs,
389 ) -> impl 'agent + AsyncCall<Value = ()> {
390 self.update(MgmtMethod::LoadCanisterSnapshot.as_ref())
391 .with_arg(load_args)
392 .with_effective_canister_id(*canister_id)
393 .build()
394 }
395
396 pub fn list_canister_snapshots(
398 &self,
399 canister_id: &Principal,
400 ) -> impl 'agent + AsyncCall<Value = (Vec<Snapshot>,)> {
401 self.update(MgmtMethod::ListCanisterSnapshots.as_ref())
402 .with_arg(CanisterIdRecord {
403 canister_id: *canister_id,
404 })
405 .with_effective_canister_id(*canister_id)
406 .build()
407 }
408
409 pub fn delete_canister_snapshot(
411 &self,
412 canister_id: &Principal,
413 delete_args: &DeleteCanisterSnapshotArgs,
414 ) -> impl 'agent + AsyncCall<Value = ()> {
415 self.update(MgmtMethod::DeleteCanisterSnapshot.as_ref())
416 .with_arg(delete_args)
417 .with_effective_canister_id(*canister_id)
418 .build()
419 }
420
421 pub fn read_canister_snapshot_metadata(
423 &self,
424 canister_id: &Principal,
425 metadata_args: &ReadCanisterSnapshotMetadataArgs,
426 ) -> impl 'agent + AsyncCall<Value = (ReadCanisterSnapshotMetadataResult,)> {
427 self.update(MgmtMethod::ReadCanisterSnapshotMetadata.as_ref())
428 .with_arg(metadata_args)
429 .with_effective_canister_id(*canister_id)
430 .build()
431 }
432
433 pub fn read_canister_snapshot_data(
435 &self,
436 canister_id: &Principal,
437 data_args: &ReadCanisterSnapshotDataArgs,
438 ) -> impl 'agent + AsyncCall<Value = (ReadCanisterSnapshotDataResult,)> {
439 self.update(MgmtMethod::ReadCanisterSnapshotData.as_ref())
440 .with_arg(data_args)
441 .with_effective_canister_id(*canister_id)
442 .build()
443 }
444
445 pub fn upload_canister_snapshot_metadata(
447 &self,
448 canister_id: &Principal,
449 metadata_args: &UploadCanisterSnapshotMetadataArgs,
450 ) -> impl 'agent + AsyncCall<Value = (UploadCanisterSnapshotMetadataResult,)> {
451 self.update(MgmtMethod::UploadCanisterSnapshotMetadata.as_ref())
452 .with_arg(metadata_args)
453 .with_effective_canister_id(*canister_id)
454 .build()
455 }
456
457 pub fn upload_canister_snapshot_data(
459 &self,
460 canister_id: &Principal,
461 data_args: &UploadCanisterSnapshotDataArgs,
462 ) -> impl 'agent + AsyncCall<Value = ()> {
463 self.update(MgmtMethod::UploadCanisterSnapshotData.as_ref())
464 .with_arg(data_args)
465 .with_effective_canister_id(*canister_id)
466 .build()
467 }
468}