Skip to content

Commit 0e80ae7

Browse files
committed
dbus: rauc: forward poller status to broker
RAUC native polling provides us with information about the recent poll attempts. This includes information about the bundle version and wether it is an update over what is currently running on the device. In other words: it gives us everything we need to show update notifications again. Forward this information to the same places we used with the tacd-based update polling. Signed-off-by: Leonard Göhrs <l.goehrs@pengutronix.de>
1 parent 0a757e4 commit 0e80ae7

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

src/dbus/rauc.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,56 @@ impl Rauc {
478478
Ok(())
479479
})?;
480480

481+
let conn_task = conn.clone();
482+
let channels = inst.channels.clone();
483+
484+
// Forward the "Poller::status" property to the broker framework
485+
wtb.spawn_task("rauc-forward-poller-status", async move {
486+
let proxy = PollerProxy::new(&conn_task).await.unwrap();
487+
488+
let mut stream = proxy.receive_status_changed().await;
489+
490+
if let Ok(status) = proxy.status().await {
491+
channels.modify(|chs| {
492+
let mut chs = chs?;
493+
494+
match chs.update_from_poll_status(status.into()) {
495+
Ok(true) => Some(chs),
496+
Ok(false) => None,
497+
Err(e) => {
498+
warn!("Could not update channel list from poll status: {e}");
499+
None
500+
}
501+
}
502+
});
503+
}
504+
505+
while let Some(status) = stream.next().await {
506+
let status = match status.get().await {
507+
Ok(status) => status,
508+
Err(e) => {
509+
warn!("Could not get poll status: {e}");
510+
continue;
511+
}
512+
};
513+
514+
channels.modify(|chs| {
515+
let mut chs = chs?;
516+
517+
match chs.update_from_poll_status(status.into()) {
518+
Ok(true) => Some(chs),
519+
Ok(false) => None,
520+
Err(e) => {
521+
warn!("Could not update channel list from poll status: {e}");
522+
None
523+
}
524+
}
525+
});
526+
}
527+
528+
Ok(())
529+
})?;
530+
481531
let conn_task = conn.clone();
482532
let channels = inst.channels.clone();
483533
let (mut install_stream, _) = inst.install.clone().subscribe_unbounded();

src/dbus/rauc/update_channels.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
// with this program; if not, write to the Free Software Foundation, Inc.,
1616
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1717

18+
#[cfg(not(feature = "demo_mode"))]
19+
use std::convert::TryFrom;
1820
use std::fs::{read_dir, read_to_string, DirEntry};
1921
use std::os::unix::ffi::OsStrExt;
2022
use std::path::Path;
@@ -64,6 +66,34 @@ pub struct ChannelFile {
6466
pub polling_interval: Option<String>,
6567
}
6668

69+
#[cfg(not(feature = "demo_mode"))]
70+
fn zvariant_walk_nested_dicts<'a, T>(map: &'a zvariant::Dict, path: &'a [&'a str]) -> Result<&'a T>
71+
where
72+
&'a T: TryFrom<&'a zvariant::Value<'a>>,
73+
<&'a T as TryFrom<&'a zvariant::Value<'a>>>::Error: Into<zvariant::Error>,
74+
{
75+
let (key, rem) = path
76+
.split_first()
77+
.ok_or_else(|| anyhow!("Got an empty path to walk"))?;
78+
79+
let value: &zvariant::Value = map
80+
.get(key)?
81+
.ok_or_else(|| anyhow!("Could not find key \"{key}\" in dict"))?;
82+
83+
if rem.is_empty() {
84+
value.downcast_ref().map_err(|e| {
85+
let type_name = std::any::type_name::<T>();
86+
anyhow!("Failed to convert value in dictionary for key \"{key}\" to {type_name}: {e}")
87+
})
88+
} else {
89+
let value = value.downcast_ref().map_err(|e| {
90+
anyhow!("Failed to convert value in dictionary for key \"{key}\" to a dict: {e}")
91+
})?;
92+
93+
zvariant_walk_nested_dicts(value, rem)
94+
}
95+
}
96+
6797
impl Channel {
6898
fn from_file(path: &Path) -> Result<Self> {
6999
let file_name = || {
@@ -177,4 +207,40 @@ impl Channels {
177207
pub(super) fn primary(&self) -> Option<&Channel> {
178208
self.0.iter().find(|ch| ch.primary)
179209
}
210+
211+
#[cfg(not(feature = "demo_mode"))]
212+
fn primary_mut(&mut self) -> Option<&mut Channel> {
213+
self.0.iter_mut().find(|ch| ch.primary)
214+
}
215+
216+
#[cfg(not(feature = "demo_mode"))]
217+
pub(super) fn update_from_poll_status(&mut self, poll_status: zvariant::Dict) -> Result<bool> {
218+
let compatible: &zvariant::Str =
219+
zvariant_walk_nested_dicts(&poll_status, &["manifest", "update", "compatible"])?;
220+
let version: &zvariant::Str =
221+
zvariant_walk_nested_dicts(&poll_status, &["manifest", "update", "version"])?;
222+
let newer_than_installed: &bool =
223+
zvariant_walk_nested_dicts(&poll_status, &["update-available"])?;
224+
225+
if let Some(pb) = self.0.iter().find_map(|ch| ch.bundle.as_ref()) {
226+
if compatible == pb.compatible.as_str()
227+
&& version == pb.version.as_str()
228+
&& *newer_than_installed == pb.newer_than_installed
229+
{
230+
return Ok(false);
231+
}
232+
}
233+
234+
self.0.iter_mut().for_each(|ch| ch.bundle = None);
235+
236+
if let Some(primary) = self.primary_mut() {
237+
primary.bundle = Some(UpstreamBundle {
238+
compatible: compatible.as_str().into(),
239+
version: version.as_str().into(),
240+
newer_than_installed: *newer_than_installed,
241+
});
242+
}
243+
244+
Ok(true)
245+
}
180246
}

0 commit comments

Comments
 (0)