atagen

macltok

public
Star0
Watch0
d8d8a9fe770a74b05da14929c5cb655208549837
3
ssh://brewery@pls.lobotomise.me:33/atagen/macltok.git

Blame: src/upload.rs

96fdf90aacd6atagen2026-09-08 08:24 UTC1
use std::time::Duration;
96fdf90aacd6atagen2026-09-08 08:24 UTC2
96fdf90aacd6atagen2026-09-08 08:24 UTC3
use matrix_sdk::{
96fdf90aacd6atagen2026-09-08 08:24 UTC4
    attachment::{
96fdf90aacd6atagen2026-09-08 08:24 UTC5
        AttachmentConfig, AttachmentInfo, BaseAudioInfo, BaseFileInfo, BaseImageInfo,
96fdf90aacd6atagen2026-09-08 08:24 UTC6
        BaseVideoInfo, Thumbnail,
96fdf90aacd6atagen2026-09-08 08:24 UTC7
    },
96fdf90aacd6atagen2026-09-08 08:24 UTC8
    ruma::events::room::message::TextMessageEventContent,
96fdf90aacd6atagen2026-09-08 08:24 UTC9
};
96fdf90aacd6atagen2026-09-08 08:24 UTC10
31ce2453c82fatagen2026-09-24 13:07 UTC11
use crate::{AttachmentUpload, Error, ErrorKind, UploadDetails};
96fdf90aacd6atagen2026-09-08 08:24 UTC12
96fdf90aacd6atagen2026-09-08 08:24 UTC13
pub(crate) fn prepare_upload(
96fdf90aacd6atagen2026-09-08 08:24 UTC14
    mut upload: AttachmentUpload,
96fdf90aacd6atagen2026-09-08 08:24 UTC15
    max_media_bytes: usize,
31ce2453c82fatagen2026-09-24 13:07 UTC16
) -> Result<(AttachmentUpload, mime::Mime, AttachmentConfig), Error> {
96fdf90aacd6atagen2026-09-08 08:24 UTC17
    if upload.bytes.len() > max_media_bytes {
31ce2453c82fatagen2026-09-24 13:07 UTC18
        return Err(Error::new(
31ce2453c82fatagen2026-09-24 13:07 UTC19
            ErrorKind::MediaTooLarge,
96fdf90aacd6atagen2026-09-08 08:24 UTC20
            "attachment exceeds the configured byte limit",
96fdf90aacd6atagen2026-09-08 08:24 UTC21
        ));
96fdf90aacd6atagen2026-09-08 08:24 UTC22
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC23
    let mimetype: mime::Mime = upload
96fdf90aacd6atagen2026-09-08 08:24 UTC24
        .mimetype
96fdf90aacd6atagen2026-09-08 08:24 UTC25
        .parse()
31ce2453c82fatagen2026-09-24 13:07 UTC26
        .map_err(|_| Error::new(ErrorKind::Invalid, "media MIME type is invalid"))?;
96fdf90aacd6atagen2026-09-08 08:24 UTC27
96fdf90aacd6atagen2026-09-08 08:24 UTC28
    let size = ruma::UInt::try_from(upload.bytes.len()).map_err(|_| {
31ce2453c82fatagen2026-09-24 13:07 UTC29
        Error::new(
31ce2453c82fatagen2026-09-24 13:07 UTC30
            ErrorKind::MediaTooLarge,
96fdf90aacd6atagen2026-09-08 08:24 UTC31
            "attachment size is not representable",
96fdf90aacd6atagen2026-09-08 08:24 UTC32
        )
96fdf90aacd6atagen2026-09-08 08:24 UTC33
    })?;
96fdf90aacd6atagen2026-09-08 08:24 UTC34
    let info = match upload.details.as_ref() {
96fdf90aacd6atagen2026-09-08 08:24 UTC35
        Some(UploadDetails::Image {
96fdf90aacd6atagen2026-09-08 08:24 UTC36
            width,
96fdf90aacd6atagen2026-09-08 08:24 UTC37
            height,
96fdf90aacd6atagen2026-09-08 08:24 UTC38
            blurhash,
96fdf90aacd6atagen2026-09-08 08:24 UTC39
        }) if mimetype.type_() == mime::IMAGE => AttachmentInfo::Image(BaseImageInfo {
96fdf90aacd6atagen2026-09-08 08:24 UTC40
            width: width.map(Into::into),
96fdf90aacd6atagen2026-09-08 08:24 UTC41
            height: height.map(Into::into),
96fdf90aacd6atagen2026-09-08 08:24 UTC42
            size: Some(size),
96fdf90aacd6atagen2026-09-08 08:24 UTC43
            blurhash: blurhash.clone(),
96fdf90aacd6atagen2026-09-08 08:24 UTC44
            ..Default::default()
96fdf90aacd6atagen2026-09-08 08:24 UTC45
        }),
96fdf90aacd6atagen2026-09-08 08:24 UTC46
        Some(UploadDetails::Video {
96fdf90aacd6atagen2026-09-08 08:24 UTC47
            width,
96fdf90aacd6atagen2026-09-08 08:24 UTC48
            height,
96fdf90aacd6atagen2026-09-08 08:24 UTC49
            duration_ms,
96fdf90aacd6atagen2026-09-08 08:24 UTC50
            blurhash,
96fdf90aacd6atagen2026-09-08 08:24 UTC51
        }) if mimetype.type_() == mime::VIDEO => AttachmentInfo::Video(BaseVideoInfo {
96fdf90aacd6atagen2026-09-08 08:24 UTC52
            width: width.map(Into::into),
96fdf90aacd6atagen2026-09-08 08:24 UTC53
            height: height.map(Into::into),
96fdf90aacd6atagen2026-09-08 08:24 UTC54
            duration: duration_ms.map(Duration::from_millis),
96fdf90aacd6atagen2026-09-08 08:24 UTC55
            size: Some(size),
96fdf90aacd6atagen2026-09-08 08:24 UTC56
            blurhash: blurhash.clone(),
96fdf90aacd6atagen2026-09-08 08:24 UTC57
        }),
96fdf90aacd6atagen2026-09-08 08:24 UTC58
        Some(UploadDetails::Audio { duration_ms }) if mimetype.type_() == mime::AUDIO => {
96fdf90aacd6atagen2026-09-08 08:24 UTC59
            AttachmentInfo::Audio(BaseAudioInfo {
96fdf90aacd6atagen2026-09-08 08:24 UTC60
                duration: duration_ms.map(Duration::from_millis),
96fdf90aacd6atagen2026-09-08 08:24 UTC61
                size: Some(size),
96fdf90aacd6atagen2026-09-08 08:24 UTC62
                ..Default::default()
96fdf90aacd6atagen2026-09-08 08:24 UTC63
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC64
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC65
        Some(UploadDetails::Voice {
96fdf90aacd6atagen2026-09-08 08:24 UTC66
            duration_ms,
96fdf90aacd6atagen2026-09-08 08:24 UTC67
            waveform,
96fdf90aacd6atagen2026-09-08 08:24 UTC68
        }) if mimetype.type_() == mime::AUDIO => {
96fdf90aacd6atagen2026-09-08 08:24 UTC69
            if waveform.iter().any(|sample| *sample > 1024) {
31ce2453c82fatagen2026-09-24 13:07 UTC70
                return Err(Error::new(
31ce2453c82fatagen2026-09-24 13:07 UTC71
                    ErrorKind::Invalid,
96fdf90aacd6atagen2026-09-08 08:24 UTC72
                    "voice waveform samples must be at most 1024",
96fdf90aacd6atagen2026-09-08 08:24 UTC73
                ));
96fdf90aacd6atagen2026-09-08 08:24 UTC74
            }
96fdf90aacd6atagen2026-09-08 08:24 UTC75
            AttachmentInfo::Voice(BaseAudioInfo {
96fdf90aacd6atagen2026-09-08 08:24 UTC76
                duration: Some(Duration::from_millis(*duration_ms)),
96fdf90aacd6atagen2026-09-08 08:24 UTC77
                size: Some(size),
96fdf90aacd6atagen2026-09-08 08:24 UTC78
                waveform: Some(
96fdf90aacd6atagen2026-09-08 08:24 UTC79
                    waveform
96fdf90aacd6atagen2026-09-08 08:24 UTC80
                        .iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC81
                        .map(|sample| f32::from(*sample) / 1024.0)
96fdf90aacd6atagen2026-09-08 08:24 UTC82
                        .collect(),
96fdf90aacd6atagen2026-09-08 08:24 UTC83
                ),
96fdf90aacd6atagen2026-09-08 08:24 UTC84
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC85
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC86
        Some(UploadDetails::File)
96fdf90aacd6atagen2026-09-08 08:24 UTC87
            if mimetype.type_() != mime::IMAGE
96fdf90aacd6atagen2026-09-08 08:24 UTC88
                && mimetype.type_() != mime::VIDEO
96fdf90aacd6atagen2026-09-08 08:24 UTC89
                && mimetype.type_() != mime::AUDIO =>
96fdf90aacd6atagen2026-09-08 08:24 UTC90
        {
96fdf90aacd6atagen2026-09-08 08:24 UTC91
            AttachmentInfo::File(BaseFileInfo { size: Some(size) })
96fdf90aacd6atagen2026-09-08 08:24 UTC92
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC93
        None => match mimetype.type_() {
96fdf90aacd6atagen2026-09-08 08:24 UTC94
            mime::IMAGE => AttachmentInfo::Image(BaseImageInfo {
96fdf90aacd6atagen2026-09-08 08:24 UTC95
                size: Some(size),
96fdf90aacd6atagen2026-09-08 08:24 UTC96
                ..Default::default()
96fdf90aacd6atagen2026-09-08 08:24 UTC97
            }),
96fdf90aacd6atagen2026-09-08 08:24 UTC98
            mime::VIDEO => AttachmentInfo::Video(BaseVideoInfo {
96fdf90aacd6atagen2026-09-08 08:24 UTC99
                size: Some(size),
96fdf90aacd6atagen2026-09-08 08:24 UTC100
                ..Default::default()
96fdf90aacd6atagen2026-09-08 08:24 UTC101
            }),
96fdf90aacd6atagen2026-09-08 08:24 UTC102
            mime::AUDIO => AttachmentInfo::Audio(BaseAudioInfo {
96fdf90aacd6atagen2026-09-08 08:24 UTC103
                size: Some(size),
96fdf90aacd6atagen2026-09-08 08:24 UTC104
                ..Default::default()
96fdf90aacd6atagen2026-09-08 08:24 UTC105
            }),
96fdf90aacd6atagen2026-09-08 08:24 UTC106
            _ => AttachmentInfo::File(BaseFileInfo { size: Some(size) }),
96fdf90aacd6atagen2026-09-08 08:24 UTC107
        },
96fdf90aacd6atagen2026-09-08 08:24 UTC108
        _ => {
31ce2453c82fatagen2026-09-24 13:07 UTC109
            return Err(Error::new(
31ce2453c82fatagen2026-09-24 13:07 UTC110
                ErrorKind::Invalid,
96fdf90aacd6atagen2026-09-08 08:24 UTC111
                "attachment metadata does not match its MIME type",
96fdf90aacd6atagen2026-09-08 08:24 UTC112
            ));
96fdf90aacd6atagen2026-09-08 08:24 UTC113
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC114
    };
96fdf90aacd6atagen2026-09-08 08:24 UTC115
    if upload.thumbnail.is_some() && mimetype.type_() == mime::AUDIO {
31ce2453c82fatagen2026-09-24 13:07 UTC116
        return Err(Error::new(
31ce2453c82fatagen2026-09-24 13:07 UTC117
            ErrorKind::Invalid,
96fdf90aacd6atagen2026-09-08 08:24 UTC118
            "audio attachments do not support thumbnails",
96fdf90aacd6atagen2026-09-08 08:24 UTC119
        ));
96fdf90aacd6atagen2026-09-08 08:24 UTC120
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC121
    let thumbnail = upload
96fdf90aacd6atagen2026-09-08 08:24 UTC122
        .thumbnail
96fdf90aacd6atagen2026-09-08 08:24 UTC123
        .take()
96fdf90aacd6atagen2026-09-08 08:24 UTC124
        .map(|thumbnail| {
96fdf90aacd6atagen2026-09-08 08:24 UTC125
            if thumbnail.bytes.len() > max_media_bytes
96fdf90aacd6atagen2026-09-08 08:24 UTC126
                || thumbnail.width == 0
96fdf90aacd6atagen2026-09-08 08:24 UTC127
                || thumbnail.height == 0
96fdf90aacd6atagen2026-09-08 08:24 UTC128
            {
31ce2453c82fatagen2026-09-24 13:07 UTC129
                return Err(Error::new(
5a52012c9b1datagen2026-09-24 23:45 UTC130
                    if thumbnail.bytes.len() > max_media_bytes {
5a52012c9b1datagen2026-09-24 23:45 UTC131
                        ErrorKind::MediaTooLarge
5a52012c9b1datagen2026-09-24 23:45 UTC132
                    } else {
5a52012c9b1datagen2026-09-24 23:45 UTC133
                        ErrorKind::Invalid
5a52012c9b1datagen2026-09-24 23:45 UTC134
                    },
96fdf90aacd6atagen2026-09-08 08:24 UTC135
                    "thumbnail size or dimensions are invalid",
96fdf90aacd6atagen2026-09-08 08:24 UTC136
                ));
96fdf90aacd6atagen2026-09-08 08:24 UTC137
            }
31ce2453c82fatagen2026-09-24 13:07 UTC138
            let content_type: mime::Mime = thumbnail
31ce2453c82fatagen2026-09-24 13:07 UTC139
                .mimetype
31ce2453c82fatagen2026-09-24 13:07 UTC140
                .parse()
31ce2453c82fatagen2026-09-24 13:07 UTC141
                .map_err(|_| Error::new(ErrorKind::Invalid, "thumbnail MIME type is invalid"))?;
96fdf90aacd6atagen2026-09-08 08:24 UTC142
            if content_type.type_() != mime::IMAGE {
31ce2453c82fatagen2026-09-24 13:07 UTC143
                return Err(Error::new(
31ce2453c82fatagen2026-09-24 13:07 UTC144
                    ErrorKind::Invalid,
96fdf90aacd6atagen2026-09-08 08:24 UTC145
                    "thumbnail MIME type must be an image",
96fdf90aacd6atagen2026-09-08 08:24 UTC146
                ));
96fdf90aacd6atagen2026-09-08 08:24 UTC147
            }
96fdf90aacd6atagen2026-09-08 08:24 UTC148
            let size = ruma::UInt::try_from(thumbnail.bytes.len()).map_err(|_| {
31ce2453c82fatagen2026-09-24 13:07 UTC149
                Error::new(
31ce2453c82fatagen2026-09-24 13:07 UTC150
                    ErrorKind::MediaTooLarge,
96fdf90aacd6atagen2026-09-08 08:24 UTC151
                    "thumbnail size is not representable",
96fdf90aacd6atagen2026-09-08 08:24 UTC152
                )
96fdf90aacd6atagen2026-09-08 08:24 UTC153
            })?;
96fdf90aacd6atagen2026-09-08 08:24 UTC154
            Ok(Thumbnail {
96fdf90aacd6atagen2026-09-08 08:24 UTC155
                data: thumbnail.bytes,
96fdf90aacd6atagen2026-09-08 08:24 UTC156
                content_type,
96fdf90aacd6atagen2026-09-08 08:24 UTC157
                width: thumbnail.width.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC158
                height: thumbnail.height.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC159
                size,
96fdf90aacd6atagen2026-09-08 08:24 UTC160
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC161
        })
96fdf90aacd6atagen2026-09-08 08:24 UTC162
        .transpose()?;
96fdf90aacd6atagen2026-09-08 08:24 UTC163
    let config = AttachmentConfig::new()
96fdf90aacd6atagen2026-09-08 08:24 UTC164
        .info(info)
96fdf90aacd6atagen2026-09-08 08:24 UTC165
        .thumbnail(thumbnail)
96fdf90aacd6atagen2026-09-08 08:24 UTC166
        .caption(upload.caption.clone().map(TextMessageEventContent::plain));
96fdf90aacd6atagen2026-09-08 08:24 UTC167
    Ok((upload, mimetype, config))
96fdf90aacd6atagen2026-09-08 08:24 UTC168
}