use std::error::Error; use std::net::SocketAddr; use std::path::PathBuf; use prometheus::Encoder; use serde::Deserialize; use warp; use warp::http::header::{HeaderMap, HeaderValue}; use warp::reject::Rejection; use warp::Filter; use crate::library::Library; fn metrics() -> impl Filter + Clone { let mut text_headers = HeaderMap::new(); text_headers.insert("content-type", HeaderValue::from_static("text/plain")); warp::path("metrics") .map(|| { 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() buffer }) .with(warp::reply::with::headers(text_headers)) } fn index() -> Result { Ok("Hello world") } fn album(lib: Library, id: String) -> Result { Ok(format!("Hello world: {}", id)) } #[derive(Debug, Deserialize)] struct ImageParams { w: Option, h: Option, c: Option, } fn image( lib: Library, image_id: String, params: ImageParams, ) -> Result { Ok(format!("Hello world: {} {:?}", image_id, params)) } pub fn run(addr: SocketAddr, root: PathBuf) -> Result<(), Box> { let lib = Library::new(root)?; let lib = warp::any().map(move || lib.clone()); let index = warp::path::end().and_then(index); let album = warp::path("album") .and(lib.clone()) .and(warp::path::param()) .and_then(album); let image = warp::path("image") .and(lib.clone()) .and(warp::path::param()) .and(warp::query::()) .and_then(image); let api = album.or(image); let api = warp::path("api").and(api); // Fallback, always keep this last. let api = api.or(index); let api = api.with(warp::log("photosync")); // We don't want metrics & heath checking filling up the logs, so we add this handler after // wrapping with the log filter. let routes = metrics().or(api); warp::serve(routes).run(addr); Ok(()) }