feat(bluetooth): PIN confirmation support
This commit is contained in:
parent
a742d3829c
commit
894cf9fc3f
6 changed files with 503 additions and 271 deletions
64
cosmic-settings/src/pages/bluetooth/agent.rs
Normal file
64
cosmic-settings/src/pages/bluetooth/agent.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use zbus::zvariant::ObjectPath;
|
||||
|
||||
const AGENT_PATH: &str = "/org/bluez/agent/cosmic_settings";
|
||||
|
||||
pub async fn unregister(connection: zbus::Connection) -> zbus::Result<()> {
|
||||
let agent_path = ObjectPath::from_static_str_unchecked(AGENT_PATH);
|
||||
let bluez = bluez_zbus::agent_manager1::AgentManager1Proxy::new(&connection).await?;
|
||||
bluez.unregister_agent(&agent_path).await
|
||||
}
|
||||
|
||||
pub async fn watch(
|
||||
connection: zbus::Connection,
|
||||
mut tx: futures::channel::mpsc::Sender<super::Message>,
|
||||
) -> zbus::Result<()> {
|
||||
let span = tracing::span!(tracing::Level::INFO, "bluetooth::agent::watch");
|
||||
let _span = span.enter();
|
||||
|
||||
let (agent, mut receiver) = bluez_zbus::agent1::create();
|
||||
|
||||
let agent_path = ObjectPath::from_static_str_unchecked(AGENT_PATH);
|
||||
|
||||
tracing::debug!("connecting agent");
|
||||
|
||||
connection.object_server().at(&agent_path, agent).await?;
|
||||
|
||||
tracing::debug!("connecting to bluez agent manager");
|
||||
|
||||
let bluez = bluez_zbus::agent_manager1::AgentManager1Proxy::new(&connection).await?;
|
||||
|
||||
tracing::debug!("registering agent");
|
||||
|
||||
bluez
|
||||
.register_agent(
|
||||
&agent_path,
|
||||
<&'static str>::from(bluez_zbus::agent1::Capability::DisplayYesNo),
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Err(why) = bluez.request_default_agent(&agent_path).await {
|
||||
_ = bluez.unregister_agent(&agent_path).await;
|
||||
Err(why)?;
|
||||
}
|
||||
|
||||
tracing::debug!("registered");
|
||||
|
||||
while let Some(msg) = receiver.next().await {
|
||||
tracing::debug!(?msg, "agent message received");
|
||||
|
||||
if tx.send(super::Message::Agent(Arc::new(msg))).await.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_ = bluez.unregister_agent(&agent_path).await;
|
||||
|
||||
tracing::debug!("exiting");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub enum Message {}
|
||||
|
|
@ -60,7 +60,10 @@ impl DeviceUpdate {
|
|||
))))
|
||||
}
|
||||
// Battery
|
||||
_ => None,
|
||||
(message, value) => {
|
||||
tracing::debug!(message, ?value, "device update");
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
|
@ -108,7 +111,10 @@ impl AdapterUpdate {
|
|||
Some(Self::Address(value.into()))
|
||||
}
|
||||
// Battery
|
||||
_ => None,
|
||||
(message, value) => {
|
||||
tracing::error!(message, ?value, "adapter update");
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
|
@ -269,18 +275,26 @@ impl Adapter {
|
|||
pub async fn from_device(
|
||||
proxy: &bluez_zbus::adapter1::Adapter1Proxy<'_>,
|
||||
) -> zbus::Result<Self> {
|
||||
let address = proxy.address().await?;
|
||||
let alias = proxy.alias().await?;
|
||||
let scanning = if proxy.discoverable().await? && proxy.discovering().await? {
|
||||
Active::Enabled
|
||||
} else {
|
||||
Active::Disabled
|
||||
};
|
||||
let enabled = if proxy.powered().await? {
|
||||
Active::Enabled
|
||||
} else {
|
||||
Active::Disabled
|
||||
};
|
||||
let (address, alias, scanning, enabled) = futures::try_join!(
|
||||
proxy.address(),
|
||||
proxy.alias(),
|
||||
async {
|
||||
Ok(
|
||||
if proxy.discoverable().await? && proxy.discovering().await? {
|
||||
Active::Enabled
|
||||
} else {
|
||||
Active::Disabled
|
||||
},
|
||||
)
|
||||
},
|
||||
async {
|
||||
Ok(if proxy.powered().await? {
|
||||
Active::Enabled
|
||||
} else {
|
||||
Active::Disabled
|
||||
})
|
||||
}
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
alias,
|
||||
|
|
@ -320,38 +334,42 @@ pub async fn start_discovery(
|
|||
adapter_path: OwnedObjectPath,
|
||||
) -> Message {
|
||||
let result: zbus::Result<()> = Ok(());
|
||||
match bluez_zbus::get_adapter(&connection, adapter_path).await {
|
||||
|
||||
let adapter = match bluez_zbus::get_adapter(&connection, adapter_path).await {
|
||||
Err(why) => {
|
||||
tracing::error!("Unable to get the adapter: {why}");
|
||||
return Message::DBusError(why.to_string());
|
||||
}
|
||||
Ok(adapter) => {
|
||||
for attempt in 1..5 {
|
||||
let result = async {
|
||||
tracing::debug!("Starting discovery");
|
||||
// We don't seem to be able to use join here as it seem to lead to some kind of race condition and not start scanning occasionally
|
||||
adapter.set_pairable(true).await?;
|
||||
adapter.set_discoverable(true).await?;
|
||||
if adapter.discovering().await? {
|
||||
return Ok(());
|
||||
}
|
||||
adapter.start_discovery().await
|
||||
}
|
||||
.await;
|
||||
if let Err(why) = result {
|
||||
tracing::warn!("Unable to start bluetooth scanning: {why}");
|
||||
tokio::time::sleep(Duration::from_millis(1000 * attempt)).await;
|
||||
} else {
|
||||
tracing::debug!("Discovery started");
|
||||
return Message::Nop;
|
||||
}
|
||||
Ok(adapter) => adapter,
|
||||
};
|
||||
|
||||
for attempt in 1..5 {
|
||||
let result = async {
|
||||
tracing::debug!("Starting discovery");
|
||||
// We don't seem to be able to use join here as it seem to lead to some kind of race condition and not start scanning occasionally
|
||||
adapter.set_pairable(true).await?;
|
||||
adapter.set_discoverable(true).await?;
|
||||
if adapter.discovering().await? {
|
||||
return Ok(());
|
||||
}
|
||||
adapter.start_discovery().await
|
||||
}
|
||||
.await;
|
||||
|
||||
if let Err(why) = result {
|
||||
tracing::warn!("Unable to start bluetooth scanning: {why}");
|
||||
tokio::time::sleep(Duration::from_millis(1000 * attempt)).await;
|
||||
} else {
|
||||
tracing::debug!("Discovery started");
|
||||
return Message::Nop;
|
||||
}
|
||||
}
|
||||
if let Err(why) = result {
|
||||
return Message::DBusError(why.to_string());
|
||||
}
|
||||
Message::Nop
|
||||
|
||||
return if let Err(why) = result {
|
||||
Message::DBusError(why.to_string())
|
||||
} else {
|
||||
Message::Nop
|
||||
};
|
||||
}
|
||||
|
||||
pub async fn stop_discovery(
|
||||
|
|
@ -359,36 +377,36 @@ pub async fn stop_discovery(
|
|||
adapter_path: OwnedObjectPath,
|
||||
) -> Message {
|
||||
let result: zbus::Result<()> = Ok(());
|
||||
match bluez_zbus::get_adapter(&connection, adapter_path).await {
|
||||
Err(why) => {
|
||||
tracing::error!("Unable to get the adapter: {why}");
|
||||
return Message::DBusError(why.to_string());
|
||||
}
|
||||
Ok(adapter) => {
|
||||
for attempt in 1..5 {
|
||||
let result = async {
|
||||
tracing::debug!("Stopping discovery");
|
||||
|
||||
// We don't seem to be able to use join here as it seem to lead to some kind of race condition and not stop scanning occasionally
|
||||
adapter.set_pairable(false).await?;
|
||||
adapter.set_discoverable(false).await?;
|
||||
if adapter.discovering().await? {
|
||||
adapter.stop_discovery().await
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
.await;
|
||||
if let Err(why) = result {
|
||||
tracing::warn!("Unable to stop bluetooth scanning: {why}");
|
||||
tokio::time::sleep(Duration::from_millis(1000 * attempt)).await;
|
||||
} else {
|
||||
tracing::debug!("Discovery stopped");
|
||||
return Message::Nop;
|
||||
}
|
||||
let adapter = match bluez_zbus::get_adapter(&connection, adapter_path).await {
|
||||
Err(why) => return Message::DBusError(format!("Unable to get the adapter: {why}")),
|
||||
Ok(adapter) => adapter,
|
||||
};
|
||||
|
||||
for attempt in 1..5 {
|
||||
let result = async {
|
||||
tracing::debug!("Stopping discovery");
|
||||
|
||||
// We don't seem to be able to use join here as it seem to lead to some kind of race condition and not stop scanning occasionally
|
||||
adapter.set_pairable(false).await?;
|
||||
adapter.set_discoverable(false).await?;
|
||||
if adapter.discovering().await? {
|
||||
adapter.stop_discovery().await
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
.await;
|
||||
|
||||
if let Err(why) = result {
|
||||
tracing::warn!("Unable to stop bluetooth scanning: {why}");
|
||||
tokio::time::sleep(Duration::from_millis(1000 * attempt)).await;
|
||||
} else {
|
||||
tracing::debug!("Discovery stopped");
|
||||
return Message::Nop;
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(why) = result {
|
||||
return Message::DBusError(why.to_string());
|
||||
}
|
||||
|
|
@ -399,103 +417,115 @@ pub async fn disconnect_device(
|
|||
connection: zbus::Connection,
|
||||
device_path: OwnedObjectPath,
|
||||
) -> Message {
|
||||
match bluez_zbus::get_device(&connection, device_path.clone()).await {
|
||||
let proxy = match bluez_zbus::get_device(&connection, device_path.clone()).await {
|
||||
Err(why) => {
|
||||
tracing::error!("Unable to get the device: {why}");
|
||||
return Message::DeviceFailed(device_path);
|
||||
}
|
||||
Ok(proxy) => {
|
||||
for attempt in 1..5 {
|
||||
let result = async {
|
||||
if !proxy.device.connected().await? {
|
||||
return Ok(());
|
||||
}
|
||||
Ok(proxy) => proxy,
|
||||
};
|
||||
|
||||
proxy.device.disconnect().await
|
||||
}
|
||||
.await;
|
||||
if let Err(why) = result {
|
||||
tracing::warn!("Unable to disconnect to device: {why}");
|
||||
tokio::time::sleep(Duration::from_millis(1000 * attempt)).await;
|
||||
} else {
|
||||
return Message::Nop;
|
||||
}
|
||||
for attempt in 1..5 {
|
||||
let result = async {
|
||||
if !proxy.device.connected().await? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
proxy.device.disconnect().await
|
||||
}
|
||||
.await;
|
||||
|
||||
if let Err(why) = result {
|
||||
tracing::warn!("Unable to disconnect to device: {why}");
|
||||
tokio::time::sleep(Duration::from_millis(1000 * attempt)).await;
|
||||
} else {
|
||||
return Message::Nop;
|
||||
}
|
||||
}
|
||||
|
||||
Message::DeviceFailed(device_path)
|
||||
}
|
||||
|
||||
pub async fn connect_device(connection: zbus::Connection, device_path: OwnedObjectPath) -> Message {
|
||||
match bluez_zbus::get_device(&connection, device_path.clone()).await {
|
||||
let proxy = match bluez_zbus::get_device(&connection, device_path.clone()).await {
|
||||
Err(why) => {
|
||||
tracing::error!("Unable to get the device: {why}");
|
||||
return Message::DeviceFailed(device_path);
|
||||
}
|
||||
Ok(proxy) => {
|
||||
for attempt in 1..5 {
|
||||
let result = async {
|
||||
if proxy.device.connected().await? {
|
||||
Ok(())
|
||||
} else {
|
||||
proxy.device.connect().await
|
||||
}
|
||||
}
|
||||
.await;
|
||||
if let Err(why) = result {
|
||||
tracing::warn!("Unable to connect to device: {why}");
|
||||
tokio::time::sleep(Duration::from_millis(1000 * attempt)).await;
|
||||
} else {
|
||||
return Message::Nop;
|
||||
}
|
||||
Ok(proxy) => proxy,
|
||||
};
|
||||
|
||||
for attempt in 1..5 {
|
||||
let result = async {
|
||||
if proxy.device.connected().await? {
|
||||
Ok(())
|
||||
} else {
|
||||
proxy.device.connect().await
|
||||
}
|
||||
}
|
||||
.await;
|
||||
|
||||
if let Err(why) = result {
|
||||
tracing::warn!("Unable to connect to device: {why}");
|
||||
tokio::time::sleep(Duration::from_millis(1000 * attempt)).await;
|
||||
} else {
|
||||
return Message::Nop;
|
||||
}
|
||||
}
|
||||
|
||||
Message::DeviceFailed(device_path)
|
||||
}
|
||||
|
||||
pub async fn forget_device(connection: zbus::Connection, device_path: OwnedObjectPath) -> Message {
|
||||
let mut result: zbus::Result<()> = Ok(());
|
||||
match bluez_zbus::get_device(&connection, device_path.clone()).await {
|
||||
|
||||
let proxy = match bluez_zbus::get_device(&connection, device_path.clone()).await {
|
||||
Err(why) => {
|
||||
tracing::error!("Unable to get the device: {why}");
|
||||
return Message::DeviceFailed(device_path);
|
||||
}
|
||||
Ok(proxy) => match proxy.device.adapter().await {
|
||||
Err(why) => {
|
||||
tracing::error!("Unable to get the adapter: {why}");
|
||||
return Message::DeviceFailed(device_path);
|
||||
}
|
||||
Ok(adapter) => match bluez_zbus::get_adapter(&connection, adapter).await {
|
||||
Err(why) => {
|
||||
tracing::error!("Unable to get the adapter: {why}");
|
||||
return Message::DeviceFailed(device_path);
|
||||
}
|
||||
Ok(adapter) => {
|
||||
for attempt in 1..5 {
|
||||
result = async {
|
||||
if proxy.device.connected().await? {
|
||||
proxy.device.disconnect().await?;
|
||||
}
|
||||
Ok(proxy) => proxy,
|
||||
};
|
||||
|
||||
adapter.remove_device(&proxy.path()).await
|
||||
}
|
||||
.await;
|
||||
if let Err(why) = &result {
|
||||
tracing::warn!("Unable to connect to device: {why}");
|
||||
tokio::time::sleep(Duration::from_millis(1000 * attempt)).await;
|
||||
} else {
|
||||
return Message::Nop;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
let adapter_path = match proxy.device.adapter().await {
|
||||
Err(why) => {
|
||||
tracing::error!("Unable to get the adapter: {why}");
|
||||
return Message::DeviceFailed(device_path);
|
||||
}
|
||||
Ok(adapter_path) => adapter_path,
|
||||
};
|
||||
|
||||
let adapter = match bluez_zbus::get_adapter(&connection, adapter_path).await {
|
||||
Err(why) => {
|
||||
tracing::error!("Unable to get the adapter: {why}");
|
||||
return Message::DeviceFailed(device_path);
|
||||
}
|
||||
Ok(adapter) => adapter,
|
||||
};
|
||||
|
||||
for attempt in 1..5 {
|
||||
result = async {
|
||||
if proxy.device.connected().await? {
|
||||
proxy.device.disconnect().await?;
|
||||
}
|
||||
|
||||
adapter.remove_device(&proxy.path()).await
|
||||
}
|
||||
.await;
|
||||
|
||||
if let Err(why) = &result {
|
||||
tracing::warn!("Unable to connect to device: {why}");
|
||||
tokio::time::sleep(Duration::from_millis(1000 * attempt)).await;
|
||||
} else {
|
||||
return Message::Nop;
|
||||
}
|
||||
}
|
||||
if result.is_err() {
|
||||
return Message::DeviceFailed(device_path);
|
||||
}
|
||||
Message::Nop
|
||||
|
||||
return if result.is_err() {
|
||||
Message::DeviceFailed(device_path)
|
||||
} else {
|
||||
Message::Nop
|
||||
};
|
||||
}
|
||||
|
||||
pub async fn change_adapter_status(
|
||||
|
|
|
|||
|
|
@ -8,19 +8,43 @@ use cosmic::widget::{self, settings, text};
|
|||
use cosmic::Command;
|
||||
use cosmic::{Apply, Element};
|
||||
use cosmic_settings_page::{self as page, section, Section};
|
||||
use futures::channel::oneshot;
|
||||
use slab::Slab;
|
||||
use slotmap::SlotMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
use zbus::zvariant::OwnedObjectPath;
|
||||
|
||||
mod agent;
|
||||
mod backend;
|
||||
pub use backend::*;
|
||||
mod subscription;
|
||||
|
||||
enum Dialog {
|
||||
// RequestAuthorization {
|
||||
// device: OwnedObjectPath,
|
||||
// response: oneshot::Sender<bool>,
|
||||
// },
|
||||
RequestConfirmation {
|
||||
device: String,
|
||||
passkey: u32,
|
||||
response: oneshot::Sender<bool>,
|
||||
},
|
||||
// RequestPasskey {
|
||||
// device: OwnedObjectPath,
|
||||
// response: oneshot::Sender<Option<u32>>,
|
||||
// },
|
||||
// RequestPinCode {
|
||||
// device: OwnedObjectPath,
|
||||
// response: oneshot::Sender<Option<String>>,
|
||||
// },
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Page {
|
||||
active: Active,
|
||||
connection: Option<zbus::Connection>,
|
||||
dialog: Option<Dialog>,
|
||||
adapters: HashMap<OwnedObjectPath, Adapter>,
|
||||
selected_adapter: Option<OwnedObjectPath>,
|
||||
heading: String,
|
||||
|
|
@ -69,7 +93,12 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
_ = cancel.send(());
|
||||
}
|
||||
|
||||
self.connection = None;
|
||||
if let Some(connection) = self.connection.take() {
|
||||
tokio::spawn(async move {
|
||||
_ = agent::unregister(connection).await;
|
||||
});
|
||||
}
|
||||
|
||||
self.adapters.clear();
|
||||
self.selected_adapter = None;
|
||||
self.devices.clear();
|
||||
|
|
@ -79,12 +108,55 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
|
||||
Command::none()
|
||||
}
|
||||
|
||||
fn dialog(&self) -> Option<Element<'_, crate::pages::Message>> {
|
||||
match self.dialog.as_ref()? {
|
||||
Dialog::RequestConfirmation {
|
||||
device, passkey, ..
|
||||
} => {
|
||||
let description = widget::text::body(fl!(
|
||||
"bluetooth-confirm-pin",
|
||||
"description",
|
||||
device = device
|
||||
))
|
||||
.wrap(Wrap::Word);
|
||||
|
||||
let pin = widget::text::title1(itoa::Buffer::new().format(*passkey).to_owned())
|
||||
.width(Length::Fill)
|
||||
.horizontal_alignment(alignment::Horizontal::Center)
|
||||
.wrap(Wrap::None);
|
||||
|
||||
let control = widget::column::with_capacity(2)
|
||||
.push(description)
|
||||
.push(pin)
|
||||
.spacing(cosmic::theme::active().cosmic().spacing.space_xxs);
|
||||
|
||||
let confirm_button =
|
||||
widget::button::suggested(fl!("confirm")).on_press(Message::PinConfirm);
|
||||
|
||||
let cancel_button =
|
||||
widget::button::standard(fl!("cancel")).on_press(Message::PinCancel);
|
||||
|
||||
let dialog = widget::dialog(fl!("bluetooth-confirm-pin"))
|
||||
.control(control)
|
||||
.primary_action(confirm_button)
|
||||
.secondary_action(cancel_button)
|
||||
.apply(Element::from)
|
||||
.map(Into::into);
|
||||
|
||||
Some(dialog)
|
||||
}
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Message {
|
||||
AddedAdapter(OwnedObjectPath, Adapter),
|
||||
AddedDevice(OwnedObjectPath, Device),
|
||||
Agent(Arc<bluez_zbus::agent1::Message>),
|
||||
ConnectDevice(OwnedObjectPath),
|
||||
DBusConnect(
|
||||
zbus::Connection,
|
||||
|
|
@ -94,6 +166,8 @@ pub enum Message {
|
|||
DeviceFailed(OwnedObjectPath),
|
||||
DisconnectDevice(OwnedObjectPath),
|
||||
ForgetDevice(OwnedObjectPath),
|
||||
PinCancel,
|
||||
PinConfirm,
|
||||
PopupDevice(Option<OwnedObjectPath>),
|
||||
PopupSetting(bool),
|
||||
Nop,
|
||||
|
|
@ -126,6 +200,61 @@ impl Page {
|
|||
let _span = span.enter();
|
||||
|
||||
match message {
|
||||
Message::Agent(message) => {
|
||||
let Some(message) = Arc::into_inner(message) else {
|
||||
return Command::none();
|
||||
};
|
||||
|
||||
match message {
|
||||
bluez_zbus::agent1::Message::RequestAuthorization { response, .. } => {
|
||||
_ = response.send(true);
|
||||
}
|
||||
|
||||
bluez_zbus::agent1::Message::RequestConfirmation {
|
||||
device,
|
||||
passkey,
|
||||
response,
|
||||
} => {
|
||||
let device = self.devices.get(&device).map_or_else(
|
||||
|| device.to_string(),
|
||||
|device| device.alias_or_addr().to_owned(),
|
||||
);
|
||||
|
||||
self.dialog = Some(Dialog::RequestConfirmation {
|
||||
device,
|
||||
passkey,
|
||||
response,
|
||||
});
|
||||
}
|
||||
|
||||
bluez_zbus::agent1::Message::RequestPasskey { response, .. } => {
|
||||
_ = response.send(None);
|
||||
}
|
||||
|
||||
bluez_zbus::agent1::Message::RequestPinCode { response, .. } => {
|
||||
_ = response.send(None);
|
||||
}
|
||||
|
||||
bluez_zbus::agent1::Message::Cancel => {
|
||||
self.dialog = None;
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
Message::PinCancel => {
|
||||
if let Some(Dialog::RequestConfirmation { response, .. }) = self.dialog.take() {
|
||||
_ = response.send(false);
|
||||
}
|
||||
}
|
||||
|
||||
Message::PinConfirm => {
|
||||
if let Some(Dialog::RequestConfirmation { response, .. }) = self.dialog.take() {
|
||||
_ = response.send(true);
|
||||
}
|
||||
}
|
||||
|
||||
Message::SetActive(active) => {
|
||||
if let Some(connection) = self.connection.clone() {
|
||||
if let Some((path, adapter)) = self.get_selected_adapter_mut() {
|
||||
|
|
@ -162,6 +291,7 @@ impl Page {
|
|||
}
|
||||
tracing::warn!("No DBus connection ready");
|
||||
}
|
||||
|
||||
Message::DBusConnect(connection, sender) => {
|
||||
self.connection = Some(connection.clone());
|
||||
|
||||
|
|
@ -170,7 +300,12 @@ impl Page {
|
|||
self.subscription = Some(crate::utils::forward_event_loop(
|
||||
sender,
|
||||
crate::pages::Message::Bluetooth,
|
||||
move |tx| async move { subscription::watch(connection, tx).await },
|
||||
move |tx| async move {
|
||||
_ = futures::join!(
|
||||
subscription::watch(connection.clone(), tx.clone()),
|
||||
agent::watch(connection, tx),
|
||||
);
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ pub async fn watch(
|
|||
connection: zbus::Connection,
|
||||
mut tx: futures::channel::mpsc::Sender<bluetooth::Message>,
|
||||
) {
|
||||
let span = tracing::span!(tracing::Level::INFO, "bluetooth::watch");
|
||||
let span = tracing::span!(tracing::Level::INFO, "bluetooth::subscription::watch");
|
||||
let _span = span.enter();
|
||||
|
||||
loop {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue