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