use crate::call::AsyncCall;
use crate::canister::CanisterBuilder;
use crate::Canister;
use candid::{CandidType, Deserialize};
use ic_agent::export::Principal;
use ic_agent::Agent;
use std::convert::AsRef;
use std::fmt::Debug;
use strum_macros::{AsRefStr, EnumString};
pub mod attributes;
pub mod builders;
pub use builders::{CreateCanisterBuilder, InstallCodeBuilder, UpdateCanisterBuilder};
#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)]
pub struct ManagementCanister;
#[derive(AsRefStr, Debug, EnumString)]
#[strum(serialize_all = "snake_case")]
pub enum MgmtMethod {
CreateCanister,
InstallCode,
StartCanister,
StopCanister,
CanisterStatus,
DeleteCanister,
DepositCycles,
RawRand,
ProvisionalCreateCanisterWithCycles,
ProvisionalTopUpCanister,
UninstallCode,
UpdateSettings,
}
impl ManagementCanister {
pub fn create(agent: &Agent) -> Canister<ManagementCanister> {
Canister::builder()
.with_agent(agent)
.with_canister_id(Principal::management_canister())
.with_interface(ManagementCanister)
.build()
.unwrap()
}
pub fn with_agent(agent: &Agent) -> CanisterBuilder<ManagementCanister> {
Canister::builder()
.with_agent(agent)
.with_canister_id(Principal::management_canister())
.with_interface(ManagementCanister)
}
}
#[derive(Clone, Debug, Deserialize)]
pub struct StatusCallResult {
pub status: CanisterStatus,
pub settings: DefiniteCanisterSettings,
pub module_hash: Option<Vec<u8>>,
pub memory_size: candid::Nat,
pub cycles: candid::Nat,
}
#[derive(Clone, Debug, Deserialize)]
pub struct DefiniteCanisterSettings {
pub controller: Principal,
pub compute_allocation: candid::Nat,
pub memory_allocation: candid::Nat,
pub freezing_threshold: candid::Nat,
}
impl std::fmt::Display for StatusCallResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
}
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum CanisterStatus {
Running,
Stopping,
Stopped,
}
impl std::fmt::Display for CanisterStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
}
}
impl<'agent> Canister<'agent, ManagementCanister> {
pub fn canister_status<'canister: 'agent>(
&'canister self,
canister_id: &Principal,
) -> impl 'agent + AsyncCall<(StatusCallResult,)> {
#[derive(CandidType)]
struct In {
canister_id: Principal,
}
self.update_(MgmtMethod::CanisterStatus.as_ref())
.with_arg(In {
canister_id: canister_id.clone(),
})
.with_effective_canister_id(canister_id.to_owned())
.build()
.map(|result: (StatusCallResult,)| (result.0,))
}
pub fn create_canister<'canister: 'agent>(
&'canister self,
) -> CreateCanisterBuilder<'agent, 'canister, ManagementCanister> {
CreateCanisterBuilder::builder(self)
}
pub fn deposit_cycles<'canister: 'agent>(
&'canister self,
canister_id: &Principal,
) -> impl 'agent + AsyncCall<()> {
#[derive(CandidType)]
struct Argument {
canister_id: Principal,
}
self.update_(MgmtMethod::DepositCycles.as_ref())
.with_arg(Argument {
canister_id: canister_id.clone(),
})
.with_effective_canister_id(canister_id.to_owned())
.build()
}
pub fn delete_canister<'canister: 'agent>(
&'canister self,
canister_id: &Principal,
) -> impl 'agent + AsyncCall<()> {
#[derive(CandidType)]
struct Argument {
canister_id: Principal,
}
self.update_(MgmtMethod::DeleteCanister.as_ref())
.with_arg(Argument {
canister_id: canister_id.clone(),
})
.with_effective_canister_id(canister_id.to_owned())
.build()
}
pub fn provisional_top_up_canister<'canister: 'agent>(
&'canister self,
canister_id: &Principal,
amount: u64,
) -> impl 'agent + AsyncCall<()> {
#[derive(CandidType)]
struct Argument {
canister_id: Principal,
amount: u64,
}
self.update_(MgmtMethod::ProvisionalTopUpCanister.as_ref())
.with_arg(Argument {
canister_id: canister_id.clone(),
amount,
})
.with_effective_canister_id(canister_id.to_owned())
.build()
}
pub fn raw_rand<'canister: 'agent>(&'canister self) -> impl 'agent + AsyncCall<(Vec<u8>,)> {
self.update_(MgmtMethod::RawRand.as_ref())
.build()
.map(|result: (Vec<u8>,)| (result.0,))
}
pub fn start_canister<'canister: 'agent>(
&'canister self,
canister_id: &Principal,
) -> impl 'agent + AsyncCall<()> {
#[derive(CandidType)]
struct Argument {
canister_id: Principal,
}
self.update_(MgmtMethod::StartCanister.as_ref())
.with_arg(Argument {
canister_id: canister_id.clone(),
})
.with_effective_canister_id(canister_id.to_owned())
.build()
}
pub fn stop_canister<'canister: 'agent>(
&'canister self,
canister_id: &Principal,
) -> impl 'agent + AsyncCall<()> {
#[derive(CandidType)]
struct Argument {
canister_id: Principal,
}
self.update_(MgmtMethod::StopCanister.as_ref())
.with_arg(Argument {
canister_id: canister_id.clone(),
})
.with_effective_canister_id(canister_id.to_owned())
.build()
}
pub fn uninstall_code<'canister: 'agent>(
&'canister self,
canister_id: &Principal,
) -> impl 'agent + AsyncCall<()> {
#[derive(CandidType)]
struct Argument {
canister_id: Principal,
}
self.update_(MgmtMethod::UninstallCode.as_ref())
.with_arg(Argument {
canister_id: canister_id.clone(),
})
.with_effective_canister_id(canister_id.to_owned())
.build()
}
pub fn install_code<'canister: 'agent>(
&'canister self,
canister_id: &Principal,
wasm: &'canister [u8],
) -> InstallCodeBuilder<'agent, 'canister, ManagementCanister> {
InstallCodeBuilder::builder(self, canister_id, wasm)
}
pub fn update_settings<'canister: 'agent>(
&'canister self,
canister_id: &Principal,
) -> UpdateCanisterBuilder<'agent, 'canister, ManagementCanister> {
UpdateCanisterBuilder::builder(self, canister_id)
}
}