cyfs_lib/prelude/
global_state_common.rs

1use crate::base::*;
2use crate::GlobalStateCategory;
3use cyfs_base::*;
4
5use std::borrow::Cow;
6use std::{fmt, str::FromStr};
7
8#[derive(Clone, Debug, Eq, PartialEq)]
9pub enum RequestGlobalStateRoot {
10    GlobalRoot(ObjectId),
11    DecRoot(ObjectId),
12}
13
14impl fmt::Display for RequestGlobalStateRoot {
15    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16        match &self {
17            Self::GlobalRoot(root) => {
18                write!(f, "root:{}", root)
19            }
20            Self::DecRoot(root) => {
21                write!(f, "dec-root:{}", root)
22            }
23        }
24    }
25}
26
27#[derive(Clone, Eq, PartialEq)]
28pub struct RequestGlobalStatePath {
29    // default is root-state, can be local-cache
30    pub global_state_category: Option<GlobalStateCategory>,
31
32    // root or dec-root object-id
33    pub global_state_root: Option<RequestGlobalStateRoot>,
34
35    // target DEC,if is none then equal as source dec-id
36    pub dec_id: Option<ObjectId>,
37
38    // inernal path of global-state, without the dec-id segment
39    pub req_path: Option<String>,
40}
41
42impl fmt::Display for RequestGlobalStatePath {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        write!(f, "{}", self.format_string())
45    }
46}
47impl fmt::Debug for RequestGlobalStatePath {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        write!(f, "{}", self.format_string())
50    }
51}
52
53impl RequestGlobalStatePath {
54    pub fn new(dec_id: Option<ObjectId>, req_path: Option<impl Into<String>>) -> Self {
55        Self {
56            global_state_category: None,
57            global_state_root: None,
58            dec_id,
59            req_path: req_path.map(|v| v.into()),
60        }
61    }
62
63    pub fn new_system_dec(req_path: Option<impl Into<String>>) -> Self {
64        Self::new(Some(cyfs_core::get_system_dec_app().to_owned()), req_path)
65    }
66
67    pub fn set_root(&mut self, root: ObjectId) {
68        self.global_state_root = Some(RequestGlobalStateRoot::GlobalRoot(root));
69    }
70    pub fn set_dec_root(&mut self, dec_root: ObjectId) {
71        self.global_state_root = Some(RequestGlobalStateRoot::DecRoot(dec_root));
72    }
73
74    pub fn category(&self) -> GlobalStateCategory {
75        match &self.global_state_category {
76            Some(v) => *v,
77            None => GlobalStateCategory::RootState,
78        }
79    }
80
81    pub fn req_path(&self) -> Cow<str> {
82        match &self.req_path {
83            Some(v) => Cow::Borrowed(v.as_str()),
84            None => Cow::Borrowed("/"),
85        }
86    }
87
88    // 如果req_path没有指定target_dec_id,那么使用source_dec_id
89    pub fn dec<'a>(&'a self, source: &'a RequestSourceInfo) -> &ObjectId {
90        match &self.dec_id {
91            Some(id) => id,
92            None => &source.dec,
93        }
94    }
95
96    /*
97    The first paragraph is optional root-state/local-cache, default root-state
98    The second paragraph is optional current/root:{root-id}/dec-root:{dec-root-id}, default is current
99    The third paragraph is required target-dec-id
100    Fourth paragraph optional global-state-inner-path
101    */
102    pub fn parse(req_path: &str) -> BuckyResult<Self> {
103        let segs: Vec<&str> = req_path
104            .trim_start_matches('/')
105            .split('/')
106            .filter(|seg| !seg.is_empty())
107            .collect();
108
109        let mut index = 0;
110        let global_state_category = if index < segs.len() {
111            let seg = segs[index];
112            match seg {
113                "root-state" => {
114                    index += 1;
115                    Some(GlobalStateCategory::RootState)
116                }
117                "local-cache" => {
118                    index += 1;
119                    Some(GlobalStateCategory::LocalCache)
120                }
121
122                _ => None,
123            }
124        } else {
125            None
126        };
127
128        let global_state_root = if index < segs.len() {
129            let seg = segs[index];
130            match seg {
131                "current" => {
132                    index += 1;
133                    None
134                }
135                _ if seg.starts_with("root:") => {
136                    index += 1;
137
138                    let id = seg.strip_prefix("root:").unwrap();
139                    let root = ObjectId::from_str(&id).map_err(|e| {
140                        let msg = format!("invalid req_path's root id: {}, {}", seg, e);
141                        error!("{msg}");
142                        BuckyError::new(BuckyErrorCode::InvalidFormat, msg)
143                    })?;
144
145                    Some(RequestGlobalStateRoot::GlobalRoot(root))
146                }
147                _ if seg.starts_with("dec-root:") => {
148                    index += 1;
149
150                    let id = seg.strip_prefix("dec-root:").unwrap();
151                    let root = ObjectId::from_str(&id).map_err(|e| {
152                        let msg = format!("invalid req_path's dec root id: {}, {}", seg, e);
153                        error!("{msg}");
154                        BuckyError::new(BuckyErrorCode::InvalidFormat, msg)
155                    })?;
156
157                    Some(RequestGlobalStateRoot::DecRoot(root))
158                }
159                _ => None,
160            }
161        } else {
162            None
163        };
164
165        let dec_id = if index < segs.len() {
166            // 如果第一段是object_id,那么认为是dec_id
167            let seg = segs[index];
168            if OBJECT_ID_BASE58_RANGE.contains(&seg.len()) {
169                let dec_id = ObjectId::from_str(seg).map_err(|e| {
170                    let msg = format!("invalid req_path's dec root id: {}, {}", seg, e);
171                    error!("{msg}");
172                    BuckyError::new(BuckyErrorCode::InvalidFormat, msg)
173                })?;
174                index += 1;
175                Some(dec_id)
176            } else {
177                None
178            }
179        } else {
180            None
181        };
182
183        let req_path = if index < segs.len() {
184            let path = segs[index..].join("/");
185            Some(format!("/{}/", path))
186        } else {
187            None
188        };
189
190        Ok(Self {
191            global_state_category,
192            global_state_root,
193            dec_id,
194            req_path,
195        })
196    }
197
198    pub fn format_string(&self) -> String {
199        let mut segs: Vec<Cow<str>> = vec![];
200        if let Some(v) = &self.global_state_category {
201            segs.push(Cow::Borrowed(v.as_str()));
202        }
203
204        if let Some(root) = &self.global_state_root {
205            segs.push(Cow::Owned(root.to_string()));
206        }
207
208        if let Some(id) = &self.dec_id {
209            let seg = Cow::Owned(id.to_string());
210            segs.push(seg);
211        };
212
213        if let Some(path) = &self.req_path {
214            segs.push(Cow::Borrowed(path.trim_start_matches('/')));
215        }
216
217        format!("/{}", segs.join("/"))
218    }
219
220    pub fn match_target(&self, target: &Self) -> bool {
221        if self.category() != target.category() {
222            return false;
223        }
224
225        if self.global_state_root != target.global_state_root {
226            return false;
227        }
228
229        if self.dec_id != target.dec_id {
230            return false;
231        }
232
233        target.req_path().starts_with(&*self.req_path())
234    }
235}
236
237impl FromStr for RequestGlobalStatePath {
238    type Err = BuckyError;
239
240    fn from_str(s: &str) -> Result<Self, Self::Err> {
241        Self::parse(s)
242    }
243}
244
245#[cfg(test)]
246mod test {
247    use super::*;
248
249    #[test]
250    fn test() {
251        let mut root = RequestGlobalStatePath {
252            global_state_category: None,
253            global_state_root: None,
254            dec_id: None,
255            req_path: Some("/a/b/".to_owned()),
256        };
257
258        let s = root.format_string();
259        println!("{}", s);
260        let r = RequestGlobalStatePath::parse(&s).unwrap();
261        assert_eq!(root, r);
262
263        root.dec_id = Some(ObjectId::default());
264        let s = root.format_string();
265        println!("{}", s);
266        
267        root.global_state_category = Some(GlobalStateCategory::RootState);
268        let s = root.format_string();
269        println!("{}", s);
270        let r = RequestGlobalStatePath::parse(&s).unwrap();
271        assert_eq!(root, r);
272
273        root.global_state_root = Some(RequestGlobalStateRoot::DecRoot(ObjectId::default()));
274        let s = root.format_string();
275        println!("{}", s);
276        let r = RequestGlobalStatePath::parse(&s).unwrap();
277        assert_eq!(root, r);
278
279        root.req_path = None;
280        let s = root.format_string();
281        println!("{}", s);
282        let r = RequestGlobalStatePath::parse(&s).unwrap();
283        assert_eq!(root, r);
284
285        root.req_path = Some("/a/".to_owned());
286        let s = root.format_string();
287        println!("{}", s);
288        let r = RequestGlobalStatePath::parse(&s).unwrap();
289        assert_eq!(root, r);
290
291        root.dec_id = Some(cyfs_core::get_system_dec_app().to_owned());
292        let s = root.format_string();
293        println!("{}", s);
294        let r = RequestGlobalStatePath::parse(&s).unwrap();
295        assert_eq!(r.dec_id, Some(cyfs_core::get_system_dec_app().to_owned()));
296
297        let root = RequestGlobalStatePath {
298            global_state_category: None,
299            global_state_root: None,
300            dec_id: None,
301            req_path: None,
302        };
303
304        let s = root.format_string();
305        println!("{}", s);
306        let r = RequestGlobalStatePath::parse(&s).unwrap();
307        assert_eq!(root, r);
308    }
309}