use crate::controllers::HttpResult; use crate::extractors::matrix_client_extractor::MatrixClientExtractor; use crate::utils::crypt_utils::sha512; use actix_web::dev::Payload; use actix_web::http::header; use actix_web::{FromRequest, HttpRequest, HttpResponse, web}; use matrix_sdk::media::{MediaFormat, MediaRequestParameters, MediaThumbnailSettings}; use matrix_sdk::ruma::events::room::MediaSource; use matrix_sdk::ruma::{OwnedMxcUri, UInt}; #[derive(serde::Deserialize)] struct MediaQuery { #[serde(default)] thumbnail: bool, } /// Serve a media file pub async fn serve_media(req: HttpRequest, media: OwnedMxcUri) -> HttpResult { let query = web::Query::::from_request(&req, &mut Payload::None).await?; let client = MatrixClientExtractor::from_request(&req, &mut Payload::None).await?; let media = client .client .client .media() .get_media_content( &MediaRequestParameters { source: MediaSource::Plain(media), format: match query.thumbnail { true => MediaFormat::Thumbnail(MediaThumbnailSettings::new( UInt::new(100).unwrap(), UInt::new(100).unwrap(), )), false => MediaFormat::File, }, }, true, ) .await?; let digest = sha512(&media); let mime_type = infer::get(&media).map(|x| x.mime_type()); // Check if the browser already knows the etag if let Some(c) = req.headers().get(header::IF_NONE_MATCH) && c.to_str().unwrap_or("") == digest { return Ok(HttpResponse::NotModified().finish()); } Ok(HttpResponse::Ok() .content_type(mime_type.unwrap_or("application/octet-stream")) .insert_header(("etag", digest)) .insert_header(("cache-control", "max-age=360000")) .body(media)) } #[derive(serde::Deserialize)] pub struct MediaMXCInPath { mxc: OwnedMxcUri, } /// Save media resource handler pub async fn serve_media_res(req: HttpRequest, media: web::Path) -> HttpResult { serve_media(req, media.into_inner().mxc).await }