1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use futures::StreamExt;
/// Monitors Bluetooth device connections and disconnections.
/// This struct listens for events related to devices being added or removed from the system.
pub struct Monitor {
/// Shared reference to the D-Bus connection.
connection: std::sync::Arc<zbus::Connection>,
/// Proxy for managing object events.
manager: std::sync::Arc<crate::ObjectManagerProxy<'static>>,
}
impl Monitor {
/// Creates a new monitor instance.
///
/// # Arguments
/// * `connection` - Shared D-Bus connection.
/// * `manager` - Proxy to the object manager.
///
/// # Returns
/// A new `Monitor` instance.
pub async fn new(
connection: std::sync::Arc<zbus::Connection>,
manager: std::sync::Arc<crate::ObjectManagerProxy<'static>>,
) -> Self {
Self {
connection,
manager,
}
}
/// Monitors the removal of Bluetooth devices.
/// This listens for D-Bus signals when devices are removed and logs the event.
pub async fn monitor_device_removed(&self) {
let mut interfaces_removed = self.manager.receive_interfaces_removed().await.unwrap();
loop {
if let Some(signal) = interfaces_removed.next().await {
let args = signal.args().unwrap();
if let Some(removed_dev) = crate::remove_device(args.object_path().as_str()) {
println!(
"❌[DEL][DEV]\tAddress({})\tAlias({})\t Interface Path: ({})",
removed_dev.address,
removed_dev.alias,
args.object_path()
);
}
}
}
}
/// Monitors the addition of new Bluetooth devices.
/// This listens for D-Bus signals when new devices are added and logs the event.
pub async fn monitor_device_added(&self) {
let mut interfaces_added = self.manager.receive_interfaces_added().await.unwrap();
loop {
if let Some(signal) = interfaces_added.next().await {
let args = signal.args().unwrap();
if let Some(interfaces) = args.interfaces().get("org.bluez.Device1") {
let address = interfaces.get("Address").unwrap().to_string();
let alias = interfaces.get("Alias").unwrap().to_string();
let connected = interfaces
.get("Connected")
.unwrap()
.downcast_ref::<bool>()
.unwrap();
let paired = interfaces
.get("Paired")
.unwrap()
.downcast_ref::<bool>()
.unwrap();
let path = args.object_path().to_string();
println!(
"✅[NEW][DEV]\tAddress({})\tAlias({})\t Interface Path: ({})",
address,
alias,
args.object_path()
);
let new_device = crate::cache::DeviceInfo {
address: address.to_string(),
alias,
connected,
paired,
};
crate::add_or_update_device(path, &new_device);
self.monitor_device_properties(
self.connection.clone(),
std::sync::Arc::new(args.object_path.to_string()),
)
.await
.unwrap();
}
}
}
}
/// Monitors property changes of Bluetooth devices.
/// Updates internal cache when a device property (e.g., alias, connection status) changes.
async fn monitor_device_properties(
&self,
conn: std::sync::Arc<zbus::Connection>,
object_path: std::sync::Arc<String>,
) -> zbus::Result<()> {
tokio::spawn(async move {
let props = zbus::fdo::PropertiesProxy::builder(&conn)
.destination("org.bluez")
.unwrap()
.path(object_path.as_str())
.unwrap()
.build()
.await
.unwrap();
let mut props_changed = props.receive_properties_changed().await.unwrap();
while let Some(signal) = props_changed.next().await {
let args = signal.args().unwrap();
let interface_name = args.interface_name().to_string();
let changed_props = args.changed_properties();
if interface_name == "org.bluez.Device1" {
if let Some(mut device) = crate::get_device(object_path.as_str()) {
if let Some(new_value) = changed_props.get("Connected") {
let val = new_value.downcast_ref::<bool>().unwrap();
device.connected = val;
}
if let Some(new_value) = changed_props.get("Paired") {
let val = new_value.downcast_ref::<bool>().unwrap();
device.paired = val;
}
if let Some(new_value) = changed_props.get("Alias") {
let val = new_value.downcast_ref::<String>().unwrap();
device.alias = val;
}
crate::add_or_update_device(object_path.to_string(), &device);
println!(
"🔄[UPT][DEV]\tAddress({})\tAlias({})\t Interface Path: ({})",
device.address, device.alias, object_path
);
}
}
}
});
Ok(())
}
}