1use std::collections::VecDeque;
2use std::sync::{Arc, Condvar, Mutex, Weak};
3
4use crate::error::Error;
5use crate::event_stash::EventStash;
6use crate::i_transport::{
7 exception_handler, message_handler, ExceptionHandler, HandlerToken, IFerroRemoteTransportConnection, Message,
8 MessageHandler,
9};
10use crate::task::{Task, TaskCompletionSource};
11
12struct SendOperation {
13 message: Message,
14 tcs: TaskCompletionSource,
15}
16
17struct Queue {
19 send_queue: VecDeque<SendOperation>,
20 worker_is_alive: bool,
21 closed: bool,
23}
24
25struct WorkerState {
26 lock: Mutex<Queue>,
27 signal: Condvar,
29}
30
31pub struct TransportConnectionWrapper {
35 conn: Arc<dyn IFerroRemoteTransportConnection>,
36 on_message: Arc<EventStash<Message>>,
37 on_exception: Arc<EventStash<Error>>,
38 worker: Arc<WorkerState>,
39}
40
41impl TransportConnectionWrapper {
42 pub fn new(conn: Arc<dyn IFerroRemoteTransportConnection>) -> Arc<TransportConnectionWrapper> {
43 Arc::new_cyclic(|this: &Weak<TransportConnectionWrapper>| {
44 let transport: Weak<dyn IFerroRemoteTransportConnection> = this.clone();
45 let on_exception = Arc::new(EventStash::<Error>::new(transport.clone(), None));
46 let on_message = {
47 let on_exception = on_exception.clone();
48 Arc::new(EventStash::<Message>::new(transport, Some(Box::new(move |e| on_exception.fire(e)))))
49 };
50 {
51 let on_exception = on_exception.clone();
52 conn.on_exception(exception_handler(move |_, e| on_exception.fire(e.clone())));
53 }
54 {
55 let on_message = on_message.clone();
56 conn.on_message(message_handler(move |_, m| on_message.fire(m.clone())));
57 }
58 TransportConnectionWrapper {
59 conn,
60 on_message,
61 on_exception,
62 worker: Arc::new(WorkerState {
63 lock: Mutex::new(Queue { send_queue: VecDeque::new(), worker_is_alive: false, closed: false }),
64 signal: Condvar::new(),
65 }),
66 }
67 })
68 }
69
70 fn worker(conn: Arc<dyn IFerroRemoteTransportConnection>, state: Arc<WorkerState>) {
75 loop {
76 let wi = {
77 let mut queue = state.lock.lock().unwrap();
78 loop {
79 if let Some(wi) = queue.send_queue.pop_front() {
80 break Some(wi);
81 }
82 if queue.closed {
83 break None;
84 }
85 queue = state.signal.wait(queue).unwrap();
86 }
87 };
88 let Some(wi) = wi else {
89 return;
90 };
91 match conn.send(wi.message).wait() {
92 Ok(()) => wi.tcs.try_set_result(),
93 Err(e) => wi.tcs.try_set_exception(e),
94 };
95 }
96 }
97}
98
99impl IFerroRemoteTransportConnection for TransportConnectionWrapper {
100 fn dispose(&self) {
101 self.conn.dispose()
102 }
103
104 fn send(&self, data: Message) -> Task {
107 let tcs = TaskCompletionSource::new();
108 let mut queue = self.worker.lock.lock().unwrap();
109 if !queue.worker_is_alive {
110 queue.worker_is_alive = true;
111 let (conn, state) = (self.conn.clone(), self.worker.clone());
112 std::thread::Builder::new()
113 .name("remote-protocol-sender".to_string())
114 .spawn(move || TransportConnectionWrapper::worker(conn, state))
115 .expect("failed to start the sender thread");
116 }
117 queue.send_queue.push_back(SendOperation { message: data, tcs: tcs.clone() });
118 self.worker.signal.notify_one();
119 tcs.task()
120 }
121
122 fn on_message(&self, handler: MessageHandler) -> HandlerToken {
123 self.on_message.add(handler)
124 }
125
126 fn remove_on_message(&self, token: HandlerToken) {
127 self.on_message.remove(token)
128 }
129
130 fn on_exception(&self, handler: ExceptionHandler) -> HandlerToken {
131 self.on_exception.add(handler)
132 }
133
134 fn remove_on_exception(&self, token: HandlerToken) {
135 self.on_exception.remove(token)
136 }
137
138 fn start(&self) {
139 self.conn.start()
140 }
141}
142
143impl Drop for TransportConnectionWrapper {
144 fn drop(&mut self) {
145 self.worker.lock.lock().unwrap().closed = true;
146 self.worker.signal.notify_all();
147 }
148}
149
150#[cfg(test)]
153mod tests {
154 use std::sync::atomic::{AtomicUsize, Ordering};
155 use std::sync::mpsc::channel;
156 use std::time::Duration;
157
158 use super::*;
159 use crate::i_transport::Delegate;
160 use crate::viewport_messages::MeasureViewportMessage;
161
162 const TIMEOUT: Duration = Duration::from_secs(5);
163
164 struct FakeConnection {
167 sent: Mutex<Vec<Message>>,
168 on_message: Mutex<Delegate<Message>>,
169 on_exception: Mutex<Delegate<Error>>,
170 disposed: AtomicUsize,
171 started: AtomicUsize,
172 fail_sends: bool,
173 }
174
175 impl FakeConnection {
176 fn new(fail_sends: bool) -> Arc<FakeConnection> {
177 Arc::new(FakeConnection {
178 sent: Mutex::new(Vec::new()),
179 on_message: Mutex::new(Delegate::new()),
180 on_exception: Mutex::new(Delegate::new()),
181 disposed: AtomicUsize::new(0),
182 started: AtomicUsize::new(0),
183 fail_sends,
184 })
185 }
186
187 fn raise_message(&self, message: Message) {
188 let handlers = self.on_message.lock().unwrap().snapshot();
189 for handler in &handlers {
190 handler(self, &message);
191 }
192 }
193
194 fn raise_exception(&self, e: Error) {
195 let handlers = self.on_exception.lock().unwrap().snapshot();
196 for handler in &handlers {
197 handler(self, &e);
198 }
199 }
200 }
201
202 impl IFerroRemoteTransportConnection for FakeConnection {
203 fn dispose(&self) {
204 self.disposed.fetch_add(1, Ordering::SeqCst);
205 }
206
207 fn send(&self, data: Message) -> Task {
208 if self.fail_sends {
209 return Task::from_result(Err(Error::InvalidOperation("refused".to_string())));
210 }
211 self.sent.lock().unwrap().push(data);
212 Task::completed()
213 }
214
215 fn on_message(&self, handler: MessageHandler) -> HandlerToken {
216 self.on_message.lock().unwrap().add(handler)
217 }
218
219 fn remove_on_message(&self, token: HandlerToken) {
220 self.on_message.lock().unwrap().remove(token);
221 }
222
223 fn on_exception(&self, handler: ExceptionHandler) -> HandlerToken {
224 self.on_exception.lock().unwrap().add(handler)
225 }
226
227 fn remove_on_exception(&self, token: HandlerToken) {
228 self.on_exception.lock().unwrap().remove(token);
229 }
230
231 fn start(&self) {
232 self.started.fetch_add(1, Ordering::SeqCst);
233 }
234 }
235
236 fn measure(width: f64) -> Message {
237 Arc::new(MeasureViewportMessage { width, height: 0.0 })
238 }
239
240 fn width_of(message: &Message) -> f64 {
241 message.downcast_ref::<MeasureViewportMessage>().unwrap().width
242 }
243
244 #[test]
245 fn events_raised_before_a_handler_is_added_are_replayed_to_the_first_handler_in_order() {
246 let inner = FakeConnection::new(false);
247 let wrapper = TransportConnectionWrapper::new(inner.clone());
248 inner.raise_message(measure(1.0));
249 inner.raise_message(measure(2.0));
250 inner.raise_exception(Error::EndOfStream);
251
252 let (sender, received) = channel();
253 wrapper.on_message(message_handler(move |_, m| {
254 let _ = sender.send(width_of(m));
255 }));
256 assert_eq!(received.try_recv(), Ok(1.0));
257 assert_eq!(received.try_recv(), Ok(2.0));
258 assert!(received.try_recv().is_err());
259
260 let (second_sender, second) = channel();
262 wrapper.on_message(message_handler(move |_, m| {
263 let _ = second_sender.send(width_of(m));
264 }));
265 assert!(second.try_recv().is_err());
266 inner.raise_message(measure(3.0));
267 assert_eq!(received.try_recv(), Ok(3.0));
268 assert_eq!(second.try_recv(), Ok(3.0));
269
270 let (error_sender, errors) = channel();
271 wrapper.on_exception(exception_handler(move |_, e| {
272 let _ = error_sender.send(e.clone());
273 }));
274 assert!(matches!(errors.try_recv(), Ok(Error::EndOfStream)));
275 assert!(errors.try_recv().is_err());
276 }
277
278 #[test]
279 fn handlers_receive_the_wrapper_as_the_connection() {
280 let inner = FakeConnection::new(false);
281 let wrapper = TransportConnectionWrapper::new(inner.clone());
282 wrapper.on_message(message_handler(|connection, m| {
285 connection.send(measure(width_of(m) + 1.0));
286 }));
287 inner.raise_message(measure(1.0));
288 let deadline = std::time::Instant::now() + TIMEOUT;
289 while inner.sent.lock().unwrap().is_empty() {
290 assert!(std::time::Instant::now() < deadline, "the answer was not sent");
291 std::thread::sleep(Duration::from_millis(5));
292 }
293 assert_eq!(width_of(&inner.sent.lock().unwrap()[0]), 2.0);
294 }
295
296 #[test]
297 fn a_removed_handler_is_not_called() {
298 let inner = FakeConnection::new(false);
299 let wrapper = TransportConnectionWrapper::new(inner.clone());
300 let (sender, received) = channel();
301 let token = wrapper.on_message(message_handler(move |_, m| {
302 let _ = sender.send(width_of(m));
303 }));
304 inner.raise_message(measure(1.0));
305 wrapper.remove_on_message(token);
306 inner.raise_message(measure(2.0));
308 assert_eq!(received.try_recv(), Ok(1.0));
309 assert!(received.try_recv().is_err());
310 }
311
312 #[test]
313 fn a_panic_of_a_handler_during_the_replay_is_raised_as_an_exception() {
314 let inner = FakeConnection::new(false);
315 let wrapper = TransportConnectionWrapper::new(inner.clone());
316 inner.raise_message(measure(1.0));
317 let (error_sender, errors) = channel();
318 wrapper.on_exception(exception_handler(move |_, e| {
319 let _ = error_sender.send(e.clone());
320 }));
321 wrapper.on_message(message_handler(|_, _| panic!("handler failed")));
322 match errors.try_recv() {
323 Ok(Error::Handler(message)) => assert_eq!(message, "handler failed"),
324 other => panic!("expected the panic of the handler, got {:?}", other),
325 }
326 }
327
328 #[test]
329 fn sends_are_queued_and_sent_in_order() {
330 let inner = FakeConnection::new(false);
331 let wrapper = TransportConnectionWrapper::new(inner.clone());
332 let tasks: Vec<Task> = (0..500).map(|i| wrapper.send(measure(i as f64))).collect();
333 for task in &tasks {
334 assert!(matches!(task.wait_timeout(TIMEOUT), Some(Ok(()))));
335 }
336 let sent = inner.sent.lock().unwrap();
337 assert_eq!(sent.len(), 500);
338 for (i, message) in sent.iter().enumerate() {
339 assert_eq!(width_of(message), i as f64);
340 }
341 }
342
343 #[test]
344 fn a_failed_send_fails_its_task() {
345 let inner = FakeConnection::new(true);
346 let wrapper = TransportConnectionWrapper::new(inner);
347 match wrapper.send(measure(1.0)).wait_timeout(TIMEOUT) {
348 Some(Err(Error::InvalidOperation(message))) => assert_eq!(message, "refused"),
349 other => panic!("expected the failure of the send, got {:?}", other),
350 }
351 }
352
353 #[test]
354 fn dispose_and_start_go_to_the_inner_connection() {
355 let inner = FakeConnection::new(false);
356 let wrapper = TransportConnectionWrapper::new(inner.clone());
357 wrapper.start();
358 wrapper.dispose();
359 assert_eq!(inner.started.load(Ordering::SeqCst), 1);
360 assert_eq!(inner.disposed.load(Ordering::SeqCst), 1);
361 }
362}