tuwunel_api/server/
media.rs1use 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::{Animate, Dim, Media};
10
11use crate::{ClientIp, Ruma};
12
13#[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#[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 animate = Animate::from(body.animated);
69 let mxc = Mxc {
70 server_name: services.globals.server_name(),
71 media_id: &body.media_id,
72 };
73
74 let Media {
75 content,
76 content_type,
77 content_disposition,
78 } = services
79 .media
80 .get_thumbnail(&mxc, &dim, animate, None)
81 .await?;
82
83 let content_disposition =
84 make_content_disposition(content_disposition.as_ref(), content_type.as_deref(), None);
85
86 let content = Content {
87 file: content,
88 content_type: content_type.map(Into::into),
89 content_disposition: Some(content_disposition),
90 };
91
92 Ok(get_content_thumbnail::v1::Response {
93 content: FileOrLocation::File(content),
94 metadata: ContentMetadata::new(),
95 })
96}