Skip to main content

tuwunel_service/admin/
attach.rs

1use ruma::{
2	Mxc,
3	events::room::{
4		MediaSource,
5		message::{FileInfo, FileMessageEventContent, MessageType, RoomMessageEventContent},
6	},
7};
8use tuwunel_core::{
9	Result, implement,
10	utils::{
11		content_disposition::make_content_disposition, math::ruma_from_usize, random_string,
12		time::now_secs,
13	},
14};
15
16use super::CommandOutput;
17use crate::media::MXC_LENGTH;
18
19/// Uploads a command's output to the media repository and builds an m.file
20/// message referencing it. The caller attaches the relation.
21#[implement(super::Service)]
22pub(super) async fn attach(&self, output: &CommandOutput) -> Result<RoomMessageEventContent> {
23	let (mime, ext) = match output {
24		| CommandOutput::Markdown(_) => ("text/markdown", "md"),
25		| CommandOutput::Plain(_) => ("text/plain", "txt"),
26	};
27
28	let text = output.as_str();
29	let filename = format!("admin-output-{}.{ext}", now_secs());
30	let media_id = random_string(MXC_LENGTH);
31	let mxc = Mxc {
32		server_name: self.services.globals.server_name(),
33		media_id: &media_id,
34	};
35
36	let content_disposition = make_content_disposition(None, Some(mime), Some(&filename));
37
38	self.services
39		.media
40		.create(
41			&mxc,
42			Some(&self.services.globals.server_user),
43			Some(&content_disposition),
44			Some(mime),
45			text.as_bytes(),
46		)
47		.await?;
48
49	let file = FileMessageEventContent {
50		body: filename.clone(),
51		formatted: None,
52		filename: Some(filename),
53		source: MediaSource::Plain(mxc.to_string().into()),
54		info: Some(Box::new(FileInfo {
55			mimetype: Some(mime.to_owned()),
56			size: Some(ruma_from_usize(text.len())),
57			..Default::default()
58		})),
59	};
60
61	Ok(RoomMessageEventContent::new(MessageType::File(file)))
62}