use super::identity::CanisterId;
use super::canister_status::CanisterStatusResult;
use super::canister_call::{
call_canister_status, call_wallet_receive, CanisterInfo, CanisterInfoShow, CanisterInitArg,
CanisterSettings, CanisterWasm,
};
#[derive(candid::CandidType, candid::Deserialize, Debug)]
pub enum ManagedCanisterRefreshResult {
Refreshed(Vec<CanisterInfoShow>),
NewCanister(CanisterInfoShow),
DeployFailed(String),
}
pub type ManagedCanisterStates = Vec<CanisterInfo>;
#[derive(candid::CandidType, candid::Deserialize, Debug, Clone)]
pub struct ManagedCanisterInitial {
pub max_canister_count: u32, pub max_canister_memory_size: u128, pub initial_canister_cycles: u128, }
#[derive(candid::CandidType, candid::Deserialize, Debug, Clone)]
pub struct ManagedCanisterMaintained {
pub min_cycles: u128, pub min_days: u16, pub recharge_cycles: u64, }
#[derive(candid::CandidType, candid::Deserialize, Debug, Clone)]
pub struct ManagedCanisterChecking {
pub check_number: u32, pub next: u32, }
#[derive(candid::CandidType, candid::Deserialize, Debug, Clone)]
pub struct ManagedCanisterConfig {
pub initial: ManagedCanisterInitial, pub maintained: ManagedCanisterMaintained, pub checking: ManagedCanisterChecking, }
impl ManagedCanisterConfig {
pub async fn refresh_status(
&self,
canisters: &Vec<CanisterId>,
) -> (u32, Vec<(usize, CanisterStatusResult)>) {
let length = canisters.len() as u32;
let mut check_number = self.checking.check_number;
if check_number == 0 || check_number > length {
check_number = length;
}
let mut next = self.checking.next;
if length == 0 {
return (next, Vec::new());
}
let mut status_list = Vec::new();
for _ in 0..check_number {
if next >= length {
next = 0;
}
let canister_id = canisters[next as usize];
let result = call_canister_status(&canister_id).await;
self.check_cycles(&canister_id, &result).await;
status_list.push((next as usize, result));
next += 1;
}
(next, status_list)
}
async fn check_cycles(&self, canister_id: &CanisterId, result: &CanisterStatusResult) {
let maintained = &self.maintained;
if maintained.min_cycles < result.cycles
&& candid::Nat::from(maintained.min_days)
< result.cycles.clone() / result.idle_cycles_burned_per_day.clone()
{
return;
}
call_wallet_receive(canister_id, maintained.recharge_cycles).await;
}
pub fn available(&self, memory_size: &candid::Nat) -> bool {
memory_size < &self.initial.max_canister_memory_size
}
pub async fn deploy_canister(
&self,
count: u32,
settings: Option<CanisterSettings>,
wasm: Option<CanisterWasm>,
arg: Option<CanisterInitArg>,
) -> Result<CanisterInfo, String> {
if 0 < self.initial.max_canister_count && self.initial.max_canister_count <= count {
return Result::Err(format!(
"max canister count: {}",
self.initial.max_canister_count
));
}
let initial_cycles = self.initial.initial_canister_cycles;
super::canister_call::deploy_canister(settings, initial_cycles, wasm, arg).await
}
}