1use std::{
8 cell::{Cell, RefCell},
9 rc::Rc,
10 sync::Arc,
11};
12
13use gled_protocol::{
14 action::route_actions_on_this_thread,
15 message::{ClientMessage, ServerMessage, Subscriptions},
16 state::{ClientInput, route_inputs_on_this_thread},
17};
18use web_time::{Duration, Instant};
19
20const SILENCE: Duration = Duration::from_secs(3);
24
25pub trait EngineLink {
27 fn send(&mut self, message: ClientMessage);
28 fn receive(&mut self) -> Vec<ServerMessage>;
30
31 fn is_remote(&self) -> bool {
34 false
35 }
36
37 fn is_open(&self) -> bool {
39 true
40 }
41
42 fn target(&self) -> Option<String> {
45 None
46 }
47
48 fn background_sender(&self) -> Option<BackgroundSender> {
51 None
52 }
53}
54
55pub type BackgroundSender = Arc<dyn Fn(ClientMessage) + Send + Sync>;
57
58#[derive(Debug, Clone, Copy)]
60pub(crate) struct Interruption {
61 pub(crate) last_contact: Duration,
63}
64
65#[derive(Clone)]
68pub struct Connection {
69 link: Rc<RefCell<Box<dyn EngineLink>>>,
70 sequence: Rc<Cell<u64>>,
72 last_contact: Rc<Cell<Option<Instant>>>,
74}
75
76impl std::fmt::Debug for Connection {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 f.debug_struct("Connection")
79 .field("sequence", &self.sequence.get())
80 .finish_non_exhaustive()
81 }
82}
83
84impl Connection {
85 pub fn new(link: Box<dyn EngineLink>, subscriptions: Subscriptions) -> Self {
88 let connection = Self {
89 link: Rc::new(RefCell::new(link)),
90 sequence: Rc::default(),
91 last_contact: Rc::default(),
92 };
93 connection.send(ClientMessage::Subscribe(subscriptions));
94 let actions = connection.clone();
95 route_actions_on_this_thread(move |action| {
96 let sequence = actions.sequence.get() + 1;
97 actions.sequence.set(sequence);
98 actions.send(ClientMessage::Input(ClientInput::Action {
99 sequence,
100 action,
101 }));
102 });
103 let inputs = connection.clone();
104 route_inputs_on_this_thread(move |input| inputs.send(ClientMessage::Input(input)));
105 connection
106 }
107
108 pub(crate) fn send(&self, message: ClientMessage) {
109 match self.link.try_borrow_mut() {
110 Ok(mut link) => link.send(message),
111 Err(_) => tracing::warn!("Dropped {message:?}: the link is busy"),
112 }
113 }
114
115 pub(crate) fn receive(&self) -> Vec<ServerMessage> {
116 let mut link = self.link.borrow_mut();
117 let messages = link.receive();
118 if !messages.is_empty() && link.is_open() {
120 self.last_contact.set(Some(Instant::now()));
121 }
122 messages
123 }
124
125 pub(crate) fn is_remote(&self) -> bool {
127 self.link.borrow().is_remote()
128 }
129
130 pub(crate) fn target(&self) -> Option<String> {
131 self.link.borrow().target()
132 }
133
134 pub(crate) fn background_sender(&self) -> Option<BackgroundSender> {
135 self.link.borrow().background_sender()
136 }
137
138 pub(crate) fn interruption(&self) -> Option<Interruption> {
142 let link = self.link.borrow();
143 let last_contact = self.last_contact.get()?.elapsed();
144 (link.is_remote() && (!link.is_open() || last_contact > SILENCE))
145 .then_some(Interruption { last_contact })
146 }
147
148 pub(crate) fn sent_sequence(&self) -> u64 {
150 self.sequence.get()
151 }
152
153 pub(crate) fn reset_sequence(&self) {
156 self.sequence.set(0);
157 }
158}