diff --git a/src/main.rs b/src/main.rs index 9678841..b7aa0c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -403,7 +403,7 @@ async fn not_found_handler( state.templating_engine.render_view( &settings, - &View::NotFound, + View::NotFound, ).await } @@ -415,7 +415,7 @@ async fn hello_world_handler( state.templating_engine.render_view( &settings, - &View::Message{ + View::Message{ title: "Hey There!".to_string(), message: "You,You are an awesome Creature!".to_string() }, @@ -459,7 +459,7 @@ async fn handle_default_route( state.templating_engine.render_view( &settings, - &View::Index{ + View::Index{ result: result, user_agent: user_agent, } @@ -489,7 +489,7 @@ async fn handle_search_request( let state = Arc::clone(&arc_state); return state.templating_engine.render_view( &settings, - &View::Asn{asn: asn}, + View::Asn{asn: asn}, ).await } } @@ -528,7 +528,7 @@ async fn handle_dns_resolver_route( let state = Arc::clone(&arc_state); state.templating_engine.render_view( &settings, - &View::DnsResolverList, + View::DnsResolverList, ).await } @@ -542,12 +542,12 @@ async fn handle_dns_resolver_route_with_path( if let Some(resolver) = state.config.dns.resolver.get(query.as_str()) { state.templating_engine.render_view( &settings, - &View::DnsResolver{ config: resolver.clone() }, + View::DnsResolver{ config: resolver.clone() }, ).await } else { state.templating_engine.render_view( &settings, - &View::NotFound, + View::NotFound, ).await } } @@ -579,7 +579,7 @@ async fn handle_ip_request( state.templating_engine.render_view( &settings, - &View::Ip{result: result} + View::Ip{result: result} ).await } @@ -668,7 +668,7 @@ async fn handle_dig_request( state.templating_engine.render_view( &settings, - &View::Dig{ query: dig_query, result: dig_result} + View::Dig{ query: dig_query, result: dig_result} ).await } diff --git a/src/mycelium/mod.rs b/src/mycelium/mod.rs index a2b6d9d..146113a 100644 --- a/src/mycelium/mod.rs +++ b/src/mycelium/mod.rs @@ -1,7 +1,9 @@ mod format; +mod query_settings; mod view; pub use self::format::HtmlTextJsonFormat; pub use self::format::MycFormat; pub use self::format::MycFormatFamily; +pub use self::query_settings::MycQuerySettings; pub use self::view::MycView; diff --git a/src/mycelium/query_settings.rs b/src/mycelium/query_settings.rs new file mode 100644 index 0000000..3b90937 --- /dev/null +++ b/src/mycelium/query_settings.rs @@ -0,0 +1,16 @@ + +use tera::Context; + +use crate::mycelium::MycFormat; + +pub trait MycQuerySettings +where F: MycFormat { + + /// Called before rendering a template to initalize it with + /// values that come from the query itself. + fn initalize_template_context(&self, context: &mut Context); + + /// Returns the requested output format + fn get_format(&self) -> F; + +} diff --git a/src/mycelium/view.rs b/src/mycelium/view.rs index 68b656a..2539302 100644 --- a/src/mycelium/view.rs +++ b/src/mycelium/view.rs @@ -4,7 +4,11 @@ use axum::response::Response; use axum::http::status::StatusCode; use serde::Serialize; -pub trait MycView: Serialize + Sized { +use crate::mycelium::MycQuerySettings; +use crate::mycelium::MycFormat; + +pub trait MycView: Serialize + Sized +where S: MycQuerySettings, F: MycFormat { /// Returns the template name that will be used to select /// the template file. @@ -20,17 +24,17 @@ pub trait MycView: Serialize + Sized { /// Returns the reponse code for the view. /// /// The numeric value will be useable as `http_status` in the template. - fn get_status_code(&self) -> StatusCode; + fn get_status_code(&self, settings: &S) -> StatusCode; /// If this returns a String it will be used as the cookie header. /// /// See: [axum: Constructing a Cookie](https://docs.rs/axum-extra/0.8.0/axum_extra/extract/cookie/struct.Cookie.html#constructing-a-cookie) - fn get_cookie_header(&self) -> Option { None } + fn get_cookie_header(&self, _settings: &S) -> Option { None } /// Update non-API responses after they have been built. /// /// Useful for setting extra headers. Does noting by default. - fn update_response(&self, _response: &mut Response) {} + fn update_response(&self, _settings: &S, _response: &mut Response) {} /// Return an API-Response /// @@ -41,7 +45,7 @@ pub trait MycView: Serialize + Sized { /// advance and set on the reulting response if it has a status code of 200. /// Otherwise it is assumed that the response genrating logic /// alredy took care of that. - fn get_api_response(self) -> Response { + fn get_api_response(self, _settings: &S) -> Response { Json(self).into_response() } } diff --git a/src/settings.rs b/src/settings.rs index 7fb7223..cb13531 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -2,6 +2,7 @@ use serde::{Deserialize,Serialize}; use std::sync::Arc; use crate::mycelium::HtmlTextJsonFormat; +use crate::mycelium::MycQuerySettings; /* Response format */ @@ -24,3 +25,16 @@ pub struct Selectable { pub weight: i32, } +impl MycQuerySettings for QuerySettings { + + fn initalize_template_context(&self, context: &mut tera::Context) { + context.insert("language", &self.lang); + context.insert("dns_resolvers", &self.available_dns_resolvers); + context.insert("dns_resolver_id", &self.dns_resolver_id); + } + + fn get_format(&self) -> ResponseFormat { + self.format.clone() + } + +} diff --git a/src/templating_engine.rs b/src/templating_engine.rs index afc28a7..01c1919 100644 --- a/src/templating_engine.rs +++ b/src/templating_engine.rs @@ -11,7 +11,6 @@ use axum::{ http::header::SET_COOKIE, response::IntoResponse, response::Response, - response::Json, }; use axum_extra::extract::cookie::Cookie; use axum_extra::extract::cookie; @@ -22,6 +21,7 @@ use crate::view::View; use crate::mycelium::MycView; use crate::mycelium::MycFormat; use crate::mycelium::MycFormatFamily; +use crate::mycelium::MycQuerySettings; use crate::settings::QuerySettings; /* The engine itself */ @@ -36,25 +36,26 @@ impl Engine { pub async fn render_view( &self, settings: &QuerySettings, - view: &View, + view: View, ) -> Response { + let status_code = view.get_status_code(&settings); + let mut response = match settings.format.get_family() { MycFormatFamily::Template => { let template_name = view.get_template_name(); - let mime_type = settings.format.get_mime_type(); - + let format = settings.get_format(); + let mime_type = format.get_mime_type(); + let mut context = tera::Context::new(); context.insert("view", &template_name); //intented for shared macros - context.insert("format", &settings.format.get_name()); + context.insert("format", &format.get_name()); context.insert("mimetype", &mime_type.to_string()); - context.insert("language", &settings.lang); - context.insert("dns_resolvers", &settings.available_dns_resolvers); - context.insert("dns_resolver_id", &settings.dns_resolver_id); context.insert("data", &view); context.insert("extra", &self.template_config); + settings.initalize_template_context(&mut context); - match self.tera.render(&(template_name.clone()+&settings.format.get_file_extension()), &context) { + match self.tera.render(&(template_name.clone()+&format.get_file_extension()), &context) { Ok(text) => ( [( @@ -74,25 +75,10 @@ impl Engine { } } MycFormatFamily::API => { - match view { - View::Dig{result, ..} => { - Json(result).into_response() - }, - View::Index{result, ..} | View::Ip{result, ..} => { - Json(result).into_response() - }, - View::DnsResolverList => { - Json(settings.available_dns_resolvers.clone()).into_response() - }, - View::DnsResolver{ config } => { - Json(config).into_response() - } - _ => Json(view).into_response(), - } + view.get_api_response(&settings) } }; // Set status code - let status_code = view.get_status_code(); if status_code != StatusCode::OK { *response.status_mut() = status_code; } diff --git a/src/view.rs b/src/view.rs index 7bbfa9e..ebba2f4 100644 --- a/src/view.rs +++ b/src/view.rs @@ -1,9 +1,14 @@ use axum::http::status::StatusCode; +use axum::Json; +use axum::response::IntoResponse; +use axum::response::Response; use crate::DigResult; use crate::IpResult; use crate::config::DnsResolverConfig; +use crate::settings::QuerySettings; +use crate::settings::ResponseFormat; use crate::mycelium::MycView; @@ -21,7 +26,7 @@ pub enum View { NotFound, } -impl MycView for View { +impl MycView for View { fn get_template_name(&self) -> String { match self { View::Asn{..} => "asn", @@ -35,11 +40,29 @@ impl MycView for View { }.to_string() } - fn get_status_code(&self) -> StatusCode { + fn get_status_code(&self, _: &QuerySettings) -> StatusCode { match self { Self::NotFound => StatusCode::NOT_FOUND, _ => StatusCode::OK, } } + + fn get_api_response(self, settings: &QuerySettings) -> Response { + match self { + Self::Dig{result, ..} => { + Json(result).into_response() + }, + Self::Index{result, ..} | Self::Ip{result, ..} => { + Json(result).into_response() + }, + Self::DnsResolverList => { + Json(settings.available_dns_resolvers.clone()).into_response() + }, + Self::DnsResolver{ config } => { + Json(config).into_response() + } + _ => Json(self).into_response(), + } + } }