use std::fmt::{Display, Formatter};
use actix_web::HttpResponse;
use http::{HeaderMap, StatusCode};
use serde_json::json;
use thiserror::Error;
use crate::http_protocol::wants_page_protocol;
#[derive(Debug, Error)]
pub enum RendererError {
#[error("runtime init failed: {0}")]
RuntimeInit(String),
#[error("render failed: {0}")]
RenderFailed(String),
#[error("render failed: {message}")]
RenderFailedHtml { message: String, html: String },
#[error("renderer worker channel closed")]
ChannelClosed,
#[error("serialization failed: {0}")]
Serialization(String),
#[error("javascript exception: {0}")]
JavaScriptException(String),
#[error("reload failed: {0}")]
ReloadFailed(String),
#[error("io failed: {0}")]
Io(String),
#[error("bundle build failed: {0}")]
BundleBuildFailed(String),
#[error("prerender failed: {0}")]
PrerenderFailed(String),
}
impl RendererError {
pub fn status_code(&self) -> StatusCode {
StatusCode::INTERNAL_SERVER_ERROR
}
pub fn into_response_for_visit(self, is_page_protocol: bool) -> HttpResponse {
if let Self::RenderFailedHtml { html, .. } = &self {
if !is_page_protocol {
return HttpResponse::build(
actix_web::http::StatusCode::from_u16(self.status_code().as_u16())
.unwrap_or(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR),
)
.content_type("text/html; charset=utf-8")
.body(html.clone());
}
}
HttpResponse::build(
actix_web::http::StatusCode::from_u16(self.status_code().as_u16())
.unwrap_or(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR),
)
.json(json!({
"error": self.to_string(),
}))
}
pub fn into_response_for_headers(self, headers: Option<&HeaderMap>) -> HttpResponse {
self.into_response_for_visit(headers.is_some_and(wants_page_protocol))
}
}
impl RendererError {
pub fn into_actix_response_for_visit(self, is_page_protocol: bool) -> HttpResponse {
self.into_response_for_visit(is_page_protocol)
}
pub fn into_actix_response_for_headers(self, headers: Option<&HeaderMap>) -> HttpResponse {
self.into_response_for_headers(headers)
}
}
impl From<std::io::Error> for RendererError {
fn from(value: std::io::Error) -> Self {
Self::Io(value.to_string())
}
}
impl From<serde_json::Error> for RendererError {
fn from(value: serde_json::Error) -> Self {
Self::Serialization(value.to_string())
}
}
impl Display for crate::renderer::RendererMode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
crate::renderer::RendererMode::Development => f.write_str("development"),
crate::renderer::RendererMode::Production => f.write_str("production"),
}
}
}