canic/ops/model/memory/directory/
app.rs1use crate::{
2 Error, ThisError,
3 config::Config,
4 model::memory::{
5 directory::{AppDirectory, PrincipalList},
6 topology::SubnetCanisterRegistry,
7 },
8 ops::{
9 model::memory::{
10 MemoryOpsError,
11 directory::{DirectoryPageDto, DirectoryView, paginate},
12 env::EnvOps,
13 },
14 prelude::*,
15 },
16};
17use std::collections::BTreeMap;
18
19#[derive(Debug, ThisError)]
24pub enum AppDirectoryOpsError {
25 #[error("canister type {0} not found in app directory")]
26 NotFound(CanisterType),
27}
28
29impl From<AppDirectoryOpsError> for Error {
30 fn from(err: AppDirectoryOpsError) -> Self {
31 MemoryOpsError::from(err).into()
32 }
33}
34
35pub struct AppDirectoryOps;
40
41impl AppDirectoryOps {
42 fn resolve_view() -> DirectoryView {
44 if EnvOps::is_root() {
45 Self::root_build_view()
46 } else {
47 AppDirectory::view()
48 }
49 }
50
51 #[must_use]
53 pub fn export() -> DirectoryView {
54 Self::resolve_view()
55 }
56
57 pub fn import(view: DirectoryView) {
59 AppDirectory::import(view);
60 }
61
62 #[must_use]
63 pub fn page(offset: u64, limit: u64) -> DirectoryPageDto {
64 paginate(Self::resolve_view(), offset, limit)
65 }
66
67 #[must_use]
69 pub fn root_build_view() -> DirectoryView {
70 let cfg = Config::get();
71 let entries = SubnetCanisterRegistry::export();
72 let mut map: BTreeMap<CanisterType, PrincipalList> = BTreeMap::new();
73
74 for entry in entries {
75 let ty = entry.ty.clone();
76
77 if cfg.app_directory.contains(&ty) {
78 map.entry(ty).or_default().0.push(entry.pid);
79 }
80 }
81
82 map.into_iter().collect()
83 }
84
85 pub fn try_get(ty: &CanisterType) -> Result<PrincipalList, Error> {
87 let target = ty.clone();
88 let view = Self::resolve_view();
89 let entry = view
90 .into_iter()
91 .find_map(|(t, pids)| (t == target).then_some(pids))
92 .ok_or_else(|| AppDirectoryOpsError::NotFound(ty.clone()))?;
93
94 Ok(entry)
95 }
96}