use core::time::Duration;
use future_form::Sendable;
use futures::future::BoxFuture;
use subduction_core::connection::{
Connection,
message::{BatchSyncRequest, BatchSyncResponse, Message, RequestId},
timeout::Timeout,
};
use subduction_http_longpoll::connection::HttpLongPollConnection;
use subduction_iroh::connection::IrohConnection;
use subduction_websocket::tokio::unified::UnifiedWebSocket;
#[derive(Debug, Clone)]
pub(crate) enum UnifiedTransport<O: Timeout<Sendable> + Send + Sync> {
WebSocket(UnifiedWebSocket<O>),
HttpLongPoll(HttpLongPollConnection<O>),
Iroh(IrohConnection<O>),
}
#[derive(Debug, Clone, Copy, thiserror::Error)]
pub(crate) enum TransportSendError {
#[error(transparent)]
WebSocket(#[from] subduction_websocket::error::SendError),
#[error(transparent)]
HttpLongPoll(#[from] subduction_http_longpoll::error::SendError),
#[error(transparent)]
Iroh(#[from] subduction_iroh::error::SendError),
}
#[derive(Debug, Clone, Copy, thiserror::Error)]
pub(crate) enum TransportRecvError {
#[error(transparent)]
WebSocket(#[from] subduction_websocket::error::RecvError),
#[error(transparent)]
HttpLongPoll(#[from] subduction_http_longpoll::error::RecvError),
#[error(transparent)]
Iroh(#[from] subduction_iroh::error::RecvError),
}
#[derive(Debug, Clone, Copy, thiserror::Error)]
pub(crate) enum TransportCallError {
#[error(transparent)]
WebSocket(#[from] subduction_websocket::error::CallError),
#[error(transparent)]
HttpLongPoll(#[from] subduction_http_longpoll::error::CallError),
#[error(transparent)]
Iroh(#[from] subduction_iroh::error::CallError),
}
#[derive(Debug, Clone, Copy, thiserror::Error)]
pub(crate) enum TransportDisconnectionError {
#[error(transparent)]
WebSocket(#[from] subduction_websocket::error::DisconnectionError),
#[error(transparent)]
HttpLongPoll(#[from] subduction_http_longpoll::error::DisconnectionError),
#[error(transparent)]
Iroh(#[from] subduction_iroh::error::DisconnectionError),
}
impl<O: Timeout<Sendable> + Send + Sync> Connection<Sendable> for UnifiedTransport<O> {
type SendError = TransportSendError;
type RecvError = TransportRecvError;
type CallError = TransportCallError;
type DisconnectionError = TransportDisconnectionError;
fn next_request_id(&self) -> BoxFuture<'_, RequestId> {
match self {
Self::WebSocket(ws) => Connection::<Sendable>::next_request_id(ws),
Self::HttpLongPoll(lp) => Connection::<Sendable>::next_request_id(lp),
Self::Iroh(iroh) => Connection::<Sendable>::next_request_id(iroh),
}
}
fn disconnect(&self) -> BoxFuture<'_, Result<(), Self::DisconnectionError>> {
match self {
Self::WebSocket(ws) => Box::pin(async {
Connection::<Sendable>::disconnect(ws)
.await
.map_err(Into::into)
}),
Self::HttpLongPoll(lp) => Box::pin(async {
Connection::<Sendable>::disconnect(lp)
.await
.map_err(Into::into)
}),
Self::Iroh(iroh) => Box::pin(async {
Connection::<Sendable>::disconnect(iroh)
.await
.map_err(Into::into)
}),
}
}
fn send(&self, message: &Message) -> BoxFuture<'_, Result<(), Self::SendError>> {
match self {
Self::WebSocket(ws) => {
let fut = Connection::<Sendable>::send(ws, message);
Box::pin(async move { fut.await.map_err(Into::into) })
}
Self::HttpLongPoll(lp) => {
let fut = Connection::<Sendable>::send(lp, message);
Box::pin(async move { fut.await.map_err(Into::into) })
}
Self::Iroh(iroh) => {
let fut = Connection::<Sendable>::send(iroh, message);
Box::pin(async move { fut.await.map_err(Into::into) })
}
}
}
fn recv(&self) -> BoxFuture<'_, Result<Message, Self::RecvError>> {
match self {
Self::WebSocket(ws) => {
Box::pin(async { Connection::<Sendable>::recv(ws).await.map_err(Into::into) })
}
Self::HttpLongPoll(lp) => {
Box::pin(async { Connection::<Sendable>::recv(lp).await.map_err(Into::into) })
}
Self::Iroh(iroh) => {
Box::pin(async { Connection::<Sendable>::recv(iroh).await.map_err(Into::into) })
}
}
}
fn call(
&self,
req: BatchSyncRequest,
timeout: Option<Duration>,
) -> BoxFuture<'_, Result<BatchSyncResponse, Self::CallError>> {
match self {
Self::WebSocket(ws) => Box::pin(async move {
Connection::<Sendable>::call(ws, req, timeout)
.await
.map_err(Into::into)
}),
Self::HttpLongPoll(lp) => Box::pin(async move {
Connection::<Sendable>::call(lp, req, timeout)
.await
.map_err(Into::into)
}),
Self::Iroh(iroh) => Box::pin(async move {
Connection::<Sendable>::call(iroh, req, timeout)
.await
.map_err(Into::into)
}),
}
}
}
impl<O: Timeout<Sendable> + Send + Sync> PartialEq for UnifiedTransport<O> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::WebSocket(a), Self::WebSocket(b)) => a == b,
(Self::HttpLongPoll(a), Self::HttpLongPoll(b)) => a == b,
(Self::Iroh(a), Self::Iroh(b)) => a == b,
_ => false,
}
}
}