use std::future::Future;
use http::StatusCode;
use http::request::Parts;
use tako_rs_core::body::TakoBody;
use tako_rs_core::extractors::FromRequest;
use tako_rs_core::extractors::FromRequestParts;
use tako_rs_core::responder::Responder;
use tako_rs_core::types::Request;
use tako_rs_core::types::Response;
mod capsule;
mod driver;
mod session;
mod stream;
pub(crate) mod upgrade;
pub use capsule::WebTransportClose;
pub use h3::webtransport::SessionId;
pub use session::WebTransportSession;
pub use stream::BidiStream;
pub use stream::RecvStream;
pub use stream::SendStream;
use upgrade::SessionSlot;
pub struct WebTransport {
slot: SessionSlot,
}
impl WebTransport {
#[cfg(not(feature = "compio"))]
pub fn on_session<F, Fut>(self, handler: F) -> Response
where
F: FnOnce(WebTransportSession) -> Fut + Send + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
self
.slot
.fill(Box::new(move |session| Box::pin(handler(session))));
Response::new(TakoBody::empty())
}
#[cfg(feature = "compio")]
pub fn on_session<F, Fut>(self, handler: F) -> Response
where
F: FnOnce(WebTransportSession) -> Fut + Send + 'static,
Fut: Future<Output = ()> + 'static,
{
self
.slot
.fill(Box::new(move |session| Box::pin(handler(session))));
Response::new(TakoBody::empty())
}
}
impl<'a> FromRequestParts<'a> for WebTransport {
type Error = WebTransportRejection;
fn from_request_parts(
parts: &'a mut Parts,
) -> impl Future<Output = Result<Self, Self::Error>> + Send + 'a {
futures_util::future::ready(take(&mut parts.extensions))
}
}
impl<'a> FromRequest<'a> for WebTransport {
type Error = WebTransportRejection;
fn from_request(
req: &'a mut Request,
) -> impl Future<Output = Result<Self, Self::Error>> + Send + 'a {
futures_util::future::ready(take(req.extensions_mut()))
}
}
fn take(extensions: &mut http::Extensions) -> Result<WebTransport, WebTransportRejection> {
extensions
.remove::<SessionSlot>()
.map(|slot| WebTransport { slot })
.ok_or(WebTransportRejection)
}
#[derive(Debug)]
pub struct WebTransportRejection;
impl Responder for WebTransportRejection {
fn into_response(self) -> Response {
(
StatusCode::BAD_REQUEST,
"expected a WebTransport session request",
)
.into_response()
}
}