Skip to content

Commit d5425bc

Browse files
authored
Implement Signal based cache updating for session (#24)
Alternative to #22 the preserves the caching behavior. In some cases repeated calles to `GetManagedObjects` have caused performance issues (adafruit/Adafruit_Python_BluefruitLE#11)
1 parent 81466fb commit d5425bc

3 files changed

Lines changed: 78 additions & 24 deletions

File tree

‎Cargo.lock‎

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ uuid = { version = "1", features = ["v4"] }
2020
thiserror = "2.0.17"
2121
strum = { version = "0.27.2", features = ["derive"] }
2222
futures-lite = "2.6.1"
23+
async-lock = {version = "3.4.2", default-features = false}
2324

2425
[dev-dependencies]
2526
clap = { version = "4.5.48", features = ["derive"] }

‎src/session.rs‎

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,55 +8,58 @@ use crate::{
88
known_network::KnownNetwork,
99
station::{Station, StationDiagnostics},
1010
};
11-
use std::collections::HashMap;
11+
use std::{collections::HashMap, future};
12+
use futures_lite::{StreamExt, FutureExt};
1213
use uuid::Uuid;
13-
use zbus::{Connection, Proxy};
14+
use zbus::{Connection, Proxy, fdo::{InterfacesAddedArgs, InterfacesAddedStream, InterfacesRemovedStream, ObjectManagerProxy}, names::OwnedInterfaceName};
1415
use zvariant::{OwnedObjectPath, OwnedValue};
1516

17+
type OwnedPropertiesMap = HashMap<String, OwnedValue>;
18+
type OwnedInterfaceMap = HashMap<OwnedInterfaceName,OwnedPropertiesMap>;
19+
1620
#[derive(Debug)]
1721
pub struct Session {
1822
connection: Connection,
19-
pub(crate) objects: HashMap<OwnedObjectPath, HashMap<String, HashMap<String, OwnedValue>>>,
23+
_object_manager: ObjectManagerProxy<'static>,
24+
cache: async_lock::Mutex<ObjectCache>
2025
}
2126

2227
impl Session {
2328
pub async fn new() -> zbus::Result<Self> {
2429
let connection = Connection::system().await?;
2530

26-
let proxy = Proxy::new(
27-
&connection,
31+
let proxy = Proxy::new_owned(
32+
connection.clone(),
2833
"net.connman.iwd",
2934
"/",
3035
"org.freedesktop.DBus.ObjectManager",
3136
)
3237
.await?;
38+
let object_manager = ObjectManagerProxy::from(proxy);
3339

34-
let objects: HashMap<OwnedObjectPath, HashMap<String, HashMap<String, OwnedValue>>> =
35-
proxy.call("GetManagedObjects", &()).await?;
40+
let objects: HashMap<OwnedObjectPath, OwnedInterfaceMap> =
41+
object_manager.get_managed_objects().await?;
42+
let interfaces_added = object_manager.receive_interfaces_added().await?;
43+
let interfaces_removed = object_manager.receive_interfaces_removed().await?;
3644

3745
Ok(Self {
3846
connection,
39-
objects,
40-
})
41-
}
42-
43-
fn object_type(
44-
&self,
45-
interface_type: &'static str,
46-
) -> impl IntoIterator<Item = OwnedObjectPath> {
47-
self.objects.iter().flat_map(move |(path, interfaces)| {
48-
let path = path.clone();
49-
interfaces
50-
.iter()
51-
.filter(move |(interface, _)| interface.as_str() == interface_type)
52-
.map(move |_| path.clone())
47+
_object_manager: object_manager,
48+
cache: async_lock::Mutex::new(ObjectCache {
49+
interfaces_added,
50+
interfaces_removed,
51+
objects,
52+
}),
5353
})
5454
}
5555

5656
async fn collect_interface<Output: iwd_interface::IwdInterface>(
5757
&self,
5858
) -> zbus::Result<Vec<Output>> {
59-
let paths: Vec<_> = self.object_type(Output::INTERFACE).into_iter().collect();
59+
let mut cache = self.cache.lock().await;
60+
cache.update_objects_cache().await?;
61+
62+
let paths: Vec<_> = cache.object_type(Output::INTERFACE).into_iter().collect();
6063
let mut results = Vec::with_capacity(paths.len());
6164
for path in paths {
6265
results.push(Output::new(self.connection.clone(), path).await?);
@@ -106,3 +109,52 @@ impl Session {
106109
self.collect_interface().await
107110
}
108111
}
112+
113+
#[derive(Debug)]
114+
struct ObjectCache {
115+
interfaces_added: InterfacesAddedStream,
116+
interfaces_removed: InterfacesRemovedStream,
117+
objects: HashMap<OwnedObjectPath, OwnedInterfaceMap>,
118+
}
119+
120+
impl ObjectCache {
121+
fn object_type(
122+
&self,
123+
interface_type: &'static str,
124+
) -> impl IntoIterator<Item = OwnedObjectPath> {
125+
self.objects.iter().flat_map(move |(path, interfaces)| {
126+
let path = path.clone();
127+
interfaces
128+
.iter()
129+
.filter(move |(interface, _)| interface.as_str() == interface_type)
130+
.map(move |_| path.clone())
131+
})
132+
}
133+
134+
async fn update_objects_cache(&mut self) -> zbus::Result<()>{
135+
while let Some(removal) = self.interfaces_removed.next().or(future::ready(None)).await {
136+
let args = removal.args()?;
137+
self.objects.remove(args.object_path());
138+
}
139+
140+
while let Some(added) = self.interfaces_added.next().or(future::ready(None)).await {
141+
let args = added.args()?;
142+
let InterfacesAddedArgs { object_path, interfaces_and_properties, .. } = args;
143+
let object_path: OwnedObjectPath = object_path.into_owned().into();
144+
let interfaces_and_properties: OwnedInterfaceMap = interfaces_and_properties.into_iter().map(|(iface, props)| {
145+
let iface = iface.into_owned().into();
146+
let props: OwnedPropertiesMap = props.into_iter().filter_map(|(key, val)| {
147+
let Ok(val) = val.try_into_owned() else {
148+
return None
149+
};
150+
Some((key.to_string(), val))
151+
}).collect();
152+
(iface, props)
153+
}).collect();
154+
self.objects.insert(object_path, interfaces_and_properties);
155+
}
156+
157+
158+
Ok(())
159+
}
160+
}

0 commit comments

Comments
 (0)