implement error pages
This commit is contained in:
parent
130581d61e
commit
50d450eb2c
146
src/service.rs
146
src/service.rs
@ -30,41 +30,73 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO make this use an io::Write, rather than warp::Reply
|
// 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
|
fn render<'a, T>(handlebars: Handlebars<'a>, name: &'a str, value: T) -> Box<dyn warp::Reply>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
{
|
{
|
||||||
// TODO deal with 404
|
let rendered = match handlebars.render(name, &value) {
|
||||||
let render = handlebars
|
Ok(res) => res,
|
||||||
.render(name, &value)
|
Err(handlebars::RenderError {
|
||||||
.unwrap_or_else(|err| err.to_string());
|
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)
|
let content_type = mime_guess::from_path(name)
|
||||||
.first_or_octet_stream()
|
.first_or_octet_stream()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
let reply = warp::reply::html(render);
|
let reply = warp::reply::html(rendered);
|
||||||
|
|
||||||
warp::reply::with_header(reply, "Content-Type", content_type)
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
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>(
|
fn render_page<'a, T, DM>(
|
||||||
render_ctx: RenderContext<'a, DM>,
|
render_ctx: RenderContext<'a, DM>,
|
||||||
name: String,
|
name: String,
|
||||||
data: T,
|
data: T,
|
||||||
) -> impl warp::Reply
|
) -> Box<dyn warp::Reply>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
DM: domain::manager::Manager,
|
DM: domain::manager::Manager,
|
||||||
{
|
{
|
||||||
#[derive(Serialize)]
|
let presenter = BasePresenter {
|
||||||
struct Presenter<T> {
|
|
||||||
page_name: String,
|
|
||||||
query_args: HashMap<String, String>,
|
|
||||||
data: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
let presenter = Presenter {
|
|
||||||
page_name: name,
|
page_name: name,
|
||||||
query_args: render_ctx.query_args,
|
query_args: render_ctx.query_args,
|
||||||
data,
|
data,
|
||||||
@ -137,18 +169,37 @@ where
|
|||||||
req: DomainGetNewRequest,
|
req: DomainGetNewRequest,
|
||||||
domain_config: util::ConfigFromURL| {
|
domain_config: util::ConfigFromURL| {
|
||||||
match render_ctx.domain_manager.get_config(&req.domain) {
|
match render_ctx.domain_manager.get_config(&req.domain) {
|
||||||
Ok(_config) => panic!("TODO"),
|
Ok(_config) => render_error_page(
|
||||||
Err(domain::manager::GetConfigError::NotFound) => render_page(
|
render_ctx.handlebars,
|
||||||
|
500,
|
||||||
|
"TODO not yet implemented".to_string(),
|
||||||
|
),
|
||||||
|
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,
|
||||||
|
400,
|
||||||
|
format!("parsing domain configuration: {}", e),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render_page(
|
||||||
render_ctx,
|
render_ctx,
|
||||||
String::from("/domain_get_new.html"),
|
String::from("/domain_get_new.html"),
|
||||||
DomainGetNewResponse {
|
DomainGetNewResponse {
|
||||||
domain: req.domain,
|
domain: req.domain,
|
||||||
config: domain_config.try_into().expect("TODO"),
|
config: domain_config,
|
||||||
},
|
},
|
||||||
),
|
)
|
||||||
Err(domain::manager::GetConfigError::Unexpected(e)) => {
|
|
||||||
panic!("{}", e) // TODO
|
|
||||||
}
|
}
|
||||||
|
Err(domain::manager::GetConfigError::Unexpected(e)) => render_error_page(
|
||||||
|
render_ctx.handlebars,
|
||||||
|
500,
|
||||||
|
format!("retrieving configuration: {}", e),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -170,7 +221,11 @@ where
|
|||||||
req: DomainPostRequest,
|
req: DomainPostRequest,
|
||||||
domain_config: util::ConfigFromURL| {
|
domain_config: util::ConfigFromURL| {
|
||||||
if req.passphrase != render_ctx.passphrase.as_str() {
|
if req.passphrase != render_ctx.passphrase.as_str() {
|
||||||
panic!("TODO")
|
return render_error_page(
|
||||||
|
render_ctx.handlebars,
|
||||||
|
401,
|
||||||
|
"Incorrect passphrase".to_string(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//if req.init {
|
//if req.init {
|
||||||
@ -182,11 +237,35 @@ where
|
|||||||
challenge_token: String,
|
challenge_token: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
let config: Option<domain::config::Config> =
|
let config: domain::config::Config = match domain_config.try_into() {
|
||||||
domain_config.try_into().expect("TODO");
|
Ok(Some(config)) => config,
|
||||||
let config = config.expect("TODO");
|
Ok(None) => {
|
||||||
|
return render_error_page(
|
||||||
|
render_ctx.handlebars,
|
||||||
|
400,
|
||||||
|
"domain config is required".to_string(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return render_error_page(
|
||||||
|
render_ctx.handlebars,
|
||||||
|
400,
|
||||||
|
format!("invalid domain config: {e}"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let config_hash = match config.hash() {
|
||||||
|
Ok(hash) => hash,
|
||||||
|
Err(e) => {
|
||||||
|
return render_error_page(
|
||||||
|
render_ctx.handlebars,
|
||||||
|
500,
|
||||||
|
format!("failed to hash domain config: {e}"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let config_hash = config.hash().expect("TODO");
|
|
||||||
let target_cname = (*render_ctx.target_cname).clone();
|
let target_cname = (*render_ctx.target_cname).clone();
|
||||||
|
|
||||||
return render_page(
|
return render_page(
|
||||||
@ -203,5 +282,16 @@ where
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(static_dir.or(index).or(domain_get).or(domain_post))
|
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())
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(static_dir
|
||||||
|
.or(index)
|
||||||
|
.or(domain_get)
|
||||||
|
.or(domain_post)
|
||||||
|
.or(not_found))
|
||||||
}
|
}
|
||||||
|
1
src/service/http_tpl/error.html
Normal file
1
src/service/http_tpl/error.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
<p style="color: red">{{ data.error_msg }}</p>
|
Loading…
Reference in New Issue
Block a user