Skip to main content

tuwunel_admin/debug/
dump_pdus.rs

1use std::path::Path;
2
3use futures::{Stream, TryFutureExt, TryStreamExt, future::try_join3};
4use tokio::{
5	fs::{self, OpenOptions},
6	io::AsyncWriteExt,
7};
8use tuwunel_core::Result;
9
10use crate::admin_command;
11
12#[admin_command]
13pub(super) async fn dump_pdus(&self, dir: String) -> Result {
14	let dir_path = Path::new(&dir);
15	fs::create_dir_all(dir_path).await?;
16
17	let normal = dumper(dir_path, "normal", self.services.timeline.pdus_raw());
18	let outlier = dumper(dir_path, "outliers", self.services.timeline.outlier_pdus_raw());
19	let retained = dumper(dir_path, "retaineds", self.services.retention.retained_pdus_raw());
20	try_join3(normal, outlier, retained).await?;
21
22	Ok(())
23}
24
25async fn dumper<'a, S>(dir: &Path, name: &str, stream: S) -> Result
26where
27	S: Stream<Item = Result<&'a [u8]>> + Send,
28{
29	let mut fopts = OpenOptions::new();
30	fopts.write(true);
31	fopts.create(true);
32	fopts.truncate(true);
33
34	let path = dir.join(name);
35	let file = fopts.open(path).await?;
36	stream
37		.try_fold(file, async |mut file, data| {
38			file.write_all(data).await?;
39
40			Ok(file)
41		})
42		.and_then(async |mut file| Ok(file.shutdown().await?))
43		.await
44}