canic_core/api/runtime/
install.rs1use crate::{
2 InternalError, InternalErrorOrigin, cdk::types::Principal, dto::error::Error,
3 format::byte_size, ids::CanisterRole,
4};
5use async_trait::async_trait;
6use std::sync::OnceLock;
7
8#[derive(Clone, Debug, Eq, PartialEq)]
13pub struct ApprovedModuleSource {
14 pub source_canister: Principal,
15 pub source_label: String,
16 pub module_hash: Vec<u8>,
17 pub chunk_hashes: Vec<Vec<u8>>,
18 pub payload_size_bytes: u64,
19}
20
21impl ApprovedModuleSource {
22 #[must_use]
24 pub fn payload_size(&self) -> String {
25 byte_size(self.payload_size_bytes)
26 }
27}
28
29#[async_trait]
34pub trait ModuleSourceResolver: Send + Sync {
35 async fn approved_module_source(
37 &self,
38 role: &CanisterRole,
39 ) -> Result<ApprovedModuleSource, Error>;
40}
41
42static MODULE_SOURCE_RESOLVER: OnceLock<&'static dyn ModuleSourceResolver> = OnceLock::new();
43
44pub struct ModuleSourceRuntimeApi;
49
50impl ModuleSourceRuntimeApi {
51 pub fn register_module_source_resolver(resolver: &'static dyn ModuleSourceResolver) {
53 let _ = MODULE_SOURCE_RESOLVER.set(resolver);
54 }
55
56 pub(crate) async fn approved_module_source(
58 role: &CanisterRole,
59 ) -> Result<ApprovedModuleSource, InternalError> {
60 let resolver = MODULE_SOURCE_RESOLVER.get().ok_or_else(|| {
61 InternalError::workflow(
62 InternalErrorOrigin::Workflow,
63 "module source resolver is not registered; root/control-plane install flows are unavailable".to_string(),
64 )
65 })?;
66
67 resolver
68 .approved_module_source(role)
69 .await
70 .map_err(InternalError::public)
71 }
72}