matrix_sdk_ui/timeline/
futures.rs

1use std::future::IntoFuture;
2
3use eyeball::SharedObservable;
4use matrix_sdk::{attachment::AttachmentConfig, TransmissionProgress};
5use matrix_sdk_base::boxed_into_future;
6use mime::Mime;
7use tracing::{Instrument as _, Span};
8
9use super::{AttachmentSource, Error, Timeline};
10
11pub struct SendAttachment<'a> {
12    timeline: &'a Timeline,
13    source: AttachmentSource,
14    mime_type: Mime,
15    config: AttachmentConfig,
16    tracing_span: Span,
17    pub(crate) send_progress: SharedObservable<TransmissionProgress>,
18    use_send_queue: bool,
19}
20
21impl<'a> SendAttachment<'a> {
22    pub(crate) fn new(
23        timeline: &'a Timeline,
24        source: AttachmentSource,
25        mime_type: Mime,
26        config: AttachmentConfig,
27    ) -> Self {
28        Self {
29            timeline,
30            source,
31            mime_type,
32            config,
33            tracing_span: Span::current(),
34            send_progress: Default::default(),
35            use_send_queue: false,
36        }
37    }
38
39    /// (Experimental) Uses the send queue to upload this media.
40    ///
41    /// This uses the send queue to upload the medias, and as such it provides
42    /// local echoes for the uploaded media too, not blocking the sending
43    /// request.
44    ///
45    /// This will be the default in future versions, when the feature work will
46    /// be done there.
47    pub fn use_send_queue(self) -> Self {
48        Self { use_send_queue: true, ..self }
49    }
50
51    /// Get a subscriber to observe the progress of sending the request body.
52    #[cfg(not(target_arch = "wasm32"))]
53    pub fn subscribe_to_send_progress(&self) -> eyeball::Subscriber<TransmissionProgress> {
54        self.send_progress.subscribe()
55    }
56}
57
58impl<'a> IntoFuture for SendAttachment<'a> {
59    type Output = Result<(), Error>;
60    boxed_into_future!(extra_bounds: 'a);
61
62    fn into_future(self) -> Self::IntoFuture {
63        let Self {
64            timeline,
65            source,
66            mime_type,
67            config,
68            tracing_span,
69            use_send_queue,
70            send_progress,
71        } = self;
72
73        let fut = async move {
74            let (data, filename) = source.try_into_bytes_and_filename()?;
75
76            if use_send_queue {
77                let send_queue = timeline.room().send_queue();
78                let fut = send_queue.send_attachment(filename, mime_type, data, config);
79                fut.await.map_err(|_| Error::FailedSendingAttachment)?;
80            } else {
81                let fut = timeline
82                    .room()
83                    .send_attachment(filename, &mime_type, data, config)
84                    .with_send_progress_observable(send_progress)
85                    .store_in_cache();
86                fut.await.map_err(|_| Error::FailedSendingAttachment)?;
87            }
88
89            Ok(())
90        };
91
92        Box::pin(fut.instrument(tracing_span))
93    }
94}