diff --git a/Cargo.lock b/Cargo.lock index 326de74..ebebcee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -733,6 +733,18 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "348138dd23e03bb0018caef99647fb1a5befec5ff4b501991de88f09854d4c28" +[[package]] +name = "filetime" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "affc17579b132fc2461adf7c575cc6e8b134ebca52c51f5411388965227dc695" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "winapi 0.3.8", +] + [[package]] name = "fnv" version = "1.0.6" @@ -781,6 +793,25 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61f9b85573bf0f203eed3633f5018abce85250886a62ca073e0eee022ed564d" +[[package]] +name = "fsevent" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" +dependencies = [ + "bitflags", + "fsevent-sys", +] + +[[package]] +name = "fsevent-sys" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" +dependencies = [ + "libc", +] + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -1366,6 +1397,26 @@ dependencies = [ "adler32", ] +[[package]] +name = "inotify" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" +dependencies = [ + "bitflags", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" +dependencies = [ + "libc", +] + [[package]] name = "input_buffer" version = "0.2.0" @@ -1455,6 +1506,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" + [[package]] name = "lcms2" version = "5.1.5" @@ -1660,6 +1717,18 @@ dependencies = [ "winapi 0.2.8", ] +[[package]] +name = "mio-extras" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" +dependencies = [ + "lazycell", + "log 0.4.8", + "mio", + "slab", +] + [[package]] name = "mio-named-pipes" version = "0.1.6" @@ -1801,6 +1870,24 @@ dependencies = [ "version_check 0.1.5", ] +[[package]] +name = "notify" +version = "4.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80ae4a7688d1fab81c5bf19c64fc8db920be8d519ce6336ed4e7efe024724dbd" +dependencies = [ + "bitflags", + "filetime", + "fsevent", + "fsevent-sys", + "inotify", + "libc", + "mio", + "mio-extras", + "walkdir", + "winapi 0.3.8", +] + [[package]] name = "num-integer" version = "0.1.42" @@ -2028,6 +2115,7 @@ dependencies = [ "regex", "reqwest", "rocket", + "rocket_contrib", "rocksdb", "rust-embed", "serde", @@ -2595,6 +2683,19 @@ dependencies = [ "yansi", ] +[[package]] +name = "rocket_contrib" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3946ca815127041d8f64455561031d058c22ae1b135251502c5ea523cf9e14b" +dependencies = [ + "log 0.4.8", + "notify", + "rocket", + "serde", + "serde_json", +] + [[package]] name = "rocket_http" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index 79cd77d..5e40965 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,3 +47,8 @@ harness = false # Build dependencies with release optimizations even in dev mode. [profile.dev.package."*"] opt-level = 3 + +[dependencies.rocket_contrib] +version = "0.4.5" +default-features = false +features = ["json"] diff --git a/src/rweb.rs b/src/rweb.rs index 1902692..b6204c6 100644 --- a/src/rweb.rs +++ b/src/rweb.rs @@ -1,23 +1,106 @@ use std::error::Error; +use std::io::Write; use std::net::SocketAddr; use std::path::PathBuf; use cacher::Cacher; +use google_photoslibrary1 as photos; +use log::error; +use photos::schemas::{Album, MediaItem}; +use prometheus::Encoder; +use rocket::error::LaunchError; use rocket::http::ContentType; use rocket::response::content::Html; use rocket::response::status::NotFound; use rocket::response::Content; use rocket::{Request, State}; +use rocket_contrib::json::Json; use rust_embed::RustEmbed; +use serde::Deserialize; use crate::library::Library; +#[get("/metrics")] +fn metrics() -> Content> { + let mut buffer = Vec::new(); + let encoder = prometheus::TextEncoder::new(); + + // Gather the metrics. + let metric_families = prometheus::gather(); + // Encode them to send. + encoder.encode(&metric_families, &mut buffer).unwrap(); + // TODO(wathiede): see if there's a wrapper like html() + Content(ContentType::Plain, buffer) +} + +#[get("/")] +fn index(lib: State) -> Result>, NotFound> { + file("index.html", lib) +} + +#[get("/")] +fn path(path: PathBuf, lib: State) -> Result>, NotFound> { + let path = path.to_str().unwrap(); + let path = if path.ends_with("/") { + format!("{}index.html", path.to_string()) + } else { + path.to_string() + }; + file(&path, lib) +} + +fn file(path: &str, lib: State) -> Result>, NotFound> { + match Asset::get(path) { + Some(bytes) => { + let mime = mime_guess::from_path(path).first_or_octet_stream(); + let ct = ContentType::parse_flexible(mime.essence_str()).unwrap_or(ContentType::Binary); + + Ok(Content(ct, bytes.into())) + } + None => Err(NotFound(path.to_string())), + } +} + +#[get("/api/albums")] +fn albums(lib: State) -> Result>, NotFound> { + let albums = lib + .albums() + .map_err(|e| NotFound(format!("Couldn't find albums: {}", e)))?; + Ok(Json(albums)) +} + +#[get("/api/album/")] +fn album(id: String, lib: State) -> Result>, NotFound> { + let album = lib + .album(&id) + .map_err(|e| NotFound(format!("Couldn't find album {}: {}", id, e)))?; + Ok(Json(album)) +} + +#[get("/api/image/?&&")] +fn image( + media_items_id: String, + w: Option, + h: Option, + fill: Option, + lib: State, +) -> Result>, NotFound> { + // TODO(wathiede): add caching headers. + match lib.thumbnail(&media_items_id, (w, h), fill.unwrap_or(false)) { + None => Err(NotFound(format!( + "Couldn't find original {}", + &media_items_id + ))), + Some(bytes) => Ok(Content(ContentType::JPEG, bytes.into())), + } +} + #[derive(RustEmbed)] #[folder = "react-slideshow/build/"] struct Asset; -/* -fn embedz() -> Result { +#[get("/embedz")] +fn embedz() -> Content> { let mut w = Vec::new(); write!( w, @@ -33,47 +116,26 @@ fn embedz() -> Result { ) .unwrap(); } - Ok(warp::http::Response::builder() - .header("Content-Type", "text/html") - .body(w)) -} -*/ - -#[get("/")] -fn index(lib: State) -> Result>, NotFound> { - dbg!("index called"); - file("index.html", lib) -} - -#[get("/")] -fn path(path: PathBuf, lib: State) -> Result>, NotFound> { - dbg!(&path); - let path = path.to_str().unwrap(); - let path = if path.ends_with("/") { - format!("{}index.html", path.to_string()) - } else { - path.to_string() - }; - file(&path, lib) -} - -fn file(path: &str, lib: State) -> Result>, NotFound> { - match Asset::get(path) { - Some(bytes) => { - dbg!(path); - let mime = mime_guess::from_path(path).first_or_octet_stream(); - let ct = ContentType::parse_flexible(mime.essence_str()).unwrap_or(ContentType::Binary); - - Ok(Content(ct, bytes.into())) - } - None => Err(NotFound(path.to_string())), - } + Content(ContentType::HTML, w) } pub fn run(addr: SocketAddr, lib: Library) -> Result<(), Box> { - rocket::ignite() + let e = rocket::ignite() .manage(lib) - .mount("/", routes![index, path]) + .mount( + "/", + routes![album, albums, image, embedz, metrics, index, path], + ) .launch(); - Ok(()) + match e.kind() { + rocket::error::LaunchErrorKind::Collision(v) => { + error!("Route collisions:"); + for (r1, r2) in v { + error!(" R1 {}", r1); + error!(" R2 {}", r2); + } + } + _ => (), + }; + return Err(e.into()); }