1use super::{
5 error::Result,
6 http_client::Client,
7 service::{Account, Collection, CollectionManager, Item, ItemManager},
8};
9use remove_dir_all::remove_dir_all;
10use std::fs;
11use std::path::{Path, PathBuf};
12
13pub struct FileSystemCache {
31 user_dir: PathBuf,
32 cols_dir: PathBuf,
33}
34
35impl FileSystemCache {
36 pub fn new(path: &Path, username: &str) -> Result<Self> {
42 let mut user_dir = PathBuf::from(path);
43 user_dir.push(username);
44 let cols_dir = user_dir.join("cols");
45 fs::create_dir_all(&cols_dir)?;
46
47 Ok(Self { user_dir, cols_dir })
48 }
49
50 fn get_collection_items_dir(&self, col_uid: &str) -> PathBuf {
51 self.cols_dir.join(col_uid).join("items")
52 }
53
54 pub fn clear_user_cache(&self) -> Result<()> {
56 let user_dir = &self.user_dir;
57 remove_dir_all(user_dir)?;
58 Ok(())
59 }
60
61 pub fn save_account(&self, etebase: &Account, encryption_key: Option<&[u8]>) -> Result<()> {
69 let account_file = self.user_dir.join("account");
70 let account = etebase.save(encryption_key)?;
71 fs::write(account_file, account)?;
72 Ok(())
73 }
74
75 pub fn load_account(&self, client: &Client, encryption_key: Option<&[u8]>) -> Result<Account> {
82 let account_file = self.user_dir.join("account");
83 let data = fs::read_to_string(account_file)?;
84 Account::restore(client.clone(), &data, encryption_key)
85 }
86
87 pub fn save_stoken(&self, stoken: &str) -> Result<()> {
92 let stoken_file = self.user_dir.join("stoken");
93 fs::write(stoken_file, stoken)?;
94 Ok(())
95 }
96
97 pub fn load_stoken(&self) -> Result<Option<String>> {
99 let stoken_file = self.user_dir.join("stoken");
100 let ret = fs::read_to_string(stoken_file);
101 match ret {
102 Err(_) => Ok(None),
103 Ok(ret) => Ok(Some(ret)),
104 }
105 }
106
107 pub fn collection_save_stoken(&self, col_uid: &str, stoken: &str) -> Result<()> {
113 let stoken_file = self.cols_dir.join(col_uid).join("stoken");
114 fs::write(stoken_file, stoken)?;
115 Ok(())
116 }
117
118 pub fn collection_load_stoken(&self, col_uid: &str) -> Result<Option<String>> {
123 let stoken_file = self.cols_dir.join(col_uid).join("stoken");
124 let ret = fs::read_to_string(stoken_file);
125 match ret {
126 Err(_) => Ok(None),
127 Ok(ret) => Ok(Some(ret)),
128 }
129 }
130
131 pub fn collection_list_raw(&self) -> Result<ListRawCacheResponse> {
133 let ret = fs::read_dir(&self.cols_dir)?;
134 Ok(ListRawCacheResponse {
135 inner_iter: ret,
136 is_collection: true,
137 })
138 }
139
140 pub fn collection(&self, col_mgr: &CollectionManager, col_uid: &str) -> Result<Collection> {
146 let col_file = self.cols_dir.join(col_uid).join("col");
147 let content = fs::read(col_file)?;
148 col_mgr.cache_load(&content)
149 }
150
151 pub fn collection_set(
157 &self,
158 col_mgr: &CollectionManager,
159 collection: &Collection,
160 ) -> Result<()> {
161 let mut col_file = self.cols_dir.join(collection.uid());
162 fs::create_dir_all(&col_file)?;
163 col_file.push("col");
164
165 let content = col_mgr.cache_save(collection)?;
166 fs::write(col_file, content)?;
167
168 let items_dir = self.get_collection_items_dir(collection.uid());
169 fs::create_dir_all(items_dir)?;
170
171 Ok(())
172 }
173
174 pub fn collection_set_with_content(
180 &self,
181 col_mgr: &CollectionManager,
182 collection: &Collection,
183 ) -> Result<()> {
184 let mut col_file = self.cols_dir.join(collection.uid());
185 fs::create_dir_all(&col_file)?;
186 col_file.push("col");
187
188 let content = col_mgr.cache_save_with_content(collection)?;
189 fs::write(col_file, content)?;
190
191 let items_dir = self.get_collection_items_dir(collection.uid());
192 fs::create_dir_all(items_dir)?;
193
194 Ok(())
195 }
196
197 pub fn collection_unset(&self, _col_mgr: &CollectionManager, col_uid: &str) -> Result<()> {
203 let col_dir = self.cols_dir.join(col_uid);
204 remove_dir_all(col_dir)?;
205 Ok(())
206 }
207
208 pub fn item_list_raw(&self, col_uid: &str) -> Result<ListRawCacheResponse> {
213 let items_dir = self.get_collection_items_dir(col_uid);
214 let ret = fs::read_dir(items_dir)?;
215 Ok(ListRawCacheResponse {
216 inner_iter: ret,
217 is_collection: false,
218 })
219 }
220
221 pub fn item(&self, item_mgr: &ItemManager, col_uid: &str, item_uid: &str) -> Result<Item> {
228 let item_file = self.get_collection_items_dir(col_uid).join(item_uid);
229 let content = fs::read(item_file)?;
230 item_mgr.cache_load(&content)
231 }
232
233 pub fn item_set(&self, item_mgr: &ItemManager, col_uid: &str, item: &Item) -> Result<()> {
240 let item_file = self.get_collection_items_dir(col_uid).join(item.uid());
241 let content = item_mgr.cache_save(item)?;
242 fs::write(item_file, content)?;
243 Ok(())
244 }
245
246 pub fn item_set_with_content(
253 &self,
254 item_mgr: &ItemManager,
255 col_uid: &str,
256 item: &Item,
257 ) -> Result<()> {
258 let item_file = self.get_collection_items_dir(col_uid).join(item.uid());
259 let content = item_mgr.cache_save_with_content(item)?;
260 fs::write(item_file, content)?;
261 Ok(())
262 }
263
264 pub fn item_unset(&self, _item_mgr: &ItemManager, col_uid: &str, item_uid: &str) -> Result<()> {
271 let item_file = self.get_collection_items_dir(col_uid).join(item_uid);
272 fs::remove_file(item_file)?;
273 Ok(())
274 }
275}
276
277pub struct ListRawCacheResponse {
279 inner_iter: fs::ReadDir,
280 is_collection: bool,
281}
282
283impl Iterator for ListRawCacheResponse {
284 type Item = Result<Vec<u8>>;
285
286 fn next(&mut self) -> Option<Self::Item> {
287 self.inner_iter.next().map(|x| -> Result<Vec<u8>> {
288 let mut col_file = x?.path();
289 if self.is_collection {
290 col_file.push("col");
291 }
292 Ok(fs::read(col_file)?)
293 })
294 }
295}