126 lines
4.7 KiB
Rust
126 lines
4.7 KiB
Rust
//! Transport-neutral primitives used by alternative MTP hosts.
|
|
//!
|
|
//! The existing public `Sender` and `Receiver` remain backed by
|
|
//! `wtransport`. These traits are deliberately introduced separately so new
|
|
//! QUIC/WebTransport backends can be added without changing that API in one
|
|
//! breaking step.
|
|
|
|
use async_trait::async_trait;
|
|
use mtp_common::CommunicationError;
|
|
|
|
/// A writable unidirectional stream suitable for MTP frames.
|
|
///
|
|
/// Implementors must also implement [`tokio::io::AsyncWrite`] so that the
|
|
/// stream can back a raw pipe via [`crate::PipeWriter`] when the `pipes`
|
|
/// feature is enabled.
|
|
#[async_trait]
|
|
pub trait TransportSendStream: tokio::io::AsyncWrite + Send + Sync {
|
|
async fn write_all(&mut self, buf: &[u8]) -> Result<(), CommunicationError>;
|
|
async fn finish(&mut self) -> Result<(), CommunicationError>;
|
|
fn reset(&mut self, code: u32) -> Result<(), CommunicationError>;
|
|
}
|
|
|
|
/// A readable unidirectional stream suitable for MTP frames.
|
|
///
|
|
/// Implementors must also implement [`tokio::io::AsyncRead`] so that the
|
|
/// stream can back a raw pipe via [`crate::PipeReader`] when the `pipes`
|
|
/// feature is enabled.
|
|
#[async_trait]
|
|
pub trait TransportRecvStream: tokio::io::AsyncRead + Send + Sync {
|
|
async fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), CommunicationError>;
|
|
async fn read_chunk(&mut self, max: usize) -> Result<Option<Vec<u8>>, CommunicationError>;
|
|
fn stop(self, code: u32) -> Result<(), CommunicationError>
|
|
where
|
|
Self: Sized;
|
|
}
|
|
|
|
/// A QUIC/WebTransport connection that provides MTP's unidirectional streams.
|
|
#[async_trait]
|
|
pub trait TransportConnection: Clone + Send + Sync + 'static {
|
|
type SendStream: TransportSendStream + 'static;
|
|
type RecvStream: TransportRecvStream + 'static;
|
|
|
|
async fn open_uni(&self) -> Result<Self::SendStream, CommunicationError>;
|
|
async fn accept_uni(&self) -> Result<Self::RecvStream, CommunicationError>;
|
|
fn close_reason(&self) -> Option<CommunicationError>;
|
|
fn close(&self, code: u32, reason: &[u8]);
|
|
}
|
|
|
|
#[async_trait]
|
|
impl TransportSendStream for wtransport::SendStream {
|
|
async fn write_all(&mut self, buf: &[u8]) -> Result<(), CommunicationError> {
|
|
wtransport::SendStream::write_all(self, buf)
|
|
.await
|
|
.map_err(|_| CommunicationError::DeliveryUnknown)
|
|
}
|
|
|
|
async fn finish(&mut self) -> Result<(), CommunicationError> {
|
|
wtransport::SendStream::finish(self)
|
|
.await
|
|
.map_err(|_| CommunicationError::StreamError)
|
|
}
|
|
|
|
fn reset(&mut self, code: u32) -> Result<(), CommunicationError> {
|
|
wtransport::SendStream::reset(self, wtransport::VarInt::from_u32(code))
|
|
.map_err(|_| CommunicationError::StreamClosed)
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl TransportRecvStream for wtransport::RecvStream {
|
|
async fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), CommunicationError> {
|
|
match wtransport::RecvStream::read_exact(self, buf).await {
|
|
Ok(()) => Ok(()),
|
|
Err(wtransport::error::StreamReadExactError::FinishedEarly(0)) => {
|
|
Err(CommunicationError::StreamClosed)
|
|
}
|
|
Err(_) => Err(CommunicationError::StreamError),
|
|
}
|
|
}
|
|
|
|
async fn read_chunk(&mut self, max: usize) -> Result<Option<Vec<u8>>, CommunicationError> {
|
|
let mut buf = vec![0; max];
|
|
match wtransport::RecvStream::read(self, &mut buf).await {
|
|
Ok(Some(size)) => {
|
|
buf.truncate(size);
|
|
Ok(Some(buf))
|
|
}
|
|
Ok(None) => Ok(None),
|
|
Err(_) => Err(CommunicationError::StreamError),
|
|
}
|
|
}
|
|
|
|
fn stop(self, code: u32) -> Result<(), CommunicationError> {
|
|
wtransport::RecvStream::stop(self, wtransport::VarInt::from_u32(code));
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl TransportConnection for wtransport::Connection {
|
|
type SendStream = wtransport::SendStream;
|
|
type RecvStream = wtransport::RecvStream;
|
|
|
|
async fn open_uni(&self) -> Result<Self::SendStream, CommunicationError> {
|
|
let opening = wtransport::Connection::open_uni(self)
|
|
.await
|
|
.map_err(CommunicationError::ConnectionError)?;
|
|
opening.await.map_err(|_| CommunicationError::StreamError)
|
|
}
|
|
|
|
async fn accept_uni(&self) -> Result<Self::RecvStream, CommunicationError> {
|
|
wtransport::Connection::accept_uni(self)
|
|
.await
|
|
.map_err(|_| CommunicationError::StreamError)
|
|
}
|
|
|
|
fn close_reason(&self) -> Option<CommunicationError> {
|
|
self.quic_connection()
|
|
.close_reason()
|
|
.map(|_| CommunicationError::StreamClosed)
|
|
}
|
|
|
|
fn close(&self, code: u32, reason: &[u8]) {
|
|
self.quic_connection().close(code.into(), reason);
|
|
}
|
|
}
|