telegram_webapp_sdk/api/
cloud_storage.rs

1use js_sys::{Array, Function, Promise, Reflect};
2use wasm_bindgen::{JsCast, prelude::*};
3use web_sys::window;
4
5/// Returns the `Telegram.WebApp.CloudStorage` object.
6fn 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
13/// Calls `Telegram.WebApp.CloudStorage.getItem()`.
14///
15/// # Errors
16/// Returns `Err(JsValue)` if CloudStorage or the method is unavailable, or if
17/// the call fails.
18///
19/// # Examples
20/// ```no_run
21/// use telegram_webapp_sdk::api::cloud_storage::get_item;
22/// use wasm_bindgen_futures::JsFuture;
23/// # async fn run() -> Result<(), wasm_bindgen::JsValue> {
24/// let value = JsFuture::from(get_item("key")?).await?;
25/// # Ok(())
26/// # }
27/// ```
28pub 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
35/// Calls `Telegram.WebApp.CloudStorage.setItem()`.
36///
37/// # Errors
38/// Returns `Err(JsValue)` if CloudStorage or the method is unavailable, or if
39/// the call fails.
40///
41/// # Examples
42/// ```no_run
43/// use telegram_webapp_sdk::api::cloud_storage::set_item;
44/// use wasm_bindgen_futures::JsFuture;
45/// # async fn run() -> Result<(), wasm_bindgen::JsValue> {
46/// JsFuture::from(set_item("key", "value")?).await?;
47/// # Ok(())
48/// # }
49/// ```
50pub 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
57/// Calls `Telegram.WebApp.CloudStorage.removeItem()`.
58///
59/// # Errors
60/// Returns `Err(JsValue)` if CloudStorage or the method is unavailable, or if
61/// the call fails.
62///
63/// # Examples
64/// ```no_run
65/// use telegram_webapp_sdk::api::cloud_storage::remove_item;
66/// use wasm_bindgen_futures::JsFuture;
67/// # async fn run() -> Result<(), wasm_bindgen::JsValue> {
68/// JsFuture::from(remove_item("key")?).await?;
69/// # Ok(())
70/// # }
71/// ```
72pub 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
79/// Calls `Telegram.WebApp.CloudStorage.getItems()`.
80///
81/// # Errors
82/// Returns `Err(JsValue)` if CloudStorage or the method is unavailable, or if
83/// the call fails.
84///
85/// # Examples
86/// ```no_run
87/// use telegram_webapp_sdk::api::cloud_storage::get_items;
88/// use wasm_bindgen_futures::JsFuture;
89/// # async fn run() -> Result<(), wasm_bindgen::JsValue> {
90/// let _ = JsFuture::from(get_items(&["a", "b"])?).await?;
91/// # Ok(())
92/// # }
93/// ```
94pub 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
104/// Calls `Telegram.WebApp.CloudStorage.setItems()`.
105///
106/// # Errors
107/// Returns `Err(JsValue)` if CloudStorage or the method is unavailable, or if
108/// the call fails.
109///
110/// # Examples
111/// ```no_run
112/// use telegram_webapp_sdk::api::cloud_storage::set_items;
113/// use wasm_bindgen_futures::JsFuture;
114/// # async fn run() -> Result<(), wasm_bindgen::JsValue> {
115/// JsFuture::from(set_items(&[("a", "1"), ("b", "2")])?).await?;
116/// # Ok(())
117/// # }
118/// ```
119pub 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
129/// Calls `Telegram.WebApp.CloudStorage.removeItems()`.
130///
131/// # Errors
132/// Returns `Err(JsValue)` if CloudStorage or the method is unavailable, or if
133/// the call fails.
134///
135/// # Examples
136/// ```no_run
137/// use telegram_webapp_sdk::api::cloud_storage::remove_items;
138/// use wasm_bindgen_futures::JsFuture;
139/// # async fn run() -> Result<(), wasm_bindgen::JsValue> {
140/// JsFuture::from(remove_items(&["a", "b"])?).await?;
141/// # Ok(())
142/// # }
143/// ```
144pub 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
155/// Calls `Telegram.WebApp.CloudStorage.getKeys()`.
156///
157/// # Errors
158/// Returns `Err(JsValue)` if CloudStorage or the method is unavailable, or if
159/// the call fails.
160///
161/// # Examples
162/// ```no_run
163/// use telegram_webapp_sdk::api::cloud_storage::get_keys;
164/// use wasm_bindgen_futures::JsFuture;
165/// # async fn run() -> Result<(), wasm_bindgen::JsValue> {
166/// let _ = JsFuture::from(get_keys()?).await?;
167/// # Ok(())
168/// # }
169/// ```
170pub 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
176/// Calls `Telegram.WebApp.CloudStorage.clear()`.
177///
178/// # Errors
179/// Returns `Err(JsValue)` if CloudStorage or the method is unavailable, or if
180/// the call fails.
181///
182/// # Examples
183/// ```no_run
184/// use telegram_webapp_sdk::api::cloud_storage::clear;
185/// use wasm_bindgen_futures::JsFuture;
186/// # async fn run() -> Result<(), wasm_bindgen::JsValue> {
187/// JsFuture::from(clear()?).await?;
188/// # Ok(())
189/// # }
190/// ```
191pub 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}