1use js_sys::{Array, Function, Promise, Reflect};
2use wasm_bindgen::{JsCast, prelude::*};
3use web_sys::window;
4
5fn cloud_storage_object() -> Result<JsValue, JsValue> {
7 let win = window().ok_or_else(|| JsValue::from_str("no window"))?;
8 let tg = Reflect::get(&win, &JsValue::from_str("Telegram"))?;
9 let webapp = Reflect::get(&tg, &JsValue::from_str("WebApp"))?;
10 Reflect::get(&webapp, &JsValue::from_str("CloudStorage"))
11}
12
13pub fn get_item(key: &str) -> Result<Promise, JsValue> {
29 let storage = cloud_storage_object()?;
30 let func = Reflect::get(&storage, &JsValue::from_str("getItem"))?.dyn_into::<Function>()?;
31 func.call1(&storage, &JsValue::from_str(key))?
32 .dyn_into::<Promise>()
33}
34
35pub fn set_item(key: &str, value: &str) -> Result<Promise, JsValue> {
51 let storage = cloud_storage_object()?;
52 let func = Reflect::get(&storage, &JsValue::from_str("setItem"))?.dyn_into::<Function>()?;
53 func.call2(&storage, &JsValue::from_str(key), &JsValue::from_str(value))?
54 .dyn_into::<Promise>()
55}
56
57pub fn remove_item(key: &str) -> Result<Promise, JsValue> {
73 let storage = cloud_storage_object()?;
74 let func = Reflect::get(&storage, &JsValue::from_str("removeItem"))?.dyn_into::<Function>()?;
75 func.call1(&storage, &JsValue::from_str(key))?
76 .dyn_into::<Promise>()
77}
78
79pub fn get_items(keys: &[&str]) -> Result<Promise, JsValue> {
95 let storage = cloud_storage_object()?;
96 let func = Reflect::get(&storage, &JsValue::from_str("getItems"))?.dyn_into::<Function>()?;
97 let array = Array::new();
98 for key in keys {
99 array.push(&JsValue::from_str(key));
100 }
101 func.call1(&storage, &array.into())?.dyn_into::<Promise>()
102}
103
104pub fn set_items(items: &[(&str, &str)]) -> Result<Promise, JsValue> {
120 let storage = cloud_storage_object()?;
121 let func = Reflect::get(&storage, &JsValue::from_str("setItems"))?.dyn_into::<Function>()?;
122 let obj = js_sys::Object::new();
123 for (key, value) in items {
124 Reflect::set(&obj, &JsValue::from_str(key), &JsValue::from_str(value))?;
125 }
126 func.call1(&storage, &obj.into())?.dyn_into::<Promise>()
127}
128
129pub fn remove_items(keys: &[&str]) -> Result<Promise, JsValue> {
145 let storage = cloud_storage_object()?;
146 let func =
147 Reflect::get(&storage, &JsValue::from_str("removeItems"))?.dyn_into::<Function>()?;
148 let array = Array::new();
149 for key in keys {
150 array.push(&JsValue::from_str(key));
151 }
152 func.call1(&storage, &array.into())?.dyn_into::<Promise>()
153}
154
155pub fn get_keys() -> Result<Promise, JsValue> {
171 let storage = cloud_storage_object()?;
172 let func = Reflect::get(&storage, &JsValue::from_str("getKeys"))?.dyn_into::<Function>()?;
173 func.call0(&storage)?.dyn_into::<Promise>()
174}
175
176pub fn clear() -> Result<Promise, JsValue> {
192 let storage = cloud_storage_object()?;
193 let func = Reflect::get(&storage, &JsValue::from_str("clear"))?.dyn_into::<Function>()?;
194 func.call0(&storage)?.dyn_into::<Promise>()
195}
196
197#[cfg(test)]
198mod tests {
199 #![allow(dead_code)]
200 use js_sys::{Array, Function, Object, Reflect};
201 use wasm_bindgen_futures::JsFuture;
202 use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure};
203 use web_sys::window;
204
205 use super::*;
206
207 wasm_bindgen_test_configure!(run_in_browser);
208
209 fn setup_cloud_storage() -> Object {
210 let win = window().unwrap();
211 let telegram = Object::new();
212 let webapp = Object::new();
213 let storage = Object::new();
214 let _ = Reflect::set(&win, &"Telegram".into(), &telegram);
215 let _ = Reflect::set(&telegram, &"WebApp".into(), &webapp);
216 let _ = Reflect::set(&webapp, &"CloudStorage".into(), &storage);
217 storage
218 }
219
220 #[wasm_bindgen_test(async)]
221 async fn get_item_ok() {
222 let storage = setup_cloud_storage();
223 let func =
224 Function::new_with_args("key", "this.called = key; return Promise.resolve('val');");
225 let _ = Reflect::set(&storage, &"getItem".into(), &func);
226 let value = JsFuture::from(get_item("test").unwrap()).await.unwrap();
227 assert_eq!(value.as_string(), Some("val".to_string()));
228 assert_eq!(
229 Reflect::get(&storage, &"called".into())
230 .unwrap()
231 .as_string(),
232 Some("test".into())
233 );
234 }
235
236 #[wasm_bindgen_test]
237 fn get_item_err() {
238 let _ = setup_cloud_storage();
239 assert!(get_item("test").is_err());
240 }
241
242 #[wasm_bindgen_test(async)]
243 async fn set_item_ok() {
244 let storage = setup_cloud_storage();
245 let func = Function::new_with_args(
246 "key, value",
247 "this.called = key + ':' + value; return Promise.resolve();"
248 );
249 let _ = Reflect::set(&storage, &"setItem".into(), &func);
250 JsFuture::from(set_item("a", "b").unwrap()).await.unwrap();
251 assert_eq!(
252 Reflect::get(&storage, &"called".into())
253 .unwrap()
254 .as_string(),
255 Some("a:b".into())
256 );
257 }
258
259 #[wasm_bindgen_test]
260 fn set_item_err() {
261 let _ = setup_cloud_storage();
262 assert!(set_item("a", "b").is_err());
263 }
264
265 #[wasm_bindgen_test(async)]
266 async fn remove_item_ok() {
267 let storage = setup_cloud_storage();
268 let func = Function::new_with_args("key", "this.called = key; return Promise.resolve();");
269 let _ = Reflect::set(&storage, &"removeItem".into(), &func);
270 JsFuture::from(remove_item("k").unwrap()).await.unwrap();
271 assert_eq!(
272 Reflect::get(&storage, &"called".into())
273 .unwrap()
274 .as_string(),
275 Some("k".into())
276 );
277 }
278
279 #[wasm_bindgen_test]
280 fn remove_item_err() {
281 let _ = setup_cloud_storage();
282 assert!(remove_item("k").is_err());
283 }
284
285 #[wasm_bindgen_test(async)]
286 async fn get_items_ok() {
287 let storage = setup_cloud_storage();
288 let func = Function::new_with_args(
289 "keys",
290 "this.called = keys; return Promise.resolve({a: '1', b: '2'});"
291 );
292 let _ = Reflect::set(&storage, &"getItems".into(), &func);
293 let result = JsFuture::from(get_items(&["a", "b"]).unwrap())
294 .await
295 .unwrap();
296 let obj = result.dyn_into::<Object>().unwrap();
297 assert_eq!(
298 Reflect::get(&obj, &"a".into()).unwrap().as_string(),
299 Some("1".into())
300 );
301 assert_eq!(
302 Reflect::get(&obj, &"b".into()).unwrap().as_string(),
303 Some("2".into())
304 );
305 let called = Reflect::get(&storage, &"called".into()).unwrap();
306 let arr = Array::from(&called);
307 assert_eq!(arr.get(0).as_string(), Some("a".into()));
308 assert_eq!(arr.get(1).as_string(), Some("b".into()));
309 }
310
311 #[wasm_bindgen_test]
312 fn get_items_err() {
313 let _ = setup_cloud_storage();
314 assert!(get_items(&["a"]).is_err());
315 }
316
317 #[wasm_bindgen_test(async)]
318 async fn set_items_ok() {
319 let storage = setup_cloud_storage();
320 let func =
321 Function::new_with_args("items", "this.called = items; return Promise.resolve();");
322 let _ = Reflect::set(&storage, &"setItems".into(), &func);
323 JsFuture::from(set_items(&[("a", "1"), ("b", "2")]).unwrap())
324 .await
325 .unwrap();
326 let called = Reflect::get(&storage, &"called".into()).unwrap();
327 assert_eq!(
328 Reflect::get(&called, &"a".into()).unwrap().as_string(),
329 Some("1".into())
330 );
331 assert_eq!(
332 Reflect::get(&called, &"b".into()).unwrap().as_string(),
333 Some("2".into())
334 );
335 }
336
337 #[wasm_bindgen_test]
338 fn set_items_err() {
339 let _ = setup_cloud_storage();
340 assert!(set_items(&[("a", "1")]).is_err());
341 }
342
343 #[wasm_bindgen_test(async)]
344 async fn remove_items_ok() {
345 let storage = setup_cloud_storage();
346 let func =
347 Function::new_with_args("keys", "this.called = keys; return Promise.resolve();");
348 let _ = Reflect::set(&storage, &"removeItems".into(), &func);
349 JsFuture::from(remove_items(&["a", "b"]).unwrap())
350 .await
351 .unwrap();
352 let called = Reflect::get(&storage, &"called".into()).unwrap();
353 let arr = Array::from(&called);
354 assert_eq!(arr.get(0).as_string(), Some("a".into()));
355 assert_eq!(arr.get(1).as_string(), Some("b".into()));
356 }
357
358 #[wasm_bindgen_test]
359 fn remove_items_err() {
360 let _ = setup_cloud_storage();
361 assert!(remove_items(&["a"]).is_err());
362 }
363
364 #[wasm_bindgen_test(async)]
365 async fn get_keys_ok() {
366 let storage = setup_cloud_storage();
367 let func = Function::new_no_args("return Promise.resolve(['x', 'y']);");
368 let _ = Reflect::set(&storage, &"getKeys".into(), &func);
369 let result = JsFuture::from(get_keys().unwrap()).await.unwrap();
370 let arr = Array::from(&result);
371 assert_eq!(arr.get(0).as_string(), Some("x".into()));
372 assert_eq!(arr.get(1).as_string(), Some("y".into()));
373 }
374
375 #[wasm_bindgen_test]
376 fn get_keys_err() {
377 let _ = setup_cloud_storage();
378 assert!(get_keys().is_err());
379 }
380
381 #[wasm_bindgen_test(async)]
382 async fn clear_ok() {
383 let storage = setup_cloud_storage();
384 let func = Function::new_no_args("this.called = true; return Promise.resolve();");
385 let _ = Reflect::set(&storage, &"clear".into(), &func);
386 JsFuture::from(clear().unwrap()).await.unwrap();
387 assert!(
388 Reflect::get(&storage, &"called".into())
389 .unwrap()
390 .as_bool()
391 .unwrap()
392 );
393 }
394
395 #[wasm_bindgen_test]
396 fn clear_err() {
397 let _ = setup_cloud_storage();
398 assert!(clear().is_err());
399 }
400}