exocore_core/cell/
cell_apps.rs

1use std::{
2    collections::HashMap,
3    path::PathBuf,
4    sync::{Arc, RwLock},
5};
6
7use exocore_protos::{generated::exocore_core::CellApplicationConfig, registry::Registry};
8
9use super::{Application, ApplicationId, CellId, Error};
10use crate::{dir::DynDirectory, sec::keys::PublicKey};
11
12/// Applications installed in a cell.
13#[derive(Clone)]
14pub struct CellApplications {
15    applications: Arc<RwLock<HashMap<ApplicationId, CellApplication>>>,
16    schemas: Arc<Registry>,
17}
18
19impl CellApplications {
20    pub(crate) fn new(schemas: Arc<Registry>) -> CellApplications {
21        CellApplications {
22            applications: Arc::new(RwLock::new(HashMap::new())),
23            schemas,
24        }
25    }
26
27    pub(crate) fn load_from_configurations<'c, I>(
28        &self,
29        cell_id: &CellId,
30        apps_dir: &DynDirectory,
31        iter: I,
32    ) -> Result<(), Error>
33    where
34        I: Iterator<Item = &'c CellApplicationConfig> + 'c,
35    {
36        for cell_app in iter {
37            let app_id = ApplicationId::from_base58_public_key(&cell_app.public_key)?;
38            let app_dir = cell_app_directory(apps_dir, &app_id, &cell_app.version);
39            let app_pk = PublicKey::decode_base58_string(&cell_app.public_key)?;
40
41            if Application::manifest_exists(app_dir.clone()) {
42                info!(
43                    "{}: Adding loaded application '{}' (id='{}')",
44                    cell_id, cell_app.name, app_id
45                );
46                let app = Application::from_directory(app_dir).map_err(|err| {
47                    Error::Application(
48                        cell_app.name.clone(),
49                        anyhow!("failed to load from directory: {}", err),
50                    )
51                })?;
52                self.add_loaded_application(cell_app.clone(), app)?;
53            } else {
54                info!(
55                    "{}: Adding unloaded application '{}' (id='{}')",
56                    cell_id, cell_app.name, app_id
57                );
58                self.add_unloaded_application(app_id, app_pk, cell_app.clone())?;
59            }
60        }
61
62        Ok(())
63    }
64
65    fn add_loaded_application(
66        &self,
67        cell_app_config: CellApplicationConfig,
68        application: Application,
69    ) -> Result<(), Error> {
70        let mut apps = self.applications.write().unwrap();
71
72        for fd_set in application.schemas() {
73            self.schemas.register_file_descriptor_set(fd_set);
74        }
75
76        apps.insert(
77            application.id().clone(),
78            CellApplication {
79                id: application.id().clone(),
80                name: application.name().to_string(),
81                version: application.version().to_string(),
82                public_key: application.public_key().clone(),
83                application: Some(application),
84                package_url: cell_app_config.package_url,
85            },
86        );
87        Ok(())
88    }
89
90    fn add_unloaded_application(
91        &self,
92        id: ApplicationId,
93        public_key: PublicKey,
94        cell_app: CellApplicationConfig,
95    ) -> Result<(), Error> {
96        let mut apps = self.applications.write().unwrap();
97
98        apps.insert(
99            id.clone(),
100            CellApplication {
101                id,
102                name: cell_app.name,
103                version: cell_app.version,
104                public_key,
105                application: None,
106                package_url: cell_app.package_url,
107            },
108        );
109        Ok(())
110    }
111
112    pub fn get(&self) -> Vec<CellApplication> {
113        let apps = self.applications.read().expect("couldn't lock inner");
114        apps.values().cloned().collect()
115    }
116}
117
118#[derive(Clone)]
119pub struct CellApplication {
120    id: ApplicationId,
121    name: String,
122    version: String,
123    public_key: PublicKey,
124    application: Option<Application>,
125    package_url: String,
126}
127
128impl CellApplication {
129    pub fn id(&self) -> &ApplicationId {
130        &self.id
131    }
132
133    pub fn name(&self) -> &str {
134        &self.name
135    }
136
137    pub fn version(&self) -> &str {
138        &self.version
139    }
140
141    pub fn public_key(&self) -> &PublicKey {
142        &self.public_key
143    }
144
145    pub fn package_url(&self) -> &str {
146        self.package_url.as_str()
147    }
148
149    pub fn is_loaded(&self) -> bool {
150        self.application.is_some()
151    }
152
153    pub fn get(&self) -> Option<&Application> {
154        self.application.as_ref()
155    }
156}
157
158pub fn cell_app_directory(
159    apps_dir: &DynDirectory,
160    app_id: &ApplicationId,
161    app_version: &str,
162) -> DynDirectory {
163    apps_dir.scope(PathBuf::from(format!("{}_{}", app_id, app_version)))
164}