1use std::{collections::HashMap, sync::Arc, time::Duration};
2
3use ashpd::WindowIdentifier;
4#[cfg(feature = "async-std")]
5use async_lock::RwLock;
6#[cfg(feature = "tokio")]
7use tokio::sync::RwLock;
8use zbus::zvariant::ObjectPath;
9
10use super::{Algorithm, Error, api};
11use crate::{AsAttributes, Key, Secret};
12
13#[derive(Debug)]
29pub struct Item {
30 inner: Arc<api::Item>,
31 session: Arc<api::Session>,
32 service: Arc<api::Service>,
33 algorithm: Algorithm,
34 available: RwLock<bool>,
36 aes_key: Option<Arc<Key>>,
37}
38
39impl Item {
40 pub(crate) fn new(
41 service: Arc<api::Service>,
42 session: Arc<api::Session>,
43 algorithm: Algorithm,
44 item: api::Item,
45 aes_key: Option<Arc<Key>>,
46 ) -> Self {
47 Self {
48 inner: Arc::new(item),
49 service,
50 session,
51 algorithm,
52 available: RwLock::new(true),
53 aes_key,
54 }
55 }
56
57 pub(crate) async fn is_available(&self) -> bool {
58 *self.available.read().await
59 }
60
61 pub async fn is_locked(&self) -> Result<bool, Error> {
63 if !self.is_available().await {
64 Err(Error::Deleted)
65 } else {
66 self.inner.is_locked().await
67 }
68 }
69
70 pub async fn label(&self) -> Result<String, Error> {
72 if !self.is_available().await {
73 Err(Error::Deleted)
74 } else {
75 self.inner.label().await
76 }
77 }
78
79 pub async fn set_label(&self, label: &str) -> Result<(), Error> {
81 if !self.is_available().await {
82 Err(Error::Deleted)
83 } else {
84 self.inner.set_label(label).await
85 }
86 }
87
88 pub async fn created(&self) -> Result<Duration, Error> {
90 if !self.is_available().await {
91 Err(Error::Deleted)
92 } else {
93 self.inner.created().await
94 }
95 }
96
97 pub async fn modified(&self) -> Result<Duration, Error> {
99 if !self.is_available().await {
100 Err(Error::Deleted)
101 } else {
102 self.inner.modified().await
103 }
104 }
105
106 pub async fn attributes(&self) -> Result<HashMap<String, String>, Error> {
108 if !self.is_available().await {
109 Err(Error::Deleted)
110 } else {
111 self.inner.attributes().await
112 }
113 }
114
115 #[cfg(feature = "schema")]
134 #[cfg_attr(docsrs, doc(cfg(feature = "schema")))]
135 pub async fn attributes_as<T>(&self) -> Result<T, Error>
136 where
137 T: std::convert::TryFrom<HashMap<String, String>, Error = crate::SchemaError>,
138 {
139 let attrs = self.attributes().await?;
140 T::try_from(attrs).map_err(Into::into)
141 }
142
143 pub async fn set_attributes(&self, attributes: &impl AsAttributes) -> Result<(), Error> {
145 if !self.is_available().await {
146 Err(Error::Deleted)
147 } else {
148 self.inner.set_attributes(attributes).await
149 }
150 }
151
152 pub async fn delete(&self, window_id: Option<WindowIdentifier>) -> Result<(), Error> {
154 if !self.is_available().await {
155 Err(Error::Deleted)
156 } else {
157 self.inner.delete(window_id).await?;
158 *self.available.write().await = false;
159 Ok(())
160 }
161 }
162
163 pub async fn secret(&self) -> Result<Secret, Error> {
165 if !self.is_available().await {
166 Err(Error::Deleted)
167 } else {
168 self.inner
169 .secret(&self.session)
170 .await?
171 .decrypt(self.aes_key.as_ref())
172 }
173 }
174
175 #[doc(alias = "SetSecret")]
181 pub async fn set_secret(&self, secret: impl Into<Secret>) -> Result<(), Error> {
182 if !self.is_available().await {
183 Err(Error::Deleted)
184 } else {
185 let secret = match self.algorithm {
186 Algorithm::Plain => api::DBusSecret::new(Arc::clone(&self.session), secret),
187 Algorithm::Encrypted => {
188 let aes_key = self.aes_key.as_ref().unwrap();
189 api::DBusSecret::new_encrypted(Arc::clone(&self.session), secret, aes_key)?
190 }
191 };
192 self.inner.set_secret(&secret).await?;
193 Ok(())
194 }
195 }
196
197 pub async fn unlock(&self, window_id: Option<WindowIdentifier>) -> Result<(), Error> {
199 if !self.is_available().await {
200 Err(Error::Deleted)
201 } else {
202 self.service
203 .unlock(&[self.inner.inner().path()], window_id)
204 .await?;
205 Ok(())
206 }
207 }
208
209 pub async fn lock(&self, window_id: Option<WindowIdentifier>) -> Result<(), Error> {
211 if !self.is_available().await {
212 Err(Error::Deleted)
213 } else {
214 self.service
215 .lock(&[self.inner.inner().path()], window_id)
216 .await?;
217 Ok(())
218 }
219 }
220
221 pub fn path(&self) -> &ObjectPath<'_> {
223 self.inner.inner().path()
224 }
225}