1use crate::{RpcHandler, error::RequestError, handler::handle_request};
2use anvil_rpc::{
3 error::RpcError,
4 request::{Id, Request},
5 response::{Response, ResponseResult},
6};
7
8use futures::{FutureExt, Sink, SinkExt, Stream, StreamExt};
9use parking_lot::Mutex;
10use serde::de::DeserializeOwned;
11use std::{
12 collections::VecDeque,
13 fmt,
14 hash::Hash,
15 pin::Pin,
16 sync::Arc,
17 task::{Context, Poll},
18};
19
20pub trait PubSubRpcHandler: Clone + Send + Sync + Unpin + 'static {
22 type Request: DeserializeOwned + Send + Sync + fmt::Debug;
24 type SubscriptionId: Hash + PartialEq + Eq + Send + Sync + fmt::Debug;
26 type Subscription: Stream<Item = serde_json::Value> + Send + Sync + Unpin;
28
29 fn on_request(
31 &self,
32 request: Self::Request,
33 cx: PubSubContext<Self>,
34 ) -> impl Future<Output = ResponseResult> + Send;
35
36 fn on_request_error(
40 &self,
41 _method: &str,
42 _id: &Id,
43 _params: &serde_json::Value,
44 _error: &RpcError,
45 ) {
46 }
47
48 fn close_on_subscription_end(&self, _subscription: &Self::Subscription) -> bool {
50 false
51 }
52}
53
54type Subscriptions<SubscriptionId, Subscription> =
55 Arc<Mutex<VecDeque<(SubscriptionId, Subscription)>>>;
56
57pub struct PubSubContext<Handler: PubSubRpcHandler> {
59 subscriptions: Subscriptions<Handler::SubscriptionId, Handler::Subscription>,
61}
62
63impl<Handler: PubSubRpcHandler> PubSubContext<Handler> {
64 pub fn add_subscription(
68 &self,
69 id: Handler::SubscriptionId,
70 subscription: Handler::Subscription,
71 ) -> Option<Handler::Subscription> {
72 let mut subscriptions = self.subscriptions.lock();
73 let mut removed = None;
74 if let Some(idx) = subscriptions.iter().position(|(i, _)| id == *i) {
75 trace!(target: "rpc", ?id, "removed subscription");
76 removed = Some(subscriptions.swap_remove_back(idx).unwrap().1);
77 }
78 trace!(target: "rpc", ?id, "added subscription");
79 subscriptions.push_back((id, subscription));
80 removed
81 }
82
83 pub fn remove_subscription(
85 &self,
86 id: &Handler::SubscriptionId,
87 ) -> Option<Handler::Subscription> {
88 let mut subscriptions = self.subscriptions.lock();
89 if let Some(idx) = subscriptions.iter().position(|(i, _)| id == i) {
90 trace!(target: "rpc", ?id, "removed subscription");
91 return Some(subscriptions.swap_remove_back(idx).unwrap().1);
92 }
93 None
94 }
95}
96
97impl<Handler: PubSubRpcHandler> Clone for PubSubContext<Handler> {
98 fn clone(&self) -> Self {
99 Self { subscriptions: Arc::clone(&self.subscriptions) }
100 }
101}
102
103impl<Handler: PubSubRpcHandler> Default for PubSubContext<Handler> {
104 fn default() -> Self {
105 Self { subscriptions: Arc::new(Mutex::new(VecDeque::new())) }
106 }
107}
108
109struct ContextAwareHandler<Handler: PubSubRpcHandler> {
111 handler: Handler,
112 context: PubSubContext<Handler>,
113}
114
115impl<Handler: PubSubRpcHandler> Clone for ContextAwareHandler<Handler> {
116 fn clone(&self) -> Self {
117 Self { handler: self.handler.clone(), context: self.context.clone() }
118 }
119}
120
121impl<Handler: PubSubRpcHandler> RpcHandler for ContextAwareHandler<Handler> {
122 type Request = Handler::Request;
123
124 fn on_request(&self, request: Self::Request) -> impl Future<Output = ResponseResult> + Send {
125 self.handler.on_request(request, self.context.clone())
126 }
127
128 fn on_request_error(
129 &self,
130 method: &str,
131 id: &Id,
132 params: &serde_json::Value,
133 error: &RpcError,
134 ) {
135 self.handler.on_request_error(method, id, params, error);
136 }
137}
138
139pub struct PubSubConnection<Handler: PubSubRpcHandler, Connection> {
143 handler: Handler,
145 context: PubSubContext<Handler>,
147 connection: Connection,
149 processing: Vec<Pin<Box<dyn Future<Output = Option<Response>> + Send>>>,
151 pending: PendingMessages,
153}
154
155impl<Handler: PubSubRpcHandler, Connection> PubSubConnection<Handler, Connection> {
156 pub fn new(connection: Connection, handler: Handler) -> Self {
157 Self {
158 connection,
159 handler,
160 context: Default::default(),
161 pending: Default::default(),
162 processing: Default::default(),
163 }
164 }
165
166 fn process_request(&mut self, req: serde_json::Result<Request>) {
167 let handler =
168 ContextAwareHandler { handler: self.handler.clone(), context: self.context.clone() };
169 self.processing.push(Box::pin(async move {
170 match req {
171 Ok(req) => handle_request(req, handler).await,
172 Err(err) => {
173 error!(target: "rpc", ?err, "invalid request");
174 let err = if err.is_syntax() || err.is_eof() {
175 RpcError::parse_error()
176 } else {
177 RpcError::invalid_request()
178 };
179 Some(Response::error(err))
180 }
181 }
182 }));
183 }
184}
185
186impl<Handler, Connection> Future for PubSubConnection<Handler, Connection>
187where
188 Handler: PubSubRpcHandler,
189 Connection: Sink<String> + Stream<Item = Result<Option<Request>, RequestError>> + Unpin,
190 <Connection as Sink<String>>::Error: fmt::Debug,
191{
192 type Output = ();
193
194 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
195 let pin = self.get_mut();
196 let mut remaining = 256;
198 loop {
199 let mut writable = true;
201 loop {
202 match pin.connection.poll_ready_unpin(cx) {
203 Poll::Ready(Ok(())) => {}
204 Poll::Ready(Err(err)) => {
205 trace!(target: "rpc", ?err, "connection err");
206 return Poll::Ready(());
207 }
208 Poll::Pending => {
209 writable = false;
210 break;
211 }
212 }
213 if let Some(msg) = pin.pending.pop_front() {
215 if let Err(err) = pin.connection.start_send_unpin(msg) {
216 error!(target: "rpc", ?err, "Failed to send message");
217 return Poll::Ready(());
218 }
219 } else {
220 break;
221 }
222 }
223
224 if let Poll::Ready(Err(err)) = pin.connection.poll_flush_unpin(cx) {
227 trace!(target: "rpc", ?err, "websocket err");
228 return Poll::Ready(());
230 }
231
232 loop {
233 match pin.connection.poll_next_unpin(cx) {
234 Poll::Ready(Some(req)) => match req {
235 Ok(Some(req)) => {
236 pin.process_request(Ok(req));
237 }
238 Err(err) => match err {
239 RequestError::Axum(err) => {
240 trace!(target: "rpc", ?err, "client disconnected");
241 return Poll::Ready(());
242 }
243 RequestError::Io(err) => {
244 trace!(target: "rpc", ?err, "client disconnected");
245 return Poll::Ready(());
246 }
247 RequestError::Serde(err) => {
248 pin.process_request(Err(err));
249 }
250 RequestError::Disconnect => {
251 trace!(target: "rpc", "client disconnected");
252 return Poll::Ready(());
253 }
254 },
255 _ => {}
256 },
257 Poll::Ready(None) => {
258 trace!(target: "rpc", "socket connection finished");
259 return Poll::Ready(());
260 }
261 Poll::Pending => break,
262 }
263 }
264
265 let mut progress = false;
266 for n in (0..pin.processing.len()).rev() {
267 let mut req = pin.processing.swap_remove(n);
268 #[allow(clippy::collapsible_match)]
269 match req.poll_unpin(cx) {
270 Poll::Ready(Some(resp)) => {
271 if let Ok(text) = serde_json::to_string(&resp) {
272 if !pin.pending.send(&mut pin.connection, cx, text, &mut writable) {
273 return Poll::Ready(());
274 }
275 progress = true;
276 }
277 }
278 Poll::Ready(None) => {}
279 Poll::Pending => pin.processing.push(req),
280 }
281 }
282
283 {
284 let mut subscriptions = pin.context.subscriptions.lock();
286 for _ in 0..subscriptions.len() {
287 let (id, mut sub) = subscriptions.pop_back().unwrap();
288 #[allow(clippy::collapsible_match)]
289 match sub.poll_next_unpin(cx) {
290 Poll::Ready(Some(res)) => {
291 if let Ok(text) = serde_json::to_string(&res) {
292 if !pin.pending.send(&mut pin.connection, cx, text, &mut writable) {
293 return Poll::Ready(());
294 }
295 progress = true;
296 }
297 remaining -= 1;
298 }
299 Poll::Ready(None) => {
300 if pin.handler.close_on_subscription_end(&sub) {
301 warn!(target: "rpc", ?id, "Closing connection after subscription ended");
302 return Poll::Ready(());
303 }
304 continue;
305 }
306 Poll::Pending => {}
307 }
308
309 subscriptions.push_front((id, sub));
310 if remaining == 0 {
311 cx.waker().wake_by_ref();
312 return Poll::Pending;
313 }
314 }
315 }
316
317 if !progress {
318 return Poll::Pending;
319 }
320 }
321 }
322}
323
324#[derive(Default)]
326struct PendingMessages {
327 messages: VecDeque<String>,
328 bytes: usize,
329}
330
331impl PendingMessages {
332 fn pop_front(&mut self) -> Option<String> {
333 let message = self.messages.pop_front()?;
334 self.bytes -= message.len();
335 Some(message)
336 }
337
338 fn send<Connection>(
341 &mut self,
342 connection: &mut Connection,
343 cx: &mut Context<'_>,
344 message: String,
345 writable: &mut bool,
346 ) -> bool
347 where
348 Connection: Sink<String> + Unpin,
349 Connection::Error: fmt::Debug,
350 {
351 if *writable {
352 debug_assert!(self.messages.is_empty());
353 match connection.poll_ready_unpin(cx) {
354 Poll::Ready(Ok(())) => {
355 if let Err(err) = connection.start_send_unpin(message) {
356 error!(target: "rpc", ?err, "Failed to send message");
357 return false;
358 }
359 return true;
360 }
361 Poll::Ready(Err(err)) => {
362 trace!(target: "rpc", ?err, "connection err");
363 return false;
364 }
365 Poll::Pending => *writable = false,
366 }
367 }
368
369 if self.messages.len() >= MAX_PENDING_MESSAGES
370 || message.len() > MAX_PENDING_BYTES - self.bytes
371 {
372 warn!(target: "rpc", "Closing connection because its outgoing backlog is full");
373 return false;
374 }
375 self.bytes += message.len();
376 self.messages.push_back(message);
377 true
378 }
379}
380
381const MAX_PENDING_BYTES: usize = 16 * 1024 * 1024;
383const MAX_PENDING_MESSAGES: usize = 4096;
384
385#[cfg(test)]
386mod tests {
387 use super::*;
388 use anvil_rpc::{
389 request::{RequestParams, RpcCall, RpcNotification, Version},
390 response::RpcResponse,
391 };
392 use futures::channel::mpsc;
393 use std::{
394 pin::pin,
395 sync::atomic::{AtomicUsize, Ordering},
396 task::{Wake, Waker},
397 };
398
399 #[derive(Clone, Default)]
400 struct TestHandler {
401 requests: Arc<AtomicUsize>,
402 remove_on_request: Option<u64>,
403 close_on_end: bool,
404 }
405
406 impl PubSubRpcHandler for TestHandler {
407 type Request = serde_json::Value;
408 type SubscriptionId = u64;
409 type Subscription = Pin<Box<dyn Stream<Item = serde_json::Value> + Send + Sync>>;
410
411 async fn on_request(
412 &self,
413 _request: Self::Request,
414 cx: PubSubContext<Self>,
415 ) -> ResponseResult {
416 self.requests.fetch_add(1, Ordering::Relaxed);
417 if let Some(id) = self.remove_on_request {
418 cx.remove_subscription(&id);
419 }
420 ResponseResult::success(serde_json::Value::Null)
421 }
422
423 fn close_on_subscription_end(&self, _subscription: &Self::Subscription) -> bool {
424 self.close_on_end
425 }
426 }
427
428 fn notification() -> RpcCall {
429 RpcCall::Notification(RpcNotification {
430 jsonrpc: Some(Version::V2),
431 method: "eth_subscribe".to_owned(),
432 params: RequestParams::None,
433 })
434 }
435
436 fn run_ready<F: Future>(future: F) -> F::Output {
437 let waker = Waker::noop();
438 let mut cx = Context::from_waker(waker);
439 let mut future = pin!(future);
440 match future.as_mut().poll(&mut cx) {
441 Poll::Ready(output) => output,
442 Poll::Pending => panic!("future unexpectedly pending"),
443 }
444 }
445
446 #[test]
447 fn process_request_keeps_empty_batch_invalid() {
448 let mut connection = PubSubConnection::new((), TestHandler::default());
449 connection.process_request(Ok(Request::Batch(vec![])));
450
451 let response = run_ready(connection.processing.pop().unwrap());
452 assert_eq!(
453 response,
454 Some(Response::Single(RpcResponse::from(RpcError::invalid_request())))
455 );
456 }
457
458 #[test]
459 fn process_request_returns_parse_error_for_malformed_json() {
460 let mut connection = PubSubConnection::new((), TestHandler::default());
461 connection.process_request(serde_json::from_str("{"));
462
463 let response = run_ready(connection.processing.pop().unwrap());
464 assert_eq!(response, Some(Response::error(RpcError::parse_error())));
465 }
466
467 #[test]
468 fn process_request_executes_notification_without_response() {
469 let handler = TestHandler::default();
470 let mut connection = PubSubConnection::new((), handler.clone());
471 connection.process_request(Ok(Request::Batch(vec![notification()])));
472
473 let response = run_ready(connection.processing.pop().unwrap());
474 assert_eq!(response, None);
475 assert_eq!(handler.requests.load(Ordering::Relaxed), 1);
476 }
477
478 #[derive(Default)]
479 struct TestConnection {
480 ready: bool,
481 fail_next_send: bool,
482 fail_after: Option<usize>,
483 ready_polls: usize,
484 sent: Vec<String>,
485 requests: VecDeque<Request>,
486 send_budget: Option<usize>,
487 ready_waker: Option<Waker>,
488 disconnected: bool,
489 }
490
491 impl Stream for TestConnection {
492 type Item = Result<Option<Request>, RequestError>;
493
494 fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
495 if self.disconnected {
496 return Poll::Ready(None);
497 }
498 match self.requests.pop_front() {
499 Some(request) => Poll::Ready(Some(Ok(Some(request)))),
500 None => Poll::Pending,
501 }
502 }
503 }
504
505 impl Sink<String> for TestConnection {
506 type Error = &'static str;
507
508 fn poll_ready(
509 mut self: Pin<&mut Self>,
510 cx: &mut Context<'_>,
511 ) -> Poll<Result<(), Self::Error>> {
512 let polls = self.ready_polls;
513 self.ready_polls += 1;
514 if self.fail_after.is_some_and(|after| polls >= after) {
515 return Poll::Ready(Err("sink failed"));
516 }
517 if self.ready {
518 Poll::Ready(Ok(()))
519 } else {
520 self.ready_waker = Some(cx.waker().clone());
521 Poll::Pending
522 }
523 }
524
525 fn start_send(mut self: Pin<&mut Self>, item: String) -> Result<(), Self::Error> {
526 assert!(self.ready);
527 if self.fail_next_send {
528 self.fail_next_send = false;
529 return Err("sink failed");
530 }
531 self.sent.push(item);
532 if let Some(budget) = &mut self.send_budget {
533 *budget -= 1;
534 self.ready = *budget != 0;
535 }
536 Ok(())
537 }
538
539 fn poll_flush(
540 self: Pin<&mut Self>,
541 _cx: &mut Context<'_>,
542 ) -> Poll<Result<(), Self::Error>> {
543 Poll::Ready(Ok(()))
544 }
545
546 fn poll_close(
547 self: Pin<&mut Self>,
548 _cx: &mut Context<'_>,
549 ) -> Poll<Result<(), Self::Error>> {
550 Poll::Ready(Ok(()))
551 }
552 }
553
554 #[test]
555 fn sink_readiness_error_terminates_connection() {
556 for fail_after in [0, 1] {
557 let transport =
558 TestConnection { ready: true, fail_after: Some(fail_after), ..Default::default() };
559 let mut connection = PubSubConnection::new(transport, TestHandler::default());
560 connection.context.add_subscription(
561 1,
562 Box::pin(futures::stream::iter(vec![serde_json::Value::Null])),
563 );
564
565 assert!(poll_once(&mut connection).is_ready());
566 assert!(connection.connection.sent.is_empty());
567 }
568 }
569
570 #[test]
571 fn response_start_send_error_terminates_connection() {
572 let transport = TestConnection { ready: true, fail_next_send: true, ..Default::default() };
573 let mut connection = PubSubConnection::new(transport, TestHandler::default());
574 connection.connection.requests.push_back(Request::Batch(vec![]));
575
576 assert!(poll_once(&mut connection).is_ready());
577 assert!(!connection.connection.fail_next_send);
578 }
579
580 #[test]
581 fn subscription_backpressure_limits_readiness_scan_and_allows_disconnect() {
582 for count in [1, 64] {
583 let mut connection = connection();
584 for id in 0..count {
585 connection.context.add_subscription(
586 id,
587 Box::pin(futures::stream::iter(vec![serde_json::Value::from(id)])),
588 );
589 }
590
591 assert!(poll_once(&mut connection).is_pending());
592 assert_eq!(connection.connection.ready_polls, 2);
594 assert!(connection.connection.sent.is_empty());
595 assert_eq!(connection.pending.messages.len(), count as usize);
596 assert!(connection.context.subscriptions.lock().is_empty());
597
598 connection.connection.disconnected = true;
599 assert!(poll_once(&mut connection).is_ready());
600 assert!(connection.connection.sent.is_empty());
601 }
602 }
603
604 #[derive(Default)]
605 struct TestWake(AtomicUsize);
606
607 impl Wake for TestWake {
608 fn wake(self: Arc<Self>) {
609 self.0.fetch_add(1, Ordering::Relaxed);
610 }
611 }
612
613 #[test]
614 fn subscription_backpressure_wakes_and_rotates_fairly() {
615 let count = 3;
616 let mut connection = connection();
617 for id in 1..=count {
618 let events = (0..if id == count { 12 } else { 3 })
619 .map(|event| serde_json::json!([id, event]))
620 .collect::<Vec<_>>();
621 connection.context.add_subscription(id, Box::pin(futures::stream::iter(events)));
622 }
623 connection.context.add_subscription(count + 1, Box::pin(futures::stream::pending()));
624 connection.context.add_subscription(count + 2, Box::pin(futures::stream::empty()));
625 let wake = Arc::new(TestWake::default());
626 let waker = Waker::from(wake.clone());
627 let mut cx = Context::from_waker(&waker);
628 assert!(Pin::new(&mut connection).poll(&mut cx).is_pending());
629
630 for window in 0..count * 3 {
631 connection.connection.ready = true;
632 connection.connection.send_budget = Some(1);
633 connection.connection.ready_waker.take().unwrap().wake();
634 assert_eq!(wake.0.swap(0, Ordering::Relaxed), 1);
635 assert!(Pin::new(&mut connection).poll(&mut cx).is_pending());
636 assert_eq!(connection.connection.sent.len(), window as usize + 1);
637 }
638 let mut sent = sent_events(&connection.connection);
639 for (event, window) in sent.as_chunks_mut::<3>().0.iter_mut().enumerate() {
640 window.sort_unstable();
641 assert_eq!(*window, [[1, event as u64], [2, event as u64], [3, event as u64]]);
642 }
643
644 connection.connection.ready = true;
645 connection.connection.send_budget = None;
646 connection.connection.ready_waker.take().unwrap().wake();
647 assert_eq!(wake.0.swap(0, Ordering::Relaxed), 1);
648 assert!(Pin::new(&mut connection).poll(&mut cx).is_pending());
649 let sent = sent_events(&connection.connection);
650 assert_eq!(sent.len(), 18);
651 for id in 1..=count {
652 let events = sent.iter().filter(|event| event[0] == id).map(|event| event[1]);
653 assert_eq!(
654 events.collect::<Vec<_>>(),
655 (0..if id == count { 12 } else { 3 }).collect::<Vec<_>>()
656 );
657 }
658 assert_eq!(sent[9..], (3..12).map(|event| [count, event]).collect::<Vec<_>>());
659 assert_eq!(connection.context.subscriptions.lock().len(), 1);
660 assert!(connection.context.remove_subscription(&(count + 1)).is_some());
661 }
662
663 #[test]
664 fn subscription_end_closes_only_when_requested() {
665 for close_on_end in [false, true] {
666 let handler = TestHandler { close_on_end, ..Default::default() };
667 let mut connection = PubSubConnection::new(TestConnection::default(), handler);
668 connection.context.add_subscription(1, Box::pin(futures::stream::empty()));
669
670 assert_eq!(poll_once(&mut connection).is_ready(), close_on_end);
671 assert!(connection.connection.sent.is_empty());
672 }
673 }
674
675 #[test]
676 fn subscription_backpressure_allows_unsubscribe_and_replacement() {
677 let handler = TestHandler { remove_on_request: Some(1), ..Default::default() };
678 let mut connection = PubSubConnection::new(TestConnection::default(), handler.clone());
679 let mut senders = Vec::new();
680 for id in 1..=3 {
681 let (tx, rx) = mpsc::unbounded();
682 tx.unbounded_send(serde_json::json!(id)).unwrap();
683 senders.push(tx);
684 connection.context.add_subscription(id, Box::pin(rx));
685 }
686 let mut cx = Context::from_waker(Waker::noop());
687 assert!(poll_once(&mut connection).is_pending());
688 assert_eq!(connection.pending.messages.len(), 3);
689
690 let mut replaced = connection
691 .context
692 .add_subscription(2, Box::pin(futures::stream::iter(vec![serde_json::json!(20)])))
693 .unwrap();
694 assert!(replaced.poll_next_unpin(&mut cx).is_pending());
695 drop(replaced);
696 connection.connection.requests.push_back(Request::Single(notification()));
697 assert!(poll_once(&mut connection).is_pending());
698 assert_eq!(handler.requests.load(Ordering::Relaxed), 1);
699 assert_eq!(connection.pending.messages.len(), 4);
700 assert!(connection.context.remove_subscription(&1).is_none());
701 assert!(connection.connection.sent.is_empty());
702 assert!(senders[0].unbounded_send(serde_json::json!(10)).is_err());
703 assert!(senders[1].unbounded_send(serde_json::json!(20)).is_err());
704 senders[2].unbounded_send(serde_json::json!(30)).unwrap();
705
706 connection.connection.ready = true;
707 assert!(poll_once(&mut connection).is_pending());
708 assert_eq!(connection.connection.sent.len(), 5);
710 let (initial, later) = connection.connection.sent.split_at_mut(3);
711 initial.sort_unstable();
712 assert_eq!(initial, ["1", "2", "3"]);
713 assert_eq!(later, ["20", "30"]);
714 assert!(connection.pending.messages.is_empty());
715 assert_eq!(connection.context.subscriptions.lock().len(), 1);
716 }
717
718 #[test]
719 fn subscription_backpressure_drains_bounded_upstream() {
720 let (mut tx, rx) = mpsc::channel(2048);
721 let mut connection = connection();
722 connection.context.add_subscription(1, Box::pin(rx.map(serde_json::Value::from)));
723
724 for event in 0..3000 {
725 tx.try_send(event).expect("the blocked connection must keep draining its upstream");
726 assert!(poll_once(&mut connection).is_pending());
727 }
728
729 connection.connection.ready = true;
730 assert!(poll_once(&mut connection).is_pending());
731 assert_eq!(
732 connection.connection.sent,
733 (0..3000).map(|event| event.to_string()).collect::<Vec<_>>()
734 );
735 }
736
737 #[test]
738 fn subscription_backlog_overflow_terminates_connection() {
739 let mut connection = connection();
740 connection
741 .context
742 .add_subscription(1, Box::pin(futures::stream::repeat(serde_json::Value::Null)));
743
744 assert!((0..=MAX_PENDING_MESSAGES).any(|_| poll_once(&mut connection).is_ready()));
745 assert_eq!(connection.pending.messages.len(), MAX_PENDING_MESSAGES);
746 assert!(connection.connection.sent.is_empty());
747 }
748
749 #[test]
750 fn responses_and_subscriptions_share_backlog_limit() {
751 let (tx, rx) = mpsc::unbounded();
752 let mut connection = connection();
753 connection.context.add_subscription(1, Box::pin(rx));
754
755 for _ in 0..MAX_PENDING_MESSAGES - 1 {
756 tx.unbounded_send(serde_json::Value::Null).unwrap();
757 assert!(poll_once(&mut connection).is_pending());
758 }
759 connection.connection.requests.push_back(Request::Batch(vec![]));
760 assert!(poll_once(&mut connection).is_pending());
761 assert_eq!(connection.pending.messages.len(), MAX_PENDING_MESSAGES);
762
763 tx.unbounded_send(serde_json::Value::Null).unwrap();
764 assert!(poll_once(&mut connection).is_ready());
765 assert!(connection.connection.sent.is_empty());
766 }
767
768 #[test]
769 fn backlog_byte_limit_reclaims_drained_messages() {
770 let (tx, rx) = mpsc::unbounded();
771 let mut connection = connection();
772 connection.context.add_subscription(1, Box::pin(rx));
773 let message = serde_json::Value::String("x".repeat(MAX_PENDING_BYTES / 2 - 2));
775 for _ in 0..2 {
776 tx.unbounded_send(message.clone()).unwrap();
777 assert!(poll_once(&mut connection).is_pending());
778 }
779 assert_eq!(connection.pending.bytes, MAX_PENDING_BYTES);
780
781 connection.connection.ready = true;
782 connection.connection.send_budget = Some(1);
783 assert!(poll_once(&mut connection).is_pending());
784 assert_eq!(connection.connection.sent.len(), 1);
785 assert_eq!(connection.pending.bytes, MAX_PENDING_BYTES / 2);
786
787 tx.unbounded_send(message).unwrap();
788 assert!(poll_once(&mut connection).is_pending());
789 assert_eq!(connection.pending.bytes, MAX_PENDING_BYTES);
790
791 tx.unbounded_send(serde_json::Value::Null).unwrap();
792 assert!(poll_once(&mut connection).is_ready());
793 assert_eq!(connection.pending.messages.len(), 2);
794 assert_eq!(connection.pending.bytes, MAX_PENDING_BYTES);
795 }
796
797 #[test]
798 fn oversized_message_requires_writable_connection() {
799 for ready in [true, false] {
800 let transport = TestConnection { ready, ..Default::default() };
801 let mut connection = PubSubConnection::new(transport, TestHandler::default());
802 connection.context.add_subscription(
803 1,
804 Box::pin(futures::stream::iter([serde_json::Value::String(
805 "x".repeat(MAX_PENDING_BYTES),
806 )])),
807 );
808
809 assert_eq!(poll_once(&mut connection).is_pending(), ready);
810 if ready {
811 assert_eq!(connection.connection.sent[0].len(), MAX_PENDING_BYTES + 2);
812 } else {
813 assert!(connection.connection.sent.is_empty());
814 }
815 assert_eq!(connection.pending.bytes, 0);
816 assert!(connection.pending.messages.is_empty());
817 }
818 }
819
820 #[test]
821 fn writable_subscription_burst_yields_and_rotates_without_buffering() {
822 let transport = TestConnection { ready: true, ..Default::default() };
823 let mut connection = PubSubConnection::new(transport, TestHandler::default());
824 connection
825 .context
826 .add_subscription(1, Box::pin(futures::stream::iter([serde_json::json!(2)])));
827 connection.context.add_subscription(
828 2,
829 Box::pin(futures::stream::iter(vec![serde_json::json!(1); MAX_PENDING_MESSAGES + 1])),
830 );
831 let wake = Arc::new(TestWake::default());
832 let waker = Waker::from(wake.clone());
833 let mut cx = Context::from_waker(&waker);
834
835 assert!(Pin::new(&mut connection).poll(&mut cx).is_pending());
836 assert_eq!(wake.0.swap(0, Ordering::Relaxed), 1);
837 let mut first = connection.connection.sent[..2].to_vec();
838 first.sort_unstable();
839 assert_eq!(first, ["1", "2"]);
840 assert!(connection.connection.sent.len() < MAX_PENDING_MESSAGES);
841
842 for _ in 0..MAX_PENDING_MESSAGES {
843 assert!(Pin::new(&mut connection).poll(&mut cx).is_pending());
844 if connection.context.subscriptions.lock().is_empty() {
845 break;
846 }
847 }
848 assert!(connection.context.subscriptions.lock().is_empty());
849 assert_eq!(connection.connection.sent.len(), MAX_PENDING_MESSAGES + 2);
850 assert_eq!(connection.connection.sent[2..], vec!["1"; MAX_PENDING_MESSAGES]);
851 assert!(connection.pending.messages.is_empty());
852 assert_eq!(connection.pending.bytes, 0);
853 }
854
855 fn connection() -> PubSubConnection<TestHandler, TestConnection> {
856 PubSubConnection::new(TestConnection::default(), TestHandler::default())
857 }
858
859 fn poll_once(connection: &mut PubSubConnection<TestHandler, TestConnection>) -> Poll<()> {
860 Pin::new(connection).poll(&mut Context::from_waker(Waker::noop()))
861 }
862
863 fn sent_events(connection: &TestConnection) -> Vec<[u64; 2]> {
864 connection.sent.iter().map(|event| serde_json::from_str(event).unwrap()).collect()
865 }
866}