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