product_os_capabilities/
features.rs1use 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 ®istry_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