refactor renderer in service
This commit is contained in:
parent
50d450eb2c
commit
f3394acaf1
242
src/service.rs
242
src/service.rs
@ -9,15 +9,9 @@ use crate::domain;
|
||||
pub mod http_tpl;
|
||||
mod util;
|
||||
|
||||
/*
|
||||
* POST /domain/config (domain, config, secret, init?) -> token?
|
||||
* GET /domain/config (domain) -> config
|
||||
* GET /domains
|
||||
*/
|
||||
|
||||
type Handlebars<'a> = sync::Arc<handlebars::Handlebars<'a>>;
|
||||
|
||||
struct RenderContext<'a, DM>
|
||||
struct Renderer<'a, DM>
|
||||
where
|
||||
DM: domain::manager::Manager,
|
||||
{
|
||||
@ -29,80 +23,78 @@ where
|
||||
query_args: HashMap<String, String>,
|
||||
}
|
||||
|
||||
// TODO make this use an io::Write, rather than warp::Reply
|
||||
fn render<'a, T>(handlebars: Handlebars<'a>, name: &'a str, value: T) -> Box<dyn warp::Reply>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let rendered = match handlebars.render(name, &value) {
|
||||
Ok(res) => res,
|
||||
Err(handlebars::RenderError {
|
||||
template_name: None,
|
||||
..
|
||||
}) => return render_error_page(handlebars, 404, "Static asset not found".to_string()),
|
||||
Err(err) => return render_error_page(handlebars, 500, format!("template error: {err}")),
|
||||
};
|
||||
|
||||
let content_type = mime_guess::from_path(name)
|
||||
.first_or_octet_stream()
|
||||
.to_string();
|
||||
|
||||
let reply = warp::reply::html(rendered);
|
||||
|
||||
Box::from(warp::reply::with_header(
|
||||
reply,
|
||||
"Content-Type",
|
||||
content_type,
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct BasePresenter<T> {
|
||||
page_name: String,
|
||||
query_args: HashMap<String, String>,
|
||||
data: T,
|
||||
struct BasePresenter<'a, T> {
|
||||
page_name: &'a str,
|
||||
query_args: &'a HashMap<String, String>,
|
||||
data: &'a T,
|
||||
}
|
||||
|
||||
fn render_error_page<'a>(
|
||||
handlebars: Handlebars<'a>,
|
||||
status_code: u16,
|
||||
e: String,
|
||||
) -> Box<dyn warp::Reply> {
|
||||
#[derive(Serialize)]
|
||||
struct Response {
|
||||
error_msg: String,
|
||||
}
|
||||
|
||||
Box::from(warp::reply::with_status(
|
||||
render(
|
||||
handlebars,
|
||||
"/base.html",
|
||||
BasePresenter {
|
||||
page_name: "/error.html".to_string(),
|
||||
query_args: HashMap::default(),
|
||||
data: Response { error_msg: e },
|
||||
},
|
||||
),
|
||||
status_code.try_into().unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
fn render_page<'a, T, DM>(
|
||||
render_ctx: RenderContext<'a, DM>,
|
||||
name: String,
|
||||
data: T,
|
||||
) -> Box<dyn warp::Reply>
|
||||
impl<'a, DM> Renderer<'a, DM>
|
||||
where
|
||||
T: Serialize,
|
||||
DM: domain::manager::Manager,
|
||||
{
|
||||
let presenter = BasePresenter {
|
||||
page_name: name,
|
||||
query_args: render_ctx.query_args,
|
||||
data,
|
||||
};
|
||||
// TODO make this use an io::Write, rather than warp::Reply
|
||||
fn render<T>(&self, name: &'_ str, value: &'_ T) -> Box<dyn warp::Reply>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let rendered = match self.handlebars.render(name, value) {
|
||||
Ok(res) => res,
|
||||
Err(handlebars::RenderError {
|
||||
template_name: None,
|
||||
..
|
||||
}) => return self.render_error_page(404, "Static asset not found"),
|
||||
Err(err) => {
|
||||
return self.render_error_page(500, format!("template error: {err}").as_str())
|
||||
}
|
||||
};
|
||||
|
||||
render(render_ctx.handlebars, "/base.html", presenter)
|
||||
let content_type = mime_guess::from_path(name)
|
||||
.first_or_octet_stream()
|
||||
.to_string();
|
||||
|
||||
let reply = warp::reply::html(rendered);
|
||||
|
||||
Box::from(warp::reply::with_header(
|
||||
reply,
|
||||
"Content-Type",
|
||||
content_type,
|
||||
))
|
||||
}
|
||||
|
||||
fn render_error_page(&self, status_code: u16, e: &'_ str) -> Box<dyn warp::Reply> {
|
||||
#[derive(Serialize)]
|
||||
struct Response<'a> {
|
||||
error_msg: &'a str,
|
||||
}
|
||||
|
||||
Box::from(warp::reply::with_status(
|
||||
self.render(
|
||||
"/base.html",
|
||||
&BasePresenter {
|
||||
page_name: "/error.html",
|
||||
query_args: &HashMap::default(),
|
||||
data: &Response { error_msg: e },
|
||||
},
|
||||
),
|
||||
status_code.try_into().unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
fn render_page<T>(&self, name: &'_ str, data: &'_ T) -> Box<dyn warp::Reply>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.render(
|
||||
"/base.html",
|
||||
&BasePresenter {
|
||||
page_name: name,
|
||||
query_args: &self.query_args,
|
||||
data,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new<DM>(
|
||||
@ -121,9 +113,9 @@ where
|
||||
let passphrase = sync::Arc::new(passphrase);
|
||||
|
||||
let hbs = sync::Arc::new(self::http_tpl::get()?);
|
||||
let with_render_ctx = warp::any()
|
||||
let with_renderer = warp::any()
|
||||
.and(warp::query::<HashMap<String, String>>())
|
||||
.map(move |query_args: HashMap<String, String>| RenderContext {
|
||||
.map(move |query_args: HashMap<String, String>| Renderer {
|
||||
domain_manager: manager.clone(),
|
||||
target_cname: target_cname.clone(),
|
||||
passphrase: passphrase.clone(),
|
||||
@ -132,21 +124,17 @@ where
|
||||
});
|
||||
|
||||
let static_dir = warp::get()
|
||||
.and(with_render_ctx.clone())
|
||||
.and(with_renderer.clone())
|
||||
.and(warp::path("static"))
|
||||
.and(warp::path::full())
|
||||
.map(
|
||||
|render_ctx: RenderContext<'_, DM>, full: warp::path::FullPath| {
|
||||
render(render_ctx.handlebars, full.as_str(), ())
|
||||
},
|
||||
);
|
||||
.map(|renderer: Renderer<'_, DM>, full: warp::path::FullPath| {
|
||||
renderer.render(full.as_str(), &())
|
||||
});
|
||||
|
||||
let index = warp::get()
|
||||
.and(with_render_ctx.clone())
|
||||
.and(with_renderer.clone())
|
||||
.and(warp::path::end())
|
||||
.map(|render_ctx: RenderContext<'_, DM>| {
|
||||
render_page(render_ctx, String::from("/index.html"), ())
|
||||
});
|
||||
.map(|renderer: Renderer<'_, DM>| renderer.render_page("/index.html", &()));
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct DomainGetNewRequest {
|
||||
@ -160,46 +148,40 @@ where
|
||||
}
|
||||
|
||||
let domain_get = warp::get()
|
||||
.and(with_render_ctx.clone())
|
||||
.and(with_renderer.clone())
|
||||
.and(warp::path!("domain.html"))
|
||||
.and(warp::query::<DomainGetNewRequest>())
|
||||
.and(warp::query::<util::ConfigFromURL>())
|
||||
.map(
|
||||
|render_ctx: RenderContext<'_, DM>,
|
||||
|renderer: Renderer<'_, DM>,
|
||||
req: DomainGetNewRequest,
|
||||
domain_config: util::ConfigFromURL| {
|
||||
match render_ctx.domain_manager.get_config(&req.domain) {
|
||||
Ok(_config) => render_error_page(
|
||||
render_ctx.handlebars,
|
||||
500,
|
||||
"TODO not yet implemented".to_string(),
|
||||
),
|
||||
match renderer.domain_manager.get_config(&req.domain) {
|
||||
Ok(_config) => renderer.render_error_page(500, "TODO not yet implemented"),
|
||||
Err(domain::manager::GetConfigError::NotFound) => {
|
||||
let domain_config = match domain_config.try_into() {
|
||||
Ok(domain_config) => domain_config,
|
||||
Err(e) => {
|
||||
return render_error_page(
|
||||
render_ctx.handlebars,
|
||||
return renderer.render_error_page(
|
||||
400,
|
||||
format!("parsing domain configuration: {}", e),
|
||||
format!("parsing domain configuration: {}", e).as_str(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
render_page(
|
||||
render_ctx,
|
||||
String::from("/domain_get_new.html"),
|
||||
DomainGetNewResponse {
|
||||
renderer.render_page(
|
||||
"/domain_get_new.html",
|
||||
&DomainGetNewResponse {
|
||||
domain: req.domain,
|
||||
config: domain_config,
|
||||
},
|
||||
)
|
||||
}
|
||||
Err(domain::manager::GetConfigError::Unexpected(e)) => render_error_page(
|
||||
render_ctx.handlebars,
|
||||
500,
|
||||
format!("retrieving configuration: {}", e),
|
||||
),
|
||||
Err(domain::manager::GetConfigError::Unexpected(e)) => renderer
|
||||
.render_error_page(
|
||||
500,
|
||||
format!("retrieving configuration: {}", e).as_str(),
|
||||
),
|
||||
}
|
||||
},
|
||||
);
|
||||
@ -212,20 +194,16 @@ where
|
||||
}
|
||||
|
||||
let domain_post = warp::post()
|
||||
.and(with_render_ctx.clone())
|
||||
.and(with_renderer.clone())
|
||||
.and(warp::path!("domain.html"))
|
||||
.and(warp::query::<DomainPostRequest>())
|
||||
.and(warp::query::<util::ConfigFromURL>())
|
||||
.map(
|
||||
|render_ctx: RenderContext<'_, DM>,
|
||||
|renderer: Renderer<'_, DM>,
|
||||
req: DomainPostRequest,
|
||||
domain_config: util::ConfigFromURL| {
|
||||
if req.passphrase != render_ctx.passphrase.as_str() {
|
||||
return render_error_page(
|
||||
render_ctx.handlebars,
|
||||
401,
|
||||
"Incorrect passphrase".to_string(),
|
||||
);
|
||||
if req.passphrase != renderer.passphrase.as_str() {
|
||||
return renderer.render_error_page(401, "Incorrect passphrase");
|
||||
}
|
||||
|
||||
//if req.init {
|
||||
@ -240,38 +218,29 @@ where
|
||||
let config: domain::config::Config = match domain_config.try_into() {
|
||||
Ok(Some(config)) => config,
|
||||
Ok(None) => {
|
||||
return render_error_page(
|
||||
render_ctx.handlebars,
|
||||
400,
|
||||
"domain config is required".to_string(),
|
||||
)
|
||||
return renderer.render_error_page(400, "domain config is required")
|
||||
}
|
||||
Err(e) => {
|
||||
return render_error_page(
|
||||
render_ctx.handlebars,
|
||||
400,
|
||||
format!("invalid domain config: {e}"),
|
||||
)
|
||||
return renderer
|
||||
.render_error_page(400, format!("invalid domain config: {e}").as_str())
|
||||
}
|
||||
};
|
||||
|
||||
let config_hash = match config.hash() {
|
||||
Ok(hash) => hash,
|
||||
Err(e) => {
|
||||
return render_error_page(
|
||||
render_ctx.handlebars,
|
||||
return renderer.render_error_page(
|
||||
500,
|
||||
format!("failed to hash domain config: {e}"),
|
||||
format!("failed to hash domain config: {e}").as_str(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let target_cname = (*render_ctx.target_cname).clone();
|
||||
let target_cname = (*renderer.target_cname).clone();
|
||||
|
||||
return render_page(
|
||||
render_ctx,
|
||||
String::from("/domain_post_init.html"),
|
||||
Response {
|
||||
return renderer.render_page(
|
||||
"/domain_post_init.html",
|
||||
&Response {
|
||||
domain: req.domain,
|
||||
config: config,
|
||||
target_cname: target_cname,
|
||||
@ -282,12 +251,9 @@ where
|
||||
},
|
||||
);
|
||||
|
||||
let not_found =
|
||||
warp::any()
|
||||
.and(with_render_ctx.clone())
|
||||
.map(|render_ctx: RenderContext<'_, DM>| {
|
||||
render_error_page(render_ctx.handlebars, 404, "Page not found".to_string())
|
||||
});
|
||||
let not_found = warp::any()
|
||||
.and(with_renderer.clone())
|
||||
.map(|renderer: Renderer<'_, DM>| renderer.render_error_page(404, "Page not found"));
|
||||
|
||||
Ok(static_dir
|
||||
.or(index)
|
||||
|
Loading…
Reference in New Issue
Block a user