2024-06-17 13:26:55 +02:00
|
|
|
use color_eyre::Result;
|
2025-08-16 15:31:06 +02:00
|
|
|
use color_eyre::eyre::Ok;
|
2025-08-10 16:37:55 +02:00
|
|
|
use futures_lite::StreamExt;
|
2025-09-03 18:11:56 +02:00
|
|
|
use std::collections::{HashMap, HashSet};
|
2025-08-14 18:14:31 +02:00
|
|
|
use std::sync::Arc;
|
2025-09-03 11:29:40 +02:00
|
|
|
use tokio::sync::{RwLock, broadcast};
|
2025-09-03 18:11:56 +02:00
|
|
|
use tokio::task::JoinHandle;
|
2025-09-03 11:29:40 +02:00
|
|
|
use tracing::debug;
|
2025-08-10 16:37:55 +02:00
|
|
|
use zbus::Connection;
|
2025-09-02 23:23:44 +02:00
|
|
|
use zbus::zvariant::ObjectPath;
|
2024-06-17 13:26:55 +02:00
|
|
|
|
2025-08-17 21:15:10 +02:00
|
|
|
use crate::clients::ClientResult;
|
2025-08-16 15:31:06 +02:00
|
|
|
use crate::clients::networkmanager::dbus::{DbusProxy, DeviceDbusProxy};
|
2025-09-02 20:42:26 +02:00
|
|
|
use crate::clients::networkmanager::event::{ClientToModuleEvent, ModuleToClientEvent};
|
2025-08-14 18:14:31 +02:00
|
|
|
use crate::{register_fallible_client, spawn};
|
2024-06-17 13:26:55 +02:00
|
|
|
|
2025-08-16 15:31:06 +02:00
|
|
|
pub mod dbus;
|
2025-08-14 18:14:31 +02:00
|
|
|
pub mod event;
|
2024-06-17 13:26:55 +02:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
2025-08-14 18:14:31 +02:00
|
|
|
pub struct Client {
|
2025-09-03 12:41:20 +02:00
|
|
|
inner: &'static ClientInner,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Client {
|
|
|
|
fn new() -> Client {
|
|
|
|
let inner = Box::leak(Box::new(ClientInner::new()));
|
|
|
|
Client { inner }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run(&self) -> Result<()> {
|
|
|
|
self.inner.run()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn subscribe(&self) -> broadcast::Receiver<ClientToModuleEvent> {
|
|
|
|
self.inner.subscribe()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_sender(&self) -> broadcast::Sender<ModuleToClientEvent> {
|
|
|
|
self.inner.get_sender()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct ClientInner {
|
2025-09-02 20:42:26 +02:00
|
|
|
controller_sender: broadcast::Sender<ClientToModuleEvent>,
|
|
|
|
sender: broadcast::Sender<ModuleToClientEvent>,
|
2025-09-04 10:59:48 +02:00
|
|
|
device_watchers: RwLock<HashMap<ObjectPath<'static>, DeviceWatcher>>,
|
2025-09-04 13:25:48 +02:00
|
|
|
dbus_connection: RwLock<Option<Connection>>,
|
2025-09-03 18:11:56 +02:00
|
|
|
}
|
|
|
|
|
2025-09-04 10:59:48 +02:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
struct DeviceWatcher {
|
|
|
|
state_watcher: Arc<JoinHandle<Result<()>>>,
|
2024-06-17 13:26:55 +02:00
|
|
|
}
|
|
|
|
|
2025-09-03 12:41:20 +02:00
|
|
|
impl ClientInner {
|
|
|
|
fn new() -> ClientInner {
|
2025-09-02 20:42:26 +02:00
|
|
|
let (controller_sender, _) = broadcast::channel(64);
|
|
|
|
let (sender, _) = broadcast::channel(8);
|
2025-09-04 10:59:48 +02:00
|
|
|
let device_watchers = RwLock::new(HashMap::new());
|
2025-09-04 13:25:48 +02:00
|
|
|
let dbus_connection = RwLock::new(None);
|
2025-09-03 12:41:20 +02:00
|
|
|
ClientInner {
|
2025-09-02 20:42:26 +02:00
|
|
|
controller_sender,
|
|
|
|
sender,
|
2025-09-04 10:59:48 +02:00
|
|
|
device_watchers,
|
2025-09-04 13:25:48 +02:00
|
|
|
dbus_connection,
|
2025-09-03 12:41:20 +02:00
|
|
|
}
|
2024-06-17 13:26:55 +02:00
|
|
|
}
|
|
|
|
|
2025-09-03 12:41:20 +02:00
|
|
|
fn run(&'static self) -> Result<()> {
|
2025-09-03 11:29:40 +02:00
|
|
|
debug!("Client running");
|
|
|
|
|
2025-09-03 12:41:20 +02:00
|
|
|
spawn(self.watch_devices_list());
|
2025-09-02 20:42:26 +02:00
|
|
|
|
2025-09-02 22:20:54 +02:00
|
|
|
let receiver = self.sender.subscribe();
|
2025-09-03 12:41:20 +02:00
|
|
|
spawn(self.handle_received_events(receiver));
|
2024-06-17 13:26:55 +02:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-09-03 18:11:56 +02:00
|
|
|
fn subscribe(&self) -> broadcast::Receiver<ClientToModuleEvent> {
|
2025-09-02 20:42:26 +02:00
|
|
|
self.controller_sender.subscribe()
|
|
|
|
}
|
|
|
|
|
2025-09-03 18:11:56 +02:00
|
|
|
fn get_sender(&self) -> broadcast::Sender<ModuleToClientEvent> {
|
2025-09-02 20:42:26 +02:00
|
|
|
self.sender.clone()
|
2024-06-17 13:26:55 +02:00
|
|
|
}
|
|
|
|
|
2025-09-03 12:41:20 +02:00
|
|
|
async fn watch_devices_list(&'static self) -> Result<()> {
|
|
|
|
debug!("D-Bus devices list watcher starting");
|
|
|
|
|
2025-09-04 13:25:48 +02:00
|
|
|
let root = DbusProxy::new(&self.dbus_connection().await?).await?;
|
2025-09-03 12:41:20 +02:00
|
|
|
|
|
|
|
let mut devices_changes = root.receive_all_devices_changed().await;
|
|
|
|
while let Some(devices_change) = devices_changes.next().await {
|
|
|
|
// The new list of devices from dbus, not to be confused with the added devices below
|
2025-09-04 10:59:48 +02:00
|
|
|
let new_device_paths = devices_change
|
2025-09-03 12:41:20 +02:00
|
|
|
.get()
|
|
|
|
.await?
|
|
|
|
.iter()
|
|
|
|
.map(ObjectPath::to_owned)
|
|
|
|
.collect::<HashSet<_>>();
|
|
|
|
|
2025-09-04 10:59:48 +02:00
|
|
|
let mut watchers = self.device_watchers.write().await;
|
|
|
|
let device_paths = watchers.keys().cloned().collect::<HashSet<_>>();
|
2025-09-03 18:11:56 +02:00
|
|
|
|
2025-09-04 10:59:48 +02:00
|
|
|
let added_device_paths = new_device_paths.difference(&device_paths);
|
|
|
|
for added_device_path in added_device_paths {
|
|
|
|
debug_assert!(!watchers.contains_key(added_device_path));
|
2025-09-03 12:41:20 +02:00
|
|
|
|
2025-09-04 10:59:48 +02:00
|
|
|
let watcher = self.watch_device(added_device_path.clone());
|
|
|
|
watchers.insert(added_device_path.clone(), watcher);
|
2025-09-03 12:41:20 +02:00
|
|
|
}
|
2024-06-17 13:26:55 +02:00
|
|
|
|
2025-09-04 10:59:48 +02:00
|
|
|
let removed_device_paths = device_paths.difference(&new_device_paths);
|
|
|
|
for removed_device_path in removed_device_paths {
|
|
|
|
let watcher = watchers
|
|
|
|
.get(removed_device_path)
|
|
|
|
.expect("Device to be removed should be present in watchers");
|
|
|
|
watcher.state_watcher.abort();
|
|
|
|
watchers.remove(removed_device_path);
|
|
|
|
|
2025-09-04 14:25:20 +02:00
|
|
|
// TODO: Replace the identifier sent to modules with the dbus device number (last segment of its path)
|
|
|
|
let dbus_connection = &self.dbus_connection().await?;
|
|
|
|
let device = DeviceDbusProxy::new(dbus_connection, removed_device_path).await?;
|
|
|
|
let interface = device.interface().await?.to_string();
|
|
|
|
self.controller_sender
|
|
|
|
.send(ClientToModuleEvent::DeviceRemoved { interface })?;
|
|
|
|
|
2025-09-04 10:59:48 +02:00
|
|
|
debug!("D-bus device watchers for {} stopped", removed_device_path);
|
2025-09-03 18:11:56 +02:00
|
|
|
}
|
2025-09-02 22:20:54 +02:00
|
|
|
}
|
|
|
|
|
2025-09-03 12:41:20 +02:00
|
|
|
Ok(())
|
2025-09-02 22:20:54 +02:00
|
|
|
}
|
|
|
|
|
2025-09-03 12:41:20 +02:00
|
|
|
async fn handle_received_events(
|
|
|
|
&'static self,
|
|
|
|
mut receiver: broadcast::Receiver<ModuleToClientEvent>,
|
|
|
|
) -> Result<()> {
|
|
|
|
while let Result::Ok(event) = receiver.recv().await {
|
|
|
|
match event {
|
|
|
|
ModuleToClientEvent::NewController => {
|
|
|
|
debug!("Client received NewController event");
|
|
|
|
|
2025-09-04 10:59:48 +02:00
|
|
|
for device_path in self.device_watchers.read().await.keys() {
|
2025-09-04 13:25:48 +02:00
|
|
|
let dbus_connection = &self.dbus_connection().await?;
|
|
|
|
let device = DeviceDbusProxy::new(dbus_connection, device_path).await?;
|
2025-09-03 12:41:20 +02:00
|
|
|
|
|
|
|
let interface = device.interface().await?.to_string();
|
|
|
|
let r#type = device.device_type().await?;
|
|
|
|
let new_state = device.state().await?;
|
|
|
|
self.controller_sender
|
|
|
|
.send(ClientToModuleEvent::DeviceChanged {
|
|
|
|
interface,
|
|
|
|
r#type,
|
|
|
|
new_state,
|
|
|
|
})?;
|
|
|
|
}
|
2025-09-02 22:20:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2025-09-03 12:41:20 +02:00
|
|
|
|
|
|
|
Ok(())
|
2025-09-02 22:20:54 +02:00
|
|
|
}
|
|
|
|
|
2025-09-04 10:59:48 +02:00
|
|
|
fn watch_device(&'static self, path: ObjectPath<'static>) -> DeviceWatcher {
|
|
|
|
let state_watcher = Arc::new(spawn(self.watch_device_state(path)));
|
2025-08-16 15:31:06 +02:00
|
|
|
|
2025-09-04 10:59:48 +02:00
|
|
|
DeviceWatcher { state_watcher }
|
2025-09-03 12:41:20 +02:00
|
|
|
}
|
2025-08-16 15:31:06 +02:00
|
|
|
|
2025-09-03 18:11:56 +02:00
|
|
|
async fn watch_device_state(&'static self, path: ObjectPath<'_>) -> Result<()> {
|
2025-09-04 10:59:48 +02:00
|
|
|
debug!("D-Bus device state watcher for {} starting", path);
|
|
|
|
|
2025-09-03 18:11:56 +02:00
|
|
|
let dbus_connection = Connection::system().await?;
|
|
|
|
let device = DeviceDbusProxy::new(&dbus_connection, path.clone()).await?;
|
2025-09-03 12:41:20 +02:00
|
|
|
|
|
|
|
let interface = device.interface().await?;
|
|
|
|
let r#type = device.device_type().await?;
|
|
|
|
|
|
|
|
// Send an event communicating the initial state
|
|
|
|
let new_state = device.state().await?;
|
|
|
|
self.controller_sender
|
|
|
|
.send(ClientToModuleEvent::DeviceChanged {
|
|
|
|
interface: interface.to_string(),
|
|
|
|
r#type: r#type.clone(),
|
|
|
|
new_state,
|
|
|
|
})?;
|
|
|
|
|
|
|
|
let mut state_changes = device.receive_state_changed().await;
|
|
|
|
while let Some(state_change) = state_changes.next().await {
|
|
|
|
let new_state = state_change.get().await?;
|
|
|
|
self.controller_sender
|
|
|
|
.send(ClientToModuleEvent::DeviceChanged {
|
|
|
|
interface: interface.to_string(),
|
|
|
|
r#type: r#type.clone(),
|
|
|
|
new_state,
|
|
|
|
})?;
|
|
|
|
}
|
2025-08-16 15:31:06 +02:00
|
|
|
|
2025-09-03 12:41:20 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
2025-09-04 13:25:48 +02:00
|
|
|
|
|
|
|
async fn dbus_connection(&self) -> Result<Connection> {
|
|
|
|
let dbus_connection_guard = self.dbus_connection.read().await;
|
|
|
|
if let Some(dbus_connection) = &*dbus_connection_guard {
|
|
|
|
Ok(dbus_connection.clone())
|
|
|
|
} else {
|
|
|
|
// Yes it's a bit awkward to first obtain a read lock and then a write lock but it
|
|
|
|
// needs to happen only once, and after that all read lock acquisitions will be
|
|
|
|
// instant
|
|
|
|
drop(dbus_connection_guard);
|
|
|
|
let dbus_connection = Connection::system().await?;
|
|
|
|
*self.dbus_connection.write().await = Some(dbus_connection.clone());
|
|
|
|
Ok(dbus_connection)
|
|
|
|
}
|
|
|
|
}
|
2025-09-03 12:41:20 +02:00
|
|
|
}
|
2025-09-03 11:29:40 +02:00
|
|
|
|
2025-09-03 12:41:20 +02:00
|
|
|
pub fn create_client() -> ClientResult<Client> {
|
|
|
|
let client = Arc::new(Client::new());
|
|
|
|
client.run()?;
|
|
|
|
Ok(client)
|
2025-08-16 15:31:06 +02:00
|
|
|
}
|
|
|
|
|
2024-08-04 19:04:15 +02:00
|
|
|
register_fallible_client!(Client, network_manager);
|