autonomi/client/high_level/vault/
user_data.rs1use std::collections::HashMap;
10
11use super::{VaultContentType, VaultError, VaultSecretKey, vault_content_type_from_app_name};
12use crate::chunk::DataMapChunk;
13use crate::client::Client;
14use crate::client::GetError;
15use crate::client::high_level::files::archive_private::PrivateArchiveDataMap;
16use crate::client::high_level::files::archive_public::ArchiveAddress;
17use crate::client::payment::PaymentOption;
18use crate::data::DataAddress;
19use crate::register::RegisterAddress;
20use ant_evm::AttoTokens;
21use ant_protocol::Bytes;
22use serde::{Deserialize, Serialize};
23use std::sync::LazyLock;
24
25pub static USER_DATA_VAULT_CONTENT_IDENTIFIER: LazyLock<VaultContentType> =
27 LazyLock::new(|| vault_content_type_from_app_name("UserData"));
28
29pub type RegisterSecretKeyHex = String;
30pub type ScratchpadSecretKeyHex = String;
31pub type PointerSecretKeyHex = String;
32
33#[derive(Debug, Clone, Serialize, Default, PartialEq, Eq, Deserialize)]
38pub struct UserData {
39 pub file_archives: HashMap<ArchiveAddress, String>,
41 pub private_file_archives: HashMap<PrivateArchiveDataMap, String>,
43 pub register_addresses: HashMap<RegisterAddress, String>,
45 #[serde(default)]
47 pub register_key: Option<RegisterSecretKeyHex>,
49 #[serde(default)]
51 pub scratchpad_key: Option<ScratchpadSecretKeyHex>,
53 #[serde(default)]
55 pub pointer_key: Option<PointerSecretKeyHex>,
57 #[serde(default)]
59 pub public_files: HashMap<DataAddress, String>,
61 #[serde(default)]
63 pub private_files: HashMap<DataMapChunk, String>,
65}
66
67#[derive(Debug, thiserror::Error)]
69pub enum UserDataVaultError {
70 #[error("Vault error: {0}")]
71 Vault(#[from] VaultError),
72 #[error("Unsupported vault content type: {0}")]
73 UnsupportedVaultContentType(VaultContentType),
74 #[error("Serialization error: {0}")]
75 Serialization(String),
76 #[error("Get error: {0}")]
77 GetError(#[from] GetError),
78}
79
80impl UserData {
81 pub fn new() -> Self {
83 Self::default()
84 }
85
86 pub fn add_register(&mut self, register: RegisterAddress, name: String) -> Option<String> {
88 self.register_addresses.insert(register, name)
89 }
90
91 pub fn add_file_archive(&mut self, archive: ArchiveAddress) -> Option<String> {
93 self.file_archives.insert(archive, "".into())
94 }
95
96 pub fn add_file_archive_with_name(
98 &mut self,
99 archive: ArchiveAddress,
100 name: String,
101 ) -> Option<String> {
102 self.file_archives.insert(archive, name)
103 }
104
105 pub fn add_private_file_archive(&mut self, archive: PrivateArchiveDataMap) -> Option<String> {
107 self.private_file_archives.insert(archive, "".into())
108 }
109
110 pub fn add_private_file_archive_with_name(
112 &mut self,
113 archive: PrivateArchiveDataMap,
114 name: String,
115 ) -> Option<String> {
116 self.private_file_archives.insert(archive, name)
117 }
118
119 pub fn remove_file_archive(&mut self, archive: ArchiveAddress) -> Option<String> {
121 self.file_archives.remove(&archive)
122 }
123
124 pub fn remove_private_file_archive(
126 &mut self,
127 archive: PrivateArchiveDataMap,
128 ) -> Option<String> {
129 self.private_file_archives.remove(&archive)
130 }
131
132 pub fn to_bytes(&self) -> Result<Bytes, rmp_serde::encode::Error> {
134 let bytes = rmp_serde::to_vec(&self)?;
135 Ok(Bytes::from(bytes))
136 }
137
138 pub fn from_bytes(bytes: Bytes) -> Result<Self, rmp_serde::decode::Error> {
140 let vault_content = rmp_serde::from_slice(&bytes)?;
141 Ok(vault_content)
142 }
143
144 pub fn display_stats(&self) {
146 let file_archives_len = self.file_archives.len();
147 let private_file_archives_len = self.private_file_archives.len();
148 let public_files_len = self.public_files.len();
149 let private_files_len = self.private_files.len();
150 let registers_len = self.register_addresses.len();
151 let register_key = match self.register_key.is_some() {
152 true => "1",
153 false => "0",
154 };
155 let scratchpad_key = match self.scratchpad_key.is_some() {
156 true => "1",
157 false => "0",
158 };
159 let pointer_key = match self.pointer_key.is_some() {
160 true => "1",
161 false => "0",
162 };
163
164 println!("{file_archives_len} public file archive(s)");
165 println!("{private_file_archives_len} private file archive(s)");
166 println!("{public_files_len} public file(s)");
167 println!("{private_files_len} private file(s)");
168 println!("{registers_len} register(s)");
169 println!("{register_key} register key");
170 println!("{scratchpad_key} scratchpad key");
171 println!("{pointer_key} pointer key");
172 }
173}
174
175impl Client {
176 pub async fn vault_get_user_data(
178 &self,
179 secret_key: &VaultSecretKey,
180 ) -> Result<UserData, UserDataVaultError> {
181 let (bytes, content_type) = self.vault_get(secret_key).await?;
182
183 if content_type != *USER_DATA_VAULT_CONTENT_IDENTIFIER {
184 return Err(UserDataVaultError::UnsupportedVaultContentType(
185 content_type,
186 ));
187 }
188
189 let vault = UserData::from_bytes(bytes).map_err(|e| {
190 UserDataVaultError::Serialization(format!("Failed to deserialize vault content: {e}"))
191 })?;
192
193 Ok(vault)
194 }
195
196 pub async fn vault_put_user_data(
200 &self,
201 secret_key: &VaultSecretKey,
202 payment_option: PaymentOption,
203 user_data: UserData,
204 ) -> Result<AttoTokens, UserDataVaultError> {
205 let bytes = user_data.to_bytes().map_err(|e| {
206 UserDataVaultError::Serialization(format!("Failed to serialize user data: {e}"))
207 })?;
208 let total_cost = self
209 .vault_put(
210 bytes,
211 payment_option,
212 secret_key,
213 *USER_DATA_VAULT_CONTENT_IDENTIFIER,
214 )
215 .await?;
216 Ok(total_cost)
217 }
218
219 #[deprecated(since = "0.2.0", note = "Use `vault_get_user_data` instead")]
221 pub async fn get_user_data_from_vault(
222 &self,
223 secret_key: &VaultSecretKey,
224 ) -> Result<UserData, UserDataVaultError> {
225 self.vault_get_user_data(secret_key).await
226 }
227
228 #[deprecated(since = "0.2.0", note = "Use `vault_put_user_data` instead")]
230 pub async fn put_user_data_to_vault(
231 &self,
232 secret_key: &VaultSecretKey,
233 payment_option: PaymentOption,
234 user_data: UserData,
235 ) -> Result<AttoTokens, UserDataVaultError> {
236 self.vault_put_user_data(secret_key, payment_option, user_data)
237 .await
238 }
239}
240
241#[cfg(test)]
242mod tests {
243 use crate::XorName;
244 use bls::SecretKey;
245
246 use super::*;
247
248 #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
250 struct UserDataV1 {
251 pub file_archives: HashMap<ArchiveAddress, String>,
252 pub private_file_archives: HashMap<PrivateArchiveDataMap, String>,
253 pub register_addresses: HashMap<RegisterAddress, String>,
254 }
255
256 #[test]
257 fn test_user_data_v1_deserialization() {
258 let v1_data = UserDataV1 {
260 file_archives: HashMap::from([(ArchiveAddress::new(XorName::random(&mut rand::thread_rng())), "test_archive".to_string())]),
261 private_file_archives: HashMap::from([(
262 PrivateArchiveDataMap::from_hex("1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef").unwrap(),
263 "test_private".to_string(),
264 )]),
265 register_addresses: HashMap::from([(RegisterAddress::new(SecretKey::random().public_key()), "test_register".to_string())]),
266 };
267
268 let serialized = rmp_serde::to_vec(&v1_data).unwrap();
270
271 let deserialized: UserData = rmp_serde::from_slice(&serialized).unwrap();
273
274 assert_eq!(deserialized.file_archives, v1_data.file_archives);
276 assert_eq!(
277 deserialized.private_file_archives,
278 v1_data.private_file_archives
279 );
280 assert_eq!(deserialized.register_addresses, v1_data.register_addresses);
281 assert_eq!(deserialized.register_key, None);
282 assert_eq!(deserialized.scratchpad_key, None);
283 assert_eq!(deserialized.pointer_key, None);
284 assert_eq!(deserialized.public_files, HashMap::new());
285 assert_eq!(deserialized.private_files, HashMap::new());
286
287 let current_data = UserData {
289 file_archives: v1_data.file_archives.clone(),
290 private_file_archives: v1_data.private_file_archives.clone(),
291 register_addresses: v1_data.register_addresses.clone(),
292 register_key: Some("test_key".to_string()),
293 scratchpad_key: Some("test_scratchpad_key".to_string()),
294 pointer_key: Some("test_pointer_key".to_string()),
295 public_files: HashMap::new(),
296 private_files: HashMap::new(),
297 };
298
299 let serialized = rmp_serde::to_vec(¤t_data).unwrap();
300 let deserialized: UserData = rmp_serde::from_slice(&serialized).unwrap();
301
302 assert_eq!(deserialized, current_data);
304 }
305}