use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::error::Error; use std::sync; use warp::Filter; use crate::domain; pub mod http_tpl; /* * POST /domain/config (domain, config, secret, init?) -> token? * GET /domain/config (domain) -> config * GET /domains */ type Handlebars<'a> = sync::Arc>; struct RenderContext<'a> { handlebars: Handlebars<'a>, query_args: HashMap, } // TODO make this use an io::Write, rather than warp::Reply fn render<'a, T>(handlebars: Handlebars<'a>, name: &'a str, value: T) -> impl warp::Reply where T: Serialize, { // TODO deal with 404 let render = handlebars .render(name, &value) .unwrap_or_else(|err| err.to_string()); let content_type = mime_guess::from_path(name) .first_or_octet_stream() .to_string(); let reply = warp::reply::html(render); warp::reply::with_header(reply, "Content-Type", content_type) } fn render_page<'a, T>(render_ctx: RenderContext<'a>, name: String, data: T) -> impl warp::Reply where T: Serialize, { #[derive(Serialize)] struct Presenter { page_name: String, query_args: HashMap, data: T, } let presenter = Presenter { page_name: name, query_args: render_ctx.query_args, data, }; render(render_ctx.handlebars, "/base.html", presenter) } pub fn new( _manager: impl domain::manager::Manager, ) -> Result< impl warp::Filter + Clone, Box, > { let hbs = sync::Arc::new(self::http_tpl::get()?); let with_render_ctx = warp::any() .and(warp::query::>()) .map(move |query_args: HashMap| RenderContext { handlebars: hbs.clone(), query_args, }); let static_dir = warp::get() .and(with_render_ctx.clone()) .and(warp::path("static")) .and(warp::path::full()) .map( |render_ctx: RenderContext<'_>, full: warp::path::FullPath| { render(render_ctx.handlebars, full.as_str(), ()) }, ); let index = warp::get() .and(with_render_ctx.clone()) .and(warp::path::end()) .map(|render_ctx: RenderContext<'_>| { render_page(render_ctx, String::from("/index.html"), ()) }); #[derive(Deserialize)] struct DomainGetNewRequest { domain: String, } let domain_get = warp::get() .and(with_render_ctx.clone()) .and(warp::path("domain.html")) .and(warp::query::()) .map(|render_ctx: RenderContext<'_>, req: DomainGetNewRequest| { #[derive(Serialize)] struct DomainGetNewResponse { domain: String, } render_page( render_ctx, String::from("/domain_get_new.html"), DomainGetNewResponse { domain: req.domain }, ) }); Ok(static_dir.or(index).or(domain_get)) }