web_local_storage_api/
lib.rs

1use 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}