use std::{
future::{poll_fn, Future},
pin::Pin,
sync::{Arc, Mutex},
task::{Context, Poll},
};
use bytes::Bytes;
use http::Response;
use tokio::sync::futures::OwnedNotified;
pub use crate::proto::http3::datagram::SendErrorKind;
use crate::{proto::http3::datagram::RequestState, rt::quic::StreamId, upgrade::Upgraded};
#[derive(Clone, Copy, Debug)]
pub struct DatagramRequest;
pub struct Session {
control: Upgraded,
sender: Sender,
receiver: Receiver,
}
pub struct Sender {
state: Arc<RequestState>,
waiting: Option<Pin<Box<OwnedNotified>>>,
}
pub struct Receiver(Arc<RequestState>);
#[derive(Debug)]
pub struct SendError {
kind: SendErrorKind,
payload: Bytes,
}
#[derive(Clone)]
pub(crate) struct Pending(Arc<Mutex<Option<Session>>>);
pub fn on<B>(response: &mut Response<B>) -> Option<Session> {
response
.extensions_mut()
.remove::<Pending>()?
.0
.lock()
.unwrap_or_else(|error| error.into_inner())
.take()
}
impl Session {
pub fn into_parts(self) -> (Upgraded, Sender, Receiver) {
(self.control, self.sender, self.receiver)
}
}
impl Pending {
pub(crate) fn new(control: Upgraded, state: Arc<RequestState>) -> Self {
Self(Arc::new(Mutex::new(Some(Session {
control,
sender: Sender::new(state.clone()),
receiver: Receiver(state),
}))))
}
}
impl Clone for Sender {
fn clone(&self) -> Self {
Self::new(self.state.clone())
}
}
impl Sender {
pub(crate) fn new(state: Arc<RequestState>) -> Self {
Self {
state,
waiting: None,
}
}
pub fn poll_send(
&mut self,
cx: &mut Context<'_>,
payload: &Bytes,
) -> Poll<Result<(), SendErrorKind>> {
let result = self.state.send(payload);
if result != Err(SendErrorKind::Full) {
self.waiting = None;
return Poll::Ready(result);
}
let waiting = self
.waiting
.get_or_insert_with(|| Box::pin(self.state.capacity().notified_owned()));
if waiting.as_mut().poll(cx).is_ready() {
self.waiting = None;
cx.waker().wake_by_ref();
return Poll::Pending;
}
match self.state.send(payload) {
Err(SendErrorKind::Full) => Poll::Pending,
result => {
self.waiting = None;
Poll::Ready(result)
}
}
}
pub async fn send(&mut self, payload: Bytes) -> Result<(), SendError> {
poll_fn(|cx| self.poll_send(cx, &payload))
.await
.map_err(|kind| SendError { kind, payload })
}
pub fn stream_id(&self) -> StreamId {
self.state.id()
}
pub fn max_datagram_size(&self) -> Option<usize> {
self.state.max_size()
}
pub fn try_send(&self, payload: Bytes) -> Result<(), SendError> {
self.state
.send(&payload)
.map_err(|kind| SendError { kind, payload })
}
}
impl Receiver {
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<Bytes>> {
self.0.poll_recv(cx)
}
pub async fn recv(&mut self) -> Option<Bytes> {
poll_fn(|cx| self.poll_recv(cx)).await
}
}
impl Drop for Receiver {
fn drop(&mut self) {
self.0.close_recv();
}
}
impl SendError {
pub fn kind(&self) -> SendErrorKind {
self.kind
}
pub fn into_payload(self) -> Bytes {
self.payload
}
}
impl std::fmt::Display for SendError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "HTTP Datagram send rejected: {:?}", self.kind)
}
}
impl std::error::Error for SendError {}