firebase_wasm/
storage.rs

1mod bindings;
2
3pub use bindings::{
4    delete_object, get_download_url, get_storage, ref_, upload_bytes, FullMetadata, Ref,
5    SettableMetadata, Storage, UploadMetadata, UploadMetadataOptions, UploadTask,
6    UploadTaskSnapshot,
7};
8use futures::Stream;
9use std::{
10    cell::RefCell,
11    pin::Pin,
12    rc::Rc,
13    task::{Context, Poll, Waker},
14};
15use wasm_bindgen::prelude::*;
16use wasm_bindgen::JsCast;
17
18impl UploadTask {
19    pub fn async_iter(&self) -> UploadTaskAsyncIter {
20        let waker: Rc<RefCell<Option<Waker>>> = Rc::default();
21        let completed: Rc<RefCell<bool>> = Rc::default();
22        let snapshot: Rc<RefCell<Option<UploadTaskSnapshot>>> = Rc::default();
23        let err: Rc<RefCell<Option<JsValue>>> = Rc::default();
24
25        let on_snapshot = Closure::new(clone!([snapshot, waker], move |js_snapshot| {
26            *snapshot.borrow_mut() = Some(js_snapshot);
27
28            if let Some(w) = waker.borrow().as_ref() {
29                w.wake_by_ref();
30            }
31        }));
32        let on_err = Closure::new(clone!([completed, err, waker], move |js_err| {
33            *err.borrow_mut() = Some(js_err);
34
35            // Complete the stream since we errored
36            *completed.borrow_mut() = true;
37
38            if let Some(w) = waker.borrow().as_ref() {
39                w.wake_by_ref()
40            }
41        }));
42        let on_complete = Closure::new(clone!([completed, waker], move || {
43            *completed.borrow_mut() = true;
44
45            // Notify waker
46            let waker_borrow = waker.borrow();
47
48            if let Some(w) = waker_borrow.as_ref() {
49                w.wake_by_ref();
50            }
51        }));
52
53        let unsub = self.on(
54            "state_changed",
55            &on_snapshot,
56            Some(&on_err),
57            Some(&on_complete),
58        );
59
60        UploadTaskAsyncIter {
61            _on_snapshot: on_snapshot,
62            _on_err: on_err,
63            _on_complete: on_complete,
64            snapshot,
65            err,
66            completed,
67            waker,
68            unsub,
69        }
70    }
71}
72
73pub struct UploadTaskAsyncIter {
74    _on_snapshot: Closure<dyn FnMut(UploadTaskSnapshot)>,
75    _on_err: Closure<dyn FnMut(JsValue)>,
76    _on_complete: Closure<dyn FnMut()>,
77    snapshot: Rc<RefCell<Option<UploadTaskSnapshot>>>,
78    err: Rc<RefCell<Option<JsValue>>>,
79    completed: Rc<RefCell<bool>>,
80    waker: Rc<RefCell<Option<Waker>>>,
81    unsub: js_sys::Function,
82}
83
84impl Drop for UploadTaskAsyncIter {
85    fn drop(&mut self) {
86        self.unsub.call0(&JsValue::UNDEFINED).unwrap();
87    }
88}
89
90impl Stream for UploadTaskAsyncIter {
91    type Item = Result<UploadTaskSnapshot, JsValue>;
92
93    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
94        // Update waker
95        *self.waker.borrow_mut() = Some(cx.waker().to_owned());
96
97        if *self.completed.borrow() {
98            if let Some(err) = self.err.borrow_mut().take() {
99                Poll::Ready(Some(Err(err)))
100            } else {
101                Poll::Ready(None)
102            }
103        } else if let Some(snapshot) = self.snapshot.borrow_mut().take() {
104            Poll::Ready(Some(Ok(snapshot)))
105        } else {
106            Poll::Pending
107        }
108    }
109}
110
111pub async fn get_metadata(ref_: Ref) -> Result<FullMetadata, JsValue> {
112    bindings::get_metadata(ref_)
113        .await
114        .map(|m| m.unchecked_into())
115}