From b30cdbaff266fcc398dd236e957761b57992ac7d Mon Sep 17 00:00:00 2001 From: Dhanuka Warusadura Date: Tue, 26 Nov 2024 17:57:01 +0530 Subject: [PATCH] server: Add Lock and Unlock implementation Issuing a prompt to lock/unlock objects is not implemented in this change. Signed-off-by: Dhanuka Warusadura --- server/src/collection.rs | 35 +++++++++++++++-- server/src/item.rs | 24 +++++++++++- server/src/service.rs | 73 +++++++++++++++++++++++++++++++---- server/src/service_manager.rs | 15 ++++++- 4 files changed, 133 insertions(+), 14 deletions(-) diff --git a/server/src/collection.rs b/server/src/collection.rs index d3f40265..a604725b 100644 --- a/server/src/collection.rs +++ b/server/src/collection.rs @@ -14,10 +14,10 @@ use oo7::{ portal::Keyring, }; use tokio::sync::{Mutex, RwLock}; -use zbus::{interface, object_server::SignalEmitter, zvariant}; +use zbus::{interface, object_server::SignalEmitter, proxy::Defaults, zvariant}; use zvariant::{ObjectPath, OwnedObjectPath}; -use crate::{error::Error, item, service_manager::ServiceManager}; +use crate::{error::Error, item, service_manager::ServiceManager, Service}; #[derive(Debug, Clone)] pub struct Collection { @@ -130,9 +130,9 @@ impl Collection { ) -> zbus::Result<()>; #[zbus(signal, name = "ItemChanged")] - async fn item_changed( + pub async fn item_changed( signal_emitter: &SignalEmitter<'_>, - item: OwnedObjectPath, + item: &OwnedObjectPath, ) -> zbus::Result<()>; } @@ -205,6 +205,33 @@ impl Collection { None } + pub async fn set_locked(&self, locked: bool) -> Result<(), ServiceError> { + let items = self.items.lock().await; + + for item in items.iter() { + item.set_locked(locked).await?; + } + + let manager = self.manager.lock().await; + + self.locked + .store(locked, std::sync::atomic::Ordering::Relaxed); + let signal_emitter = manager.signal_emitter(&self.path)?; + self.locked_changed(&signal_emitter).await?; + + let service_path = oo7::dbus::api::Service::PATH.as_ref().unwrap(); + let signal_emitter = manager.signal_emitter(service_path)?; + Service::collection_changed(&signal_emitter, &self.path).await?; + + tracing::debug!( + "Collection: {} is {}.", + self.path, + if locked { "locked" } else { "unlocked" } + ); + + Ok(()) + } + pub async fn dispatch_items(&self) -> Result<(), Error> { let keyring_items = self.keyring.items().await; let mut items = self.items.lock().await; diff --git a/server/src/item.rs b/server/src/item.rs index 163e559f..67824011 100644 --- a/server/src/item.rs +++ b/server/src/item.rs @@ -12,7 +12,7 @@ use oo7::{ use tokio::sync::Mutex; use zbus::zvariant::{ObjectPath, OwnedObjectPath}; -use crate::service_manager::ServiceManager; +use crate::{collection::Collection, service_manager::ServiceManager}; #[derive(Debug, Clone)] pub struct Item { @@ -21,6 +21,7 @@ pub struct Item { inner: Arc>, // Other attributes manager: Arc>, + collection_path: OwnedObjectPath, path: OwnedObjectPath, } @@ -160,6 +161,7 @@ impl Item { Self { locked: Arc::new(AtomicBool::new(locked)), inner: Arc::new(Mutex::new(item)), + collection_path: collection_path.clone(), path: OwnedObjectPath::try_from(format!("{}/{}", collection_path, item_index)).unwrap(), manager, } @@ -168,4 +170,24 @@ impl Item { pub fn path(&self) -> &OwnedObjectPath { &self.path } + + pub async fn set_locked(&self, locked: bool) -> Result<(), ServiceError> { + let manager = self.manager.lock().await; + + self.locked + .store(locked, std::sync::atomic::Ordering::Relaxed); + let signal_emitter = manager.signal_emitter(&self.path)?; + self.locked_changed(&signal_emitter).await?; + + let signal_emitter = manager.signal_emitter(&self.collection_path)?; + Collection::item_changed(&signal_emitter, &self.path).await?; + + tracing::debug!( + "Item: {} is {}.", + self.path, + if locked { "locked" } else { "unlocked" } + ); + + Ok(()) + } } diff --git a/server/src/service.rs b/server/src/service.rs index e3c73a30..533f5ce8 100644 --- a/server/src/service.rs +++ b/server/src/service.rs @@ -115,17 +115,21 @@ impl Service { #[zbus(out_args("unlocked", "prompt"))] pub async fn unlock( &mut self, - _objects: Vec, - ) -> Result<(Vec, ObjectPath), ServiceError> { - todo!() + objects: Vec, + ) -> Result<(Vec, OwnedObjectPath), ServiceError> { + let (unlocked, _not_unlocked) = self.set_locked(false, &objects).await?; + + Ok((unlocked, OwnedObjectPath::default())) } #[zbus(out_args("locked", "prompt"))] pub async fn lock( &mut self, - _objects: Vec, - ) -> Result<(Vec, ObjectPath), ServiceError> { - todo!() + objects: Vec, + ) -> Result<(Vec, OwnedObjectPath), ServiceError> { + let (locked, _not_locked) = self.set_locked(true, &objects).await?; + + Ok((locked, OwnedObjectPath::default())) } #[zbus(out_args("secrets"))] @@ -231,9 +235,9 @@ impl Service { ) -> zbus::Result<()>; #[zbus(signal, name = "CollectionChanged")] - async fn collection_changed( + pub async fn collection_changed( signal_emitter: &SignalEmitter<'_>, - collection: OwnedObjectPath, + collection: &OwnedObjectPath, ) -> zbus::Result<()>; } @@ -293,4 +297,57 @@ impl Service { Ok(()) } + + pub async fn set_locked( + &self, + locked: bool, + objects: &[OwnedObjectPath], + ) -> Result<(Vec, Vec), ServiceError> { + let mut without_prompt = Vec::new(); + let mut with_prompt = Vec::new(); + let collections = self.collections.lock().await; + + for object in objects { + for collection in collections.iter() { + let collection_locked = collection.is_locked().await; + if object == collection.path() { + if collection_locked == locked { + tracing::debug!( + "Collection: {} is already {}.", + object, + if locked { "locked" } else { "unlocked" } + ); + without_prompt.push(object.clone()); + } else { + // TODO: remove this once the prompt implementation is complete. + collection.set_locked(locked).await?; + with_prompt.push(object.clone()); + } + break; + } else if let Some(item) = collection.item_from_path(object).await { + if locked == item.is_locked().await { + tracing::debug!( + "Item: {} is already {}.", + object, + if locked { "locked" } else { "unlocked" } + ); + without_prompt.push(object.clone()); + // If the collection is in a similar state, update the Item + // without a prompt. + } else if collection_locked == locked { + item.set_locked(locked).await?; + without_prompt.push(object.clone()); + } else { + // TODO: remove this once the prompt implementation is complete. + item.set_locked(locked).await?; + with_prompt.push(object.clone()); + } + break; + } + tracing::warn!("Object: {} does not exist.", object); + } + } + + Ok((without_prompt, with_prompt)) + } } diff --git a/server/src/service_manager.rs b/server/src/service_manager.rs index e96bf17d..495727fe 100644 --- a/server/src/service_manager.rs +++ b/server/src/service_manager.rs @@ -3,7 +3,7 @@ use std::{collections::HashMap, sync::Arc}; use tokio::sync::RwLock; -use zbus::zvariant::OwnedObjectPath; +use zbus::zvariant::{ObjectPath, OwnedObjectPath}; use crate::session::Session; @@ -40,6 +40,19 @@ impl ServiceManager { self.sessions.remove(path); } + pub fn signal_emitter<'a, P>( + &self, + path: P, + ) -> Result, oo7::dbus::ServiceError> + where + P: TryInto>, + P::Error: Into, + { + let signal_emitter = zbus::object_server::SignalEmitter::new(&self.connection, path)?; + + Ok(signal_emitter) + } + pub async fn session_index(&self) -> u32 { let n_sessions = *self.session_index.read().await + 1; *self.session_index.write().await = n_sessions;