web_local_storage_api/
lib.rs1use anyhow::Result;
2use anyhow::*;
3use directories::ProjectDirs;
4use lazy_static::*;
5use parking_lot::Mutex;
6use std::collections::HashMap;
7use std::fs::{write, File};
8use std::io::BufReader;
9
10lazy_static! {
11 static ref STORAGE: Mutex<HashMap<String, String>> = Mutex::new(
12 load().unwrap_or_else(|_| panic!("could not load local storage from {:?}", get_path()))
13 );
14}
15
16pub fn get_item(key: &str) -> Result<Option<String>> {
17 let s = STORAGE.lock();
18 match s.get(key) {
19 Some(txt) => Ok(Some(txt.to_string())),
20 None => Ok(None),
21 }
22}
23
24pub fn remove_item(key: &str) -> Result<Option<String>> {
25 let mut s = STORAGE.lock();
26 let r = match s.remove(key) {
27 Some(txt) => Ok(Some(txt)),
28 None => Ok(None),
29 };
30 save(&s)?;
31 r
32}
33
34pub fn set_item(key: &str, value: &str) -> Result<()> {
35 let mut s = STORAGE.lock();
36 s.insert(key.to_string(), value.to_string());
37 save(&s)?;
38 Ok(())
39}
40
41fn get_project_path() -> Result<String> {
42 let dir = if let Some(proj_dirs) = ProjectDirs::from("", "", env!("CARGO_PKG_NAME")) {
43 if let Some(s) = proj_dirs.config_dir().to_str() {
44 s.to_string()
45 } else {
46 ".".to_string()
47 }
48 } else {
49 ".".to_string()
50 };
51 let p = std::path::Path::new(&dir);
52 let p = p.join("local_storage.json");
53 let s = p.to_str().unwrap().to_string();
54 Ok(s)
55}
56
57fn get_path() -> String {
58 get_project_path().unwrap_or("local_storage.json".to_string())
59}
60
61fn load() -> Result<HashMap<String, String>> {
62 let fp = &get_path();
63 if !std::path::Path::new(fp).exists() {
64 return Ok(HashMap::new());
65 }
66 let file = File::open(fp)?;
67 let reader = BufReader::new(file);
68
69 let u: HashMap<String, String> = serde_json::from_reader(reader)?;
70 Ok(u)
71}
72
73fn save(h: &HashMap<String, String>) -> Result<()> {
74 let fp = &get_path();
75 std::fs::create_dir_all(std::path::Path::new(fp).parent().unwrap())?;
76 let txt = serde_json::to_string(h)?;
77 write(fp, txt)?;
78 Ok(())
79}
80
81pub fn clear() -> Result<()> {
82 let mut s = STORAGE.lock();
83 s.clear();
84 Ok(())
85}
86
87pub fn length() -> Result<usize> {
88 let s = STORAGE.lock();
89 save(&s)?;
90 Ok(s.len())
91}
92
93pub fn key(index: usize) -> Result<Option<String>> {
94 let s = STORAGE.lock();
95 let mut vals = s.values();
96 let v = vals.nth(index);
97 match v {
98 Some(key) => match s.get(key) {
99 Some(txt) => Ok(Some(txt.to_string())),
100 None => Ok(None),
101 },
102 None => Err(anyhow!("index out of bounds")),
103 }
104}
105
106pub fn location() -> String {
107 get_path()
108}