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}