canic/ops/model/memory/directory/
subnet.rs1use crate::{
2 Error, ThisError,
3 model::memory::directory::{DirectoryView, PrincipalList, SubnetDirectory},
4 ops::{
5 config::ConfigOps,
6 model::memory::{
7 MemoryOpsError,
8 directory::{DirectoryPageDto, paginate},
9 env::EnvOps,
10 topology::SubnetCanisterRegistryOps,
11 },
12 },
13 types::CanisterType,
14};
15use std::collections::BTreeMap;
16
17#[derive(Debug, ThisError)]
22pub enum SubnetDirectoryOpsError {
23 #[error("canister type {0} not found in subnet directory")]
24 NotFound(CanisterType),
25}
26
27impl From<SubnetDirectoryOpsError> for Error {
28 fn from(err: SubnetDirectoryOpsError) -> Self {
29 MemoryOpsError::from(err).into()
30 }
31}
32
33pub struct SubnetDirectoryOps;
38
39impl SubnetDirectoryOps {
40 fn resolve_view() -> DirectoryView {
42 if EnvOps::is_root() {
43 Self::root_build_view()
44 } else {
45 SubnetDirectory::view()
46 }
47 }
48
49 pub fn try_get(ty: &CanisterType) -> Result<PrincipalList, Error> {
50 let view = Self::resolve_view();
51
52 view.iter()
53 .find_map(|(t, pids)| (t == ty).then_some(pids.clone()))
54 .ok_or_else(|| SubnetDirectoryOpsError::NotFound(ty.clone()).into())
55 }
56
57 pub fn page(offset: u64, limit: u64) -> Result<DirectoryPageDto, Error> {
58 Ok(paginate(Self::resolve_view(), offset, limit))
59 }
60
61 #[must_use]
62 pub fn export() -> DirectoryView {
63 Self::resolve_view()
64 }
65
66 pub fn import(view: DirectoryView) {
67 SubnetDirectory::import(view);
68 }
69
70 #[must_use]
72 pub fn root_build_view() -> DirectoryView {
73 let Ok(subnet_cfg) = ConfigOps::current_subnet() else {
74 return Vec::new();
75 };
76
77 let entries = SubnetCanisterRegistryOps::export();
78 let mut map: BTreeMap<CanisterType, PrincipalList> = BTreeMap::new();
79
80 for entry in entries {
81 let ty = entry.ty.clone();
82
83 if subnet_cfg.subnet_directory.contains(&ty) {
84 map.entry(ty).or_default().0.push(entry.pid);
85 }
86 }
87
88 map.into_iter().collect()
89 }
90}