use std::sync::Arc;
use utoipa_axum::{router::OpenApiRouter, routes};
use crate::api::http::model::PgWapSessionManager;
pub const PG_WAP_API_V1: &str = "/pg-wap/api/v1";
pub fn pg_wap_router(pg_wap_session_manager: Arc<dyn PgWapSessionManager>) -> OpenApiRouter {
OpenApiRouter::new()
.routes(routes!(pg_wap::new_session))
.with_state(pg_wap_session_manager)
}
mod pg_wap {
use std::{
net::{IpAddr, SocketAddr},
sync::Arc,
};
use axum::{
Json,
extract::{ConnectInfo, State, rejection::JsonRejection},
};
use chrono::DateTime;
use crate::api::http::model::PgWapSessionManager;
#[derive(serde::Deserialize, utoipa::ToSchema)]
pub struct NewSessionRequest {
#[schema(example = json!(["example.com"]), min_length = 1)]
target_domains: Vec<String>,
}
#[derive(serde::Serialize, utoipa::ToSchema)]
pub struct SessionResponse {
#[schema(value_type = String, example = "1.2.3.4")]
client_ip: IpAddr,
ap_id: String,
data_plane_port: u16,
until: DateTime<chrono::Utc>,
target_domains: Vec<String>,
}
#[utoipa::path(
post,
path = "/sessions", // Appended to the root: /pg-wap/api/v1/sessions
request_body = NewSessionRequest,
responses(
(status = 200, description = "HTTP request processed successfully", body = SessionResponse),
(status = 400, description = "Invalid HTTP request"),
(status = 500, description = "Internal server error")
),
tag = "Control"
)]
#[axum::debug_handler]
pub async fn new_session(
State(pg_wap_session_manager): State<Arc<dyn PgWapSessionManager>>,
ip: ConnectInfo<SocketAddr>,
request: Result<Json<NewSessionRequest>, JsonRejection>,
) -> Result<Json<SessionResponse>, axum::http::StatusCode> {
let Json(request) = request.map_err(|err| {
tracing::debug!(?err, "Invalid new session request body");
axum::http::StatusCode::BAD_REQUEST
})?;
let target_domains: Vec<&str> = request.target_domains.iter().map(String::as_str).collect();
if target_domains.is_empty() {
tracing::debug!("Invalid new session request: target domains empty");
return Err(axum::http::StatusCode::BAD_REQUEST);
}
match pg_wap_session_manager.new_session(ip.ip(), &target_domains) {
Ok(session) => {
Ok(Json(SessionResponse {
client_ip: session.ip,
ap_id: session.ap_id.to_string(),
data_plane_port: session.data_plane_port,
until: session.valid_until,
target_domains: session.target_domains,
}))
}
Err(err) => {
tracing::debug!(?err, "Error creating new session");
Err(axum::http::StatusCode::INTERNAL_SERVER_ERROR)
}
}
}
}