Repository: bilelmoussaoui/oo7 (language: rust)

Issue:
Implement locking and unlocking items
Currently, the general `oo7::Item` has no `lock`, `unlock` and `is_locked` methods like the `oo7::dbus::Item` has. This can cause issues when the generic `oo7::Item` is used, the backend uses dbus and the queried item is locked.

Related downstream issue: https://gitlab.com/Schmiddiii/flare/-/issues/88


Discussion / hints:

Fix patch:
diff --git a/Cargo.toml b/Cargo.toml
index ebeb44f94..aa055b525 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "oo7"
-version = "0.1.2"
+version = "0.2.0"
 edition = "2021"
 authors = ["Bilal Elmoussaoui", "Sophie Herold", "Maximiliano Sandoval"]
 description = "James Bond went on a new mission and this time as a Secret Service provider"
diff --git a/src/dbus/api/collection.rs b/src/dbus/api/collection.rs
index 3431db2fe..ed29cda28 100644
--- a/src/dbus/api/collection.rs
+++ b/src/dbus/api/collection.rs
@@ -1,6 +1,6 @@
 use std::{collections::HashMap, fmt, time::Duration};
 
-use futures_util::StreamExt;
+use futures_util::{Stream, StreamExt};
 use serde::Serialize;
 use zbus::zvariant::{ObjectPath, OwnedObjectPath, Type};
 
@@ -51,27 +51,33 @@ impl<'a> Collection<'a> {
     }
 
     #[doc(alias = "ItemCreated")]
-    pub async fn receive_item_created(&self) -> Result<Item<'a>, Error> {
+    pub async fn receive_item_created(&self) -> Result<impl Stream<Item = Item<'_>>, Error> {
         let mut stream = self.inner().receive_signal("ItemCreated").await?;
-        let message = stream.next().await.unwrap();
-        let object_path = message.body::<OwnedObjectPath>()?;
-        Item::new(self.inner().connection(), object_path).await
+        let conn = self.inner().connection();
+        Ok(stream.filter_map(move |message| async move {
+            let path = message.body::<OwnedObjectPath>().ok()?;
+            Item::new(&conn.clone(), path).await.ok()
+        }))
     }
 
     #[doc(alias = "ItemDeleted")]
-    pub async fn receive_item_deleted(&self) -> Result<Item<'a>, Error> {
+    pub async fn receive_item_deleted(&self) -> Result<impl Stream<Item = Item<'_>>, Error> {
         let mut stream = self.inner().receive_signal("ItemDeleted").await?;
-        let message = stream.next().await.unwrap();
-        let object_path = message.body::<OwnedObjectPath>()?;
-        Item::new(self.inner().connection(), object_path).await
+        let conn = self.inner().connection();
+        Ok(stream.filter_map(move |message| async move {
+            let path = message.body::<OwnedObjectPath>().ok()?;
+            Item::new(&conn.clone(), path).await.ok()
+        }))
     }
 
     #[doc(alias = "ItemChanged")]
-    pub async fn receive_item_changed(&self) -> Result<Item<'a>, Error> {
+    pub async fn receive_item_changed(&self) -> Result<impl Stream<Item = Item<'_>>, Error> {
         let mut stream = self.inner().receive_signal("ItemChanged").await?;
-        let message = stream.next().await.unwrap();
-        let object_path = message.body::<OwnedObjectPath>()?;
-        Item::new(self.inner().connection(), object_path).await
+        let conn = self.inner().connection();
+        Ok(stream.filter_map(move |message| async move {
+            let path = message.body::<OwnedObjectPath>().ok()?;
+            Item::new(&conn.clone(), path).await.ok()
+        }))
     }
 
     pub async fn items(&self) -> Result<Vec<Item<'a>>, Error> {
diff --git a/src/dbus/api/service.rs b/src/dbus/api/service.rs
index 88c66a746..02f33b8d7 100644
--- a/src/dbus/api/service.rs
+++ b/src/dbus/api/service.rs
@@ -1,6 +1,6 @@
 use std::{collections::HashMap, fmt};
 
-use futures_util::StreamExt;
+use futures_util::{Stream, StreamExt};
 use zbus::zvariant::{self, ObjectPath, OwnedObjectPath, OwnedValue, Type, Value};
 
 use super::{
@@ -34,27 +34,39 @@ impl<'a> Service<'a> {
     }
 
     #[doc(alias = "CollectionCreated")]
-    pub async fn receive_collection_created(&self) -> Result<Collection<'a>, Error> {
+    pub async fn receive_collection_created(
+        &self,
+    ) -> Result<impl Stream<Item = Collection<'_>>, Error> {
         let mut stream = self.inner().receive_signal("CollectionCreated").await?;
-        let message = stream.next().await.unwrap();
-        let object_path = message.body::<OwnedObjectPath>()?;
-        Collection::new(self.inner().connection(), object_path).await
+        let conn = self.inner().connection();
+        Ok(stream.filter_map(move |message| async move {
+            let path = message.body::<OwnedObjectPath>().ok()?;
+            Collection::new(&conn.clone(), path).await.ok()
+        }))
     }
 
     #[doc(alias = "CollectionDeleted")]
-    pub async fn receive_collection_deleted(&self) -> Result<Collection<'a>, Error> {
+    pub async fn receive_collection_deleted(
+        &self,
+    ) -> Result<impl Stream<Item = Collection<'_>>, Error> {
         let mut stream = self.inner().receive_signal("CollectionDeleted").await?;
-        let message = stream.next().await.unwrap();
-        let object_path = message.body::<OwnedObjectPath>()?;
-        Collection::new(self.inner().connection(), object_path).await
+        let conn = self.inner().connection();
+        Ok(stream.filter_map(move |message| async move {
+            let path = message.body::<OwnedObjectPath>().ok()?;
+            Collection::new(&conn.clone(), path).await.ok()
+        }))
     }
 
     #[doc(alias = "CollectionChanged")]
-    pub async fn receive_collection_changed(&self) -> Result<Collection<'a>, Error> {
+    pub async fn receive_collection_changed(
+        &self,
+    ) -> Result<impl Stream<Item = Collection<'_>>, Error> {
         let mut stream = self.inner().receive_signal("CollectionChanged").await?;
-        let message = stream.next().await.unwrap();
-        let object_path = message.body::<OwnedObjectPath>()?;
-        Collection::new(self.inner().connection(), object_path).await
+        let conn = self.inner().connection();
+        Ok(stream.filter_map(move |message| async move {
+            let path = message.body::<OwnedObjectPath>().ok()?;
+            Collection::new(&conn.clone(), path).await.ok()
+        }))
     }
 
     pub async fn collections(&self) -> Result<Vec<Collection<'a>>, Error> {
diff --git a/src/keyring.rs b/src/keyring.rs
index 456b8f7df..4c91a70e4 100644
--- a/src/keyring.rs
+++ b/src/keyring.rs
@@ -300,6 +300,26 @@ impl Item {
         Ok(secret)
     }
 
+    /// Lock the item
+    ///
+    /// The method does nothing if keyring is backed by a file backend.
+    pub async fn lock(&self) -> Result<()> {
+        if let Self::DBus(item) = self {
+            item.lock().await?;
+        }
+        Ok(())
+    }
+
+    /// Unlock the item
+    ///
+    /// The method does nothing if keyring is backed by a file backend.
+    pub async fn unlock(&self) -> Result<()> {
+        if let Self::DBus(item) = self {
+            item.unlock().await?;
+        }
+        Ok(())
+    }
+
     /// Delete the item.
     pub async fn delete(&self) -> Result<()> {
         match self {


Test patch: