Middlewarre!

This commit is contained in:
Slatian
2023-02-21 00:06:49 +01:00
parent 2abc5844ad
commit 52ace5f61f
8 changed files with 106 additions and 62 deletions

View File

@ -1,7 +1,12 @@
use axum::{
extract::Query,
extract::State,
extract,
extract::{
self,
Query,
State,
Extension,
},
http::Request,
middleware::{self, Next},
response::Response,
Router,
routing::get,
@ -9,6 +14,7 @@ use axum::{
use axum_client_ip::SecureClientIp;
use clap::Parser;
use tera::Tera;
use tower::ServiceBuilder;
use trust_dns_resolver::{
TokioAsyncResolver,
// config::ResolverOpts,
@ -36,26 +42,29 @@ use crate::templating_engine::ResponseFormat;
use crate::ipinfo::{AddressCast,AddressInfo,AddressScope};
#[derive(serde::Deserialize, serde::Serialize)]
#[derive(serde::Deserialize, serde::Serialize, Clone)]
pub struct BaseQuery {
format: Option<ResponseFormat>,
lang: Option<String>,
}
#[derive(serde::Deserialize, serde::Serialize)]
#[derive(serde::Deserialize, serde::Serialize, Clone)]
pub struct QuerySettings {
format: ResponseFormat,
lang: String,
}
#[derive(serde::Deserialize, serde::Serialize, Clone)]
pub struct IpQuery {
format: Option<ResponseFormat>,
lang: Option<String>,
ip: IpAddr,
}
#[derive(serde::Deserialize, serde::Serialize)]
#[derive(serde::Deserialize, serde::Serialize, Clone)]
pub struct DigQuery {
format: Option<ResponseFormat>,
name: String,
}
#[derive(serde::Deserialize, serde::Serialize)]
#[derive(serde::Deserialize, serde::Serialize, Clone)]
pub struct IpResult {
hostname: Option<String>,
asn: Option<AsnResult>,
@ -158,6 +167,11 @@ async fn main() {
}
};
let templating_engine = templating_engine::Engine{
tera: tera,
template_config: template_extra_config,
};
// Initalize GeoIP Database
let mut asn_db = geoip::MMDBCarrier {
@ -198,14 +212,11 @@ async fn main() {
// Initialize shared state
let shared_state = Arc::new(
ServiceSharedState {
templating_engine: templating_engine::Engine{
tera: tera,
template_config: template_extra_config,
},
templating_engine: templating_engine,
dns_resolver: dns_resolver,
asn_db: asn_db,
location_db: location_db,
config: config,
config: config.clone(),
});
// Initalize axum server
@ -217,7 +228,12 @@ async fn main() {
.route("/ip/:address", get(handle_ip_route_with_path))
.route("/hi", get(hello_world_handler))
.with_state(shared_state)
.layer(ip_header.into_extension())
.layer(
ServiceBuilder::new()
.layer(ip_header.into_extension())
.layer(Extension(config))
.layer(middleware::from_fn(format_and_language_middleware))
)
;
println!("Starting Server ...");
@ -228,77 +244,90 @@ async fn main() {
.unwrap();
}
async fn format_and_language_middleware<B>(
Query(query): Query<BaseQuery>,
Extension(config): Extension<config::EchoIpServiceConfig>,
mut req: Request<B>,
next: Next<B>
) -> Response {
let format = query.format.unwrap_or(ResponseFormat::TextHtml);
req.extensions_mut().insert(QuerySettings{
format: format,
lang: query.lang.unwrap_or("en".to_string()),
});
next.run(req).await
}
#[axum::debug_handler]
async fn hello_world_handler(
State(arc_state): State<Arc<ServiceSharedState>>,
Extension(settings): Extension<QuerySettings>,
) -> Response {
let state = Arc::clone(&arc_state);
state.templating_engine.render_view(
ResponseFormat::TextPlain,
View::Message("Hello! There, You, Awesome Creature!".to_string())
).await
settings.format,
&View::Message("Hello! There, You, Awesome Creature!".to_string())
).await
}
async fn handle_default_route(
Query(query): Query<BaseQuery>,
State(arc_state): State<Arc<ServiceSharedState>>,
Extension(settings): Extension<QuerySettings>,
SecureClientIp(address): SecureClientIp
) -> Response {
let format = query.format.unwrap_or(ResponseFormat::TextHtml);
let ip_query = IpQuery {
format: query.format,
lang: query.lang,
ip: address,
};
let state = Arc::clone(&arc_state);
let result = get_ip_result(&ip_query, &state).await;
let result = get_ip_result(&ip_query, &settings.lang, &state).await;
state.templating_engine.render_view(
format,
View::Index{query: ip_query, result: result}
settings.format,
&View::Index{query: ip_query, result: result}
).await
}
async fn handle_ip_route(
Query(ip_query): Query<IpQuery>,
Extension(settings): Extension<QuerySettings>,
State(arc_state): State<Arc<ServiceSharedState>>,
) -> Response {
return handle_ip_request(ip_query, arc_state).await
return handle_ip_request(ip_query, settings, arc_state).await
}
async fn handle_ip_route_with_path(
Query(query): Query<BaseQuery>,
Extension(settings): Extension<QuerySettings>,
State(arc_state): State<Arc<ServiceSharedState>>,
extract::Path(address): extract::Path<IpAddr>,
) -> Response {
return handle_ip_request(IpQuery {
format: query.format,
lang: query.lang,
ip: address,
}, arc_state).await
}, settings, arc_state).await
}
async fn handle_ip_request(
ip_query: IpQuery,
settings: QuerySettings,
arc_state: Arc<ServiceSharedState>,
) -> Response {
let state = Arc::clone(&arc_state);
let result = get_ip_result(&ip_query, &state).await;
let format = ip_query.format.unwrap_or(ResponseFormat::TextHtml);
let result = get_ip_result(&ip_query, &settings.lang, &state).await;
state.templating_engine.render_view(
format,
View::Ip{query: ip_query, result: result}
settings.format,
&View::Ip{query: ip_query, result: result}
).await
}
async fn get_ip_result(
ip_query: &IpQuery,
lang: &String,
state: &ServiceSharedState,
) -> IpResult {
let address = ip_query.ip;
@ -329,7 +358,7 @@ async fn get_ip_result(
// location lookup
let location_result = state.location_db.query_location_for_ip(
address,
&vec![&ip_query.lang.as_ref().unwrap_or(&"en".to_string()), &"en".to_string()]
&vec![lang, &"en".to_string()]
);
// filter reverse lookup
@ -354,35 +383,35 @@ async fn get_ip_result(
async fn handle_dig_route(
Query(dig_query): Query<DigQuery>,
Extension(settings): Extension<QuerySettings>,
State(arc_state): State<Arc<ServiceSharedState>>,
) -> Response {
return handle_dig_request(dig_query, arc_state).await
return handle_dig_request(dig_query, settings, arc_state).await
}
async fn handle_dig_route_with_path(
Query(query): Query<BaseQuery>,
Extension(settings): Extension<QuerySettings>,
State(arc_state): State<Arc<ServiceSharedState>>,
extract::Path(name): extract::Path<String>,
) -> Response {
return handle_dig_request(DigQuery {
format: query.format,
name: name,
}, arc_state).await
}, settings, arc_state).await
}
async fn handle_dig_request(
dig_query: DigQuery,
settings: QuerySettings,
arc_state: Arc<ServiceSharedState>,
) -> Response {
let state = Arc::clone(&arc_state);
let format = dig_query.format.unwrap_or(ResponseFormat::TextHtml);
let dig_result = get_dig_result(&dig_query, &state).await;
state.templating_engine.render_view(
format,
View::Dig{ query: dig_query, result: dig_result}
settings.format,
&View::Dig{ query: dig_query, result: dig_result}
).await
}