reth_ipc/server/
connection.rs1use super::MESSAGE_BUFFER_CAPACITY;
4use crate::stream_codec::StreamCodec;
5use futures::{stream::FuturesUnordered, FutureExt, Sink, Stream};
6use std::{
7 collections::VecDeque,
8 future::Future,
9 io,
10 pin::Pin,
11 task::{Context, Poll},
12};
13use tokio::{
14 io::{AsyncRead, AsyncWrite},
15 sync::mpsc,
16};
17use tokio_util::codec::Framed;
18use tower::Service;
19
20pub(crate) type JsonRpcStream<T> = Framed<T, StreamCodec>;
21
22#[pin_project::pin_project]
23pub(crate) struct IpcConn<T>(#[pin] pub(crate) T);
24
25impl<T> Stream for IpcConn<JsonRpcStream<T>>
26where
27 T: AsyncRead + AsyncWrite,
28{
29 type Item = io::Result<String>;
30
31 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
32 self.project().0.poll_next(cx)
33 }
34}
35
36impl<T> Sink<String> for IpcConn<JsonRpcStream<T>>
37where
38 T: AsyncRead + AsyncWrite,
39{
40 type Error = io::Error;
41
42 fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
43 self.project().0.poll_flush(cx)
46 }
47
48 fn start_send(self: Pin<&mut Self>, item: String) -> Result<(), Self::Error> {
49 self.project().0.start_send(item)
50 }
51
52 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
53 self.project().0.poll_flush(cx)
54 }
55
56 fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
57 self.project().0.poll_close(cx)
58 }
59}
60
61#[pin_project::pin_project]
68#[must_use = "futures do nothing unless you `.await` or poll them"]
69pub(crate) struct IpcConnDriver<T, S, Fut> {
70 #[pin]
71 pub(crate) conn: IpcConn<JsonRpcStream<T>>,
72 pub(crate) service: S,
73 #[pin]
75 pub(crate) pending_calls: FuturesUnordered<Fut>,
76 pub(crate) items: VecDeque<String>,
77 pub(crate) messages: mpsc::Receiver<String>,
79}
80
81impl<T, S> Future for IpcConnDriver<T, S, S::Future>
82where
83 S: Service<String, Response = Option<String>> + Send + 'static,
84 S::Error: Into<Box<dyn core::error::Error + Send + Sync>>,
85 S::Future: Send + Unpin,
86 T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
87{
88 type Output = ();
89
90 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
91 let mut this = self.project();
92
93 let mut budget = 5;
97
98 'outer: loop {
100 budget -= 1;
101 if budget == 0 {
102 cx.waker().wake_by_ref();
104 return Poll::Pending
105 }
106
107 let mut messages_pending = false;
110 while this.items.len() < MESSAGE_BUFFER_CAPACITY {
111 let Poll::Ready(Some(item)) = this.messages.poll_recv(cx) else {
112 messages_pending = true;
113 break
114 };
115 this.items.push_back(item);
116 }
117
118 while this.conn.as_mut().poll_ready(cx).is_ready() {
120 if let Some(item) = this.items.pop_front() {
121 if let Err(err) = this.conn.as_mut().start_send(item) {
122 tracing::warn!("IPC response failed: {:?}", err);
123 return Poll::Ready(())
124 }
125 } else {
126 break
127 }
128 }
129
130 if !messages_pending && this.items.len() < MESSAGE_BUFFER_CAPACITY {
133 continue 'outer
134 }
135
136 'inner: loop {
137 let drained = if this.pending_calls.is_empty() {
139 false
140 } else {
141 if let Poll::Ready(Some(res)) = this.pending_calls.as_mut().poll_next(cx) {
142 let item = match res {
143 Ok(Some(resp)) => resp,
144 Ok(None) => continue 'inner,
145 Err(err) => err.into().to_string(),
146 };
147 this.items.push_back(item);
148 continue 'outer;
149 }
150 true
151 };
152
153 if this.items.len() >= MESSAGE_BUFFER_CAPACITY {
156 return Poll::Pending
157 }
158
159 match this.conn.as_mut().poll_next(cx) {
161 Poll::Ready(res) => match res {
162 Some(Ok(item)) => {
163 let mut call = this.service.call(item);
164 match call.poll_unpin(cx) {
165 Poll::Ready(res) => {
166 let item = match res {
167 Ok(Some(resp)) => resp,
168 Ok(None) => continue 'inner,
169 Err(err) => err.into().to_string(),
170 };
171 this.items.push_back(item);
172 continue 'outer
173 }
174 Poll::Pending => {
175 this.pending_calls.push(call);
176 }
177 }
178 }
179 Some(Err(err)) => {
180 tracing::debug!("IPC request failed: {:?}", err);
182 return Poll::Ready(())
183 }
184 None => return Poll::Ready(()),
185 },
186 Poll::Pending => {
187 if drained || this.pending_calls.is_empty() {
188 return Poll::Pending
190 }
191 }
192 }
193 }
194 }
195 }
196}
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201 use std::{
202 pin::pin,
203 sync::{
204 atomic::{AtomicBool, Ordering},
205 Arc, Mutex,
206 },
207 task::{Wake, Waker},
208 };
209 use tokio::io::ReadBuf;
210 use tokio_util::codec::Decoder;
211
212 #[derive(Clone, Default)]
214 struct MockIo(Arc<Mutex<MockState>>);
215
216 #[derive(Default)]
217 struct MockState {
218 blocked: bool,
219 written: Vec<u8>,
220 }
221
222 impl AsyncRead for MockIo {
223 fn poll_read(
224 self: Pin<&mut Self>,
225 _: &mut Context<'_>,
226 _: &mut ReadBuf<'_>,
227 ) -> Poll<io::Result<()>> {
228 Poll::Pending
229 }
230 }
231
232 impl AsyncWrite for MockIo {
233 fn poll_write(
234 self: Pin<&mut Self>,
235 _: &mut Context<'_>,
236 buf: &[u8],
237 ) -> Poll<io::Result<usize>> {
238 let mut state = self.0.lock().unwrap();
239 if state.blocked {
240 return Poll::Pending
241 }
242 state.written.extend_from_slice(buf);
243 Poll::Ready(Ok(buf.len()))
244 }
245
246 fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
247 Poll::Ready(Ok(()))
248 }
249
250 fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
251 Poll::Ready(Ok(()))
252 }
253 }
254
255 struct NoCalls;
257
258 impl Service<String> for NoCalls {
259 type Response = Option<String>;
260 type Error = io::Error;
261 type Future = std::future::Ready<Result<Self::Response, Self::Error>>;
262
263 fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
264 Poll::Ready(Ok(()))
265 }
266
267 fn call(&mut self, _: String) -> Self::Future {
268 std::future::ready(Ok(None))
269 }
270 }
271
272 #[derive(Default)]
274 struct Woken(AtomicBool);
275
276 impl Wake for Woken {
277 fn wake(self: Arc<Self>) {
278 self.0.store(true, Ordering::Relaxed);
279 }
280 }
281
282 fn poll_until_parked(mut driver: Pin<&mut impl Future<Output = ()>>) {
284 let woken = Arc::new(Woken::default());
285 let waker = Waker::from(woken.clone());
286 let mut cx = Context::from_waker(&waker);
287 loop {
288 woken.0.store(false, Ordering::Relaxed);
289 assert!(driver.as_mut().poll(&mut cx).is_pending());
290 if !woken.0.load(Ordering::Relaxed) {
291 return
292 }
293 }
294 }
295
296 #[test]
297 fn takes_waiting_messages_after_draining_full_queue() {
298 let io = MockIo::default();
299 io.0.lock().unwrap().blocked = true;
300 let (tx, rx) = mpsc::channel(MESSAGE_BUFFER_CAPACITY);
301 let mut driver = pin!(IpcConnDriver {
302 conn: IpcConn(StreamCodec::stream_incoming().framed(io.clone())),
303 service: NoCalls,
304 pending_calls: Default::default(),
305 items: Default::default(),
306 messages: rx,
307 });
308
309 let mut sent = 0;
311 loop {
312 while tx.try_send(format!("<{sent}>")).is_ok() {
313 sent += 1;
314 }
315 poll_until_parked(driver.as_mut());
316 if tx.capacity() == 0 {
317 break
318 }
319 }
320 assert!(io.0.lock().unwrap().written.is_empty());
321
322 io.0.lock().unwrap().blocked = false;
325 poll_until_parked(driver.as_mut());
326
327 let written = String::from_utf8(io.0.lock().unwrap().written.clone()).unwrap();
328 assert_eq!(written.matches('<').count(), sent);
329 }
330}