use crate::formats::SerdeFormat;
use crate::maybe_send::MaybeSend;
use crate::{
ChannelBuilder, RpcError, RpcFrameHead, RpcMsgHandler, RpcMsgHandlerWrapper, RpcServiceSchema,
ServiceFactory, XyRpcChannel, new_transport_sink, new_transport_stream,
};
use compio::io::compat::AsyncStream;
use compio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use futures_util::future::Either;
use std::future::Future;
pub trait ChannelBuilderCompioExt<SF, CS, MH, MSG> {
fn build_from_compio(
self,
io: impl AsyncRead + AsyncWrite + Unpin + 'static,
) -> (
XyRpcChannel<SF, CS>,
impl Future<Output = Result<(), RpcError>> + 'static,
)
where
XyRpcChannel<SF, CS>: Clone,
CS: RpcServiceSchema,
MH: ServiceFactory<SF, CS>;
fn build_from_compio_read_write(
self,
io: (
impl AsyncRead + Unpin + 'static,
impl AsyncWrite + Unpin + 'static,
),
) -> (
XyRpcChannel<SF, CS>,
impl Future<Output = Result<(), RpcError>> + 'static,
)
where
XyRpcChannel<SF, CS>: Clone,
CS: RpcServiceSchema,
MH: ServiceFactory<SF, CS>;
}
impl<SF, CS, MH, MSG> ChannelBuilderCompioExt<SF, CS, MH, MSG> for ChannelBuilder<SF, CS, MH, MSG>
where
SF: SerdeFormat,
{
fn build_from_compio(
self,
io: impl AsyncRead + AsyncWrite + Unpin + 'static,
) -> (
XyRpcChannel<SF, CS>,
impl Future<Output = Result<(), RpcError>> + 'static,
)
where
XyRpcChannel<SF, CS>: Clone,
CS: RpcServiceSchema,
MH: ServiceFactory<SF, CS>,
{
self.build_from_compio_read_write(compio::io::split(io))
}
fn build_from_compio_read_write(
self,
(read, write): (
impl AsyncRead + Unpin + 'static,
impl AsyncWrite + Unpin + 'static,
),
) -> (
XyRpcChannel<SF, CS>,
impl Future<Output = Result<(), RpcError>> + 'static,
)
where
XyRpcChannel<SF, CS>: Clone,
CS: RpcServiceSchema,
MH: ServiceFactory<SF, CS>,
{
let read = AsyncStream::new(read);
let write = AsyncStream::new(write);
let stream = new_transport_stream(read);
let sink = new_transport_sink(write);
self.build_from_transport(sink, stream)
}
}
pub async fn write_frame(
mut write: impl AsyncWrite + Unpin,
frame: &RpcFrameHead,
) -> Result<(), RpcError> {
let bits: u64 = frame.into();
write.write_u64(bits).await?;
Ok(())
}
pub async fn read_frame(mut read: impl AsyncRead + Unpin) -> Result<RpcFrameHead, RpcError> {
let bits = read.read_u64().await?;
bits.try_into()
}
pub async fn serve_duplex_from_compio<
SF: SerdeFormat,
T1: 'static,
T2: 'static,
O1: MaybeSend + 'static,
O2: MaybeSend + 'static,
CS1: RpcServiceSchema + MaybeSend + 'static,
CS2: RpcServiceSchema + MaybeSend + 'static,
F1: Future<Output = Result<O1, RpcError>> + MaybeSend + 'static,
F2: Future<Output = Result<O2, RpcError>> + MaybeSend + 'static,
>(
(duplex1, duplex2): (
(
impl AsyncRead + Unpin + MaybeSend + 'static,
impl AsyncWrite + Unpin + MaybeSend + 'static,
),
(
impl AsyncRead + Unpin + MaybeSend + 'static,
impl AsyncWrite + Unpin + MaybeSend + 'static,
),
),
serde_format: SF,
(serve1, mut f1): (
impl FnOnce(XyRpcChannel<SF, CS2>) -> T1,
impl FnMut(XyRpcChannel<SF, CS2>) -> F1 + MaybeSend + 'static,
),
(serve2, mut f2): (
impl FnOnce(XyRpcChannel<SF, CS1>) -> T2,
impl FnMut(XyRpcChannel<SF, CS1>) -> F2 + MaybeSend + 'static,
),
) -> Result<(O1, O2), RpcError>
where
RpcMsgHandlerWrapper<T1>: RpcMsgHandler<CS1>,
RpcMsgHandlerWrapper<T2>: RpcMsgHandler<CS2>,
{
let json_channel_builder = ChannelBuilder::new(serde_format);
let (channel, serve_future_1) = json_channel_builder
.clone()
.call_and_serve(serve1)
.build_from_compio_read_write(duplex1);
let (channel2, serve_future_2) = json_channel_builder
.call_and_serve(serve2)
.build_from_compio_read_write(duplex2);
let r = match futures_util::future::select(
{
let channel = channel.clone();
let channel2 = channel2.clone();
compio::runtime::spawn(
async move { futures_util::try_join!(f1(channel), f2(channel2)) },
)
},
compio::runtime::spawn(async move {
futures_util::try_join!(serve_future_1, serve_future_2)
}),
)
.await
{
Either::Left((f_end, r_future)) => {
let f_end = f_end.map_err(|err| RpcError::OtherError {
message: format!("panic: {err:?}"),
})?;
drop(channel);
drop(channel2);
r_future.await.map_err(|err| RpcError::OtherError {
message: format!("panic: {err:?}"),
})??;
f_end?
}
Either::Right((r_end, f_future)) => {
f_future.await.map_err(|err| RpcError::OtherError {
message: format!("panic: {err:?}"),
})??;
drop(channel);
drop(channel2);
r_end.map_err(|err| RpcError::OtherError {
message: format!("panic: {err:?}"),
})??;
return Err(RpcError::ServeExceptionEnd);
}
};
Ok(r)
}