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    pub fn subscribe_to_send_progress(&self) -> eyeball::Subscriber<TransmissionProgress> {
53        self.send_progress.subscribe()
54    }
55}
56
57impl<'a> IntoFuture for SendAttachment<'a> {
58    type Output = Result<(), Error>;
59    boxed_into_future!(extra_bounds: 'a);
60
61    fn into_future(self) -> Self::IntoFuture {
62        let Self {
63            timeline,
64            source,
65            mime_type,
66            config,
67            tracing_span,
68            use_send_queue,
69            send_progress,
70        } = self;
71
72        let fut = async move {
73            let (data, filename) = source.try_into_bytes_and_filename()?;
74
75            if use_send_queue {
76                let send_queue = timeline.room().send_queue();
77                let fut = send_queue.send_attachment(filename, mime_type, data, config);
78                fut.await.map_err(|_| Error::FailedSendingAttachment)?;
79            } else {
80                let fut = timeline
81                    .room()
82                    .send_attachment(filename, &mime_type, data, config)
83                    .with_send_progress_observable(send_progress)
84                    .store_in_cache();
85                fut.await.map_err(|_| Error::FailedSendingAttachment)?;
86            }
87
88            Ok(())
89        };
90
91        Box::pin(fut.instrument(tracing_span))
92    }
93}
94
95#[cfg(feature = "unstable-msc4274")]
96pub use galleries::*;
97
98#[cfg(feature = "unstable-msc4274")]
99mod galleries {
100    use std::future::IntoFuture;
101
102    use matrix_sdk_base::boxed_into_future;
103    use tracing::{Instrument as _, Span};
104
105    use super::{Error, Timeline};
106    use crate::timeline::GalleryConfig;
107
108    pub struct SendGallery<'a> {
109        timeline: &'a Timeline,
110        gallery: GalleryConfig,
111        tracing_span: Span,
112    }
113
114    impl<'a> SendGallery<'a> {
115        pub(crate) fn new(timeline: &'a Timeline, gallery: GalleryConfig) -> Self {
116            Self { timeline, gallery, tracing_span: Span::current() }
117        }
118    }
119
120    impl<'a> IntoFuture for SendGallery<'a> {
121        type Output = Result<(), Error>;
122        boxed_into_future!(extra_bounds: 'a);
123
124        fn into_future(self) -> Self::IntoFuture {
125            let Self { timeline, gallery, tracing_span } = self;
126
127            let fut = async move {
128                let send_queue = timeline.room().send_queue();
129                let fut = send_queue.send_gallery(gallery.try_into()?);
130                fut.await.map_err(|_| Error::FailedSendingAttachment)?;
131
132                Ok(())
133            };
134
135            Box::pin(fut.instrument(tracing_span))
136        }
137    }
138}