workflow_store/
store.rs

1use crate::result::Result;
2use cfg_if::cfg_if;
3use std::collections::hash_map::DefaultHasher;
4use std::hash::{Hash, Hasher};
5
6cfg_if! {
7    if #[cfg(not(target_arch = "wasm32"))] {
8        use async_std::path::PathBuf;
9        use async_std::fs;
10    } else {
11        // use base64::{Engine as _, engine::general_purpose};
12    }
13}
14
15///
16/// # Store
17///
18/// A simple file loader that allows user to
19/// specify different paths on various
20/// operating systems with fallbacks.
21///
22pub struct Store {
23    // linux (fallsback to unix, generic)
24    pub linux: Option<String>,
25    // macos (fallsback to unix, generic)
26    pub macos: Option<String>,
27    // unix (fallsback to generic)
28    pub unix: Option<String>,
29    // windows (fallsback to generic)
30    pub windows: Option<String>,
31    // fallback for all OSes
32    pub generic: Option<String>,
33    // browser locastorage (fallsback to a hash of generic in hex)
34    pub browser: Option<String>,
35}
36
37impl Default for Store {
38    fn default() -> Self {
39        Self::new()
40    }
41}
42
43impl Store {
44    pub fn new() -> Store {
45        Store {
46            linux: None,
47            macos: None,
48            unix: None,
49            windows: None,
50            generic: None,
51            browser: None,
52        }
53    }
54
55    pub fn with_linux(&mut self, linux: &str) -> &mut Store {
56        self.linux = Some(linux.to_string());
57        self
58    }
59
60    pub fn with_macos(&mut self, macos: &str) -> &mut Store {
61        self.macos = Some(macos.to_string());
62        self
63    }
64
65    pub fn with_unix(&mut self, unix: &str) -> &mut Store {
66        self.unix = Some(unix.to_string());
67        self
68    }
69
70    pub fn with_windows(&mut self, windows: &str) -> &mut Store {
71        self.windows = Some(windows.to_string());
72        self
73    }
74
75    pub fn with_generic(&mut self, generic: &str) -> &mut Store {
76        self.generic = Some(generic.to_string());
77        self
78    }
79
80    pub fn with_browser(&mut self, browser: &str) -> &mut Store {
81        self.browser = Some(browser.to_string());
82        self
83    }
84
85    pub fn filename(&self) -> String {
86        cfg_if! {
87            if #[cfg(target_os = "macos")] {
88                find(&[self.macos.as_ref(),self.unix.as_ref(),self.generic.as_ref()])
89            } else if #[cfg(target_os = "linux")] {
90                find(&[self.linux.as_ref(),self.unix.as_ref(),self.generic.as_ref()])
91            } else if #[cfg(target_family = "unix")] {
92                find(&[self.unix.as_ref(),self.generic.as_ref()])
93            } else if #[cfg(target_family = "windows")] {
94                find(&[self.windows.as_ref(),self.generic.as_ref()])
95            } else if #[cfg(target_arch = "wasm32")] {
96                if let Some(browser) = self.browser.as_ref() {
97                    browser.clone()
98                } else if let Some(generic) = self.generic.as_ref() {
99                    // hash of generic
100                    hash(generic)
101                } else {
102                    panic!("no path found for the current operating environment");
103                }
104            }
105        }
106    }
107
108    cfg_if! {
109        if #[cfg(target_arch = "wasm32")] {
110            pub async fn exists(&self) -> Result<bool> {
111                let filename = self.filename();
112                Ok(local_storage().get_item(&filename)?.is_some())
113            }
114
115            pub async fn read_to_string(&self) -> Result<String> {
116                let filename = self.filename();
117                let v = local_storage().get_item(&filename)?.unwrap();
118                // Ok(general_purpose::STANDARD.decode(v)?)
119                Ok(v)
120            }
121
122            pub async fn write_string(&self, data: &str) -> Result<()> {
123                let filename = self.filename();
124                // let v = general_purpose::STANDARD.encode(data);
125                local_storage().set_item(&filename, data)?;
126                Ok(())
127            }
128
129        } else {
130            pub async fn exists(&self) -> Result<bool> {
131                let filename = parse(self.filename());
132                Ok(filename.exists().await)
133            }
134
135            pub async fn read_to_string(&self) -> Result<String> {
136                let filename = parse(self.filename());
137                Ok(fs::read_to_string(&filename).await?)
138            }
139
140            pub async fn write_string(&self, data: &str) -> Result<()> {
141                let filename = parse(self.filename());
142                Ok(fs::write(&filename, data).await?)
143            }
144        }
145    }
146}
147
148cfg_if! {
149    if #[cfg(not(target_arch = "wasm32"))] {
150        pub fn parse(path : String) -> PathBuf {
151
152            if let Some(stripped) = path.strip_prefix('~') {
153                let home_dir: PathBuf = home::home_dir().unwrap().into();
154                home_dir.join(stripped)
155            } else {
156                PathBuf::from(path)
157            }
158        }
159    } else {
160        pub fn local_storage() -> web_sys::Storage {
161            web_sys::window().unwrap().local_storage().unwrap().unwrap()
162        }
163    }
164}
165
166pub fn find(paths: &[Option<&String>]) -> String {
167    for path in paths.iter() {
168        if let Some(path) = *path {
169            return path.clone();
170        }
171    }
172    panic!("no path found for the current operating environment");
173}
174
175pub fn hash<T>(t: T) -> String
176where
177    T: Hash,
178{
179    let mut hasher = DefaultHasher::new();
180    t.hash(&mut hasher);
181    let v = hasher.finish();
182    format!("{v:x}")
183}