tuwunel_service/admin/
context.rs1use std::{fmt, fmt::Debug, time::SystemTime};
2
3use futures::{FutureExt, lock::Mutex};
4use tokio::time::Instant;
5use tuwunel_core::{Err, Result};
6
7use crate::Services;
8
9const OUTPUT_MAX_BYTES: usize = 64 * 1024 * 1024;
12
13pub struct Context<'a> {
14 pub services: &'a Services,
15 pub body: &'a [&'a str],
16 pub timer: SystemTime,
17 pub output: Mutex<String>,
18}
19
20impl Context<'_> {
21 pub async fn write_timed_query<F, T>(&self, query: F) -> Result
22 where
23 F: Future<Output = T>,
24 T: Debug,
25 {
26 let timer = Instant::now();
27 let result = query.await;
28 let query_time = timer.elapsed();
29
30 self.write_string(format!(
31 "Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
32 ))
33 .await
34 }
35
36 pub async fn write_timed_query_try<F, T>(&self, query: F) -> Result
37 where
38 F: Future<Output = Result<T>>,
39 T: Debug,
40 {
41 let timer = Instant::now();
42 let result = query.await?;
43 let query_time = timer.elapsed();
44
45 self.write_string(format!(
46 "Query completed in {query_time:?}:\n\n```rs\n{result:#?}\n```"
47 ))
48 .await
49 }
50
51 pub fn write_fmt(
52 &self,
53 arguments: fmt::Arguments<'_>,
54 ) -> impl Future<Output = Result> + Send + '_ + use<'_> {
55 let buf = format!("{arguments}");
56 self.write_string(buf)
57 }
58
59 #[inline]
60 pub async fn write_string(&self, s: String) -> Result { self.write_str(&s).await }
61
62 pub fn write_str<'a>(&'a self, s: &'a str) -> impl Future<Output = Result> + Send + 'a {
63 self.output.lock().map(move |mut output| {
64 if output.len().saturating_add(s.len()) > OUTPUT_MAX_BYTES {
65 return Err!("Command output exceeded the maximum size and was aborted.");
66 }
67
68 output.push_str(s);
69 Ok(())
70 })
71 }
72}