From 0193c243853ce7dabf3fa280faa98baebc669f11 Mon Sep 17 00:00:00 2001 From: Slatian Date: Sun, 12 Feb 2023 17:53:50 +0100 Subject: [PATCH] Moved templating to its own module --- src/main.rs | 111 ++++----------------------------------- src/templating_engine.rs | 111 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 100 deletions(-) create mode 100644 src/templating_engine.rs diff --git a/src/main.rs b/src/main.rs index c24c961..63c3af9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,7 @@ use axum::{ extract::Query, extract::State, - http::StatusCode, - response::Html, - response::IntoResponse, response::Response, - response::Json, Router, routing::get, }; @@ -16,82 +12,37 @@ use trust_dns_resolver::{ config::ResolverConfig, }; - use std::net::{IpAddr, Ipv4Addr}; use std::sync::Arc; mod simple_dns; +mod templating_engine; -#[derive(serde::Deserialize, serde::Serialize, Clone, Copy)] -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() - } -} +use crate::templating_engine::View; +use crate::templating_engine::ResponseFormat; #[derive(serde::Deserialize, serde::Serialize)] -struct IpQuery { +pub struct IpQuery { ip: Option, format: Option, } #[derive(serde::Deserialize, serde::Serialize)] -struct DigQuery { +pub struct DigQuery { name: String, format: Option, } #[derive(serde::Deserialize, serde::Serialize)] -struct IpResult { +pub struct IpResult { hostname: Option, } -struct TemplatingEngine { - tera: Tera, -} - struct ServiceSharedState { - templating_engine: TemplatingEngine, + templating_engine: templating_engine::Engine, dns_resolver: TokioAsyncResolver, } -#[derive(serde::Deserialize, serde::Serialize)] -#[serde(untagged)] -enum EchoipView { - Dig { query: DigQuery, result: simple_dns::DnsLookupResult }, - Index { query: IpQuery, result: IpResult }, - Ip { query: IpQuery, result: IpResult }, - Message(String), - #[serde(rename="404")] - NotFound, -} - -impl EchoipView { - fn template_name(&self) -> String { - match self { - EchoipView::Dig{..} => "dig", - EchoipView::Index{..} => "index", - EchoipView::Ip{..} => "ip", - EchoipView::Message(..) => "message", - EchoipView::NotFound => "404", - }.to_string() - } -} - - #[tokio::main] async fn main() { // Initalize Tera templates @@ -119,7 +70,7 @@ async fn main() { // Initialize shared state let shared_state = Arc::new(ServiceSharedState{ - templating_engine: TemplatingEngine{ + templating_engine: templating_engine::Engine{ tera: tera, }, dns_resolver: dns_resolver, @@ -148,50 +99,10 @@ async fn hello_world_handler( state.templating_engine.render_view( ResponseFormat::TextPlain, - EchoipView::Message("Hello! There, You, Awesome Creature!".to_string()) + View::Message("Hello! There, You, Awesome Creature!".to_string()) ).await } -impl TemplatingEngine { - async fn render_view( - &self, - format: ResponseFormat, - view: EchoipView, - ) -> Response { - match 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", &format.to_string()); - context.insert("data", &view); - - 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 { - EchoipView::Dig{result, ..} => { - Json(result).into_response() - }, - EchoipView::Index{result, ..} | EchoipView::Ip{result, ..} => { - Json(result).into_response() - }, - _ => Json(view).into_response(), - } - } - } - } -} - async fn handle_default_route( Query(ip_query): Query, State(arc_state): State>, @@ -211,7 +122,7 @@ async fn handle_default_route( state.templating_engine.render_view( format, - EchoipView::Index{query: ip_query, result: result} + View::Index{query: ip_query, result: result} ).await } @@ -228,7 +139,7 @@ async fn handle_dig_route( state.templating_engine.render_view( format, - EchoipView::Dig{ query: dig_query, result: dig_result} + View::Dig{ query: dig_query, result: dig_result} ).await } diff --git a/src/templating_engine.rs b/src/templating_engine.rs new file mode 100644 index 0000000..b30d046 --- /dev/null +++ b/src/templating_engine.rs @@ -0,0 +1,111 @@ +/* + * 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 crate::simple_dns; +use crate::IpResult; +use crate::IpQuery; +use crate::DigQuery; + +/* 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() + } +} + +/* The echoip view */ + +#[derive(serde::Deserialize, serde::Serialize)] +#[serde(untagged)] +pub enum View { + Dig { query: DigQuery, result: simple_dns::DnsLookupResult }, + Index { query: IpQuery, result: IpResult }, + Ip { query: IpQuery, result: IpResult }, + 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 */ + +pub struct Engine { + pub tera: Tera, +} + +impl Engine { + pub async fn render_view( + &self, + format: ResponseFormat, + view: View, + ) -> Response { + match 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", &format.to_string()); + context.insert("data", &view); + + 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(), + } + } + } + } +}