canic_core/ops/
config.rs

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