From 948700d35f0eddbc2e0fd29548991e687362983d Mon Sep 17 00:00:00 2001 From: metamuffin Date: Wed, 11 Jan 2023 16:27:16 +0100 Subject: move files --- Cargo.toml | 22 +----- server/Cargo.toml | 20 +++++ server/src/database.rs | 13 ++++ server/src/frontend/mod.rs | 2 + server/src/frontend/pages/home.rs | 14 ++++ server/src/frontend/pages/layout.rs | 20 +++++ server/src/frontend/pages/mod.rs | 69 +++++++++++++++++ server/src/frontend/pages/node.rs | 60 +++++++++++++++ server/src/frontend/style/layout.css | 42 +++++++++++ server/src/frontend/style/mod.rs | 2 + server/src/library.rs | 141 +++++++++++++++++++++++++++++++++++ server/src/main.rs | 45 +++++++++++ server/src/metadata.rs | 11 +++ src/database.rs | 13 ---- src/frontend/mod.rs | 2 - src/frontend/pages/home.rs | 14 ---- src/frontend/pages/layout.rs | 20 ----- src/frontend/pages/mod.rs | 69 ----------------- src/frontend/pages/node.rs | 60 --------------- src/frontend/style/layout.css | 42 ----------- src/frontend/style/mod.rs | 2 - src/library.rs | 141 ----------------------------------- src/main.rs | 45 ----------- src/metadata.rs | 11 --- 24 files changed, 441 insertions(+), 439 deletions(-) create mode 100644 server/Cargo.toml create mode 100644 server/src/database.rs create mode 100644 server/src/frontend/mod.rs create mode 100644 server/src/frontend/pages/home.rs create mode 100644 server/src/frontend/pages/layout.rs create mode 100644 server/src/frontend/pages/mod.rs create mode 100644 server/src/frontend/pages/node.rs create mode 100644 server/src/frontend/style/layout.css create mode 100644 server/src/frontend/style/mod.rs create mode 100644 server/src/library.rs create mode 100644 server/src/main.rs create mode 100644 server/src/metadata.rs delete mode 100644 src/database.rs delete mode 100644 src/frontend/mod.rs delete mode 100644 src/frontend/pages/home.rs delete mode 100644 src/frontend/pages/layout.rs delete mode 100644 src/frontend/pages/mod.rs delete mode 100644 src/frontend/pages/node.rs delete mode 100644 src/frontend/style/layout.css delete mode 100644 src/frontend/style/mod.rs delete mode 100644 src/library.rs delete mode 100644 src/main.rs delete mode 100644 src/metadata.rs diff --git a/Cargo.toml b/Cargo.toml index 70b8752..cae9660 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,20 +1,2 @@ -[package] -name = "jellything" -version = "0.1.0" -edition = "2021" - -[dependencies] -serde = { version = "1.0.152", features = ["derive"] } -serde_json = "1.0.91" - -log = "0.4.17" -env_logger = "0.10.0" -anyhow = "1.0.68" - -rocket = "0.5.0-rc.2" -tokio = "1.24.1" -markup = "0.13.1" -chashmap = "2.2.2" - -sled = "0.34.7" -typed-sled = "0.2.3" +[workspace] +members = ["server"] diff --git a/server/Cargo.toml b/server/Cargo.toml new file mode 100644 index 0000000..70b8752 --- /dev/null +++ b/server/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "jellything" +version = "0.1.0" +edition = "2021" + +[dependencies] +serde = { version = "1.0.152", features = ["derive"] } +serde_json = "1.0.91" + +log = "0.4.17" +env_logger = "0.10.0" +anyhow = "1.0.68" + +rocket = "0.5.0-rc.2" +tokio = "1.24.1" +markup = "0.13.1" +chashmap = "2.2.2" + +sled = "0.34.7" +typed-sled = "0.2.3" diff --git a/server/src/database.rs b/server/src/database.rs new file mode 100644 index 0000000..3ba8c52 --- /dev/null +++ b/server/src/database.rs @@ -0,0 +1,13 @@ +use anyhow::Context; + +#[derive(Debug)] +pub struct Database { + pub db: sled::Db, +} + +impl Database { + pub fn open(path: &str) -> Result { + let db = sled::open(path).context("opening database")?; + Ok(Self { db }) + } +} diff --git a/server/src/frontend/mod.rs b/server/src/frontend/mod.rs new file mode 100644 index 0000000..99c22f8 --- /dev/null +++ b/server/src/frontend/mod.rs @@ -0,0 +1,2 @@ +pub mod style; +pub mod pages; diff --git a/server/src/frontend/pages/home.rs b/server/src/frontend/pages/home.rs new file mode 100644 index 0000000..5076177 --- /dev/null +++ b/server/src/frontend/pages/home.rs @@ -0,0 +1,14 @@ +use crate::frontend::pages::node::NodePage; +use crate::{frontend::pages::HtmlTemplate, AppState}; +use rocket::{get, State}; + +#[get("/")] +pub async fn page_home(state: &State) -> HtmlTemplate { + HtmlTemplate( + "Home".to_string(), + markup::new! { + p { "Welcome to Jellything" } + @NodePage { node: state.library.root.clone() } + }, + ) +} diff --git a/server/src/frontend/pages/layout.rs b/server/src/frontend/pages/layout.rs new file mode 100644 index 0000000..5654d3b --- /dev/null +++ b/server/src/frontend/pages/layout.rs @@ -0,0 +1,20 @@ +use markup::Render; + +markup::define! { + Layout(title: String, main: Main) { + @markup::doctype() + html { + head { + title { @title " - Jellything" } + link[rel="stylesheet", href="/assets/style.css"]; + } + body { + nav { + h1 { "Jellything" } + + } + #main { @main } + } + } + } +} diff --git a/server/src/frontend/pages/mod.rs b/server/src/frontend/pages/mod.rs new file mode 100644 index 0000000..a20fa0e --- /dev/null +++ b/server/src/frontend/pages/mod.rs @@ -0,0 +1,69 @@ +use markup::Render; +use rocket::{ + http::ContentType, + response::{self, Responder}, + Request, Response, +}; +use std::{fmt::Display, io::Cursor}; + +use self::layout::Layout; + +pub mod home; +pub mod layout; +pub mod node; + +pub struct HtmlTemplate(pub String, pub T); + +impl<'r, T: Render> Responder<'r, 'static> for HtmlTemplate { + fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> { + let mut out = String::new(); + Layout { + title: self.0, + main: self.1, + } + .render(&mut out) + .unwrap(); + Response::build() + .header(ContentType::HTML) + .streamed_body(Cursor::new(out)) + .ok() + } +} + +#[derive(Debug)] +pub struct MyError(anyhow::Error); + +impl<'r> Responder<'r, 'static> for MyError { + fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> { + let mut out = String::new(); + Layout { + title: "Error".to_string(), + main: markup::new! { + h2 { "An error occured. Nobody is sorry"} + pre.error { @format!("{:?}", self.0) } + }, + } + .render(&mut out) + .unwrap(); + Response::build() + .header(ContentType::HTML) + .streamed_body(Cursor::new(out)) + .ok() + } +} + +impl Display for MyError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} +impl From for MyError { + fn from(err: anyhow::Error) -> MyError { + MyError(err) + } +} +impl From for MyError { + fn from(err: std::fmt::Error) -> MyError { + MyError(anyhow::anyhow!("{err}")) + } +} diff --git a/server/src/frontend/pages/node.rs b/server/src/frontend/pages/node.rs new file mode 100644 index 0000000..7ac4332 --- /dev/null +++ b/server/src/frontend/pages/node.rs @@ -0,0 +1,60 @@ +use crate::{ + frontend::pages::HtmlTemplate, + library::{Directory, Item, Node}, + AppState, +}; +use anyhow::Context; +use rocket::{get, uri, State}; +use std::{ops::Deref, path::PathBuf, sync::Arc}; + +use super::MyError; + +#[get("/library/")] +pub async fn page_library_node( + path: PathBuf, + state: &State, +) -> Result, MyError> { + let path = path.to_str().unwrap().to_string(); + let node = state + .library + .nested(&path) + .context("retrieving library node")? + .clone(); + Ok(HtmlTemplate( + format!("{}", node.title()), + markup::new! { + @NodePage { node: node.clone() } + }, + )) +} + +markup::define! { + NodePage(node: Arc) { + @match node.deref() { + Node::Directory(dir) => { @DirectoryPage { dir: dir.clone() } } + Node::Item(item) => { @ItemPage { item: item.clone() } } + } + } + DirectoryCard(dir: Arc) { + span { a[href=&uri!(page_library_node(&dir.lib_path)).to_string()] { @dir.data.name } } + } + DirectoryPage(dir: Arc) { + h1 { @dir.data.name } + ul.directorylisting { + @for el in &dir.children { + li { + span.title { @match el.deref().to_owned() { + Node::Directory(dir) => { @DirectoryCard { dir } } + Node::Item(item) => { @ItemCard { item } } + }} + } + } + } + } + ItemCard(item: Arc) { + span { a[href=&uri!(page_library_node(&item.lib_path)).to_string()] { @item.data.title } } + } + ItemPage(item: Arc) { + h1 { @item.data.title } + } +} diff --git a/server/src/frontend/style/layout.css b/server/src/frontend/style/layout.css new file mode 100644 index 0000000..4418903 --- /dev/null +++ b/server/src/frontend/style/layout.css @@ -0,0 +1,42 @@ +@import url("https://s.metamuffin.org/static/font-ubuntu/include.css"); + +* { + color: white; + font-family: "Ubuntu", sans-serif; + font-weight: 300; + margin: 0px; + padding: 0px; +} + +body { + background-color: #1a1a1a; + width: 100vw; +} + +nav { + position: absolute; + top: 0px; + left: 0px; + padding: 1em; + width: calc(100vw - 2em); + height: 2em; + background-color: #41414144; +} + +nav h1 { + margin: 0px; + font-size: 1.5em; +} + +#main { + margin-top: 5em; + padding: 1em; + padding-left: 3em; + padding-right: 3em; +} + +.error { + padding: 1em; + color: rgb(255, 117, 117); + font-family: monospace; +} diff --git a/server/src/frontend/style/mod.rs b/server/src/frontend/style/mod.rs new file mode 100644 index 0000000..9d0729e --- /dev/null +++ b/server/src/frontend/style/mod.rs @@ -0,0 +1,2 @@ + +pub const CSS_BUNDLE: &'static str = include_str!("layout.css"); diff --git a/server/src/library.rs b/server/src/library.rs new file mode 100644 index 0000000..0c42a73 --- /dev/null +++ b/server/src/library.rs @@ -0,0 +1,141 @@ +use crate::metadata::{DirectoryInfo, ItemInfo}; +use anyhow::{anyhow, bail, Context, Ok}; +use std::{ffi::OsStr, fs::File, path::PathBuf, sync::Arc}; + +pub struct Library { + pub root: Arc, +} + +#[derive(Debug, Clone)] +pub enum Node { + Directory(Arc), + Item(Arc), +} + +#[derive(Debug, Clone)] +pub struct Directory { + pub lib_path: PathBuf, + pub identifier: String, + pub data: DirectoryInfo, + pub children: Vec>, +} + +#[derive(Debug, Clone)] +pub struct Item { + pub lib_path: PathBuf, + pub identifier: String, + pub data: ItemInfo, +} + +impl Library { + pub fn open(path: &str) -> anyhow::Result { + Ok(Self { + root: Node::from_path(path.into(), PathBuf::new(), true).context("indexing root")?, + }) + } + pub fn nested(&self, path: &str) -> anyhow::Result> { + let mut n = self.root.clone(); + if path == "" { + return Ok(n); + } + for seg in path.split("/") { + n = n + .get_directory()? + .child_by_ident(seg) + .ok_or(anyhow!("does not exist"))?; + } + Ok(n) + } +} + +impl Node { + pub fn get_directory(&self) -> anyhow::Result<&Directory> { + match self { + Node::Directory(d) => Ok(d), + Node::Item(_) => bail!("not a directory"), + } + } + pub fn title(&self) -> &str { + match self { + 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, + mut lib_path: PathBuf, + root: bool, + ) -> anyhow::Result> { + if path.is_dir() { + let mpath = path.join("directory.json"); + let data: DirectoryInfo = + serde_json::from_reader(File::open(mpath).context("metadata missing")?)?; + + let identifier = path.file_name().unwrap().to_str().unwrap().to_string(); + if !root { + lib_path = lib_path.join(identifier.clone()); + } + + let children = path + .read_dir()? + .map(|e| e.unwrap().path()) + .filter(|e| e.extension() != Some(OsStr::new("json"))) + .map(|e| { + Node::from_path(e.clone(), lib_path.clone(), false) + .context(format!("loading {e:?}")) + }) + .into_iter() + .collect::>>()?; + + Ok(Node::Directory(Arc::new(Directory { + lib_path, + children, + data, + identifier, + })) + .into()) + } else if path.is_file() { + let mpath = path.clone().with_extension("metadata.json"); + let datafile = File::open(mpath.clone()) + .context(format!("metadata missing, tried path {mpath:?}"))?; + let data: ItemInfo = serde_json::from_reader(datafile).context("invalid metadata")?; + let identifier = path + .with_extension("") + .file_name() + .unwrap() + .to_str() + .unwrap() + .to_string(); + Ok(Node::Item(Arc::new(Item { + lib_path: lib_path.join(identifier.clone()), + data, + identifier, + })) + .into()) + } else { + bail!("did somebody really put a fifo or socket in the library?!") + } + } +} +impl Item { + pub fn path(&self) -> String { + self.lib_path.to_str().unwrap().to_string() + } +} +impl Directory { + pub fn path(&self) -> String { + self.lib_path.to_str().unwrap().to_string() + } + pub fn child_by_ident(&self, i: &str) -> Option> { + self.children + .iter() + .find(|e| e.identifier() == i) + .map(|e| e.to_owned()) + } +} diff --git a/server/src/main.rs b/server/src/main.rs new file mode 100644 index 0000000..b7a3249 --- /dev/null +++ b/server/src/main.rs @@ -0,0 +1,45 @@ +#![feature(box_syntax)] + +use crate::frontend::style::CSS_BUNDLE; +use database::Database; +use frontend::pages::{home::page_home, node::page_library_node}; +use library::Library; +use rocket::{get, http::ContentType, launch, routes}; +use std::fs::read_to_string; + +pub mod database; +pub mod frontend; +pub mod library; +pub mod metadata; + +#[get("/assets/style.css")] +async fn assets_style() -> (ContentType, String) { + ( + ContentType::CSS, + if cfg!(debug_assertions) { + read_to_string("src/frontend/style/layout.css").unwrap() + } else { + CSS_BUNDLE.to_string() + }, + ) +} + +pub struct AppState { + pub database: Database, + pub library: Library, +} + +#[launch] +fn rocket() -> _ { + env_logger::init_from_env("LOG"); + let db_path = std::env::var("DB_PATH").unwrap_or("data/db".to_string()); + let lib_path = std::env::var("LIB_PATH").unwrap_or("data/library".to_string()); + let state = AppState { + library: Library::open(&lib_path).unwrap(), + database: Database::open(&db_path).unwrap(), + }; + + rocket::build() + .manage(state) + .mount("/", routes![page_home, page_library_node, assets_style]) +} diff --git a/server/src/metadata.rs b/server/src/metadata.rs new file mode 100644 index 0000000..ff45af2 --- /dev/null +++ b/server/src/metadata.rs @@ -0,0 +1,11 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct DirectoryInfo { + pub name: String, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ItemInfo { + pub title: String, +} diff --git a/src/database.rs b/src/database.rs deleted file mode 100644 index 3ba8c52..0000000 --- a/src/database.rs +++ /dev/null @@ -1,13 +0,0 @@ -use anyhow::Context; - -#[derive(Debug)] -pub struct Database { - pub db: sled::Db, -} - -impl Database { - pub fn open(path: &str) -> Result { - let db = sled::open(path).context("opening database")?; - Ok(Self { db }) - } -} diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs deleted file mode 100644 index 99c22f8..0000000 --- a/src/frontend/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod style; -pub mod pages; diff --git a/src/frontend/pages/home.rs b/src/frontend/pages/home.rs deleted file mode 100644 index 5076177..0000000 --- a/src/frontend/pages/home.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::frontend::pages::node::NodePage; -use crate::{frontend::pages::HtmlTemplate, AppState}; -use rocket::{get, State}; - -#[get("/")] -pub async fn page_home(state: &State) -> HtmlTemplate { - HtmlTemplate( - "Home".to_string(), - markup::new! { - p { "Welcome to Jellything" } - @NodePage { node: state.library.root.clone() } - }, - ) -} diff --git a/src/frontend/pages/layout.rs b/src/frontend/pages/layout.rs deleted file mode 100644 index 5654d3b..0000000 --- a/src/frontend/pages/layout.rs +++ /dev/null @@ -1,20 +0,0 @@ -use markup::Render; - -markup::define! { - Layout(title: String, main: Main) { - @markup::doctype() - html { - head { - title { @title " - Jellything" } - link[rel="stylesheet", href="/assets/style.css"]; - } - body { - nav { - h1 { "Jellything" } - - } - #main { @main } - } - } - } -} diff --git a/src/frontend/pages/mod.rs b/src/frontend/pages/mod.rs deleted file mode 100644 index a20fa0e..0000000 --- a/src/frontend/pages/mod.rs +++ /dev/null @@ -1,69 +0,0 @@ -use markup::Render; -use rocket::{ - http::ContentType, - response::{self, Responder}, - Request, Response, -}; -use std::{fmt::Display, io::Cursor}; - -use self::layout::Layout; - -pub mod home; -pub mod layout; -pub mod node; - -pub struct HtmlTemplate(pub String, pub T); - -impl<'r, T: Render> Responder<'r, 'static> for HtmlTemplate { - fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> { - let mut out = String::new(); - Layout { - title: self.0, - main: self.1, - } - .render(&mut out) - .unwrap(); - Response::build() - .header(ContentType::HTML) - .streamed_body(Cursor::new(out)) - .ok() - } -} - -#[derive(Debug)] -pub struct MyError(anyhow::Error); - -impl<'r> Responder<'r, 'static> for MyError { - fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> { - let mut out = String::new(); - Layout { - title: "Error".to_string(), - main: markup::new! { - h2 { "An error occured. Nobody is sorry"} - pre.error { @format!("{:?}", self.0) } - }, - } - .render(&mut out) - .unwrap(); - Response::build() - .header(ContentType::HTML) - .streamed_body(Cursor::new(out)) - .ok() - } -} - -impl Display for MyError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.0.fmt(f) - } -} -impl From for MyError { - fn from(err: anyhow::Error) -> MyError { - MyError(err) - } -} -impl From for MyError { - fn from(err: std::fmt::Error) -> MyError { - MyError(anyhow::anyhow!("{err}")) - } -} diff --git a/src/frontend/pages/node.rs b/src/frontend/pages/node.rs deleted file mode 100644 index 7ac4332..0000000 --- a/src/frontend/pages/node.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::{ - frontend::pages::HtmlTemplate, - library::{Directory, Item, Node}, - AppState, -}; -use anyhow::Context; -use rocket::{get, uri, State}; -use std::{ops::Deref, path::PathBuf, sync::Arc}; - -use super::MyError; - -#[get("/library/")] -pub async fn page_library_node( - path: PathBuf, - state: &State, -) -> Result, MyError> { - let path = path.to_str().unwrap().to_string(); - let node = state - .library - .nested(&path) - .context("retrieving library node")? - .clone(); - Ok(HtmlTemplate( - format!("{}", node.title()), - markup::new! { - @NodePage { node: node.clone() } - }, - )) -} - -markup::define! { - NodePage(node: Arc) { - @match node.deref() { - Node::Directory(dir) => { @DirectoryPage { dir: dir.clone() } } - Node::Item(item) => { @ItemPage { item: item.clone() } } - } - } - DirectoryCard(dir: Arc) { - span { a[href=&uri!(page_library_node(&dir.lib_path)).to_string()] { @dir.data.name } } - } - DirectoryPage(dir: Arc) { - h1 { @dir.data.name } - ul.directorylisting { - @for el in &dir.children { - li { - span.title { @match el.deref().to_owned() { - Node::Directory(dir) => { @DirectoryCard { dir } } - Node::Item(item) => { @ItemCard { item } } - }} - } - } - } - } - ItemCard(item: Arc) { - span { a[href=&uri!(page_library_node(&item.lib_path)).to_string()] { @item.data.title } } - } - ItemPage(item: Arc) { - h1 { @item.data.title } - } -} diff --git a/src/frontend/style/layout.css b/src/frontend/style/layout.css deleted file mode 100644 index 4418903..0000000 --- a/src/frontend/style/layout.css +++ /dev/null @@ -1,42 +0,0 @@ -@import url("https://s.metamuffin.org/static/font-ubuntu/include.css"); - -* { - color: white; - font-family: "Ubuntu", sans-serif; - font-weight: 300; - margin: 0px; - padding: 0px; -} - -body { - background-color: #1a1a1a; - width: 100vw; -} - -nav { - position: absolute; - top: 0px; - left: 0px; - padding: 1em; - width: calc(100vw - 2em); - height: 2em; - background-color: #41414144; -} - -nav h1 { - margin: 0px; - font-size: 1.5em; -} - -#main { - margin-top: 5em; - padding: 1em; - padding-left: 3em; - padding-right: 3em; -} - -.error { - padding: 1em; - color: rgb(255, 117, 117); - font-family: monospace; -} diff --git a/src/frontend/style/mod.rs b/src/frontend/style/mod.rs deleted file mode 100644 index 9d0729e..0000000 --- a/src/frontend/style/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ - -pub const CSS_BUNDLE: &'static str = include_str!("layout.css"); diff --git a/src/library.rs b/src/library.rs deleted file mode 100644 index 0c42a73..0000000 --- a/src/library.rs +++ /dev/null @@ -1,141 +0,0 @@ -use crate::metadata::{DirectoryInfo, ItemInfo}; -use anyhow::{anyhow, bail, Context, Ok}; -use std::{ffi::OsStr, fs::File, path::PathBuf, sync::Arc}; - -pub struct Library { - pub root: Arc, -} - -#[derive(Debug, Clone)] -pub enum Node { - Directory(Arc), - Item(Arc), -} - -#[derive(Debug, Clone)] -pub struct Directory { - pub lib_path: PathBuf, - pub identifier: String, - pub data: DirectoryInfo, - pub children: Vec>, -} - -#[derive(Debug, Clone)] -pub struct Item { - pub lib_path: PathBuf, - pub identifier: String, - pub data: ItemInfo, -} - -impl Library { - pub fn open(path: &str) -> anyhow::Result { - Ok(Self { - root: Node::from_path(path.into(), PathBuf::new(), true).context("indexing root")?, - }) - } - pub fn nested(&self, path: &str) -> anyhow::Result> { - let mut n = self.root.clone(); - if path == "" { - return Ok(n); - } - for seg in path.split("/") { - n = n - .get_directory()? - .child_by_ident(seg) - .ok_or(anyhow!("does not exist"))?; - } - Ok(n) - } -} - -impl Node { - pub fn get_directory(&self) -> anyhow::Result<&Directory> { - match self { - Node::Directory(d) => Ok(d), - Node::Item(_) => bail!("not a directory"), - } - } - pub fn title(&self) -> &str { - match self { - 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, - mut lib_path: PathBuf, - root: bool, - ) -> anyhow::Result> { - if path.is_dir() { - let mpath = path.join("directory.json"); - let data: DirectoryInfo = - serde_json::from_reader(File::open(mpath).context("metadata missing")?)?; - - let identifier = path.file_name().unwrap().to_str().unwrap().to_string(); - if !root { - lib_path = lib_path.join(identifier.clone()); - } - - let children = path - .read_dir()? - .map(|e| e.unwrap().path()) - .filter(|e| e.extension() != Some(OsStr::new("json"))) - .map(|e| { - Node::from_path(e.clone(), lib_path.clone(), false) - .context(format!("loading {e:?}")) - }) - .into_iter() - .collect::>>()?; - - Ok(Node::Directory(Arc::new(Directory { - lib_path, - children, - data, - identifier, - })) - .into()) - } else if path.is_file() { - let mpath = path.clone().with_extension("metadata.json"); - let datafile = File::open(mpath.clone()) - .context(format!("metadata missing, tried path {mpath:?}"))?; - let data: ItemInfo = serde_json::from_reader(datafile).context("invalid metadata")?; - let identifier = path - .with_extension("") - .file_name() - .unwrap() - .to_str() - .unwrap() - .to_string(); - Ok(Node::Item(Arc::new(Item { - lib_path: lib_path.join(identifier.clone()), - data, - identifier, - })) - .into()) - } else { - bail!("did somebody really put a fifo or socket in the library?!") - } - } -} -impl Item { - pub fn path(&self) -> String { - self.lib_path.to_str().unwrap().to_string() - } -} -impl Directory { - pub fn path(&self) -> String { - self.lib_path.to_str().unwrap().to_string() - } - pub fn child_by_ident(&self, i: &str) -> Option> { - self.children - .iter() - .find(|e| e.identifier() == i) - .map(|e| e.to_owned()) - } -} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index b7a3249..0000000 --- a/src/main.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![feature(box_syntax)] - -use crate::frontend::style::CSS_BUNDLE; -use database::Database; -use frontend::pages::{home::page_home, node::page_library_node}; -use library::Library; -use rocket::{get, http::ContentType, launch, routes}; -use std::fs::read_to_string; - -pub mod database; -pub mod frontend; -pub mod library; -pub mod metadata; - -#[get("/assets/style.css")] -async fn assets_style() -> (ContentType, String) { - ( - ContentType::CSS, - if cfg!(debug_assertions) { - read_to_string("src/frontend/style/layout.css").unwrap() - } else { - CSS_BUNDLE.to_string() - }, - ) -} - -pub struct AppState { - pub database: Database, - pub library: Library, -} - -#[launch] -fn rocket() -> _ { - env_logger::init_from_env("LOG"); - let db_path = std::env::var("DB_PATH").unwrap_or("data/db".to_string()); - let lib_path = std::env::var("LIB_PATH").unwrap_or("data/library".to_string()); - let state = AppState { - library: Library::open(&lib_path).unwrap(), - database: Database::open(&db_path).unwrap(), - }; - - rocket::build() - .manage(state) - .mount("/", routes![page_home, page_library_node, assets_style]) -} diff --git a/src/metadata.rs b/src/metadata.rs deleted file mode 100644 index ff45af2..0000000 --- a/src/metadata.rs +++ /dev/null @@ -1,11 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct DirectoryInfo { - pub name: String, -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct ItemInfo { - pub title: String, -} -- cgit v1.2.3-70-g09d2