use std::future::Future;
use std::sync::Arc;
use axum::extract::{Query, State};
use axum::http::{HeaderMap, StatusCode};
use axum::response::{IntoResponse, Response};
use axum::{Router, routing};
use serde::Deserialize;
use crate::error::Error;
use crate::models::electricity::{WimAblehnung, WimAnmeldungRequest, WimBestaetigung};
pub trait WimOrderHandler: Send + Sync + 'static {
fn on_anmeldung(
&self,
_tx_id: String,
_creation_dt: String,
_request: WimAnmeldungRequest,
) -> impl Future<Output = Result<(), Error>> + Send {
async {
Err(Error::Http {
status: 501,
body: "not implemented".into(),
})
}
}
fn on_bestaetigung(
&self,
_tx_id: String,
_creation_dt: String,
_response: WimBestaetigung,
) -> impl Future<Output = Result<(), Error>> + Send {
async {
Err(Error::Http {
status: 501,
body: "not implemented".into(),
})
}
}
fn on_ablehnung(
&self,
_tx_id: String,
_creation_dt: String,
_response: WimAblehnung,
) -> impl Future<Output = Result<(), Error>> + Send {
async {
Err(Error::Http {
status: 501,
body: "not implemented".into(),
})
}
}
}
pub fn router<S>(state: Arc<S>) -> Router
where
S: WimOrderHandler + Clone,
{
Router::new()
.route(
"/wimBestellung/v1/anmeldung/",
routing::post(handle_anmeldung::<S>),
)
.route(
"/wimBestellung/v1/bestaetigung/",
routing::post(handle_bestaetigung::<S>),
)
.route(
"/wimBestellung/v1/ablehnung/",
routing::post(handle_ablehnung::<S>),
)
.with_state(state)
}
#[derive(Deserialize)]
struct AnmeldungQuery {
#[serde(rename = "anmeldung")]
anmeldung: String,
}
#[derive(Deserialize)]
struct BestaetigungQuery {
#[serde(rename = "bestaetigung")]
bestaetigung: String,
}
#[derive(Deserialize)]
struct AblehnungQuery {
#[serde(rename = "ablehnung")]
ablehnung: String,
}
fn str_header(h: &HeaderMap, name: &str) -> String {
h.get(name)
.and_then(|v| v.to_str().ok())
.unwrap_or("")
.to_owned()
}
async fn handle_anmeldung<S: WimOrderHandler>(
State(svc): State<Arc<S>>,
headers: HeaderMap,
Query(q): Query<AnmeldungQuery>,
) -> Response {
let request: WimAnmeldungRequest = match serde_json::from_str(&q.anmeldung) {
Ok(r) => r,
Err(e) => return (StatusCode::BAD_REQUEST, e.to_string()).into_response(),
};
match svc
.on_anmeldung(
str_header(&headers, "transactionId"),
str_header(&headers, "creationDateTime"),
request,
)
.await
{
Ok(()) => StatusCode::ACCEPTED.into_response(),
Err(e) => handler_error(e),
}
}
async fn handle_bestaetigung<S: WimOrderHandler>(
State(svc): State<Arc<S>>,
headers: HeaderMap,
Query(q): Query<BestaetigungQuery>,
) -> Response {
let response: WimBestaetigung = match serde_json::from_str(&q.bestaetigung) {
Ok(r) => r,
Err(e) => return (StatusCode::BAD_REQUEST, e.to_string()).into_response(),
};
match svc
.on_bestaetigung(
str_header(&headers, "transactionId"),
str_header(&headers, "creationDateTime"),
response,
)
.await
{
Ok(()) => StatusCode::ACCEPTED.into_response(),
Err(e) => handler_error(e),
}
}
async fn handle_ablehnung<S: WimOrderHandler>(
State(svc): State<Arc<S>>,
headers: HeaderMap,
Query(q): Query<AblehnungQuery>,
) -> Response {
let response: WimAblehnung = match serde_json::from_str(&q.ablehnung) {
Ok(r) => r,
Err(e) => return (StatusCode::BAD_REQUEST, e.to_string()).into_response(),
};
match svc
.on_ablehnung(
str_header(&headers, "transactionId"),
str_header(&headers, "creationDateTime"),
response,
)
.await
{
Ok(()) => StatusCode::ACCEPTED.into_response(),
Err(e) => handler_error(e),
}
}
fn handler_error(e: Error) -> Response {
match e {
Error::Http { status, body } => (
StatusCode::from_u16(status).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR),
body,
)
.into_response(),
other => (StatusCode::INTERNAL_SERVER_ERROR, other.to_string()).into_response(),
}
}