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}