diff options
author | metamuffin <metamuffin@disroot.org> | 2023-01-10 08:44:06 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2023-01-10 08:44:06 +0100 |
commit | 0c30e065b678d41d8932b3bf0926608cfa15a7ac (patch) | |
tree | 0dd1c03c25ed49b97985d840790b108f2d4fe967 /src | |
parent | c64d3cd8cda389909b4b3dbdf00c0710e2c9a490 (diff) | |
download | jellything-0c30e065b678d41d8932b3bf0926608cfa15a7ac.tar jellything-0c30e065b678d41d8932b3bf0926608cfa15a7ac.tar.bz2 jellything-0c30e065b678d41d8932b3bf0926608cfa15a7ac.tar.zst |
first listing
Diffstat (limited to 'src')
-rw-r--r-- | src/frontend/pages/home.rs | 4 | ||||
-rw-r--r-- | src/frontend/pages/layout.rs | 10 | ||||
-rw-r--r-- | src/frontend/pages/mod.rs | 61 | ||||
-rw-r--r-- | src/frontend/pages/node.rs | 46 | ||||
-rw-r--r-- | src/frontend/style/layout.css | 35 | ||||
-rw-r--r-- | src/frontend/style/master.css | 0 | ||||
-rw-r--r-- | src/frontend/style/mod.rs | 2 | ||||
-rw-r--r-- | src/library.rs | 91 | ||||
-rw-r--r-- | src/main.rs | 28 |
9 files changed, 250 insertions, 27 deletions
diff --git a/src/frontend/pages/home.rs b/src/frontend/pages/home.rs index a694c3c..bb0eb59 100644 --- a/src/frontend/pages/home.rs +++ b/src/frontend/pages/home.rs @@ -5,9 +5,9 @@ use crate::{ use actix_web::{get, web::Data, Responder}; #[get("/")] -async fn page_home(state: Data<AppState>) -> impl Responder { +pub async fn page_home(state: Data<AppState>) -> impl Responder { HtmlTemplate(Layout { - title: "Home - Jellything", + title: String::from("Home"), main: markup::new! { h1 { "It works!" } }, diff --git a/src/frontend/pages/layout.rs b/src/frontend/pages/layout.rs index e02336d..5654d3b 100644 --- a/src/frontend/pages/layout.rs +++ b/src/frontend/pages/layout.rs @@ -1,17 +1,19 @@ use markup::Render; markup::define! { - Layout<'a, Main: Render>(title: &'a str, main: Main) { + Layout<Main: Render>(title: String, main: Main) { @markup::doctype() html { head { - title { @title } + title { @title " - Jellything" } link[rel="stylesheet", href="/assets/style.css"]; } body { - header { "Grain" } + nav { + h1 { "Jellything" } + + } #main { @main } - footer { span { "jellything" } } } } } diff --git a/src/frontend/pages/mod.rs b/src/frontend/pages/mod.rs index 08e0e77..6e7bd87 100644 --- a/src/frontend/pages/mod.rs +++ b/src/frontend/pages/mod.rs @@ -1,7 +1,17 @@ -use actix_web::{body::BoxBody, http::StatusCode, HttpResponseBuilder, Responder}; +use std::{error::Error, fmt::Display}; + +use actix_web::{ + body::BoxBody, + http::{ + header::{HeaderName, HeaderValue}, + StatusCode, + }, + HttpResponseBuilder, Responder, +}; pub mod home; pub mod layout; +pub mod node; struct HtmlTemplate<T>(pub T); @@ -17,3 +27,52 @@ impl<T: markup::Render> Responder for HtmlTemplate<T> { .respond_to(req) } } + +pub struct ContentType<T>(pub &'static str, pub T); + +impl<T: Responder> Responder for ContentType<T> { + type Body = T::Body; + + fn respond_to(self, req: &actix_web::HttpRequest) -> actix_web::HttpResponse<Self::Body> { + let mut r = self.1.respond_to(req); + r.headers_mut().insert( + HeaderName::from_static("content-type"), + HeaderValue::from_static(self.0), + ); + r + } +} + +pub type MyResult<T> = actix_web::Result<T, MyError>; + +#[derive(Debug)] +pub struct MyError(anyhow::Error); + +impl Responder for MyError { + type Body = BoxBody; + fn respond_to(self, req: &actix_web::HttpRequest) -> actix_web::HttpResponse<Self::Body> { + HttpResponseBuilder::new(StatusCode::BAD_REQUEST) + .body(format!("error: {}", self.0)) + .respond_to(req) + } +} +impl actix_web::error::ResponseError for MyError { + fn status_code(&self) -> StatusCode { + StatusCode::BAD_REQUEST + } +} +impl Display for MyError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} +impl From<anyhow::Error> for MyError { + fn from(err: anyhow::Error) -> MyError { + MyError(err) + } +} +impl From<std::fmt::Error> 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 new file mode 100644 index 0000000..c3f7791 --- /dev/null +++ b/src/frontend/pages/node.rs @@ -0,0 +1,46 @@ +use super::layout::Layout; +use crate::{ + frontend::pages::{HtmlTemplate, MyError, MyResult}, + library::{LibDirectory, LibItem, LibNode}, + AppState, +}; +use actix_web::{get, web, Responder}; +use actix_web_lab::respond::Html; +use log::debug; +use markup::Render; +use std::{ops::Deref, sync::Arc}; + +#[get("/library/{path:.*}")] +pub async fn page_library_node( + state: web::Data<AppState>, + params: web::Path<(String,)>, +) -> MyResult<impl Responder> { + debug!("request: {:?}", params.0); + let node = state.library.nested(¶ms.0)?; + let mut out = String::new(); + match node.deref() { + LibNode::Directory(dir) => Layout { + title: format!( + "{} - Library", + dir.path.file_name().unwrap().to_str().unwrap() + ), + main: Directory { dir: dir.clone() }, + } + .render(&mut out)?, + LibNode::Item(item) => Layout { + title: "".to_string(), + main: Item { item: item.clone() }, + } + .render(&mut out)?, + }; + Ok(Html(out)) +} + +markup::define! { + Directory(dir: Arc<LibDirectory>) { + h1 { @dir.data.name } + } + Item(item: Arc<LibItem>) { + h1 { "thats an item" } + } +} diff --git a/src/frontend/style/layout.css b/src/frontend/style/layout.css new file mode 100644 index 0000000..d6196b0 --- /dev/null +++ b/src/frontend/style/layout.css @@ -0,0 +1,35 @@ +@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; +} + +nav { + position: absolute; + top: 0px; + left: 0px; + padding: 1em; + width: 100vw; + 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; +} diff --git a/src/frontend/style/master.css b/src/frontend/style/master.css deleted file mode 100644 index e69de29..0000000 --- a/src/frontend/style/master.css +++ /dev/null diff --git a/src/frontend/style/mod.rs b/src/frontend/style/mod.rs index 180fe0e..9d0729e 100644 --- a/src/frontend/style/mod.rs +++ b/src/frontend/style/mod.rs @@ -1,2 +1,2 @@ -pub const CSS_BUNDLE: &'static str = include_str!("master.css"); +pub const CSS_BUNDLE: &'static str = include_str!("layout.css"); diff --git a/src/library.rs b/src/library.rs index 576ed77..e4c7fe6 100644 --- a/src/library.rs +++ b/src/library.rs @@ -1,23 +1,96 @@ -use anyhow::Ok; +use std::{fs::File, path::PathBuf, str::FromStr, sync::Arc}; + +use anyhow::{bail, Context, Ok}; +use chashmap::CHashMap; +use serde::{Deserialize, Serialize}; pub struct Library { - path: String, - tree: LibNode, + path: PathBuf, + cache: CHashMap<String, LibNode>, // TODO } +#[derive(Debug, Clone)] pub enum LibNode { - Directory(LibDirectory), - Item(LibItem), + Directory(Arc<LibDirectory>), + Item(Arc<LibItem>), +} + +#[derive(Debug, Clone)] +pub struct LibDirectory { + pub path: PathBuf, + pub child_nodes: Vec<PathBuf>, + pub data: LibDirectoryData, +} + +#[derive(Debug, Clone)] +pub struct LibItem { + pub data: LibItemData, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct LibDirectoryData { + pub name: String, } -pub struct LibDirectory {} -pub struct LibItem {} +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct LibItemData {} impl Library { pub fn open(path: &str) -> anyhow::Result<Self> { Ok(Self { - path: path.to_string(), - tree: , + path: PathBuf::from_str(path).unwrap(), + cache: CHashMap::new(), }) } + 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()?; + if path == "" { + return Ok(n); + } + for seg in path.split("/") { + n = n.get_directory()?.get_child(seg)? + } + Ok(n) + } +} +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) + } +} +impl LibNode { + pub fn get_directory(&self) -> anyhow::Result<&LibDirectory> { + match self { + LibNode::Directory(d) => Ok(d), + LibNode::Item(_) => bail!("not a directory"), + } + } + pub fn from_path(path: PathBuf) -> anyhow::Result<Arc<LibNode>> { + if path.is_dir() { + let mpath = path.join("directory.json"); + let data: LibDirectoryData = + serde_json::from_reader(File::open(mpath).context("metadata missing")?)?; + let child_nodes = path.read_dir()?.map(|e| e.unwrap().path()).collect(); + Ok(LibNode::Directory(Arc::new(LibDirectory { + path, + child_nodes, + data, + })) + .into()) + } else if path.is_file() { + let mpath = path.clone().with_extension(".metadata.json"); + let data: LibItemData = serde_json::from_reader(File::open(mpath)?)?; + Ok(LibNode::Item(Arc::new(LibItem { data })).into()) + } else { + bail!("did somebody really put a fifo or socket in the library?!") + } + } } diff --git a/src/main.rs b/src/main.rs index f400920..39a4a5a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,12 @@ -use crate::frontend::style::CSS_BUNDLE; +#![feature(box_syntax)] + +use std::fs::read_to_string; + +use crate::frontend::{pages::ContentType, style::CSS_BUNDLE}; use actix_web::{get, web, App, HttpServer, Responder}; use database::Database; -use frontend::pages::home::page_home; +use frontend::pages::{home::page_home, node::page_library_node}; +use library::Library; pub mod database; pub mod frontend; @@ -9,30 +14,33 @@ pub mod library; #[get("/assets/style.css")] async fn assets_style() -> impl Responder { - CSS_BUNDLE -} - -#[get("/{name}")] -async fn hello(name: web::Path<String>) -> impl Responder { - format!("Hello {}!", &name) + // ContentType("text/css", CSS_BUNDLE) + ContentType( + "text/css", + read_to_string("src/frontend/style/layout.css").unwrap(), + ) } pub struct AppState { pub database: Database, + pub library: Library, } #[actix_web::main] async fn main() -> std::io::Result<()> { 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 = web::Data::new(AppState { - database: Database::open(&db_path).unwrap().into(), + library: Library::open(&lib_path).unwrap(), + database: Database::open(&db_path).unwrap(), }); HttpServer::new(move || { App::new() .app_data(state.clone()) .service(page_home) - .service(hello) + .service(assets_style) + .service(page_library_node) }) .bind(("127.0.0.1", 8080))? .run() |