use std::{convert::Infallible, net::SocketAddr, sync::Arc}; use warp::{hyper::StatusCode, Filter, Rejection, Reply}; use crate::{dimension::Dimension, render::Renderer, tiling::Tiler}; pub fn serve_http(dimension: Dimension, bind: SocketAddr) { tokio::runtime::Builder::new_multi_thread() .enable_all() .build() .unwrap() .block_on(async move { let renderer = Renderer::new(dimension); let tiler = Arc::new(Tiler::new(renderer)); let tiler: _ = warp::any().map(move || tiler.clone()); let tiles = warp::path!("tiles" / isize / isize / isize) .and(tiler.clone()) .and_then(|z, x, y, tiler: Arc| async move { Ok::<_, Infallible>(warp::reply::with_header( tiler.get_tile(z, x, y), // TODO consider using tokio::spawn_blocking so we dont block the event loop "content-type", "image/png", )) }); let viewer_html: _ = warp::path!().and(warp::fs::file("./src/viewer/viewer.html")); let viewer_js: _ = warp::path!("viewer.js").and(warp::fs::file("./src/viewer/viewer.js")); let router: _ = tiles .or(viewer_html) .or(viewer_js) .recover(handle_rejection); warp::serve(router).run(bind).await; }) } async fn handle_rejection(err: Rejection) -> Result { let code; let message; if err.is_not_found() { code = StatusCode::NOT_FOUND; message = "Not found"; } else if let Some(_) = err.find::() { code = StatusCode::METHOD_NOT_ALLOWED; message = "Method not allowed"; } else { eprintln!("unhandled rejection: {:?}", err); code = StatusCode::INTERNAL_SERVER_ERROR; message = "Unhandled rejection :("; } Ok(warp::reply::with_status(message, code)) }