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}