product_os_capabilities/
features.rs

1use std::prelude::v1::*;
2
3use serde::{ Deserialize, Serialize };
4use std::fmt::{ Debug, Formatter };
5use std::collections::BTreeMap;
6use std::sync::Arc;
7use matchit::{ Router };
8use parking_lot::Mutex;
9use crate::RegistryFeature;
10
11
12#[derive(Deserialize, Serialize)]
13#[serde(rename_all = "camelCase")]
14pub struct Features {
15    feature_map: BTreeMap<String, crate::RegistryFeature>,
16    #[serde(skip)]
17    feature_router: Router<String>,
18    feature_fallback: Option<String>
19}
20
21impl Features {
22    pub fn new() -> Self {
23        Self {
24            feature_map: BTreeMap::new(),
25            feature_router: Router::new(),
26            feature_fallback: None
27        }
28    }
29
30    pub async fn add(&mut self, feature_arc: Arc<dyn crate::Feature>, base_path: String, router: &mut product_os_router::ProductOSRouter) {
31        let registry_feature = feature_arc.register(feature_arc.to_owned(), base_path, router).await;
32        let identifier = registry_feature.identifier.to_owned();
33        self.feature_map.insert(identifier.to_owned(), registry_feature);
34
35        match feature_arc.init_feature().await {
36            Ok(_) => {}
37            Err(_) => {}
38        }
39
40        self.setup_router();
41    }
42
43    pub async fn add_mut(&mut self, feature_arc_mut: Arc<Mutex<dyn crate::Feature>>, base_path: String, router: &mut product_os_router::ProductOSRouter) {
44        let feature_locked = feature_arc_mut.try_lock_for(core::time::Duration::new(10, 0));
45
46        match feature_locked {
47            Some(mut feature_mut) => {
48                let registry_feature = feature_mut.register_mut(feature_arc_mut.to_owned(), base_path, router).await;
49                let identifier = registry_feature.identifier.to_owned();
50                self.feature_map.insert(identifier.to_owned(), registry_feature);
51
52                match feature_mut.init_feature_mut().await {
53                    Ok(_) => {}
54                    Err(_) => {}
55                }
56
57                self.setup_router();
58            }
59            None => panic!("Failed to lock mut feature")
60        }
61    }
62
63    pub fn remove(&mut self, identifier: &str) {
64        self.feature_map.remove(identifier);
65
66        self.setup_router();
67    }
68
69    pub fn get(&self, identifier: &str) -> Option<&RegistryFeature> {
70        self.feature_map.get(identifier)
71    }
72
73    pub fn find(&self, path: &str) -> Option<(&RegistryFeature, BTreeMap<String, String>)> {
74        match self.feature_router.at(path) {
75            Ok(result) => {
76                match self.get(result.value.as_str()) {
77                    None => None,
78                    Some(registry_feature) => {
79                        let mut parameters = BTreeMap::new();
80
81                        for (key, value) in result.params.iter() {
82                            parameters.insert(key.to_string(), value.to_string());
83                        }
84
85                        Some((registry_feature, parameters))
86                    }
87                }
88            },
89            Err(_) => {
90                match &self.feature_fallback {
91                    None => None,
92                    Some(id) => {
93                        let mut parameters = BTreeMap::new();
94
95                        parameters.insert("*path".to_string(), path.to_string());
96
97                        Some((self.feature_map.get(id.as_str()).unwrap(), parameters))
98                    }
99                }
100            }
101        }
102    }
103
104    pub fn setup_router(&mut self) {
105        self.feature_router = Router::new();
106        self.feature_fallback = None;
107
108        for (identifier, registry_feature) in self.feature_map.iter() {
109            for path in &registry_feature.paths {
110                if path.starts_with("/*") {
111                    if self.feature_fallback == None {
112                        self.feature_fallback = Some(identifier.to_owned())
113                    }
114                    else {
115                        panic!("Issue setting fallback router {} - fallback already defined", identifier)
116                    }
117                }
118                else {
119                    match self.feature_router.insert(path, identifier.to_owned()) {
120                        Ok(_) => {}
121                        Err(e) => panic!("Issue inserting path for identifier {}: {} - {}", identifier, path, e)
122                    }
123                }
124            }
125        }
126    }
127}
128
129
130impl Debug for Features {
131    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
132        write!(f, "{:?}", self.feature_map)
133    }
134}
135
136