diff options
Diffstat (limited to 'src/library.rs')
-rw-r--r-- | src/library.rs | 133 |
1 files changed, 65 insertions, 68 deletions
diff --git a/src/library.rs b/src/library.rs index d650733..ea0b9ed 100644 --- a/src/library.rs +++ b/src/library.rs @@ -1,119 +1,116 @@ -use std::{fs::File, path::PathBuf, str::FromStr, sync::Arc}; - -use anyhow::{bail, Context, Ok}; -use chashmap::CHashMap; -use serde::{Deserialize, Serialize}; +use crate::metadata::{DirectoryInfo, ItemInfo}; +use anyhow::{anyhow, bail, Context, Ok}; +use std::{ffi::OsStr, fs::File, path::PathBuf, sync::Arc}; pub struct Library { - path: PathBuf, - cache: CHashMap<String, LibNode>, // TODO + root: Arc<Node>, } #[derive(Debug, Clone)] -pub enum LibNode { - Directory(Arc<LibDirectory>), - Item(Arc<LibItem>), +pub enum Node { + Directory(Arc<Directory>), + Item(Arc<Item>), } #[derive(Debug, Clone)] -pub struct LibDirectory { - pub path: PathBuf, - pub child_names: Vec<String>, - pub data: LibDirectoryData, +pub struct Directory { + pub identifier: String, + pub data: DirectoryInfo, + pub children: Vec<Arc<Node>>, } #[derive(Debug, Clone)] -pub struct LibItem { - pub data: LibItemData, -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct LibDirectoryData { - pub name: String, -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct LibItemData { - title: String, +pub struct Item { + pub identifier: String, + pub data: ItemInfo, } impl Library { pub fn open(path: &str) -> anyhow::Result<Self> { Ok(Self { - path: PathBuf::from_str(path).unwrap(), - cache: CHashMap::new(), + root: Node::from_path(path.into()).context("indexing root")?, }) } - pub fn root(&self) -> anyhow::Result<Arc<LibNode>> { - LibNode::from_path(self.path.clone()) - } - pub fn nested(&self, path: &str) -> anyhow::Result<Arc<LibNode>> { - let mut n = self.root()?; + pub fn nested(&self, path: &str) -> anyhow::Result<Arc<Node>> { + let mut n = self.root.clone(); if path == "" { return Ok(n); } for seg in path.split("/") { - n = n.get_directory()?.get_child(seg)? + n = n + .get_directory()? + .child_by_ident(seg) + .ok_or(anyhow!("does not exist"))?; } Ok(n) } } -impl LibNode { - pub fn get_directory(&self) -> anyhow::Result<&LibDirectory> { +impl Node { + pub fn get_directory(&self) -> anyhow::Result<&Directory> { match self { - LibNode::Directory(d) => Ok(d), - LibNode::Item(_) => bail!("not a directory"), + Node::Directory(d) => Ok(d), + Node::Item(_) => bail!("not a directory"), } } pub fn title(&self) -> &str { match self { - LibNode::Directory(d) => &d.data.name, - LibNode::Item(i) => &i.data.title, + Node::Directory(d) => &d.data.name, + Node::Item(i) => &i.data.title, + } + } + pub fn identifier(&self) -> &str { + match self { + Node::Directory(d) => &d.identifier, + Node::Item(i) => &i.identifier, } } - pub fn from_path(path: PathBuf) -> anyhow::Result<Arc<LibNode>> { + pub fn from_path(path: PathBuf) -> anyhow::Result<Arc<Node>> { if path.is_dir() { let mpath = path.join("directory.json"); - let data: LibDirectoryData = + let data: DirectoryInfo = serde_json::from_reader(File::open(mpath).context("metadata missing")?)?; - let child_names = path + let children = path .read_dir()? - .map(|e| e.unwrap().file_name().to_str().unwrap().to_string()) - .filter(|e| !e.ends_with(".json")) - .collect(); - Ok(LibNode::Directory(Arc::new(LibDirectory { - path, - child_names, + .map(|e| e.unwrap().path()) + .filter(|e| e.extension() != Some(OsStr::new("json"))) + .map(|e| Node::from_path(e.clone()).context(format!("loading {e:?}"))) + .into_iter() + .collect::<anyhow::Result<Vec<_>>>()?; + + Ok(Node::Directory(Arc::new(Directory { + children, data, + identifier: path.file_name().unwrap().to_str().unwrap().to_string(), })) .into()) } else if path.is_file() { let mpath = path.clone().with_extension("metadata.json"); - let data: LibItemData = - serde_json::from_reader(File::open(mpath).context("metadata missing")?) - .context("invalid metadata")?; - Ok(LibNode::Item(Arc::new(LibItem { data })).into()) + let datafile = File::open(mpath.clone()) + .context(format!("metadata missing, tried path {mpath:?}"))?; + let data: ItemInfo = serde_json::from_reader(datafile).context("invalid metadata")?; + Ok(Node::Item(Arc::new(Item { + data, + identifier: path + .with_extension("") + .file_name() + .unwrap() + .to_str() + .unwrap() + .to_string(), + })) + .into()) } else { bail!("did somebody really put a fifo or socket in the library?!") } } } -impl LibDirectory { - pub fn get_child(&self, p: &str) -> anyhow::Result<Arc<LibNode>> { - if p.contains("..") || p.starts_with("/") { - bail!("no! dont do that.") - } - let path = self.path.join(p); - // if !path.exists() {bail!("does not exist");} - LibNode::from_path(path) - } - pub fn child_nodes(&self) -> anyhow::Result<Vec<Arc<LibNode>>> { - let mut o = vec![]; - for name in &self.child_names { - o.push(self.get_child(&name)?) - } - Ok(o) +impl Directory { + pub fn child_by_ident(&self, i: &str) -> Option<Arc<Node>> { + self.children + .iter() + .find(|e| e.identifier() == i) + .map(|e| e.to_owned()) } } |