Krolyxon
Commit e7b881a

Branches

Refs →

budctlcratesbudctl-guisrcworker.rs

60 lines · 2.3 KB · Rust

1//! The connection to the buds: budctl-core's worker, which owns the session on a thread of its
2//! own, run as an iced subscription and connected through BlueZ.
3
4use std::time::Duration;
5
6use budctl_core::bt::BdAddr;
7use budctl_core::worker::{self, Connect, Report};
8pub use budctl_core::worker::{Command, Event, IDLE, Reading};
9use iced::futures::channel::mpsc as channel;
10use iced::futures::{SinkExt, Stream, StreamExt};
11
12use crate::{Message, log};
13
14/// The worker, as a stream of messages for an iced subscription: [`Message::Ready`] once it takes
15/// commands, then each of its events. `device` picks the buds, as `budctl --device` does; `idle`
16/// is how long a session stays open after the last command.
17pub fn run(&(device, idle): &(Option<BdAddr>, Duration)) -> impl Stream<Item = Message> + use<> {
18 iced::stream::channel(16, async move |mut output: channel::Sender<Message>| {
19 let (events, mut outbox) = channel::unbounded();
20 let commands = match worker::start(bluetooth(device), Box::new(Window(events)), idle) {
21 Ok(commands) => commands,
22 Err(e) => {
23 let message = format!("could not start the Bluetooth thread: {e}");
24 let _ = output.send(Message::Worker(Event::Lost(message))).await;
25 return;
26 }
27 };
28 if output.send(Message::Ready(commands)).await.is_err() {
29 return;
30 }
31 while let Some(event) = outbox.next().await {
32 if output.send(Message::Worker(event)).await.is_err() {
33 break;
34 }
35 }
36 })
37}
38
39/// The window's side of the worker: events go to the subscription, lines to the GUI's log.
40struct Window(channel::UnboundedSender<Event>);
41
42impl Report for Window {
43 fn event(&self, event: Event) {
44 // An error only means the window is gone; the worker ends once its sender is dropped.
45 let _ = self.0.unbounded_send(event);
46 }
47
48 fn log(&self, line: &str) {
49 log::line(line);
50 }
51}
52
53/// Over Bluetooth, through BlueZ: what the window uses.
54fn bluetooth(device: Option<BdAddr>) -> Connect {
55 Box::new(move |found| {
56 let (device, model) = budctl_core::select(budctl_core::scan()?, device)?;
57 found(device.alias.clone());
58 budctl_core::connect(&device, model)
59 })
60}