1use crate::{Client, ClientError};
4use futures::channel::oneshot::{Sender, channel};
5use std::{
6 collections::BTreeMap,
7 fmt,
8 sync::{Arc, Mutex},
9};
10
11#[derive(Clone, Default)]
20pub struct RequestDeduplicationClient<C> {
21 inner: C,
22 requests: Arc<Mutex<BTreeMap<DeduplicationKey, Vec<Sender<Response>>>>>,
23}
24
25impl<C: fmt::Debug> fmt::Debug for RequestDeduplicationClient<C> {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 f.debug_struct("RequestDeduplicationClient")
28 .field("inner", &self.inner)
29 .field("requests", &self.requests.lock().unwrap().len())
30 .finish()
31 }
32}
33
34impl<C> RequestDeduplicationClient<C> {
35 pub fn new(inner: C) -> Self {
36 Self {
37 inner,
38 requests: Arc::new(Mutex::new(BTreeMap::new())),
39 }
40 }
41}
42
43impl<C: Client> Client for RequestDeduplicationClient<C> {
44 #[tracing::instrument(level = "trace")]
45 async fn get(
46 &self,
47 url: &url::Url,
48 params: &[(&str, &str)],
49 ) -> Result<(u16, std::sync::Arc<String>), ClientError> {
50 let response = self
51 .try_get_or_wait(url, params, async {
52 match self.inner.get(url, params).await {
53 Ok((status, data)) => Response::String(status, data),
54 Err(err) => Response::Error(err),
55 }
56 })
57 .await;
58
59 match response {
60 Response::String(status, data) => Ok((status, data)),
61 Response::Binary(_, _) => panic!(),
62 Response::Error(client_error) => Err(client_error),
63 }
64 }
65
66 #[tracing::instrument(level = "trace")]
67 async fn get_bin(
68 &self,
69 url: &url::Url,
70 params: &[(&str, &str)],
71 ) -> Result<(u16, std::sync::Arc<Vec<u8>>), ClientError> {
72 let response = self
73 .try_get_or_wait(url, params, async {
74 match self.inner.get_bin(url, params).await {
75 Ok((status, data)) => Response::Binary(status, data),
76 Err(err) => Response::Error(err),
77 }
78 })
79 .await;
80
81 match response {
82 Response::String(_, _) => panic!(),
83 Response::Binary(status, data) => Ok((status, data)),
84 Response::Error(client_error) => Err(client_error),
85 }
86 }
87}
88
89impl<C: Client> RequestDeduplicationClient<C> {
90 async fn try_get_or_wait(
91 &self,
92 url: &url::Url,
93 params: &[(&str, &str)],
94 getter: impl Future<Output = Response>,
95 ) -> Response {
96 let key = DeduplicationKey {
97 url: url.clone(),
98 params: params
99 .iter()
100 .map(|(k, v)| (k.to_string(), v.to_string()))
101 .collect(),
102 };
103
104 let (rx, request) = {
105 let mut requests = self.requests.lock().unwrap();
106
107 let (tx, rx) = channel::<Response>();
108 match requests.get_mut(&key) {
109 Some(ongoing_requests) => {
110 ongoing_requests.push(tx);
111
112 tracing::trace!(
113 "Deduplicated request to {}. Queue length: {}",
114 key,
115 ongoing_requests.len()
116 );
117 (rx, None)
118 }
119 None => {
120 tracing::debug!("A fresh request to: {}", key);
121
122 requests.insert(key.clone(), vec![tx]);
123
124 let request = async move {
125 let response = getter.await;
126 let mut requests = self.requests.lock().unwrap();
127
128 let senders = requests
129 .remove(&key)
130 .expect("Key no longer exist. This is a bug");
131
132 tracing::debug!(
133 "Sending response of {} to {} requesters",
134 key,
135 senders.len()
136 );
137
138 for tx in senders {
139 tx.send(response.clone()).unwrap();
140 }
141 };
142
143 (rx, Some(request))
144 }
145 }
146 };
147
148 if let Some(request) = request {
150 request.await;
151 }
152
153 rx.await
155 .expect("Dedup channel closed instead of answered. This is a bug")
156 }
157}
158
159#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
160struct DeduplicationKey {
161 url: url::Url,
162 params: Vec<(String, String)>,
163}
164
165impl fmt::Display for DeduplicationKey {
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 write!(f, "DeduplicationKey: {}:{:?}", self.url, self.params)
168 }
169}
170
171#[derive(Debug, Clone)]
172enum Response {
173 String(u16, std::sync::Arc<String>),
174 Binary(u16, std::sync::Arc<Vec<u8>>),
175 Error(ClientError),
176}