diem_secure_storage/
on_disk.rs1use crate::{CryptoKVStorage, Error, GetResponse, KVStorage};
9use serde::{de::DeserializeOwned, Serialize};
10use serde_json::Value;
11use std::{
12 collections::HashMap,
13 fs::File,
14 io::{Read, Write},
15 path::{Path, PathBuf},
16 time::{SystemTime, UNIX_EPOCH},
17};
18
19pub struct OnDiskStorage {
32 file_path: PathBuf,
33}
34
35impl OnDiskStorage {
36 pub fn new(file_path: PathBuf) -> Self {
37 if !file_path.exists() {
38 File::create(&file_path).expect("Unable to create storage");
39 }
40 Self { file_path }
41 }
42
43 pub fn file_path(&self) -> &PathBuf { &self.file_path }
44
45 fn read(&self) -> Result<HashMap<String, Value>, Error> {
46 let mut file = File::open(&self.file_path)?;
47 let mut contents = String::new();
48 file.read_to_string(&mut contents)?;
49 if contents.is_empty() {
50 return Ok(HashMap::new());
51 }
52 Ok(serde_json::from_str(&contents)?)
53 }
54
55 fn write(&self, data: &HashMap<String, Value>) -> Result<(), Error> {
56 let contents = serde_json::to_vec(data)?;
57 let dir = self.file_path.parent().unwrap_or_else(|| Path::new("."));
58 let mut temp = tempfile::Builder::new().tempfile_in(dir)?;
59 temp.write_all(&contents)?;
60 temp.persist(&self.file_path)
61 .map_err(|e| Error::from(e.error))?;
62 Ok(())
63 }
64}
65
66impl KVStorage for OnDiskStorage {
67 fn available(&self) -> Result<(), Error> { Ok(()) }
68
69 fn get<V: DeserializeOwned>(
70 &self, key: &str,
71 ) -> Result<GetResponse<V>, Error> {
72 let mut data = self.read()?;
73 data.remove(key)
74 .ok_or_else(|| Error::KeyNotSet(key.to_string()))
75 .and_then(|value| {
76 serde_json::from_value(value).map_err(|e| e.into())
77 })
78 }
79
80 fn set<V: Serialize>(&mut self, key: &str, value: V) -> Result<(), Error> {
81 let now = SystemTime::now()
82 .duration_since(UNIX_EPOCH)
83 .expect("System time is before UNIX_EPOCH")
84 .as_secs();
85 let mut data = self.read()?;
86 data.insert(
87 key.to_string(),
88 serde_json::to_value(&GetResponse::new(value, now))?,
89 );
90 self.write(&data)
91 }
92
93 #[cfg(any(test, feature = "testing"))]
94 fn reset_and_clear(&mut self) -> Result<(), Error> {
95 self.write(&HashMap::new())
96 }
97}
98
99impl CryptoKVStorage for OnDiskStorage {}