Skip to main content

wrpc_transport/frame/conn/
server.rs

1use core::fmt::{Debug, Display};
2use core::marker::PhantomData;
3
4use std::collections::{HashMap, hash_map};
5use std::sync::Arc;
6
7use anyhow::bail;
8use futures::{Stream, StreamExt as _};
9use tokio::io::{AsyncBufRead, AsyncWrite};
10use tokio::sync::{Mutex, mpsc};
11use tokio_stream::wrappers::ReceiverStream;
12use tracing::{instrument, trace};
13
14use crate::Serve;
15use crate::frame::{ConnHandler, Header, HeaderReadError, Incoming, Outgoing};
16
17/// wRPC server for framed transports
18#[derive(Debug)]
19pub struct Server<C, I, O, H = ()> {
20    handlers: Mutex<HashMap<String, HashMap<String, mpsc::Sender<(C, I, O)>>>>,
21    conn_handler: PhantomData<H>,
22}
23
24impl<C, I, O, H> Server<C, I, O, H> {
25    /// Constructs a new [Server]
26    #[must_use]
27    pub fn new() -> Self {
28        Self {
29            handlers: Mutex::default(),
30            conn_handler: PhantomData,
31        }
32    }
33}
34
35impl<C, I, O> Default for Server<C, I, O> {
36    fn default() -> Self {
37        Self::new()
38    }
39}
40
41/// Error returned by [`Server::accept`]
42pub enum AcceptError<C, I, O> {
43    /// Header read error
44    HeaderRead(HeaderReadError),
45    /// Function was not handled
46    UnhandledFunction {
47        /// Instance
48        instance: String,
49        /// Function name
50        name: String,
51    },
52    /// Message sending failed
53    Send(mpsc::error::SendError<(C, I, O)>),
54}
55
56impl<C, I, O> From<HeaderReadError> for AcceptError<C, I, O> {
57    fn from(err: HeaderReadError) -> Self {
58        Self::HeaderRead(err)
59    }
60}
61
62impl<C, I, O> From<mpsc::error::SendError<(C, I, O)>> for AcceptError<C, I, O> {
63    fn from(err: mpsc::error::SendError<(C, I, O)>) -> Self {
64        Self::Send(err)
65    }
66}
67
68impl<C, I, O> Debug for AcceptError<C, I, O> {
69    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
70        match self {
71            Self::HeaderRead(err) => Debug::fmt(err, f),
72            Self::UnhandledFunction { instance, name } => {
73                write!(f, "`{instance}#{name}` does not have a handler registered")
74            }
75            Self::Send(err) => Debug::fmt(err, f),
76        }
77    }
78}
79
80impl<C, I, O> Display for AcceptError<C, I, O> {
81    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
82        match self {
83            Self::HeaderRead(err) => Display::fmt(err, f),
84            Self::UnhandledFunction { instance, name } => {
85                write!(f, "`{instance}#{name}` does not have a handler registered")
86            }
87            Self::Send(err) => Display::fmt(err, f),
88        }
89    }
90}
91
92impl<C, I, O> core::error::Error for AcceptError<C, I, O> {}
93
94impl<C, I, O, H> Server<C, I, O, H>
95where
96    I: AsyncBufRead + Unpin,
97    H: ConnHandler<I, O>,
98{
99    /// Accept an already-established connection.
100    ///
101    /// # Errors
102    ///
103    /// Returns an error if handling the invocation fails
104    #[instrument(level = "trace", skip_all, ret(level = "trace"))]
105    pub async fn accept(&self, cx: C, tx: O, mut rx: I) -> Result<(), AcceptError<C, I, O>> {
106        let Header { instance, name } = Header::read(&mut rx).await?;
107        let h = self
108            .handlers
109            .lock()
110            .await
111            .get(&instance)
112            .and_then(|h| h.get(&name))
113            .cloned()
114            .ok_or_else(|| AcceptError::UnhandledFunction { instance, name })?;
115        h.send((cx, rx, tx)).await?;
116        Ok(())
117    }
118}
119
120#[instrument(level = "trace", skip(srv, paths))]
121async fn serve<C, I, O, H>(
122    srv: &Server<C, I, O, H>,
123    instance: &str,
124    func: &str,
125    paths: Arc<[Box<[Option<usize>]>]>,
126) -> anyhow::Result<
127    impl Stream<Item = anyhow::Result<(C, Outgoing, Incoming)>> + 'static + use<C, I, O, H>,
128>
129where
130    C: Send + Sync + 'static,
131    I: AsyncBufRead + Send + Sync + Unpin + 'static,
132    O: AsyncWrite + Send + Sync + Unpin + 'static,
133    H: ConnHandler<I, O>,
134{
135    let (tx, rx) = mpsc::channel(1024);
136    let mut handlers = srv.handlers.lock().await;
137    match handlers
138        .entry(instance.to_string())
139        .or_default()
140        .entry(func.to_string())
141    {
142        hash_map::Entry::Occupied(_) => {
143            bail!("handler for `{instance}#{func}` already exists")
144        }
145        hash_map::Entry::Vacant(entry) => {
146            entry.insert(tx);
147        }
148    }
149    Ok(ReceiverStream::new(rx).map(move |(cx, rx, tx)| {
150        trace!("received invocation");
151        let rx = Incoming::new(rx, paths.as_ref(), H::DRAIN, |rx, res| {
152            H::on_ingress(rx, res)
153        });
154        let tx = Outgoing::new(tx, |tx, res| H::on_egress(tx, res));
155        Ok((cx, tx, rx))
156    }))
157}
158
159impl<C, I, O, H> Serve for Server<C, I, O, H>
160where
161    C: Send + Sync + 'static,
162    I: AsyncBufRead + Send + Sync + Unpin + 'static,
163    O: AsyncWrite + Send + Sync + Unpin + 'static,
164    H: ConnHandler<I, O> + Send + Sync,
165{
166    type Context = C;
167
168    async fn serve(
169        &self,
170        instance: &str,
171        func: &str,
172        paths: Arc<[Box<[Option<usize>]>]>,
173    ) -> anyhow::Result<
174        impl Stream<Item = anyhow::Result<(Self::Context, Outgoing, Incoming)>>
175        + 'static
176        + use<C, I, O, H>,
177    > {
178        serve(self, instance, func, paths).await
179    }
180}
181
182impl<'a, C, I, O, H> Serve for &'a Server<C, I, O, H>
183where
184    C: Send + Sync + 'static,
185    I: AsyncBufRead + Send + Sync + Unpin + 'static,
186    O: AsyncWrite + Send + Sync + Unpin + 'static,
187    H: ConnHandler<I, O> + Send + Sync,
188{
189    type Context = C;
190
191    async fn serve(
192        &self,
193        instance: &str,
194        func: &str,
195        paths: Arc<[Box<[Option<usize>]>]>,
196    ) -> anyhow::Result<
197        impl Stream<Item = anyhow::Result<(Self::Context, Outgoing, Incoming)>>
198        + 'static
199        + use<'a, C, I, O, H>,
200    > {
201        serve(self, instance, func, paths).await
202    }
203}