1use std::{
19 collections::HashMap,
20 io::{self, Read, Write},
21 sync::{
22 Arc,
23 atomic::{AtomicU32, Ordering},
24 mpsc::{Receiver, SyncSender, sync_channel},
25 },
26};
27
28use parking_lot::Mutex;
29
30use crate::wearable::{
31 WearableError, WearableEvent, WearableLink, WearablePeer, WearableStream,
32 publish_wearable_event,
33};
34
35pub const CHUNK_BYTES: usize = 16 * 1024;
40
41const PENDING_CHUNKS: usize = 256;
44
45const MESSAGE: u8 = 0;
46const OPEN: u8 = 1;
47const CHUNK: u8 = 2;
48const END: u8 = 3;
49
50const STREAM_HEADER: usize = 5;
52
53pub trait WearableTransport: Send + Sync + 'static {
55 fn peers(&self) -> Result<Vec<WearablePeer>, WearableError>;
57
58 fn send(&self, peer: &str, frame: &[u8], confirm: bool) -> Result<(), WearableError>;
63
64 fn open_url(&self, peer: &str, url: &str) -> Result<(), WearableError>;
66}
67
68pub struct FramedWearableLink<T> {
74 transport: Arc<T>,
75 next_stream: AtomicU32,
76 incoming: Mutex<HashMap<String, Streams>>,
77}
78
79type Streams = HashMap<u32, SyncSender<Vec<u8>>>;
81
82impl<T: WearableTransport> FramedWearableLink<T> {
83 pub fn new(transport: T) -> Self {
85 Self {
86 transport: Arc::new(transport),
87 next_stream: AtomicU32::new(0),
88 incoming: Mutex::new(HashMap::new()),
89 }
90 }
91
92 pub fn receive(&self, peer: &str, frame: &[u8]) {
95 let Some((&kind, body)) = frame.split_first() else {
96 log::warn!("wearable: an empty frame from {peer}");
97 return;
98 };
99 if kind == MESSAGE {
100 match split_path(body) {
101 Some((path, data)) => publish_wearable_event(WearableEvent::Message {
102 peer: peer.to_owned(),
103 path: path.to_owned(),
104 data: data.to_vec(),
105 }),
106 None => log::warn!("wearable: a message frame without its path from {peer}"),
107 }
108 return;
109 }
110 let Some((id, body)) = split_stream(body) else {
111 log::warn!("wearable: a stream frame without its number from {peer}");
112 return;
113 };
114 match kind {
115 OPEN => self.open_incoming(peer, id, body),
116 CHUNK => {
117 let sender = self
119 .incoming
120 .lock()
121 .get(peer)
122 .and_then(|streams| streams.get(&id))
123 .cloned();
124 if let Some(sender) = sender
125 && sender.send(body.to_vec()).is_err()
126 {
127 self.end_incoming(peer, id);
128 }
129 }
130 END => self.end_incoming(peer, id),
131 _ => log::warn!("wearable: a frame of unknown kind {kind} from {peer}"),
132 }
133 }
134
135 pub fn disconnect(&self, peer: &str) {
138 self.incoming.lock().remove(peer);
139 }
140
141 fn open_incoming(&self, peer: &str, id: u32, path: &[u8]) {
142 let Ok(path) = std::str::from_utf8(path) else {
143 log::warn!("wearable: a stream from {peer} with a path that is not UTF-8");
144 return;
145 };
146 let (sender, chunks) = sync_channel(PENDING_CHUNKS);
147 self.incoming
150 .lock()
151 .entry(peer.to_owned())
152 .or_default()
153 .insert(id, sender);
154 publish_wearable_event(WearableEvent::Stream(WearableStream::new(
155 peer.to_owned(),
156 path.to_owned(),
157 Box::new(ChunkReader {
158 chunks,
159 chunk: Vec::new(),
160 read: 0,
161 }),
162 )));
163 }
164
165 fn end_incoming(&self, peer: &str, id: u32) {
166 if let Some(streams) = self.incoming.lock().get_mut(peer) {
167 streams.remove(&id);
168 }
169 }
170}
171
172impl<T: WearableTransport> WearableLink for FramedWearableLink<T> {
173 fn peers(&self) -> Result<Vec<WearablePeer>, WearableError> {
174 self.transport.peers()
175 }
176
177 fn send_message(&self, peer: &str, path: &str, data: &[u8]) -> Result<(), WearableError> {
178 let length = u16::try_from(path.len())
179 .map_err(|_| WearableError::Failed(format!("the path {path} is too long")))?;
180 let mut frame = Vec::with_capacity(3 + path.len() + data.len());
181 frame.push(MESSAGE);
182 frame.extend_from_slice(&length.to_le_bytes());
183 frame.extend_from_slice(path.as_bytes());
184 frame.extend_from_slice(data);
185 self.transport.send(peer, &frame, true)
186 }
187
188 fn open_stream(&self, peer: &str, path: &str) -> Result<Box<dyn Write + Send>, WearableError> {
189 let id = self.next_stream.fetch_add(1, Ordering::Relaxed);
190 let mut frame = Vec::with_capacity(STREAM_HEADER + CHUNK_BYTES.max(path.len()));
191 frame.push(OPEN);
192 frame.extend_from_slice(&id.to_le_bytes());
193 frame.extend_from_slice(path.as_bytes());
194 self.transport.send(peer, &frame, true)?;
195 frame[0] = CHUNK;
196 frame.truncate(STREAM_HEADER);
197 Ok(Box::new(ChunkWriter {
198 transport: Arc::clone(&self.transport),
199 peer: peer.to_owned(),
200 frame,
201 }))
202 }
203
204 fn open_url(&self, peer: &str, url: &str) -> Result<(), WearableError> {
205 self.transport.open_url(peer, url)
206 }
207}
208
209fn split_path(body: &[u8]) -> Option<(&str, &[u8])> {
210 let (length, rest) = body.split_first_chunk::<2>()?;
211 let (path, data) = rest.split_at_checked(usize::from(u16::from_le_bytes(*length)))?;
212 Some((std::str::from_utf8(path).ok()?, data))
213}
214
215fn split_stream(body: &[u8]) -> Option<(u32, &[u8])> {
216 let (id, rest) = body.split_first_chunk::<4>()?;
217 Some((u32::from_le_bytes(*id), rest))
218}
219
220struct ChunkWriter<T: WearableTransport> {
223 transport: Arc<T>,
224 peer: String,
225 frame: Vec<u8>,
226}
227
228impl<T: WearableTransport> ChunkWriter<T> {
229 fn send_chunk(&mut self) -> io::Result<()> {
230 if self.frame.len() == STREAM_HEADER {
231 return Ok(());
232 }
233 let sent = self.transport.send(&self.peer, &self.frame, false);
234 self.frame.truncate(STREAM_HEADER);
235 sent.map_err(io::Error::other)
236 }
237}
238
239impl<T: WearableTransport> Write for ChunkWriter<T> {
240 fn write(&mut self, data: &[u8]) -> io::Result<usize> {
241 let room = STREAM_HEADER + CHUNK_BYTES - self.frame.len();
242 let taken = data.len().min(room);
243 self.frame.extend_from_slice(&data[..taken]);
244 if self.frame.len() == STREAM_HEADER + CHUNK_BYTES {
245 self.send_chunk()?;
246 }
247 Ok(taken)
248 }
249
250 fn flush(&mut self) -> io::Result<()> {
251 self.send_chunk()
252 }
253}
254
255impl<T: WearableTransport> Drop for ChunkWriter<T> {
256 fn drop(&mut self) {
257 if let Err(error) = self.send_chunk() {
258 log::warn!(
259 "wearable: the last bytes of a stream to {}: {error}",
260 self.peer
261 );
262 }
263 self.frame[0] = END;
264 if let Err(error) = self.transport.send(&self.peer, &self.frame, false) {
265 log::warn!("wearable: the end of a stream to {}: {error}", self.peer);
266 }
267 }
268}
269
270struct ChunkReader {
272 chunks: Receiver<Vec<u8>>,
273 chunk: Vec<u8>,
274 read: usize,
275}
276
277impl Read for ChunkReader {
278 fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
279 if out.is_empty() {
280 return Ok(0);
281 }
282 while self.read == self.chunk.len() {
283 match self.chunks.recv() {
284 Ok(chunk) => {
285 self.chunk = chunk;
286 self.read = 0;
287 }
288 Err(_) => return Ok(0),
290 }
291 }
292 let count = out.len().min(self.chunk.len() - self.read);
293 out[..count].copy_from_slice(&self.chunk[self.read..self.read + count]);
294 self.read += count;
295 Ok(count)
296 }
297}
298
299#[cfg(test)]
300#[path = "tests/wearable_framed_tests.rs"]
301mod tests;