Skip to main content

hashtree_cli/webrtc/
session.rs

1use anyhow::Result;
2use std::sync::Arc;
3use std::time::Duration;
4
5use nostr::{Event, Filter};
6
7use super::bluetooth_peer::BluetoothPeer;
8use super::peer::Peer;
9use super::signaling::PeerTransport;
10use super::types::{MeshNostrFrame, PeerHTLConfig};
11
12#[derive(Clone)]
13pub enum MeshPeer {
14    WebRtc(Arc<Peer>),
15    Bluetooth(Arc<BluetoothPeer>),
16    #[cfg(test)]
17    Mock(Arc<TestMeshPeer>),
18}
19
20impl MeshPeer {
21    pub fn is_ready(&self) -> bool {
22        match self {
23            Self::WebRtc(peer) => peer.has_data_channel(),
24            Self::Bluetooth(peer) => peer.is_connected(),
25            #[cfg(test)]
26            Self::Mock(peer) => peer.ready,
27        }
28    }
29
30    pub fn is_connected(&self) -> bool {
31        match self {
32            Self::WebRtc(peer) => peer.is_connected(),
33            Self::Bluetooth(peer) => peer.is_connected(),
34            #[cfg(test)]
35            Self::Mock(peer) => peer.connected,
36        }
37    }
38
39    pub fn htl_config(&self) -> PeerHTLConfig {
40        match self {
41            Self::WebRtc(peer) => *peer.htl_config(),
42            Self::Bluetooth(peer) => *peer.htl_config(),
43            #[cfg(test)]
44            Self::Mock(peer) => peer.htl_config,
45        }
46    }
47
48    pub fn transport(&self) -> PeerTransport {
49        match self {
50            Self::WebRtc(_) => PeerTransport::WebRtc,
51            Self::Bluetooth(_) => PeerTransport::Bluetooth,
52            #[cfg(test)]
53            Self::Mock(_) => PeerTransport::WebRtc,
54        }
55    }
56
57    pub async fn request(&self, hash_hex: &str, timeout: Duration) -> Result<Option<Vec<u8>>> {
58        match self {
59            Self::WebRtc(peer) => peer.request_with_timeout(hash_hex, timeout).await,
60            Self::Bluetooth(peer) => peer.request_with_timeout(hash_hex, timeout).await,
61            #[cfg(test)]
62            Self::Mock(peer) => peer.request(hash_hex, timeout).await,
63        }
64    }
65
66    pub async fn query_nostr_events(
67        &self,
68        filters: Vec<Filter>,
69        timeout: Duration,
70    ) -> Result<Vec<Event>> {
71        match self {
72            Self::WebRtc(peer) => peer.query_nostr_events(filters, timeout).await,
73            Self::Bluetooth(peer) => peer.query_nostr_events(filters, timeout).await,
74            #[cfg(test)]
75            Self::Mock(peer) => peer.query_nostr_events(filters, timeout).await,
76        }
77    }
78
79    pub async fn send_mesh_frame_text(&self, frame: &MeshNostrFrame) -> Result<()> {
80        match self {
81            Self::WebRtc(peer) => peer.send_mesh_frame_text(frame).await,
82            Self::Bluetooth(peer) => peer.send_mesh_frame_text(frame).await,
83            #[cfg(test)]
84            Self::Mock(peer) => peer.send_mesh_frame_text(frame).await,
85        }
86    }
87
88    pub async fn close(&self) -> Result<()> {
89        match self {
90            Self::WebRtc(peer) => peer.close().await,
91            Self::Bluetooth(peer) => peer.close().await,
92            #[cfg(test)]
93            Self::Mock(peer) => peer.close().await,
94        }
95    }
96
97    pub fn as_webrtc(&self) -> Option<&Arc<Peer>> {
98        match self {
99            Self::WebRtc(peer) => Some(peer),
100            Self::Bluetooth(_) => None,
101            #[cfg(test)]
102            Self::Mock(_) => None,
103        }
104    }
105}
106
107#[cfg(test)]
108use anyhow::anyhow;
109
110#[cfg(test)]
111pub struct TestMeshPeer {
112    pub ready: bool,
113    pub connected: bool,
114    pub htl_config: PeerHTLConfig,
115    request_response: tokio::sync::Mutex<Option<Vec<u8>>>,
116    response_delay: Duration,
117    query_events: tokio::sync::Mutex<Vec<Event>>,
118    query_delay: Duration,
119    sent_frames: tokio::sync::Mutex<Vec<MeshNostrFrame>>,
120    close_delay: Duration,
121    closed: std::sync::atomic::AtomicBool,
122}
123
124#[cfg(test)]
125impl TestMeshPeer {
126    pub fn with_response(response: Option<Vec<u8>>) -> Self {
127        Self {
128            ready: true,
129            connected: true,
130            htl_config: PeerHTLConfig::from_flags(false, false),
131            request_response: tokio::sync::Mutex::new(response),
132            response_delay: Duration::ZERO,
133            query_events: tokio::sync::Mutex::new(Vec::new()),
134            query_delay: Duration::ZERO,
135            sent_frames: tokio::sync::Mutex::new(Vec::new()),
136            close_delay: Duration::ZERO,
137            closed: std::sync::atomic::AtomicBool::new(false),
138        }
139    }
140
141    pub fn with_delayed_response(response: Option<Vec<u8>>, response_delay: Duration) -> Self {
142        Self {
143            ready: true,
144            connected: true,
145            htl_config: PeerHTLConfig::from_flags(false, false),
146            request_response: tokio::sync::Mutex::new(response),
147            response_delay,
148            query_events: tokio::sync::Mutex::new(Vec::new()),
149            query_delay: Duration::ZERO,
150            sent_frames: tokio::sync::Mutex::new(Vec::new()),
151            close_delay: Duration::ZERO,
152            closed: std::sync::atomic::AtomicBool::new(false),
153        }
154    }
155
156    pub fn with_events(events: Vec<Event>) -> Self {
157        Self {
158            ready: true,
159            connected: true,
160            htl_config: PeerHTLConfig::from_flags(false, false),
161            request_response: tokio::sync::Mutex::new(None),
162            response_delay: Duration::ZERO,
163            query_events: tokio::sync::Mutex::new(events),
164            query_delay: Duration::ZERO,
165            sent_frames: tokio::sync::Mutex::new(Vec::new()),
166            close_delay: Duration::ZERO,
167            closed: std::sync::atomic::AtomicBool::new(false),
168        }
169    }
170
171    pub fn with_delayed_events(events: Vec<Event>, query_delay: Duration) -> Self {
172        Self {
173            ready: true,
174            connected: true,
175            htl_config: PeerHTLConfig::from_flags(false, false),
176            request_response: tokio::sync::Mutex::new(None),
177            response_delay: Duration::ZERO,
178            query_events: tokio::sync::Mutex::new(events),
179            query_delay,
180            sent_frames: tokio::sync::Mutex::new(Vec::new()),
181            close_delay: Duration::ZERO,
182            closed: std::sync::atomic::AtomicBool::new(false),
183        }
184    }
185
186    pub fn with_delayed_close(close_delay: Duration) -> Self {
187        Self {
188            ready: true,
189            connected: false,
190            htl_config: PeerHTLConfig::from_flags(false, false),
191            request_response: tokio::sync::Mutex::new(None),
192            response_delay: Duration::ZERO,
193            query_events: tokio::sync::Mutex::new(Vec::new()),
194            query_delay: Duration::ZERO,
195            sent_frames: tokio::sync::Mutex::new(Vec::new()),
196            close_delay,
197            closed: std::sync::atomic::AtomicBool::new(false),
198        }
199    }
200
201    pub async fn request(&self, _hash_hex: &str, _timeout: Duration) -> Result<Option<Vec<u8>>> {
202        if !self.response_delay.is_zero() {
203            tokio::time::sleep(self.response_delay).await;
204        }
205        Ok(self.request_response.lock().await.clone())
206    }
207
208    pub async fn query_nostr_events(
209        &self,
210        _filters: Vec<Filter>,
211        _timeout: Duration,
212    ) -> Result<Vec<Event>> {
213        if !self.query_delay.is_zero() {
214            tokio::time::sleep(self.query_delay).await;
215        }
216        Ok(self.query_events.lock().await.clone())
217    }
218
219    pub async fn send_mesh_frame_text(&self, frame: &MeshNostrFrame) -> Result<()> {
220        self.sent_frames.lock().await.push(frame.clone());
221        Ok(())
222    }
223
224    pub async fn close(&self) -> Result<()> {
225        if !self.close_delay.is_zero() {
226            tokio::time::sleep(self.close_delay).await;
227        }
228        self.closed
229            .store(true, std::sync::atomic::Ordering::Relaxed);
230        Ok(())
231    }
232
233    pub async fn sent_frame_count(&self) -> usize {
234        self.sent_frames.lock().await.len()
235    }
236
237    pub fn is_closed(&self) -> bool {
238        self.closed.load(std::sync::atomic::Ordering::Relaxed)
239    }
240}
241
242#[cfg(test)]
243impl MeshPeer {
244    pub fn mock_for_tests(peer: TestMeshPeer) -> Self {
245        Self::Mock(Arc::new(peer))
246    }
247
248    pub fn mock_ref(&self) -> Result<&Arc<TestMeshPeer>> {
249        match self {
250            Self::Mock(peer) => Ok(peer),
251            _ => Err(anyhow!("mesh peer is not a mock")),
252        }
253    }
254}