Skip to main content

tuwunel_admin/debug/
get_remote_pdu.rs

1use futures::FutureExt;
2use ruma::{CanonicalJsonObject, OwnedEventId, OwnedServerName};
3use serde_json::value::RawValue as RawJsonValue;
4use tuwunel_core::{Err, Result, err, info, warn};
5use tuwunel_service::fetcher::{Op, Opts};
6
7use crate::admin_command;
8
9#[admin_command]
10pub(super) async fn get_remote_pdu(
11	&self,
12	event_id: OwnedEventId,
13	server: OwnedServerName,
14) -> Result {
15	if !self.services.server.config.allow_federation {
16		return Err!("Federation is disabled on this homeserver.");
17	}
18
19	if server == self.services.globals.server_name() {
20		return Err!(
21			"Not allowed to send federation requests to ourselves. Please use `get-pdu` for \
22			 fetching local PDUs.",
23		);
24	}
25
26	let opts = Opts::unscoped(Op::Event)
27		.event_id(event_id.clone())
28		.hint(server.clone())
29		.checks(false);
30
31	let outcome = self
32		.services
33		.fetcher
34		.fetch(opts)
35		.await
36		.map_err(|e| {
37			err!("Remote server did not have PDU or failed sending request to remote server: {e}")
38		})?;
39
40	let pdu: Box<RawJsonValue> = serde_json::from_slice(&outcome.bytes).map_err(|e| {
41		warn!(
42			"Requested event ID {event_id} from {server} but failed to parse the response as a \
43			 PDU (malformed event/response?): {e}"
44		);
45		err!(Request(Unknown("Received response from server but failed to parse PDU")))
46	})?;
47
48	let json: CanonicalJsonObject = serde_json::from_slice(&outcome.bytes).map_err(|e| {
49		err!(
50			"Got a PDU from {server} but could not convert it to canonical JSON for display: {e}"
51		)
52	})?;
53
54	let (room_id, ..) = self
55		.services
56		.event_handler
57		.parse_incoming_pdu(&pdu)
58		.boxed()
59		.await
60		.map_err(|e| {
61			warn!("Failed to parse PDU: {e}");
62			info!("Full PDU: {pdu:?}");
63			err!("Failed to parse PDU remote server {server} sent us: {e}")
64		})?;
65
66	info!("Attempting to handle event ID {event_id} as backfilled PDU");
67	self.services
68		.timeline
69		.backfill_pdu(&room_id, &outcome.origin, pdu)
70		.await?;
71
72	let text = serde_json::to_string_pretty(&json)?;
73	let msg = "Got PDU from specified server and handled as backfilled";
74	write!(self, "{msg}. Event body:\n```json\n{text}\n```").await
75}