cyfs-util 0.6.8

Rust cyfs-util package
Documentation
use cyfs_base::*;

pub struct SNDirParser;

impl SNDirParser {
    pub fn parse(id: Option<&ObjectId>, object_raw: &[u8]) -> BuckyResult<Vec<(DeviceId, Device)>> {
        let dir = Dir::clone_from_slice(&object_raw)?;
        let id = id.cloned().unwrap_or(dir.desc().calculate_id());

        let mut sn_list = vec![];
        match dir.desc().content().obj_list() {
            NDNObjectInfo::ObjList(list) => {
                for (path, node) in list.object_map() {
                    let path = path.trim_start_matches('/');
                    if path.starts_with("list/") {
                        let (sn_id, buf) = Self::load_sn_node(&id, &dir, &node)?;
                        match Device::clone_from_slice(&buf) {
                            Ok(device) => {
                                let real_id = device.desc().device_id();
                                if real_id != *sn_id {
                                    let msg = format!(
                                        "sn device id not matched with configed in dir! dir={}, config={}, real={}",
                                        id, sn_id, real_id,
                                    );
                                    error!("{}", msg);
                                    return Err(BuckyError::new(BuckyErrorCode::InvalidData, msg));
                                }

                                info!("got sn device from dir config: dir={}, sn={}", id, real_id);
                                sn_list.push((real_id, device));
                            }
                            Err(e) => {
                                let msg = format!(
                                    "invalid sn device object: dir={}, sn={}, {}",
                                    id, sn_id, e
                                );
                                error!("{}", msg);
                                return Err(BuckyError::new(BuckyErrorCode::InvalidData, msg));
                            }
                        }
                    }
                }
            }
            NDNObjectInfo::Chunk(_) => {
                let msg = format!("dir chunk mode for sn config not support! id={}", id);
                error!("{}", msg);
                return Err(BuckyError::new(BuckyErrorCode::NotSupport, msg));
            }
        }

        Ok(sn_list)
    }

    pub fn load_sn_node<'a>(
        id: &ObjectId,
        dir: &'a Dir,
        node: &'a InnerNodeInfo,
    ) -> BuckyResult<(&'a ObjectId, &'a Vec<u8>)> {
        match node.node() {
            InnerNode::ObjId(sn_id) => {
                match dir.body() {
                    Some(body) => {
                        match body.content() {
                            DirBodyContent::ObjList(list) => {
                                match list.get(sn_id) {
                                    Some(value) => Ok((sn_id, value)),
                                    None => {
                                        let msg = format!("load sn item from dir body but not found! id={}, sn={}", id, sn_id);
                                        error!("{}", msg);
                                        Err(BuckyError::new(BuckyErrorCode::NotFound, msg))
                                    }
                                }
                            }
                            _ => {
                                let msg = format!("dir body chunk content format for sn config not support! id={}", id);
                                error!("{}", msg);
                                Err(BuckyError::new(BuckyErrorCode::NotSupport, msg))
                            }
                        }
                    }
                    None => {
                        let msg = format!("dir body content not exists! id={}", id);
                        error!("{}", msg);
                        Err(BuckyError::new(BuckyErrorCode::InvalidData, msg))
                    }
                }
            }
            _ => {
                let msg = format!(
                    "dir desc inner node format for sn config not support! id={}, node={:?}",
                    id, node
                );
                error!("{}", msg);
                Err(BuckyError::new(BuckyErrorCode::NotSupport, msg))
            }
        }
    }
}

use std::collections::HashMap;
use std::path::Path;

use super::bdt_util::load_device_objects_list;

pub struct SNDirGenerator;

impl SNDirGenerator {
    pub fn gen_from_dir(owner_id: &Option<ObjectId>, root: &Path) -> BuckyResult<Dir> {
        let list = load_device_objects_list(root);
        if list.is_empty() {
            let msg = format!("sn device folder is empty! dir={}", root.display());
            error!("{}", msg);
            return Err(BuckyError::new(BuckyErrorCode::InvalidData, msg));
        }

        Self::gen_from_list(owner_id, list)
    }

    pub fn gen_from_list(
        owner_id: &Option<ObjectId>,
        list: Vec<(DeviceId, Device)>,
    ) -> BuckyResult<Dir> {
        let mut object_map = HashMap::new();
        let mut body_map = HashMap::new();
        for (id, sn) in list {
            let inner_node = InnerNodeInfo::new(
                Attributes::default(),
                InnerNode::ObjId(id.object_id().clone()),
            );

            let path = format!("list/{}", id);
            info!("will add sn item to dir: {}", path);
            if let Some(_prev) = object_map.insert(path, inner_node) {
                let msg = format!("sn device item already exists in desc! id={}", id);
                error!("{}", msg);
                return Err(BuckyError::new(BuckyErrorCode::AlreadyExists, msg));
            }

            let buf = sn.to_vec()?;
            if let Some(_prev) = body_map.insert(id.object_id().clone(), buf) {
                let msg = format!("sn device item already exists in body! id={}", id);
                error!("{}", msg);
                return Err(BuckyError::new(BuckyErrorCode::AlreadyExists, msg));
            }
        }

        let list = NDNObjectList {
            parent_chunk: None,
            object_map,
        };

        let attr = Attributes::new(0);
        let builder = Dir::new(attr, NDNObjectInfo::ObjList(list.clone()), body_map);
        let dir = builder
            .option_owner(owner_id.to_owned())
            .no_create_time()
            .update_time(bucky_time_now())
            .build();
        let dir_id = dir.desc().calculate_id();

        info!("gen sn dir complete! dir={}", dir_id);
        Ok(dir)
    }
}

#[cfg(test)]
mod test {
    use cyfs_base::*;

    use crate::*;

    #[test]
    fn test() {
        crate::init_log("test-sn-dir", None);

        let root = crate::get_cyfs_root_path_ref().join("etc");
        let dir = SNDirGenerator::gen_from_dir(&None, &root).unwrap();
        let object_raw = dir.to_vec().unwrap();
        let dir_id = dir.desc().calculate_id();
        let list = SNDirParser::parse(Some(&dir_id), &object_raw).unwrap();
        for item in list {
            info!("got sn item: {}", item.0);
        }
    }
}