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::{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 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}