Skip to main content

tuwunel_api/server/
media.rs

1use axum::extract::State;
2use ruma::{
3	Mxc,
4	api::federation::authenticated_media::{
5		Content, ContentMetadata, FileOrLocation, get_content, get_content_thumbnail,
6	},
7};
8use tuwunel_core::{Result, utils::content_disposition::make_content_disposition};
9use tuwunel_service::media::{Dim, Media};
10
11use crate::{ClientIp, Ruma};
12
13/// # `GET /_matrix/federation/v1/media/download/{mediaId}`
14///
15/// Load media from our server.
16#[tracing::instrument(
17	name = "media_get",
18	level = "debug",
19	skip_all,
20	fields(%client)
21)]
22pub(crate) async fn get_content_route(
23	State(services): State<crate::State>,
24	ClientIp(client): ClientIp,
25	body: Ruma<get_content::v1::Request>,
26) -> Result<get_content::v1::Response> {
27	let mxc = Mxc {
28		server_name: services.globals.server_name(),
29		media_id: &body.media_id,
30	};
31
32	let Media {
33		content,
34		content_type,
35		content_disposition,
36	} = services.media.get(&mxc, None).await?;
37
38	let content_disposition =
39		make_content_disposition(content_disposition.as_ref(), content_type.as_deref(), None);
40
41	let content = Content {
42		file: content,
43		content_type: content_type.map(Into::into),
44		content_disposition: Some(content_disposition),
45	};
46
47	Ok(get_content::v1::Response {
48		content: FileOrLocation::File(content),
49		metadata: ContentMetadata::new(),
50	})
51}
52
53/// # `GET /_matrix/federation/v1/media/thumbnail/{mediaId}`
54///
55/// Load media thumbnail from our server.
56#[tracing::instrument(
57	name = "media_thumbnail_get",
58	level = "debug",
59	skip_all,
60	fields(%client)
61)]
62pub(crate) async fn get_content_thumbnail_route(
63	State(services): State<crate::State>,
64	ClientIp(client): ClientIp,
65	body: Ruma<get_content_thumbnail::v1::Request>,
66) -> Result<get_content_thumbnail::v1::Response> {
67	let dim = Dim::from_ruma(body.width, body.height, body.method.clone())?;
68	let mxc = Mxc {
69		server_name: services.globals.server_name(),
70		media_id: &body.media_id,
71	};
72
73	let Media {
74		content,
75		content_type,
76		content_disposition,
77	} = services
78		.media
79		.get_thumbnail(&mxc, &dim, None)
80		.await?;
81
82	let content_disposition =
83		make_content_disposition(content_disposition.as_ref(), content_type.as_deref(), None);
84
85	let content = Content {
86		file: content,
87		content_type: content_type.map(Into::into),
88		content_disposition: Some(content_disposition),
89	};
90
91	Ok(get_content_thumbnail::v1::Response {
92		content: FileOrLocation::File(content),
93		metadata: ContentMetadata::new(),
94	})
95}