1use super::*;
2
3pub struct Host {
4 members: Arc<Members>,
5 pairing: Mutex<Option<Live>>,
6}
7
8#[allow(clippy::type_complexity)]
9struct Members {
10 me: Hello,
11 notebook: String,
12 reach: Option<Reach>,
13 relay: Option<String>,
14 sharing: Mutex<Sharing>,
15 changes: Mutex<()>,
16 pending: Mutex<BTreeMap<[u8; 16], (Arc<Hello>, Line, Weak<super::super::Shared>)>>,
17 access: Mutex<HashMap<[u8; 16], Live>>,
18 room: Mutex<Option<Live>>,
19 served: Arc<Served>,
20 events: Arc<dyn Fn() + Send + Sync>,
21 keep: Box<dyn Fn(&Sharing) -> io::Result<()> + Send + Sync>,
22}
23
24impl Host {
25 /// Shares a notebook, keeping every credential change before granting or revoking access.
26 #[allow(clippy::too_many_arguments)]
27 pub fn start(
28 storage: Box<dyn Storage>,
29 me: Hello,
30 sharing: Sharing,
31 notebook: &str,
32 reach: Option<Reach>,
33 relay: Option<&str>,
34 events: impl Fn() + Send + Sync + 'static,
35 keep: impl Fn(&Sharing) -> io::Result<()> + Send + Sync + 'static,
36 ) -> io::Result<Self> {
37 keep(&sharing)?;
38 let members = Arc::new(Members {
39 me,
40 notebook: notebook.to_owned(),
41 reach,
42 relay: relay.map(str::to_owned),
43 sharing: Mutex::new(sharing),
44 changes: Mutex::default(),
45 pending: Mutex::default(),
46 access: Mutex::default(),
47 room: Mutex::default(),
48 served: Arc::new(Served {
49 storage,
50 images: Mutex::default(),
51 snapshots: Mutex::default(),
52 puts: Mutex::default(),
53 guests: Mutex::default(),
54 writers: Mutex::default(),
55 host: Mutex::default(),
56 room: Mutex::default(),
57 }),
58 events: Arc::new(events),
59 keep: Box::new(keep),
60 });
61 let sharing = members.sharing.lock().unwrap().clone();
62 members.presence(sharing.secret)?;
63 for device in &sharing.members {
64 members.open(device.secret)?;
65 }
66 let pairing = Mutex::new(Some(members.pair(&sharing)?));
67 Ok(Self { members, pairing })
68 }
69
70 pub fn code(&self) -> Option<String> {
71 let mut pairing = self.pairing.lock().unwrap();
72 let pairing = pairing.as_mut()?;
73 let mut sharing = self.members.sharing.lock().unwrap();
74 if pairing.burned() {
75 let mut next = sharing.clone();
76 next.code = super::super::code::secret().ok()?;
77 (self.members.keep)(&next).ok()?;
78 *pairing = self.members.pair(&next).ok()?;
79 *sharing = next;
80 }
81 let code = pairing.code();
82 if let Some(code) = &code
83 && *code != sharing.code
84 {
85 let mut next = sharing.clone();
86 next.code = code.clone();
87 (self.members.keep)(&next).ok()?;
88 *sharing = next;
89 }
90 code
91 }
92
93 pub fn sharing(&self) -> Sharing {
94 self.code();
95 self.members.sharing.lock().unwrap().clone()
96 }
97
98 pub fn relayed(&self) -> Relayed {
99 self.pairing
100 .lock()
101 .unwrap()
102 .as_ref()
103 .map_or(Relayed::Unknown, Live::relayed)
104 }
105
106 pub fn guests(&self) -> Vec<Peer> {
107 self.members
108 .room
109 .lock()
110 .unwrap()
111 .as_ref()
112 .map(Live::peers)
113 .unwrap_or_default()
114 }
115
116 pub fn devices(&self) -> Vec<(Device, bool)> {
117 let sharing = self.members.sharing.lock().unwrap();
118 let access = self.members.access.lock().unwrap();
119 sharing
120 .members
121 .iter()
122 .map(|device| {
123 let connected = access
124 .get(&device.secret)
125 .is_some_and(|live| !live.peers().is_empty());
126 (device.clone(), connected)
127 })
128 .collect()
129 }
130
131 pub fn requests(&self) -> Vec<Arc<Hello>> {
132 self.members
133 .pending
134 .lock()
135 .unwrap()
136 .values()
137 .map(|(hello, _, _)| Arc::clone(hello))
138 .collect()
139 }
140
141 pub fn approve(&self, approve: bool) -> io::Result<()> {
142 let mut sharing = self.members.sharing.lock().unwrap();
143 let mut next = sharing.clone();
144 next.approve = approve;
145 (self.members.keep)(&next)?;
146 *sharing = next;
147 drop(sharing);
148 if !approve {
149 for hello in self.requests() {
150 self.allow(&hello.peer)?;
151 }
152 }
153 (self.members.events)();
154 Ok(())
155 }
156
157 /// Admits the device asking as `peer`, or drops its request if it has gone.
158 pub fn allow(&self, peer: &[u8; 16]) -> io::Result<()> {
159 let request = self.members.pending.lock().unwrap().remove(peer);
160 let Some((hello, line, source)) = request else {
161 return Ok(());
162 };
163 let connected = || {
164 source
165 .upgrade()
166 .is_some_and(|source| source.connected(&hello))
167 };
168 if connected()
169 && let Err(error) = self.members.grant(&hello, &line)
170 {
171 let mut pending = self.members.pending.lock().unwrap();
172 if connected() && !pending.contains_key(peer) {
173 pending.insert(*peer, (hello, line, source));
174 }
175 return Err(error);
176 }
177 (self.members.events)();
178 Ok(())
179 }
180
181 pub fn decline(&self, peer: &[u8; 16]) {
182 let request = self.members.pending.lock().unwrap().remove(peer);
183 if let Some((_, line, _)) = request {
184 let _ = line.send(kind::APPROVAL, &wire::Approval::Declined);
185 (self.members.events)();
186 }
187 }
188
189 pub fn remove(&self, secret: &[u8; 16]) -> io::Result<()> {
190 let _change = self.members.changes.lock().unwrap();
191 let mut sharing = self.members.sharing.lock().unwrap();
192 if !sharing
193 .members
194 .iter()
195 .any(|device| device.secret == *secret)
196 {
197 return Ok(());
198 }
199 let mut next = sharing.clone();
200 next.members.retain(|device| device.secret != *secret);
201 getrandom::fill(&mut next.secret)
202 .map_err(|_| io::Error::other("System random source failed"))?;
203 next.code = super::super::code::secret()?;
204 (self.members.keep)(&next)?;
205 *sharing = next.clone();
206 drop(sharing);
207 let removed = self.members.access.lock().unwrap().remove(secret);
208 if let Some(removed) = removed {
209 for peer in removed.peers() {
210 self.members.served.forget(&peer.hello.peer, None);
211 }
212 removed.leave("removed");
213 }
214 self.members.presence(next.secret)?;
215 *self.pairing.lock().unwrap() = Some(self.members.pair(&next)?);
216 let welcomes = {
217 let access = self.members.access.lock().unwrap();
218 next.members
219 .iter()
220 .filter_map(|device| Some((device.secret, access.get(&device.secret)?)))
221 .flat_map(|(secret, live)| {
222 let welcome = self.members.welcome(&next, secret);
223 (live.peers().into_iter())
224 .filter_map(|peer| live.line(&peer.hello.peer))
225 .map(move |line| (welcome.clone(), line))
226 })
227 .collect::<Vec<_>>()
228 };
229 // Browser send failures may reenter a removal that rotates the room again.
230 #[cfg(target_arch = "wasm32")]
231 drop(_change);
232 for (welcome, line) in welcomes {
233 #[cfg(target_arch = "wasm32")]
234 if self.members.sharing.lock().unwrap().secret != next.secret {
235 break;
236 }
237 let _ = line.send(kind::WELCOME, &welcome);
238 }
239 (self.members.events)();
240 Ok(())
241 }
242
243 pub fn set_presence(&self, presence: Presence) {
244 if let Some(room) = &*self.members.room.lock().unwrap() {
245 room.set_presence(presence);
246 }
247 }
248
249 pub fn on_changed(&self, listener: crate::session::Listener) {
250 *self.members.served.host.lock().unwrap() = Some(listener);
251 }
252
253 pub fn touched(&self, paths: &[String]) {
254 for path in paths {
255 self.members.served.changed_here(path);
256 }
257 self.members.served.tell(paths);
258 }
259
260 pub fn stop(&self) {
261 let _change = self.members.changes.lock().unwrap();
262 drop(self.pairing.lock().unwrap().take());
263 self.members.pending.lock().unwrap().clear();
264 let access = std::mem::take(&mut *self.members.access.lock().unwrap());
265 for (_, live) in access {
266 live.leave(STOPPED);
267 }
268 drop(self.members.room.lock().unwrap().take());
269 }
270}
271
272impl Members {
273 fn welcome(&self, sharing: &Sharing, secret: [u8; 16]) -> Welcome {
274 Welcome {
275 share: sharing.share,
276 secret,
277 room: sharing.secret,
278 notebook: self.notebook.clone(),
279 host: self.me.name.clone(),
280 }
281 }
282
283 fn presence(self: &Arc<Self>, secret: [u8; 16]) -> io::Result<()> {
284 let told = Arc::clone(&self.events);
285 let live = Live::start(
286 self.me.clone(),
287 &Room::Notebook(secret),
288 self.reach,
289 self.relay.as_deref(),
290 move |_| told(),
291 )?;
292 *self.served.room.lock().unwrap() = Some(live.sender());
293 *self.room.lock().unwrap() = Some(live);
294 Ok(())
295 }
296
297 fn open(self: &Arc<Self>, secret: [u8; 16]) -> io::Result<()> {
298 let members = Arc::downgrade(self);
299 let live = Live::start_with(
300 Hello {
301 serves: Some(self.sharing.lock().unwrap().share),
302 ..self.me.clone()
303 },
304 &Room::Notebook(secret),
305 self.reach,
306 self.relay.as_deref(),
307 move |source, event| {
308 let Some(members) = members.upgrade() else {
309 return;
310 };
311 match event {
312 Event::Met(hello, line) => {
313 let sharing = members.sharing.lock().unwrap();
314 let admitted =
315 if sharing.members.iter().any(|device| device.secret == secret) {
316 Ok(members
317 .served
318 .admit(source, hello, line)
319 .then(|| members.welcome(&sharing, secret)))
320 } else {
321 Err(())
322 };
323 // Browser send failures may reenter membership callbacks.
324 #[cfg(target_arch = "wasm32")]
325 drop(sharing);
326 match admitted {
327 Ok(Some(welcome)) => {
328 let _ = line.send(kind::WELCOME, &welcome);
329 }
330 Err(()) => line.hang_up("removed"),
331 Ok(None) => {}
332 }
333 }
334 Event::Left(hello) => members.served.forget(&hello.peer, Some((source, hello))),
335 Event::Frame { from, kind, body }
336 if wire::KNOWN.contains(&kind) && kind > 256 && kind != kind::REPLY =>
337 {
338 members.served.queue(source, from, kind, body)
339 }
340 Event::Changed => (members.events)(),
341 _ => {}
342 }
343 },
344 )?;
345 self.access.lock().unwrap().insert(secret, live);
346 Ok(())
347 }
348
349 fn grant(self: &Arc<Self>, hello: &Hello, line: &Line) -> io::Result<()> {
350 let _change = self.changes.lock().unwrap();
351 if self.room.lock().unwrap().is_none() {
352 return Err(io::ErrorKind::NotConnected.into());
353 }
354 let mut secret = [0; 16];
355 getrandom::fill(&mut secret)
356 .map_err(|_| io::Error::other("System random source failed"))?;
357 if self.sharing.lock().unwrap().members.len() >= 64 {
358 return Err(io::ErrorKind::ResourceBusy.into());
359 }
360 self.open(secret)?;
361 let kept = (|| -> io::Result<Welcome> {
362 let mut sharing = self.sharing.lock().unwrap();
363 let mut next = sharing.clone();
364 next.members.push(Device {
365 secret,
366 name: hello.name.clone(),
367 device: hello.device.clone(),
368 });
369 (self.keep)(&next)?;
370 *sharing = next;
371 Ok(self.welcome(&sharing, secret))
372 })();
373 let welcome = match kept {
374 Ok(welcome) => welcome,
375 Err(error) => {
376 drop(self.access.lock().unwrap().remove(&secret));
377 return Err(error);
378 }
379 };
380 line.send(kind::WELCOME, &welcome)?;
381 (self.events)();
382 Ok(())
383 }
384
385 fn pair(self: &Arc<Self>, sharing: &Sharing) -> io::Result<Live> {
386 let members = Arc::downgrade(self);
387 Live::start_with(
388 Hello {
389 serves: None,
390 ..self.me.clone()
391 },
392 &Room::share(&sharing.code, &sharing.password),
393 self.reach,
394 self.relay.as_deref(),
395 move |source, event| {
396 let Some(members) = members.upgrade() else {
397 return;
398 };
399 match event {
400 Event::Met(hello, line) => {
401 let approve = members.sharing.lock().unwrap().approve;
402 let (approval, retired) = {
403 let mut pending = members.pending.lock().unwrap();
404 if !source.connected(hello) {
405 return;
406 }
407 if approve {
408 if pending.len() < 32 || pending.contains_key(&hello.peer) {
409 (
410 Some(wire::Approval::Pending),
411 pending.insert(
412 hello.peer,
413 (
414 Arc::clone(hello),
415 line.clone(),
416 Arc::downgrade(source),
417 ),
418 ),
419 )
420 } else {
421 (Some(wire::Approval::Failed), None)
422 }
423 } else {
424 (None, None)
425 }
426 };
427 drop(retired);
428 if let Some(approval) = approval {
429 let _ = line.send(kind::APPROVAL, &approval);
430 (members.events)();
431 } else if let Err(error) = members.grant(hello, line) {
432 eprintln!("Live Share: could not admit a device: {error}");
433 let _ = line.send(kind::APPROVAL, &wire::Approval::Failed);
434 }
435 }
436 Event::Left(hello) => {
437 let retired = {
438 let mut pending = members.pending.lock().unwrap();
439 if source.gone(hello)
440 && pending
441 .get(&hello.peer)
442 .is_some_and(|(admitted, _, _)| Arc::ptr_eq(admitted, hello))
443 {
444 pending.remove(&hello.peer)
445 } else {
446 None
447 }
448 };
449 drop(retired);
450 (members.events)();
451 }
452 Event::Changed => (members.events)(),
453 _ => {}
454 }
455 },
456 )
457 }
458}
459
460#[cfg(all(test, not(target_arch = "wasm32")))]
461#[path = "handover_tests.rs"]
462mod handover_tests;