Rocket based webserver now has parity with warp version.

This commit is contained in:
2020-06-20 14:36:00 -07:00
parent 80ef93f20f
commit 76594dc0c1
3 changed files with 208 additions and 40 deletions

View File

@@ -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<Vec<u8>> {
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<Library>) -> Result<Content<Vec<u8>>, NotFound<String>> {
file("index.html", lib)
}
#[get("/<path..>")]
fn path(path: PathBuf, lib: State<Library>) -> Result<Content<Vec<u8>>, NotFound<String>> {
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<Library>) -> Result<Content<Vec<u8>>, NotFound<String>> {
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<Library>) -> Result<Json<Vec<Album>>, NotFound<String>> {
let albums = lib
.albums()
.map_err(|e| NotFound(format!("Couldn't find albums: {}", e)))?;
Ok(Json(albums))
}
#[get("/api/album/<id>")]
fn album(id: String, lib: State<Library>) -> Result<Json<Vec<MediaItem>>, NotFound<String>> {
let album = lib
.album(&id)
.map_err(|e| NotFound(format!("Couldn't find album {}: {}", id, e)))?;
Ok(Json(album))
}
#[get("/api/image/<media_items_id>?<w>&<h>&<fill>")]
fn image(
media_items_id: String,
w: Option<u32>,
h: Option<u32>,
fill: Option<bool>,
lib: State<Library>,
) -> Result<Content<Vec<u8>>, NotFound<String>> {
// 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<impl warp::Reply, warp::Rejection> {
#[get("/embedz")]
fn embedz() -> Content<Vec<u8>> {
let mut w = Vec::new();
write!(
w,
@@ -33,47 +116,26 @@ fn embedz() -> Result<impl warp::Reply, warp::Rejection> {
)
.unwrap();
}
Ok(warp::http::Response::builder()
.header("Content-Type", "text/html")
.body(w))
}
*/
#[get("/")]
fn index(lib: State<Library>) -> Result<Content<Vec<u8>>, NotFound<String>> {
dbg!("index called");
file("index.html", lib)
}
#[get("/<path..>")]
fn path(path: PathBuf, lib: State<Library>) -> Result<Content<Vec<u8>>, NotFound<String>> {
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<Library>) -> Result<Content<Vec<u8>>, NotFound<String>> {
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<dyn Error>> {
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());
}