use cyfs_base::{
BuckyError, BuckyErrorCode, BuckyResult, Device, FileDecoder, NamedObject, PrivateKey,
StandardObject,
};
use std::collections::{hash_map::Entry, HashMap};
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use lazy_static::lazy_static;
#[derive(Clone, Debug)]
pub struct DeviceInfo {
pub device: Device,
pub private_key: Option<PrivateKey>,
}
struct LocalDeviceManagerImpl {
root: PathBuf,
list: HashMap<String, DeviceInfo>,
}
impl LocalDeviceManagerImpl {
fn new() -> Self {
let root = crate::get_cyfs_root_path().join("etc").join("desc");
Self {
root,
list: HashMap::new(),
}
}
pub fn get_root(&self) -> PathBuf {
self.root.clone()
}
pub fn set_root(&mut self, dir: &Path) {
if self.root != dir {
info!(
"change ood desc dir: {} -> {}",
self.root.display(),
dir.display()
);
self.root = dir.to_owned();
self.list.clear();
}
}
pub fn clear_cache(&mut self) {
self.list.clear();
}
pub fn add(&mut self, name: &str, device: DeviceInfo) -> BuckyResult<()> {
match self.list.entry(name.to_owned()) {
Entry::Occupied(_o) => {
error!(
"direct add new device but already exists! id={}, device={}",
name,
device.device.desc().device_id()
);
Err(BuckyError::from(BuckyErrorCode::AlreadyExists))
}
Entry::Vacant(v) => {
info!(
"direct add new device info: id={}, device={}",
name,
device.device.desc().device_id()
);
v.insert(device);
Ok(())
}
}
}
pub fn load(&mut self, name: &str) -> BuckyResult<DeviceInfo> {
if let Some(desc) = self.list.get(name) {
return Ok(desc.clone());
}
let desc = self.load_direct(name)?;
let ret = desc.clone();
self.list.insert(name.to_owned(), desc);
Ok(ret)
}
pub fn load_direct(&self, name: &str) -> BuckyResult<DeviceInfo> {
let desc_file_name = format!("{}.desc", name);
let desc_file = self.root.join(desc_file_name);
if !desc_file.is_file() {
let msg = format!("desc file not exists! file={}", desc_file.display());
error!("{}", msg);
return Err(BuckyError::new(BuckyErrorCode::NotFound, msg));
}
let mut buf: Vec<u8> = Vec::new();
let ret = StandardObject::decode_from_file(desc_file.as_path(), &mut buf);
if let Err(e) = ret {
let msg = format!("load desc file error! file={}, {}", desc_file.display(), e,);
error!("{}", msg);
return Err(BuckyError::new(BuckyErrorCode::InvalidFormat, msg));
}
info!("load desc success! file={}", desc_file.display());
let (desc, _) = ret.unwrap();
let device;
match desc {
StandardObject::Device(p) => {
device = p;
}
other @ _ => {
let msg = format!(
"unsupport desc type! file={}, desc={:?}",
desc_file.display(),
other
);
error!("{}", msg);
return Err(BuckyError::new(BuckyErrorCode::UnSupport, msg));
}
};
let mut device_info = DeviceInfo {
device,
private_key: None,
};
let sec_file_name = format!("{}.sec", name);
let sec_file = self.root.join(sec_file_name);
if sec_file.is_file() {
let mut buf: Vec<u8> = Vec::new();
let ret = PrivateKey::decode_from_file(sec_file.as_path(), &mut buf);
if let Err(e) = ret {
let msg = format!("load sec file error! file={}, {}", sec_file.display(), e,);
error!("{}", msg);
return Err(BuckyError::new(BuckyErrorCode::InvalidFormat, msg));
}
info!("load sec success! file={}", sec_file.display());
let (private_key, _) = ret.unwrap();
device_info.private_key = Some(private_key);
} else {
warn!("sec file not exists! file={}", sec_file.display());
}
Ok(device_info)
}
}
#[derive(Clone)]
pub struct LocalDeviceManager(Arc<Mutex<LocalDeviceManagerImpl>>);
impl LocalDeviceManager {
pub fn new() -> Self {
Self(Arc::new(Mutex::new(LocalDeviceManagerImpl::new())))
}
pub fn get_root(&self) -> PathBuf {
self.0.lock().unwrap().get_root()
}
pub fn set_root(&self, dir: &Path) {
self.0.lock().unwrap().set_root(dir)
}
pub fn clear_cache(&self) {
self.0.lock().unwrap().clear_cache()
}
pub fn add(&self, name: &str, device: DeviceInfo) -> BuckyResult<()> {
self.0.lock().unwrap().add(name, device)
}
pub fn load(&self, name: &str) -> BuckyResult<DeviceInfo> {
self.0.lock().unwrap().load(name)
}
pub fn load_direct(&self, name: &str) -> BuckyResult<DeviceInfo> {
self.0.lock().unwrap().load_direct(name)
}
}
lazy_static! {
pub static ref LOCAL_DEVICE_MANAGER: LocalDeviceManager = LocalDeviceManager::new();
}