palpo_core/federation/knock.rs
1use itertools::Itertools;
2use reqwest::Url;
3/// Endpoints for handling room knocking.
4/// `GET /_matrix/federation/*/make_knock/{room_id}/{user_id}`
5///
6/// Send a request for a knock event template to a resident server.
7/// `/v1/` ([spec])
8///
9/// [spec]: https://spec.matrix.org/latest/server-server-api/#get_matrixfederationv1make_knockroomiduser_id
10use salvo::prelude::*;
11use serde::{Deserialize, Serialize};
12
13use crate::events::AnyStrippedStateEvent;
14use crate::sending::{SendRequest, SendResult};
15use crate::serde::{RawJson, RawJsonValue};
16use crate::{OwnedEventId, OwnedRoomId, OwnedUserId, RoomVersionId};
17// const METADATA: Metadata = metadata! {
18// method: GET,
19// rate_limited: false,
20// authentication: ServerSignatures,
21// history: {
22// unstable => "/_matrix/federation/unstable/xyz.amorgan.knock/make_knock/:room_id/:user_id",
23// 1.1 => "/_matrix/federation/v1/make_knock/:room_id/:user_id",
24// }
25// };
26
27pub fn make_knock_request(origin: &str, args: MakeKnockReqArgs) -> SendResult<SendRequest> {
28 let ver = args.ver.iter().map(|v| format!("ver={v}")).join("&");
29 let ver = if ver.is_empty() { "" } else { &*format!("?{}", ver) };
30 let url = Url::parse(&format!(
31 "{origin}/_matrix/federation/v1/make_knock/{}/{}{}",
32 args.room_id, args.user_id, ver
33 ))?;
34 Ok(crate::sending::get(url))
35}
36
37/// Request type for the `create_knock_event_template` endpoint.
38#[derive(ToParameters, Deserialize, Debug)]
39pub struct MakeKnockReqArgs {
40 /// The room ID that should receive the knock.
41 #[salvo(parameter(parameter_in = Path))]
42 pub room_id: OwnedRoomId,
43
44 /// The user ID the knock event will be for.
45 #[salvo(parameter(parameter_in = Path))]
46 pub user_id: OwnedUserId,
47
48 /// The room versions the sending has support for.
49 ///
50 /// Defaults to `vec![RoomVersionId::V1]`.
51 #[salvo(parameter(parameter_in = Query))]
52 pub ver: Vec<RoomVersionId>,
53}
54
55/// Response type for the `create_knock_event_template` endpoint.
56#[derive(ToSchema, Serialize, Deserialize, Debug)]
57
58pub struct MakeKnockResBody {
59 /// The version of the room where the server is trying to knock.
60 pub room_version: RoomVersionId,
61
62 /// An unsigned template event.
63 ///
64 /// May differ between room versions.
65 #[salvo(schema(value_type = Object, additional_properties = true))]
66 pub event: Box<RawJsonValue>,
67}
68
69impl MakeKnockResBody {
70 /// Creates a new `Response` with the given room version ID and event.
71 pub fn new(room_version: RoomVersionId, event: Box<RawJsonValue>) -> Self {
72 Self { room_version, event }
73 }
74}
75
76/// `PUT /_matrix/federation/*/send_knock/{room_id}/{event_id}`
77///
78/// Submits a signed knock event to the resident homeserver for it to accept into the room's graph.
79/// `/v1/` ([spec])
80///
81/// [spec]: https://spec.matrix.org/latest/server-server-api/#put_matrixfederationv1send_knockroomideventid
82
83// const METADATA: Metadata = metadata! {
84// method: PUT,
85// rate_limited: false,
86// authentication: ServerSignatures,
87// history: {
88// unstable => "/_matrix/federation/unstable/xyz.amorgan.knock/send_knock/:room_id/:event_id",
89// 1.1 => "/_matrix/federation/v1/send_knock/:room_id/:event_id",
90// }
91// };
92
93pub fn send_knock_request(origin: &str, args: SendKnockReqArgs, body: SendKnockReqBody) -> SendResult<SendRequest> {
94 let url = Url::parse(&format!(
95 "{origin}/_matrix/federation/v1/send_knock/{}/{}",
96 args.room_id, args.event_id
97 ))?;
98 Ok(crate::sending::put(url).stuff(body)?)
99}
100
101#[derive(ToParameters, Deserialize, Debug)]
102pub struct SendKnockReqArgs {
103 /// The room ID that should receive the knock.
104 #[salvo(parameter(parameter_in = Path))]
105 pub room_id: OwnedRoomId,
106
107 /// The user ID the knock event will be for.
108 #[salvo(parameter(parameter_in = Path))]
109 pub event_id: OwnedEventId,
110}
111
112/// Request type for the `send_knock` endpoint.
113
114#[derive(ToSchema, Serialize, Deserialize, Debug)]
115pub struct SendKnockReqBody {
116 // /// The room ID that should receive the knock.
117 // #[salvo(parameter(parameter_in = Path))]
118 // pub room_id: OwnedRoomId,
119
120 // /// The event ID for the knock event.
121 // #[salvo(parameter(parameter_in = Path))]
122 // pub event_id: OwnedEventId,
123 /// The PDU.
124 #[salvo(schema(value_type = Object, additional_properties = true))]
125 #[serde(flatten)]
126 pub pdu: Box<RawJsonValue>,
127}
128impl SendKnockReqBody {
129 /// Creates a new `Request` with the given PDU.
130 pub fn new(pdu: Box<RawJsonValue>) -> Self {
131 Self { pdu }
132 }
133}
134crate::json_body_modifier!(SendKnockReqBody);
135
136/// Response type for the `send_knock` endpoint.
137#[derive(ToSchema, Serialize, Deserialize, Debug)]
138
139pub struct SendKnockResBody {
140 /// State events providing public room metadata.
141 pub knock_room_state: Vec<RawJson<AnyStrippedStateEvent>>,
142}
143
144impl SendKnockResBody {
145 /// Creates a new `Response` with the given public room metadata state events.
146 pub fn new(knock_room_state: Vec<RawJson<AnyStrippedStateEvent>>) -> Self {
147 Self { knock_room_state }
148 }
149}