canic_core/ops/
config.rs

1use crate::{
2    Error, ThisError,
3    config::{
4        Config, ConfigModel,
5        schema::{CanisterConfig, LogConfig, ScalingConfig, SubnetConfig},
6    },
7    ids::{CanisterRole, SubnetRole},
8    ops::{OpsError, runtime::env::EnvOps},
9};
10use candid::Principal;
11use std::sync::Arc;
12
13///
14/// ConfigOpsError
15///
16
17#[derive(Debug, ThisError)]
18pub enum ConfigOpsError {
19    #[error("subnet {0} not found in configuration")]
20    SubnetNotFound(String),
21
22    #[error("canister {0} not defined in subnet {1}")]
23    CanisterNotFound(String, String),
24}
25
26impl From<ConfigOpsError> for Error {
27    fn from(err: ConfigOpsError) -> Self {
28        OpsError::from(err).into()
29    }
30}
31
32///
33/// ConfigOps
34///
35/// Ops-layer façade for configuration access.
36///
37/// Responsibilities:
38/// - Provide fallible lookups over the configuration model (`try_get_*`)
39/// - Provide infallible access to the *current* subnet/canister context,
40///   assuming environment initialization has completed
41///
42
43pub struct ConfigOps;
44
45impl ConfigOps {
46    // ---------------------------------------------------------------------
47    // Explicit / fallible lookups
48    // ---------------------------------------------------------------------
49
50    /// Export the full current configuration as TOML.
51    pub fn export_toml() -> Result<String, Error> {
52        Config::to_toml()
53    }
54
55    /// Fetch a subnet configuration by role.
56    pub fn try_get_subnet(role: &SubnetRole) -> Result<SubnetConfig, Error> {
57        let cfg = Config::get()?;
58
59        cfg.get_subnet(role)
60            .ok_or_else(|| ConfigOpsError::SubnetNotFound(role.to_string()).into())
61    }
62
63    /// Fetch a canister configuration within a specific subnet.
64    pub fn try_get_canister(
65        subnet_role: &SubnetRole,
66        canister_role: &CanisterRole,
67    ) -> Result<CanisterConfig, Error> {
68        let subnet_cfg = Self::try_get_subnet(subnet_role)?;
69
70        subnet_cfg.get_canister(canister_role).ok_or_else(|| {
71            ConfigOpsError::CanisterNotFound(canister_role.to_string(), subnet_role.to_string())
72                .into()
73        })
74    }
75
76    // ---------------------------------------------------------------------
77    // Current-context / infallible helpers
78    // ---------------------------------------------------------------------
79
80    pub fn get() -> Result<Arc<ConfigModel>, Error> {
81        Config::get()
82    }
83
84    pub fn controllers() -> Result<Vec<Principal>, Error> {
85        Ok(Config::get()?.controllers.clone())
86    }
87
88    pub fn log_config() -> Result<LogConfig, Error> {
89        Ok(Config::get()?.log.clone())
90    }
91
92    /// Fetch the configuration record for the *current* subnet.
93    pub fn current_subnet() -> Result<SubnetConfig, Error> {
94        let subnet_role = EnvOps::subnet_role()?;
95
96        Self::try_get_subnet(&subnet_role)
97    }
98
99    /// Fetch the configuration record for the *current* canister.
100    pub fn current_canister() -> Result<CanisterConfig, Error> {
101        let subnet_role = EnvOps::subnet_role()?;
102        let canister_role = EnvOps::canister_role()?;
103
104        Self::try_get_canister(&subnet_role, &canister_role)
105    }
106
107    /// Fetch the scaling configuration for the *current* canister.
108    pub fn current_scaling_config() -> Result<Option<ScalingConfig>, Error> {
109        Ok(Self::current_canister()?.scaling)
110    }
111
112    /// Fetch the configuration for a specific canister in the *current* subnet.
113    pub fn current_subnet_canister(canister_role: &CanisterRole) -> Result<CanisterConfig, Error> {
114        let subnet_role = EnvOps::subnet_role()?;
115
116        Self::try_get_canister(&subnet_role, canister_role)
117    }
118}