mirror of
				https://codeberg.org/slatian/service.echoip-slatecave.git
				synced 2025-11-04 02:28:58 +01:00 
			
		
		
		
	Moved templating to its own module
This commit is contained in:
		
							
								
								
									
										111
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								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<IpAddr>,
 | 
			
		||||
	format: Option<ResponseFormat>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Deserialize, serde::Serialize)]
 | 
			
		||||
struct DigQuery {
 | 
			
		||||
pub struct DigQuery {
 | 
			
		||||
	name:   String,
 | 
			
		||||
	format: Option<ResponseFormat>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Deserialize, serde::Serialize)]
 | 
			
		||||
struct IpResult {
 | 
			
		||||
pub struct IpResult {
 | 
			
		||||
	hostname: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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<IpQuery>,
 | 
			
		||||
	State(arc_state): State<Arc<ServiceSharedState>>,
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user