/* * This is the echoip-slatecave templating engine. * It wraps around tera in is specialized for echoip-slatecave. */ use axum::{ http::StatusCode, response::Html, response::IntoResponse, response::Response, response::Json, }; use tera::Tera; use toml::Table; use std::net::IpAddr; use crate::simple_dns; use crate::IpResult; /* Response format */ #[derive(serde::Deserialize, serde::Serialize, Clone, Copy)] pub enum ResponseFormat { #[serde(rename="text/plain", alias="text")] TextPlain, #[serde(rename="text/html", alias="html")] TextHtml, #[serde(rename="application/json", alias="json")] ApplicationJson, } impl ToString for ResponseFormat { fn to_string(&self) -> String { match self { ResponseFormat::TextPlain => "text/plain", ResponseFormat::TextHtml => "text/html", ResponseFormat::ApplicationJson => "application/json", }.to_string() } } /* Template Settings */ #[derive(serde::Deserialize, serde::Serialize, Clone)] pub struct TemplateSettings { pub format: ResponseFormat, pub lang: String, } /* The echoip view */ #[derive(serde::Deserialize, serde::Serialize, Clone)] #[serde(untagged)] pub enum View { Dig { query: String, result: simple_dns::DnsLookupResult }, Index { query: IpAddr, result: IpResult, user_agent: Option }, Ip { query: IpAddr, result: IpResult }, Message{ title: String, message: String }, #[serde(rename="404")] NotFound, } impl View { pub fn template_name(&self) -> String { match self { View::Dig{..} => "dig", View::Index{..} => "index", View::Ip{..} => "ip", View::Message{..} => "message", View::NotFound => "404", }.to_string() } } /* The engine itself */ #[derive(Clone)] pub struct Engine { pub tera: Tera, pub template_config: Option, } impl Engine { pub async fn render_view( &self, settings: &TemplateSettings, view: &View, ) -> Response { match settings.format { ResponseFormat::TextHtml => { let template_name = view.template_name(); let mut context = tera::Context::new(); context.insert("view", &template_name); //intented for shared macros context.insert("format", &settings.format.to_string()); context.insert("language", &settings.lang); context.insert("data", &view); context.insert("extra", &self.template_config); match self.tera.render(&(template_name+".html"), &context) { Ok(html) => Html(html).into_response(), Err(e) => { println!("There was an error while rendering index.html: {e:?}"); StatusCode::INTERNAL_SERVER_ERROR.into_response() } } } //TODO: Plain Text should have its own matcher ResponseFormat::ApplicationJson | ResponseFormat::TextPlain => { match view { View::Dig{result, ..} => { Json(result).into_response() }, View::Index{result, ..} | View::Ip{result, ..} => { Json(result).into_response() }, _ => Json(view).into_response(), } } } } }