cyfs_util/util/
sn_dir.rs

1use cyfs_base::*;
2
3pub struct SNDirParser;
4
5impl SNDirParser {
6    pub fn parse(id: Option<&ObjectId>, object_raw: &[u8]) -> BuckyResult<Vec<(DeviceId, Device)>> {
7        let dir = Dir::clone_from_slice(&object_raw)?;
8        let id = id.cloned().unwrap_or(dir.desc().calculate_id());
9
10        let mut sn_list = vec![];
11        match dir.desc().content().obj_list() {
12            NDNObjectInfo::ObjList(list) => {
13                for (path, node) in list.object_map() {
14                    let path = path.trim_start_matches('/');
15                    if path.starts_with("list/") {
16                        let (sn_id, buf) = Self::load_sn_node(&id, &dir, &node)?;
17                        match Device::clone_from_slice(&buf) {
18                            Ok(device) => {
19                                let real_id = device.desc().device_id();
20                                if real_id != *sn_id {
21                                    let msg = format!(
22                                        "sn device id not matched with configed in dir! dir={}, config={}, real={}",
23                                        id, sn_id, real_id,
24                                    );
25                                    error!("{}", msg);
26                                    return Err(BuckyError::new(BuckyErrorCode::InvalidData, msg));
27                                }
28
29                                info!("got sn device from dir config: dir={}, sn={}", id, real_id);
30                                sn_list.push((real_id, device));
31                            }
32                            Err(e) => {
33                                let msg = format!(
34                                    "invalid sn device object: dir={}, sn={}, {}",
35                                    id, sn_id, e
36                                );
37                                error!("{}", msg);
38                                return Err(BuckyError::new(BuckyErrorCode::InvalidData, msg));
39                            }
40                        }
41                    }
42                }
43            }
44            NDNObjectInfo::Chunk(_) => {
45                let msg = format!("dir chunk mode for sn config not support! id={}", id);
46                error!("{}", msg);
47                return Err(BuckyError::new(BuckyErrorCode::NotSupport, msg));
48            }
49        }
50
51        Ok(sn_list)
52    }
53
54    pub fn load_sn_node<'a>(
55        id: &ObjectId,
56        dir: &'a Dir,
57        node: &'a InnerNodeInfo,
58    ) -> BuckyResult<(&'a ObjectId, &'a Vec<u8>)> {
59        match node.node() {
60            InnerNode::ObjId(sn_id) => {
61                match dir.body() {
62                    Some(body) => {
63                        match body.content() {
64                            DirBodyContent::ObjList(list) => {
65                                match list.get(sn_id) {
66                                    Some(value) => Ok((sn_id, value)),
67                                    None => {
68                                        let msg = format!("load sn item from dir body but not found! id={}, sn={}", id, sn_id);
69                                        error!("{}", msg);
70                                        Err(BuckyError::new(BuckyErrorCode::NotFound, msg))
71                                    }
72                                }
73                            }
74                            _ => {
75                                let msg = format!("dir body chunk content format for sn config not support! id={}", id);
76                                error!("{}", msg);
77                                Err(BuckyError::new(BuckyErrorCode::NotSupport, msg))
78                            }
79                        }
80                    }
81                    None => {
82                        let msg = format!("dir body content not exists! id={}", id);
83                        error!("{}", msg);
84                        Err(BuckyError::new(BuckyErrorCode::InvalidData, msg))
85                    }
86                }
87            }
88            _ => {
89                let msg = format!(
90                    "dir desc inner node format for sn config not support! id={}, node={:?}",
91                    id, node
92                );
93                error!("{}", msg);
94                Err(BuckyError::new(BuckyErrorCode::NotSupport, msg))
95            }
96        }
97    }
98}
99
100use std::collections::HashMap;
101use std::path::Path;
102
103use super::bdt_util::load_device_objects_list;
104
105pub struct SNDirGenerator;
106
107impl SNDirGenerator {
108    pub fn gen_from_dir(owner_id: &Option<ObjectId>, root: &Path) -> BuckyResult<Dir> {
109        let list = load_device_objects_list(root);
110        if list.is_empty() {
111            let msg = format!("sn device folder is empty! dir={}", root.display());
112            error!("{}", msg);
113            return Err(BuckyError::new(BuckyErrorCode::InvalidData, msg));
114        }
115
116        Self::gen_from_list(owner_id, list)
117    }
118
119    pub fn gen_from_list(
120        owner_id: &Option<ObjectId>,
121        list: Vec<(DeviceId, Device)>,
122    ) -> BuckyResult<Dir> {
123        let mut object_map = HashMap::new();
124        let mut body_map = HashMap::new();
125        for (id, sn) in list {
126            let inner_node = InnerNodeInfo::new(
127                Attributes::default(),
128                InnerNode::ObjId(id.object_id().clone()),
129            );
130
131            let path = format!("list/{}", id);
132            info!("will add sn item to dir: {}", path);
133            if let Some(_prev) = object_map.insert(path, inner_node) {
134                let msg = format!("sn device item already exists in desc! id={}", id);
135                error!("{}", msg);
136                return Err(BuckyError::new(BuckyErrorCode::AlreadyExists, msg));
137            }
138
139            let buf = sn.to_vec()?;
140            if let Some(_prev) = body_map.insert(id.object_id().clone(), buf) {
141                let msg = format!("sn device item already exists in body! id={}", id);
142                error!("{}", msg);
143                return Err(BuckyError::new(BuckyErrorCode::AlreadyExists, msg));
144            }
145        }
146
147        let list = NDNObjectList {
148            parent_chunk: None,
149            object_map,
150        };
151
152        let attr = Attributes::new(0);
153        let builder = Dir::new(attr, NDNObjectInfo::ObjList(list.clone()), body_map);
154        let dir = builder
155            .option_owner(owner_id.to_owned())
156            .no_create_time()
157            .update_time(bucky_time_now())
158            .build();
159        let dir_id = dir.desc().calculate_id();
160
161        info!("gen sn dir complete! dir={}", dir_id);
162        Ok(dir)
163    }
164}
165
166#[cfg(test)]
167mod test {
168    use cyfs_base::*;
169
170    use crate::*;
171
172    #[test]
173    fn test() {
174        crate::init_log("test-sn-dir", None);
175
176        let root = crate::get_cyfs_root_path_ref().join("etc");
177        let dir = SNDirGenerator::gen_from_dir(&None, &root).unwrap();
178        let object_raw = dir.to_vec().unwrap();
179        let dir_id = dir.desc().calculate_id();
180        let list = SNDirParser::parse(Some(&dir_id), &object_raw).unwrap();
181        for item in list {
182            info!("got sn item: {}", item.0);
183        }
184    }
185}