Add send transaction endpoint
Also refactor PDU types and move them to ruma-events
This commit is contained in:
parent
7c934e1b8f
commit
bfad8cf1f1
@ -10,6 +10,7 @@ Breaking changes:
|
||||
struct variants
|
||||
* This change removes the types `EventMatchCondition`, `RoomMemberCountCondition` and
|
||||
`SenderNotificationPermissionCondition`
|
||||
* Add PDU types: `pdu::{Pdu, PduStub}`
|
||||
|
||||
Improvements:
|
||||
|
||||
|
@ -147,6 +147,7 @@ pub mod forwarded_room_key;
|
||||
pub mod fully_read;
|
||||
pub mod ignored_user_list;
|
||||
pub mod key;
|
||||
pub mod pdu;
|
||||
pub mod presence;
|
||||
pub mod push_rules;
|
||||
pub mod receipt;
|
||||
|
325
ruma-events/src/pdu.rs
Normal file
325
ruma-events/src/pdu.rs
Normal file
@ -0,0 +1,325 @@
|
||||
//! Types for persistent data unit schemas
|
||||
//!
|
||||
//! The differences between the `RoomV1Pdu` schema and the `RoomV3Pdu` schema are
|
||||
//! that the `RoomV1Pdu` takes an `event_id` field (`RoomV3Pdu` does not), and
|
||||
//! `auth_events` and `prev_events` take `Vec<(EventId, EventHash)> rather than
|
||||
//! `Vec<EventId>` in `RoomV3Pdu`.
|
||||
//!
|
||||
//! The stubbed versions of each PDU type remove the `event_id` field (if any)
|
||||
//! and the `room_id` field for use in PDU templates.
|
||||
|
||||
use std::{collections::BTreeMap, time::SystemTime};
|
||||
|
||||
use js_int::UInt;
|
||||
use ruma_events::EventType;
|
||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
/// Enum for PDU schemas
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Pdu {
|
||||
/// PDU for room versions 1 and 2.
|
||||
RoomV1Pdu(RoomV1Pdu),
|
||||
/// PDU for room versions 3 and above.
|
||||
RoomV3Pdu(RoomV3Pdu),
|
||||
}
|
||||
|
||||
/// A 'persistent data unit' (event) for room versions 1 and 2.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct RoomV1Pdu {
|
||||
/// Event ID for the PDU.
|
||||
pub event_id: EventId,
|
||||
|
||||
/// The room this event belongs to.
|
||||
pub room_id: RoomId,
|
||||
|
||||
/// The user id of the user who sent this event.
|
||||
pub sender: UserId,
|
||||
|
||||
/// The `server_name` of the homeserver that created this event.
|
||||
pub origin: String,
|
||||
|
||||
/// Timestamp (milliseconds since the UNIX epoch) on originating homeserver
|
||||
/// of when this event was created.
|
||||
#[serde(with = "ruma_serde::time::ms_since_unix_epoch")]
|
||||
pub origin_server_ts: SystemTime,
|
||||
|
||||
// TODO: Encode event type as content enum variant, like event enums do
|
||||
/// The event's type.
|
||||
#[serde(rename = "type")]
|
||||
pub kind: EventType,
|
||||
|
||||
/// The event's content.
|
||||
pub content: JsonValue,
|
||||
|
||||
/// A key that determines which piece of room state the event represents.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub state_key: Option<String>,
|
||||
|
||||
/// Event IDs for the most recent events in the room that the homeserver was
|
||||
/// aware of when it created this event.
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub prev_events: Vec<(EventId, EventHash)>,
|
||||
|
||||
/// The maximum depth of the `prev_events`, plus one.
|
||||
pub depth: UInt,
|
||||
|
||||
/// Event IDs for the authorization events that would allow this event to be
|
||||
/// in the room.
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub auth_events: Vec<(EventId, EventHash)>,
|
||||
|
||||
/// For redaction events, the ID of the event being redacted.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub redacts: Option<EventId>,
|
||||
|
||||
/// Additional data added by the origin server but not covered by the
|
||||
/// signatures.
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub unsigned: BTreeMap<String, JsonValue>,
|
||||
|
||||
/// Content hashes of the PDU.
|
||||
pub hashes: EventHash,
|
||||
|
||||
/// Signatures for the PDU.
|
||||
pub signatures: BTreeMap<String, BTreeMap<String, String>>,
|
||||
}
|
||||
|
||||
/// A 'persistent data unit' (event) for room versions 3 and beyond.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct RoomV3Pdu {
|
||||
/// The room this event belongs to.
|
||||
pub room_id: RoomId,
|
||||
|
||||
/// The user id of the user who sent this event.
|
||||
pub sender: UserId,
|
||||
|
||||
/// The `server_name` of the homeserver that created this event.
|
||||
pub origin: String,
|
||||
|
||||
/// Timestamp (milliseconds since the UNIX epoch) on originating homeserver
|
||||
/// of when this event was created.
|
||||
#[serde(with = "ruma_serde::time::ms_since_unix_epoch")]
|
||||
pub origin_server_ts: SystemTime,
|
||||
|
||||
// TODO: Encode event type as content enum variant, like event enums do
|
||||
/// The event's type.
|
||||
#[serde(rename = "type")]
|
||||
pub kind: EventType,
|
||||
|
||||
/// The event's content.
|
||||
pub content: JsonValue,
|
||||
|
||||
/// A key that determines which piece of room state the event represents.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub state_key: Option<String>,
|
||||
|
||||
/// Event IDs for the most recent events in the room that the homeserver was
|
||||
/// aware of when it created this event.
|
||||
pub prev_events: Vec<EventId>,
|
||||
|
||||
/// The maximum depth of the `prev_events`, plus one.
|
||||
pub depth: UInt,
|
||||
|
||||
/// Event IDs for the authorization events that would allow this event to be
|
||||
/// in the room.
|
||||
pub auth_events: Vec<EventId>,
|
||||
|
||||
/// For redaction events, the ID of the event being redacted.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub redacts: Option<EventId>,
|
||||
|
||||
/// Additional data added by the origin server but not covered by the
|
||||
/// signatures.
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub unsigned: BTreeMap<String, JsonValue>,
|
||||
|
||||
/// Content hashes of the PDU.
|
||||
pub hashes: EventHash,
|
||||
|
||||
/// Signatures for the PDU.
|
||||
pub signatures: BTreeMap<String, BTreeMap<String, String>>,
|
||||
}
|
||||
|
||||
/// PDU type without event and room IDs.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum PduStub {
|
||||
/// Stub for PDUs of room version 1 and 2.
|
||||
RoomV1PduStub(RoomV1PduStub),
|
||||
|
||||
/// Stub for PDUs of room versions 3 and above.
|
||||
RoomV3PduStub(RoomV3PduStub),
|
||||
}
|
||||
|
||||
impl PduStub {
|
||||
/// Helper method to get PDU from a PDU stub.
|
||||
pub fn into_pdu(self, room_id: RoomId, event_id: EventId) -> Pdu {
|
||||
match self {
|
||||
PduStub::RoomV1PduStub(v1_stub) => {
|
||||
Pdu::RoomV1Pdu(v1_stub.into_v1_pdu(room_id, event_id))
|
||||
}
|
||||
PduStub::RoomV3PduStub(v3_stub) => Pdu::RoomV3Pdu(v3_stub.into_v3_pdu(room_id)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stub for PDUs of room version 1 and 2.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct RoomV1PduStub {
|
||||
/// The user id of the user who sent this event.
|
||||
pub sender: UserId,
|
||||
|
||||
/// The `server_name` of the homeserver that created this event.
|
||||
pub origin: String,
|
||||
|
||||
/// Timestamp (milliseconds since the UNIX epoch) on originating homeserver
|
||||
/// of when this event was created.
|
||||
#[serde(with = "ruma_serde::time::ms_since_unix_epoch")]
|
||||
pub origin_server_ts: SystemTime,
|
||||
|
||||
// TODO: Encode event type as content enum variant, like event enums do
|
||||
/// The event's type.
|
||||
#[serde(rename = "type")]
|
||||
pub kind: EventType,
|
||||
|
||||
/// The event's content.
|
||||
pub content: JsonValue,
|
||||
|
||||
/// A key that determines which piece of room state the event represents.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub state_key: Option<String>,
|
||||
|
||||
/// Event IDs for the most recent events in the room that the homeserver was
|
||||
/// aware of when it created this event.
|
||||
pub prev_events: Vec<(EventId, EventHash)>,
|
||||
|
||||
/// The maximum depth of the `prev_events`, plus one.
|
||||
pub depth: UInt,
|
||||
|
||||
/// Event IDs for the authorization events that would allow this event to be
|
||||
/// in the room.
|
||||
pub auth_events: Vec<(EventId, EventHash)>,
|
||||
|
||||
/// For redaction events, the ID of the event being redacted.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub redacts: Option<EventId>,
|
||||
|
||||
/// Additional data added by the origin server but not covered by the
|
||||
/// signatures.
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub unsigned: BTreeMap<String, JsonValue>,
|
||||
|
||||
/// Content hashes of the PDU.
|
||||
pub hashes: EventHash,
|
||||
|
||||
/// Signatures for the PDU.
|
||||
pub signatures: BTreeMap<String, BTreeMap<String, String>>,
|
||||
}
|
||||
|
||||
impl RoomV1PduStub {
|
||||
/// Converts a V1 PDU stub into a full V1 PDU.
|
||||
pub fn into_v1_pdu(self, room_id: RoomId, event_id: EventId) -> RoomV1Pdu {
|
||||
RoomV1Pdu {
|
||||
event_id,
|
||||
room_id,
|
||||
sender: self.sender,
|
||||
origin: self.origin,
|
||||
origin_server_ts: self.origin_server_ts,
|
||||
kind: self.kind,
|
||||
content: self.content,
|
||||
state_key: self.state_key,
|
||||
prev_events: self.prev_events,
|
||||
depth: self.depth,
|
||||
auth_events: self.auth_events,
|
||||
redacts: self.redacts,
|
||||
unsigned: self.unsigned,
|
||||
hashes: self.hashes,
|
||||
signatures: self.signatures,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stub for PDUs of room versions 3 and above.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct RoomV3PduStub {
|
||||
/// The user id of the user who sent this event.
|
||||
pub sender: UserId,
|
||||
|
||||
/// The `server_name` of the homeserver that created this event.
|
||||
pub origin: String,
|
||||
|
||||
/// Timestamp (milliseconds since the UNIX epoch) on originating homeserver
|
||||
/// of when this event was created.
|
||||
#[serde(with = "ruma_serde::time::ms_since_unix_epoch")]
|
||||
pub origin_server_ts: SystemTime,
|
||||
|
||||
// TODO: Encode event type as content enum variant, like event enums do
|
||||
/// The event's type.
|
||||
#[serde(rename = "type")]
|
||||
pub kind: EventType,
|
||||
|
||||
/// The event's content.
|
||||
pub content: JsonValue,
|
||||
|
||||
/// A key that determines which piece of room state the event represents.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub state_key: Option<String>,
|
||||
|
||||
/// Event IDs for the most recent events in the room that the homeserver was
|
||||
/// aware of when it created this event.
|
||||
pub prev_events: Vec<EventId>,
|
||||
|
||||
/// The maximum depth of the `prev_events`, plus one.
|
||||
pub depth: UInt,
|
||||
|
||||
/// Event IDs for the authorization events that would allow this event to be
|
||||
/// in the room.
|
||||
pub auth_events: Vec<EventId>,
|
||||
|
||||
/// For redaction events, the ID of the event being redacted.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub redacts: Option<EventId>,
|
||||
|
||||
/// Additional data added by the origin server but not covered by the
|
||||
/// signatures.
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub unsigned: BTreeMap<String, JsonValue>,
|
||||
|
||||
/// Content hashes of the PDU.
|
||||
pub hashes: EventHash,
|
||||
|
||||
/// Signatures for the PDU.
|
||||
pub signatures: BTreeMap<String, BTreeMap<String, String>>,
|
||||
}
|
||||
|
||||
impl RoomV3PduStub {
|
||||
/// Converts a V3 PDU stub into a full V3 PDU.
|
||||
pub fn into_v3_pdu(self, room_id: RoomId) -> RoomV3Pdu {
|
||||
RoomV3Pdu {
|
||||
room_id,
|
||||
sender: self.sender,
|
||||
origin: self.origin,
|
||||
origin_server_ts: self.origin_server_ts,
|
||||
kind: self.kind,
|
||||
content: self.content,
|
||||
state_key: self.state_key,
|
||||
prev_events: self.prev_events,
|
||||
depth: self.depth,
|
||||
auth_events: self.auth_events,
|
||||
redacts: self.redacts,
|
||||
unsigned: self.unsigned,
|
||||
hashes: self.hashes,
|
||||
signatures: self.signatures,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Content hashes of a PDU.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct EventHash {
|
||||
/// The SHA-256 hash.
|
||||
pub sha256: String,
|
||||
}
|
605
ruma-events/tests/pdu.rs
Normal file
605
ruma-events/tests/pdu.rs
Normal file
@ -0,0 +1,605 @@
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
convert::TryFrom,
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
use matches::assert_matches;
|
||||
use ruma_events::{
|
||||
pdu::{EventHash, Pdu, PduStub, RoomV1Pdu, RoomV1PduStub, RoomV3Pdu, RoomV3PduStub},
|
||||
EventType,
|
||||
};
|
||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
|
||||
|
||||
#[test]
|
||||
fn serialize_stub_as_v1() {
|
||||
let mut signatures = BTreeMap::new();
|
||||
let mut inner_signature = BTreeMap::new();
|
||||
inner_signature.insert(
|
||||
"ed25519:key_version".to_string(),
|
||||
"86BytesOfSignatureOfTheRedactedEvent".to_string(),
|
||||
);
|
||||
signatures.insert("example.com".to_string(), inner_signature);
|
||||
|
||||
let mut unsigned = BTreeMap::new();
|
||||
unsigned.insert("somekey".to_string(), json!({"a": 456}));
|
||||
|
||||
let v1_stub = RoomV1PduStub {
|
||||
sender: UserId::try_from("@sender:example.com").unwrap(),
|
||||
origin: "matrix.org".to_string(),
|
||||
origin_server_ts: SystemTime::UNIX_EPOCH + Duration::from_millis(1_592_050_773_658),
|
||||
kind: EventType::RoomPowerLevels,
|
||||
content: json!({"testing": 123}),
|
||||
state_key: Some("state".to_string()),
|
||||
prev_events: vec![(
|
||||
EventId::try_from("$previousevent:matrix.org").unwrap(),
|
||||
EventHash { sha256: "123567".to_string() },
|
||||
)],
|
||||
depth: 2_u32.into(),
|
||||
auth_events: vec![(
|
||||
EventId::try_from("$someauthevent:matrix.org").unwrap(),
|
||||
EventHash { sha256: "21389CFEDABC".to_string() },
|
||||
)],
|
||||
redacts: Some(EventId::try_from("$9654:matrix.org").unwrap()),
|
||||
unsigned,
|
||||
hashes: EventHash { sha256: "1233543bABACDEF".to_string() },
|
||||
signatures,
|
||||
};
|
||||
let pdu_stub = PduStub::RoomV1PduStub(v1_stub);
|
||||
let json = json!({
|
||||
"sender": "@sender:example.com",
|
||||
"origin": "matrix.org",
|
||||
"origin_server_ts": 1_592_050_773_658 as usize,
|
||||
"type": "m.room.power_levels",
|
||||
"content": {
|
||||
"testing": 123
|
||||
},
|
||||
"state_key": "state",
|
||||
"prev_events": [
|
||||
[ "$previousevent:matrix.org", {"sha256": "123567"} ]
|
||||
],
|
||||
"depth": 2,
|
||||
"auth_events": [
|
||||
["$someauthevent:matrix.org", {"sha256": "21389CFEDABC"}]
|
||||
],
|
||||
"redacts": "$9654:matrix.org",
|
||||
"unsigned": {
|
||||
"somekey": { "a": 456 } },
|
||||
"hashes": { "sha256": "1233543bABACDEF" },
|
||||
"signatures": {
|
||||
"example.com": { "ed25519:key_version":"86BytesOfSignatureOfTheRedactedEvent" }
|
||||
}
|
||||
});
|
||||
|
||||
assert_eq!(to_json_value(&pdu_stub).unwrap(), json);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_stub_as_v3() {
|
||||
let mut signatures = BTreeMap::new();
|
||||
let mut inner_signature = BTreeMap::new();
|
||||
inner_signature.insert(
|
||||
"ed25519:key_version".to_string(),
|
||||
"86BytesOfSignatureOfTheRedactedEvent".to_string(),
|
||||
);
|
||||
signatures.insert("example.com".to_string(), inner_signature);
|
||||
|
||||
let mut unsigned = BTreeMap::new();
|
||||
unsigned.insert("somekey".to_string(), json!({"a": 456}));
|
||||
|
||||
let v3_stub = RoomV3PduStub {
|
||||
sender: UserId::try_from("@sender:example.com").unwrap(),
|
||||
origin: "matrix.org".to_string(),
|
||||
origin_server_ts: SystemTime::UNIX_EPOCH + Duration::from_millis(1_592_050_773_658),
|
||||
kind: EventType::RoomPowerLevels,
|
||||
content: json!({"testing": 123}),
|
||||
state_key: Some("state".to_string()),
|
||||
prev_events: vec![EventId::try_from("$previousevent:matrix.org").unwrap()],
|
||||
depth: 2_u32.into(),
|
||||
auth_events: vec![EventId::try_from("$someauthevent:matrix.org").unwrap()],
|
||||
redacts: Some(EventId::try_from("$9654:matrix.org").unwrap()),
|
||||
unsigned,
|
||||
hashes: EventHash { sha256: "1233543bABACDEF".to_string() },
|
||||
signatures,
|
||||
};
|
||||
let pdu_stub = PduStub::RoomV3PduStub(v3_stub);
|
||||
let json = json!({
|
||||
"sender": "@sender:example.com",
|
||||
"origin": "matrix.org",
|
||||
"origin_server_ts": 1_592_050_773_658 as usize,
|
||||
"type": "m.room.power_levels",
|
||||
"content": {
|
||||
"testing": 123
|
||||
},
|
||||
"state_key": "state",
|
||||
"prev_events": [ "$previousevent:matrix.org" ],
|
||||
"depth": 2,
|
||||
"auth_events": ["$someauthevent:matrix.org" ],
|
||||
"redacts": "$9654:matrix.org",
|
||||
"unsigned": {
|
||||
"somekey": { "a": 456 } },
|
||||
"hashes": { "sha256": "1233543bABACDEF" },
|
||||
"signatures": {
|
||||
"example.com": { "ed25519:key_version":"86BytesOfSignatureOfTheRedactedEvent" }
|
||||
}
|
||||
});
|
||||
|
||||
assert_eq!(to_json_value(&pdu_stub).unwrap(), json);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_stub_as_v1() {
|
||||
let json = json!({
|
||||
"auth_events": [
|
||||
[
|
||||
"$abc123:matrix.org",
|
||||
{
|
||||
"sha256": "Base64EncodedSha256HashesShouldBe43BytesLong"
|
||||
}
|
||||
]
|
||||
],
|
||||
"content": {
|
||||
"key": "value"
|
||||
},
|
||||
"depth": 12,
|
||||
"event_id": "$a4ecee13e2accdadf56c1025:example.com",
|
||||
"hashes": {
|
||||
"sha256": "ThisHashCoversAllFieldsInCaseThisIsRedacted"
|
||||
},
|
||||
"origin": "matrix.org",
|
||||
"origin_server_ts": 1_234_567_890,
|
||||
"prev_events": [
|
||||
[
|
||||
"$abc123:matrix.org",
|
||||
{
|
||||
"sha256": "Base64EncodedSha256HashesShouldBe43BytesLong"
|
||||
}
|
||||
]
|
||||
],
|
||||
"redacts": "$def456:matrix.org",
|
||||
"room_id": "!abc123:matrix.org",
|
||||
"sender": "@someone:matrix.org",
|
||||
"signatures": {
|
||||
"example.com": {
|
||||
"ed25519:key_version:": "86BytesOfSignatureOfTheRedactedEvent"
|
||||
}
|
||||
},
|
||||
"state_key": "my_key",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"key": "value"
|
||||
}
|
||||
});
|
||||
let parsed = from_json_value::<PduStub>(json).unwrap();
|
||||
|
||||
match parsed {
|
||||
PduStub::RoomV1PduStub(v1_stub) => {
|
||||
assert_eq!(
|
||||
v1_stub.auth_events.first().unwrap().0,
|
||||
EventId::try_from("$abc123:matrix.org").unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
v1_stub.auth_events.first().unwrap().1.sha256,
|
||||
"Base64EncodedSha256HashesShouldBe43BytesLong"
|
||||
);
|
||||
}
|
||||
PduStub::RoomV3PduStub(_) => panic!("Matched V3 stub"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_stub_as_v3() {
|
||||
let json = json!({
|
||||
"auth_events": [
|
||||
"$abc123:matrix.org"
|
||||
],
|
||||
"content": {
|
||||
"key": "value"
|
||||
},
|
||||
"depth": 12,
|
||||
"event_id": "$a4ecee13e2accdadf56c1025:example.com",
|
||||
"hashes": {
|
||||
"sha256": "ThisHashCoversAllFieldsInCaseThisIsRedacted"
|
||||
},
|
||||
"origin": "matrix.org",
|
||||
"origin_server_ts": 1_234_567_890,
|
||||
"prev_events": [
|
||||
"$abc123:matrix.org"
|
||||
],
|
||||
"redacts": "$def456:matrix.org",
|
||||
"room_id": "!abc123:matrix.org",
|
||||
"sender": "@someone:matrix.org",
|
||||
"signatures": {
|
||||
"example.com": {
|
||||
"ed25519:key_version:": "86BytesOfSignatureOfTheRedactedEvent"
|
||||
}
|
||||
},
|
||||
"state_key": "my_key",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"key": "value"
|
||||
}
|
||||
});
|
||||
let parsed = from_json_value::<PduStub>(json).unwrap();
|
||||
|
||||
match parsed {
|
||||
PduStub::RoomV1PduStub(_) => panic!("Matched V1 stub"),
|
||||
PduStub::RoomV3PduStub(v3_stub) => {
|
||||
assert_eq!(
|
||||
v3_stub.auth_events.first().unwrap(),
|
||||
&EventId::try_from("$abc123:matrix.org").unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_pdu_as_v1() {
|
||||
let mut signatures = BTreeMap::new();
|
||||
let mut inner_signature = BTreeMap::new();
|
||||
inner_signature.insert(
|
||||
"ed25519:key_version".to_string(),
|
||||
"86BytesOfSignatureOfTheRedactedEvent".to_string(),
|
||||
);
|
||||
signatures.insert("example.com".to_string(), inner_signature);
|
||||
|
||||
let mut unsigned = BTreeMap::new();
|
||||
unsigned.insert("somekey".to_string(), json!({"a": 456}));
|
||||
|
||||
let v1_pdu = RoomV1Pdu {
|
||||
room_id: RoomId::try_from("!n8f893n9:example.com").unwrap(),
|
||||
event_id: EventId::try_from("$somejoinevent:matrix.org").unwrap(),
|
||||
sender: UserId::try_from("@sender:example.com").unwrap(),
|
||||
origin: "matrix.org".to_string(),
|
||||
origin_server_ts: SystemTime::UNIX_EPOCH + Duration::from_millis(1_592_050_773_658),
|
||||
kind: EventType::RoomPowerLevels,
|
||||
content: json!({"testing": 123}),
|
||||
state_key: Some("state".to_string()),
|
||||
prev_events: vec![(
|
||||
EventId::try_from("$previousevent:matrix.org").unwrap(),
|
||||
EventHash { sha256: "123567".to_string() },
|
||||
)],
|
||||
depth: 2_u32.into(),
|
||||
auth_events: vec![(
|
||||
EventId::try_from("$someauthevent:matrix.org").unwrap(),
|
||||
EventHash { sha256: "21389CFEDABC".to_string() },
|
||||
)],
|
||||
redacts: Some(EventId::try_from("$9654:matrix.org").unwrap()),
|
||||
unsigned,
|
||||
hashes: EventHash { sha256: "1233543bABACDEF".to_string() },
|
||||
signatures,
|
||||
};
|
||||
let pdu = Pdu::RoomV1Pdu(v1_pdu);
|
||||
let json = json!({
|
||||
"room_id": "!n8f893n9:example.com",
|
||||
"event_id": "$somejoinevent:matrix.org",
|
||||
"sender": "@sender:example.com",
|
||||
"origin": "matrix.org",
|
||||
"origin_server_ts": 1_592_050_773_658 as usize,
|
||||
"type": "m.room.power_levels",
|
||||
"content": {
|
||||
"testing": 123
|
||||
},
|
||||
"state_key": "state",
|
||||
"prev_events": [
|
||||
[ "$previousevent:matrix.org", {"sha256": "123567"} ]
|
||||
],
|
||||
"depth": 2,
|
||||
"auth_events": [
|
||||
["$someauthevent:matrix.org", {"sha256": "21389CFEDABC"}]
|
||||
],
|
||||
"redacts": "$9654:matrix.org",
|
||||
"unsigned": {
|
||||
"somekey": { "a": 456 } },
|
||||
"hashes": { "sha256": "1233543bABACDEF" },
|
||||
"signatures": {
|
||||
"example.com": { "ed25519:key_version":"86BytesOfSignatureOfTheRedactedEvent" }
|
||||
}
|
||||
});
|
||||
|
||||
assert_eq!(to_json_value(&pdu).unwrap(), json);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_pdu_as_v3() {
|
||||
let mut signatures = BTreeMap::new();
|
||||
let mut inner_signature = BTreeMap::new();
|
||||
inner_signature.insert(
|
||||
"ed25519:key_version".to_string(),
|
||||
"86BytesOfSignatureOfTheRedactedEvent".to_string(),
|
||||
);
|
||||
signatures.insert("example.com".to_string(), inner_signature);
|
||||
|
||||
let mut unsigned = BTreeMap::new();
|
||||
unsigned.insert("somekey".to_string(), json!({"a": 456}));
|
||||
|
||||
let v3_pdu = RoomV3Pdu {
|
||||
room_id: RoomId::try_from("!n8f893n9:example.com").unwrap(),
|
||||
sender: UserId::try_from("@sender:example.com").unwrap(),
|
||||
origin: "matrix.org".to_string(),
|
||||
origin_server_ts: SystemTime::UNIX_EPOCH + Duration::from_millis(1_592_050_773_658),
|
||||
kind: EventType::RoomPowerLevels,
|
||||
content: json!({"testing": 123}),
|
||||
state_key: Some("state".to_string()),
|
||||
prev_events: vec![EventId::try_from("$previousevent:matrix.org").unwrap()],
|
||||
depth: 2_u32.into(),
|
||||
auth_events: vec![EventId::try_from("$someauthevent:matrix.org").unwrap()],
|
||||
redacts: Some(EventId::try_from("$9654:matrix.org").unwrap()),
|
||||
unsigned,
|
||||
hashes: EventHash { sha256: "1233543bABACDEF".to_string() },
|
||||
signatures,
|
||||
};
|
||||
let pdu_stub = Pdu::RoomV3Pdu(v3_pdu);
|
||||
let json = json!({
|
||||
"room_id": "!n8f893n9:example.com",
|
||||
"sender": "@sender:example.com",
|
||||
"origin": "matrix.org",
|
||||
"origin_server_ts": 1_592_050_773_658 as usize,
|
||||
"type": "m.room.power_levels",
|
||||
"content": {
|
||||
"testing": 123
|
||||
},
|
||||
"state_key": "state",
|
||||
"prev_events": [ "$previousevent:matrix.org" ],
|
||||
"depth": 2,
|
||||
"auth_events": ["$someauthevent:matrix.org" ],
|
||||
"redacts": "$9654:matrix.org",
|
||||
"unsigned": {
|
||||
"somekey": { "a": 456 } },
|
||||
"hashes": { "sha256": "1233543bABACDEF" },
|
||||
"signatures": {
|
||||
"example.com": { "ed25519:key_version":"86BytesOfSignatureOfTheRedactedEvent" }
|
||||
}
|
||||
});
|
||||
|
||||
assert_eq!(to_json_value(&pdu_stub).unwrap(), json);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_pdu_as_v1() {
|
||||
let json = json!({
|
||||
"room_id": "!n8f893n9:example.com",
|
||||
"event_id": "$somejoinevent:matrix.org",
|
||||
"auth_events": [
|
||||
[
|
||||
"$abc123:matrix.org",
|
||||
{
|
||||
"sha256": "Base64EncodedSha256HashesShouldBe43BytesLong"
|
||||
}
|
||||
]
|
||||
],
|
||||
"content": {
|
||||
"key": "value"
|
||||
},
|
||||
"depth": 12,
|
||||
"event_id": "$a4ecee13e2accdadf56c1025:example.com",
|
||||
"hashes": {
|
||||
"sha256": "ThisHashCoversAllFieldsInCaseThisIsRedacted"
|
||||
},
|
||||
"origin": "matrix.org",
|
||||
"origin_server_ts": 1_234_567_890,
|
||||
"prev_events": [
|
||||
[
|
||||
"$abc123:matrix.org",
|
||||
{
|
||||
"sha256": "Base64EncodedSha256HashesShouldBe43BytesLong"
|
||||
}
|
||||
]
|
||||
],
|
||||
"redacts": "$def456:matrix.org",
|
||||
"room_id": "!abc123:matrix.org",
|
||||
"sender": "@someone:matrix.org",
|
||||
"signatures": {
|
||||
"example.com": {
|
||||
"ed25519:key_version:": "86BytesOfSignatureOfTheRedactedEvent"
|
||||
}
|
||||
},
|
||||
"state_key": "my_key",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"key": "value"
|
||||
}
|
||||
});
|
||||
let parsed = from_json_value::<Pdu>(json).unwrap();
|
||||
|
||||
match parsed {
|
||||
Pdu::RoomV1Pdu(v1_pdu) => {
|
||||
assert_eq!(
|
||||
v1_pdu.auth_events.first().unwrap().0,
|
||||
EventId::try_from("$abc123:matrix.org").unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
v1_pdu.auth_events.first().unwrap().1.sha256,
|
||||
"Base64EncodedSha256HashesShouldBe43BytesLong"
|
||||
);
|
||||
}
|
||||
Pdu::RoomV3Pdu(_) => panic!("Matched V3 PDU"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_pdu_as_v3() {
|
||||
let json = json!({
|
||||
"room_id": "!n8f893n9:example.com",
|
||||
"auth_events": [
|
||||
"$abc123:matrix.org"
|
||||
],
|
||||
"content": {
|
||||
"key": "value"
|
||||
},
|
||||
"depth": 12,
|
||||
"event_id": "$a4ecee13e2accdadf56c1025:example.com",
|
||||
"hashes": {
|
||||
"sha256": "ThisHashCoversAllFieldsInCaseThisIsRedacted"
|
||||
},
|
||||
"origin": "matrix.org",
|
||||
"origin_server_ts": 1_234_567_890,
|
||||
"prev_events": [
|
||||
"$abc123:matrix.org"
|
||||
],
|
||||
"redacts": "$def456:matrix.org",
|
||||
"room_id": "!abc123:matrix.org",
|
||||
"sender": "@someone:matrix.org",
|
||||
"signatures": {
|
||||
"example.com": {
|
||||
"ed25519:key_version:": "86BytesOfSignatureOfTheRedactedEvent"
|
||||
}
|
||||
},
|
||||
"state_key": "my_key",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"key": "value"
|
||||
}
|
||||
});
|
||||
let parsed = from_json_value::<Pdu>(json).unwrap();
|
||||
|
||||
match parsed {
|
||||
Pdu::RoomV1Pdu(_) => panic!("Matched V1 PDU"),
|
||||
Pdu::RoomV3Pdu(v3_pdu) => {
|
||||
assert_eq!(
|
||||
v3_pdu.auth_events.first().unwrap(),
|
||||
&EventId::try_from("$abc123:matrix.org").unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_v1_stub_to_pdu() {
|
||||
let mut signatures = BTreeMap::new();
|
||||
let mut inner_signature = BTreeMap::new();
|
||||
inner_signature.insert(
|
||||
"ed25519:key_version".to_string(),
|
||||
"86BytesOfSignatureOfTheRedactedEvent".to_string(),
|
||||
);
|
||||
signatures.insert("example.com".to_string(), inner_signature);
|
||||
|
||||
let mut unsigned = BTreeMap::new();
|
||||
unsigned.insert("somekey".to_string(), json!({"a": 456}));
|
||||
|
||||
let v1_stub = RoomV1PduStub {
|
||||
sender: UserId::try_from("@sender:example.com").unwrap(),
|
||||
origin: "matrix.org".to_string(),
|
||||
origin_server_ts: SystemTime::UNIX_EPOCH + Duration::from_millis(1_592_050_773_658),
|
||||
kind: EventType::RoomPowerLevels,
|
||||
content: json!({"testing": 123}),
|
||||
state_key: Some("state".to_string()),
|
||||
prev_events: vec![(
|
||||
EventId::try_from("$previousevent:matrix.org").unwrap(),
|
||||
EventHash { sha256: "123567".to_string() },
|
||||
)],
|
||||
depth: 2_u32.into(),
|
||||
auth_events: vec![(
|
||||
EventId::try_from("$someauthevent:matrix.org").unwrap(),
|
||||
EventHash { sha256: "21389CFEDABC".to_string() },
|
||||
)],
|
||||
redacts: Some(EventId::try_from("$9654:matrix.org").unwrap()),
|
||||
unsigned: (&unsigned).clone(),
|
||||
hashes: EventHash { sha256: "1233543bABACDEF".to_string() },
|
||||
signatures: (&signatures).clone(),
|
||||
};
|
||||
|
||||
assert_matches!(
|
||||
v1_stub.into_v1_pdu(
|
||||
RoomId::try_from("!n8f893n9:example.com").unwrap(),
|
||||
EventId::try_from("$somejoinevent:matrix.org").unwrap()
|
||||
),
|
||||
RoomV1Pdu {
|
||||
room_id,
|
||||
event_id,
|
||||
sender,
|
||||
origin,
|
||||
origin_server_ts,
|
||||
kind,
|
||||
content,
|
||||
state_key,
|
||||
prev_events,
|
||||
depth,
|
||||
auth_events,
|
||||
redacts,
|
||||
unsigned,
|
||||
hashes: EventHash { sha256 },
|
||||
signatures,
|
||||
} if room_id == RoomId::try_from("!n8f893n9:example.com").unwrap()
|
||||
&& event_id == EventId::try_from("$somejoinevent:matrix.org").unwrap()
|
||||
&& sender == UserId::try_from("@sender:example.com").unwrap()
|
||||
&& origin == "matrix.org"
|
||||
&& origin_server_ts == SystemTime::UNIX_EPOCH + Duration::from_millis(1_592_050_773_658)
|
||||
&& kind == EventType::RoomPowerLevels
|
||||
&& content == json!({"testing": 123})
|
||||
&& state_key == Some("state".to_string())
|
||||
&& prev_events[0].0 == EventId::try_from("$previousevent:matrix.org").unwrap()
|
||||
&& prev_events[0].1.sha256 == "123567"
|
||||
&& depth == 2_u32.into()
|
||||
&& auth_events.first().unwrap().0 == EventId::try_from("$someauthevent:matrix.org").unwrap()
|
||||
&& auth_events.first().unwrap().1.sha256 == "21389CFEDABC"
|
||||
&& redacts == Some(EventId::try_from("$9654:matrix.org").unwrap())
|
||||
&& unsigned == (&unsigned).clone()
|
||||
&& sha256 == "1233543bABACDEF"
|
||||
&& signatures == (&signatures).clone()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_v3_stub_to_pdu() {
|
||||
let mut signatures = BTreeMap::new();
|
||||
let mut inner_signature = BTreeMap::new();
|
||||
inner_signature.insert(
|
||||
"ed25519:key_version".to_string(),
|
||||
"86BytesOfSignatureOfTheRedactedEvent".to_string(),
|
||||
);
|
||||
signatures.insert("example.com".to_string(), inner_signature);
|
||||
|
||||
let mut unsigned = BTreeMap::new();
|
||||
unsigned.insert("somekey".to_string(), json!({"a": 456}));
|
||||
|
||||
let v3_stub = RoomV3PduStub {
|
||||
sender: UserId::try_from("@sender:example.com").unwrap(),
|
||||
origin: "matrix.org".to_string(),
|
||||
origin_server_ts: SystemTime::UNIX_EPOCH + Duration::from_millis(1_592_050_773_658),
|
||||
kind: EventType::RoomPowerLevels,
|
||||
content: json!({"testing": 123}),
|
||||
state_key: Some("state".to_string()),
|
||||
prev_events: vec![EventId::try_from("$previousevent:matrix.org").unwrap()],
|
||||
depth: 2_u32.into(),
|
||||
auth_events: vec![EventId::try_from("$someauthevent:matrix.org").unwrap()],
|
||||
redacts: Some(EventId::try_from("$9654:matrix.org").unwrap()),
|
||||
unsigned: (&unsigned).clone(),
|
||||
hashes: EventHash { sha256: "1233543bABACDEF".to_string() },
|
||||
signatures: (&signatures).clone(),
|
||||
};
|
||||
|
||||
assert_matches!(
|
||||
v3_stub.into_v3_pdu(RoomId::try_from("!n8f893n9:example.com").unwrap()),
|
||||
RoomV3Pdu {
|
||||
room_id,
|
||||
sender,
|
||||
origin,
|
||||
origin_server_ts,
|
||||
kind,
|
||||
content,
|
||||
state_key,
|
||||
prev_events,
|
||||
depth,
|
||||
auth_events,
|
||||
redacts,
|
||||
unsigned,
|
||||
hashes: EventHash { sha256 },
|
||||
signatures,
|
||||
} if room_id == RoomId::try_from("!n8f893n9:example.com").unwrap()
|
||||
&& sender == UserId::try_from("@sender:example.com").unwrap()
|
||||
&& origin == "matrix.org"
|
||||
&& origin_server_ts == SystemTime::UNIX_EPOCH + Duration::from_millis(1_592_050_773_658)
|
||||
&& kind == EventType::RoomPowerLevels
|
||||
&& content == json!({"testing": 123})
|
||||
&& state_key == Some("state".to_string())
|
||||
&& prev_events == vec![EventId::try_from("$previousevent:matrix.org").unwrap()]
|
||||
&& depth == 2_u32.into()
|
||||
&& auth_events == vec![EventId::try_from("$someauthevent:matrix.org").unwrap()]
|
||||
&& redacts == Some(EventId::try_from("$9654:matrix.org").unwrap())
|
||||
&& unsigned == (&unsigned).clone()
|
||||
&& sha256 == "1233543bABACDEF"
|
||||
&& signatures == (&signatures).clone()
|
||||
);
|
||||
}
|
@ -1,5 +1,9 @@
|
||||
# [unreleased]
|
||||
|
||||
Breaking Changes:
|
||||
|
||||
* Replace `RoomV3Pdu` with `ruma_events::pdu::{Pdu, PduStub}`.
|
||||
|
||||
Improvements:
|
||||
|
||||
* Add endpoints:
|
||||
@ -15,6 +19,7 @@ Improvements:
|
||||
create_join_event_template::v1
|
||||
},
|
||||
query::get_room_information::v1,
|
||||
transactions::send_transaction_message::v1,
|
||||
version::get_server_version::v1
|
||||
```
|
||||
|
||||
|
@ -2,69 +2,10 @@
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
use std::{collections::BTreeMap, time::SystemTime};
|
||||
|
||||
use ::serde::{Deserialize, Serialize};
|
||||
use js_int::UInt;
|
||||
use ruma_events::EventType;
|
||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
mod serde;
|
||||
|
||||
pub mod directory;
|
||||
pub mod discovery;
|
||||
pub mod membership;
|
||||
pub mod query;
|
||||
|
||||
/// A 'persistent data unit' (event) for room versions 3 and beyond.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct RoomV3Pdu {
|
||||
/// The room this event belongs to.
|
||||
pub room_id: RoomId,
|
||||
/// The user id of the user who sent this event.
|
||||
pub sender: UserId,
|
||||
/// The `server_name` of the homeserver that created this event.
|
||||
pub origin: String,
|
||||
/// Timestamp (milliseconds since the UNIX epoch) on originating homeserver
|
||||
/// of when this event was created.
|
||||
#[serde(with = "ruma_serde::time::ms_since_unix_epoch")]
|
||||
pub origin_server_ts: SystemTime,
|
||||
|
||||
// TODO: Replace with event content collection from ruma-events once that exists
|
||||
/// The event's type.
|
||||
#[serde(rename = "type")]
|
||||
pub kind: EventType,
|
||||
/// The event's content.
|
||||
pub content: JsonValue,
|
||||
|
||||
/// A key that determines which piece of room state the event represents.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub state_key: Option<String>,
|
||||
/// Event IDs for the most recent events in the room that the homeserver was
|
||||
/// aware of when it created this event.
|
||||
pub prev_events: Vec<EventId>,
|
||||
/// The maximum depth of the `prev_events`, plus one.
|
||||
pub depth: UInt,
|
||||
/// Event IDs for the authorization events that would allow this event to be
|
||||
/// in the room.
|
||||
pub auth_events: Vec<EventId>,
|
||||
/// For redaction events, the ID of the event being redacted.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub redacts: Option<EventId>,
|
||||
/// Additional data added by the origin server but not covered by the
|
||||
/// signatures.
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub unsigned: BTreeMap<String, JsonValue>,
|
||||
/// Content hashes of the PDU.
|
||||
pub hashes: EventHash,
|
||||
/// Signatures for the PDU.
|
||||
pub signatures: BTreeMap<String, BTreeMap<String, String>>,
|
||||
}
|
||||
|
||||
/// Content hashes of a PDU.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct EventHash {
|
||||
/// The SHA-256 hash.
|
||||
pub sha256: String,
|
||||
}
|
||||
pub mod transactions;
|
||||
|
@ -2,11 +2,9 @@
|
||||
|
||||
pub mod v1;
|
||||
|
||||
use ruma_events::EventJson;
|
||||
use ruma_events::{pdu::Pdu, EventJson};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::RoomV3Pdu;
|
||||
|
||||
/// Full state of the room.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct RoomState {
|
||||
@ -14,7 +12,7 @@ pub struct RoomState {
|
||||
pub origin: String,
|
||||
/// The full set of authorization events that make up the state of the room,
|
||||
/// and their authorization events, recursively.
|
||||
pub auth_chain: Vec<EventJson<RoomV3Pdu>>,
|
||||
pub auth_chain: Vec<EventJson<Pdu>>,
|
||||
/// The room state.
|
||||
pub state: Vec<EventJson<RoomV3Pdu>>,
|
||||
pub state: Vec<EventJson<Pdu>>,
|
||||
}
|
||||
|
@ -1,15 +1,10 @@
|
||||
//! [PUT /_matrix/federation/v1/send_join/{roomId}/{eventId}](https://matrix.org/docs/spec/server_server/r0.1.3#put-matrix-federation-v1-send-join-roomid-eventid)
|
||||
|
||||
use std::{collections::BTreeMap, time::SystemTime};
|
||||
|
||||
use js_int::UInt;
|
||||
use ruma_api::ruma_api;
|
||||
use ruma_events::EventType;
|
||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||
use serde_json::Value as JsonValue;
|
||||
use ruma_events::pdu::PduStub;
|
||||
use ruma_identifiers::{EventId, RoomId};
|
||||
|
||||
use super::RoomState;
|
||||
use crate::{EventHash, RoomV3Pdu};
|
||||
|
||||
ruma_api! {
|
||||
metadata {
|
||||
@ -29,44 +24,9 @@ ruma_api! {
|
||||
#[ruma_api(path)]
|
||||
pub event_id: EventId,
|
||||
|
||||
/// The user id of the user who sent this event.
|
||||
pub sender: UserId,
|
||||
/// The `server_name` of the homeserver that created this event.
|
||||
pub origin: String,
|
||||
/// Timestamp (milliseconds since the UNIX epoch) on originating homeserver
|
||||
/// of when this event was created.
|
||||
#[serde(with = "ruma_serde::time::ms_since_unix_epoch")]
|
||||
pub origin_server_ts: SystemTime,
|
||||
|
||||
// TODO: Replace with event content collection from ruma-events once that exists
|
||||
/// The event's type.
|
||||
#[serde(rename = "type")]
|
||||
pub kind: EventType,
|
||||
/// The event's content.
|
||||
pub content: JsonValue,
|
||||
|
||||
/// A key that determines which piece of room state the event represents.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub state_key: Option<String>,
|
||||
/// Event IDs for the most recent events in the room that the homeserver was
|
||||
/// aware of when it created this event.
|
||||
pub prev_events: Vec<EventId>,
|
||||
/// The maximum depth of the `prev_events`, plus one.
|
||||
pub depth: UInt,
|
||||
/// Event IDs for the authorization events that would allow this event to be
|
||||
/// in the room.
|
||||
pub auth_events: Vec<EventId>,
|
||||
/// For redaction events, the ID of the event being redacted.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub redacts: Option<EventId>,
|
||||
/// Additional data added by the origin server but not covered by the
|
||||
/// signatures.
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub unsigned: BTreeMap<String, JsonValue>,
|
||||
/// Content hashes of the PDU.
|
||||
pub hashes: EventHash,
|
||||
/// Signatures for the PDU.
|
||||
pub signatures: BTreeMap<String, BTreeMap<String, String>>,
|
||||
/// PDU type without event and room IDs.
|
||||
#[ruma_api(body)]
|
||||
pub pdu_stub: PduStub,
|
||||
}
|
||||
|
||||
response {
|
||||
@ -76,29 +36,3 @@ ruma_api! {
|
||||
pub room_state: RoomState,
|
||||
}
|
||||
}
|
||||
|
||||
impl Request {
|
||||
/// Helper method to get event ID and PDU (with room ID) from the request
|
||||
/// parameters.
|
||||
pub fn into_id_and_v3_pdu(self) -> (EventId, RoomV3Pdu) {
|
||||
(
|
||||
self.event_id,
|
||||
RoomV3Pdu {
|
||||
room_id: self.room_id,
|
||||
sender: self.sender,
|
||||
origin: self.origin,
|
||||
origin_server_ts: self.origin_server_ts,
|
||||
kind: self.kind,
|
||||
content: self.content,
|
||||
state_key: self.state_key,
|
||||
prev_events: self.prev_events,
|
||||
depth: self.depth,
|
||||
auth_events: self.auth_events,
|
||||
redacts: self.redacts,
|
||||
unsigned: self.unsigned,
|
||||
hashes: self.hashes,
|
||||
signatures: self.signatures,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,9 @@
|
||||
|
||||
use js_int::UInt;
|
||||
use ruma_api::ruma_api;
|
||||
use ruma_events::EventJson;
|
||||
use ruma_events::{pdu::Pdu, EventJson};
|
||||
use ruma_identifiers::{RoomId, UserId};
|
||||
|
||||
use crate::RoomV3Pdu;
|
||||
|
||||
ruma_api! {
|
||||
metadata {
|
||||
description: "Send a request for a join event template to a resident server.",
|
||||
@ -34,6 +32,6 @@ ruma_api! {
|
||||
/// The version of the room where the server is trying to join.
|
||||
pub room_version: Option<UInt>,
|
||||
/// An unsigned template event.
|
||||
pub event: EventJson<RoomV3Pdu>,
|
||||
pub event: EventJson<Pdu>,
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
//! Modules for custom serde de/-serialization implementations.
|
||||
|
||||
pub mod pdu_process_response;
|
||||
pub mod room_state;
|
||||
|
156
ruma-federation-api/src/serde/pdu_process_response.rs
Normal file
156
ruma-federation-api/src/serde/pdu_process_response.rs
Normal file
@ -0,0 +1,156 @@
|
||||
use std::{collections::BTreeMap, fmt};
|
||||
|
||||
use ruma_identifiers::EventId;
|
||||
use serde::{
|
||||
de::{Deserializer, MapAccess, Visitor},
|
||||
ser::{SerializeMap, Serializer},
|
||||
Deserialize, Serialize,
|
||||
};
|
||||
|
||||
pub fn serialize<S>(
|
||||
response: &BTreeMap<EventId, Result<(), String>>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut map = serializer.serialize_map(Some(response.len()))?;
|
||||
for (key, value) in response {
|
||||
let wrapped_error = WrappedError {
|
||||
error: match value {
|
||||
Ok(_) => None,
|
||||
Err(error) => Some(error.clone()),
|
||||
},
|
||||
};
|
||||
map.serialize_entry(&key, &wrapped_error)?;
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<BTreeMap<EventId, Result<(), String>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_map(PduProcessResponseVisitor)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct WrappedError {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
error: Option<String>,
|
||||
}
|
||||
|
||||
struct PduProcessResponseVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for PduProcessResponseVisitor {
|
||||
type Value = BTreeMap<EventId, Result<(), String>>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("A map of EventIds to a map of optional errors")
|
||||
}
|
||||
|
||||
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
let mut map = BTreeMap::new();
|
||||
|
||||
while let Some((key, value)) = access.next_entry::<EventId, WrappedError>()? {
|
||||
let v = match value.error {
|
||||
None => Ok(()),
|
||||
Some(error) => Err(error),
|
||||
};
|
||||
map.insert(key, v);
|
||||
}
|
||||
Ok(map)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{collections::BTreeMap, convert::TryFrom};
|
||||
|
||||
use ruma_identifiers::EventId;
|
||||
use serde_json::{json, value::Serializer as JsonSerializer};
|
||||
|
||||
use super::{deserialize, serialize};
|
||||
|
||||
#[test]
|
||||
fn serialize_error() {
|
||||
let mut response: BTreeMap<EventId, Result<(), String>> = BTreeMap::new();
|
||||
response.insert(
|
||||
EventId::try_from("$someevent:matrix.org").unwrap(),
|
||||
Err("Some processing error.".into()),
|
||||
);
|
||||
|
||||
let serialized = serialize(&response, JsonSerializer).unwrap();
|
||||
let json = json!({
|
||||
"$someevent:matrix.org": { "error": "Some processing error." }
|
||||
});
|
||||
assert_eq!(serialized, json);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_ok() {
|
||||
let mut response: BTreeMap<EventId, Result<(), String>> = BTreeMap::new();
|
||||
response.insert(EventId::try_from("$someevent:matrix.org").unwrap(), Ok(()));
|
||||
|
||||
let serialized = serialize(&response, serde_json::value::Serializer).unwrap();
|
||||
let json = json!({
|
||||
"$someevent:matrix.org": {}
|
||||
});
|
||||
assert_eq!(serialized, json);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_error() {
|
||||
let json = json!({
|
||||
"$someevent:matrix.org": { "error": "Some processing error." }
|
||||
});
|
||||
|
||||
let response = deserialize(json).unwrap();
|
||||
let event_id = EventId::try_from("$someevent:matrix.org").unwrap();
|
||||
|
||||
let event_response = response.get(&event_id).unwrap().clone().unwrap_err();
|
||||
assert_eq!(event_response, "Some processing error.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_null_error_is_ok() {
|
||||
let json = json!({
|
||||
"$someevent:matrix.org": { "error": null }
|
||||
});
|
||||
|
||||
let response = deserialize(json).unwrap();
|
||||
let event_id = EventId::try_from("$someevent:matrix.org").unwrap();
|
||||
|
||||
assert!(response.get(&event_id).unwrap().is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desieralize_empty_error_is_err() {
|
||||
let json = json!({
|
||||
"$someevent:matrix.org": { "error": "" }
|
||||
});
|
||||
|
||||
let response = deserialize(json).unwrap();
|
||||
let event_id = EventId::try_from("$someevent:matrix.org").unwrap();
|
||||
|
||||
let event_response = response.get(&event_id).unwrap().clone().unwrap_err();
|
||||
assert_eq!(event_response, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_ok() {
|
||||
let json = json!({
|
||||
"$someevent:matrix.org": {}
|
||||
});
|
||||
let response = deserialize(json).unwrap();
|
||||
assert!(response
|
||||
.get(&EventId::try_from("$someevent:matrix.org").unwrap())
|
||||
.unwrap()
|
||||
.is_ok());
|
||||
}
|
||||
}
|
3
ruma-federation-api/src/transactions.rs
Normal file
3
ruma-federation-api/src/transactions.rs
Normal file
@ -0,0 +1,3 @@
|
||||
//! Endpoints for exchanging transaction messages between homeservers.
|
||||
|
||||
pub mod send_transaction_message;
|
@ -0,0 +1,3 @@
|
||||
//! Endpoint to send live activity messages to another server.
|
||||
|
||||
pub mod v1;
|
@ -0,0 +1,59 @@
|
||||
//! [PUT /_matrix/federation/v1/send/{txnId}](https://matrix.org/docs/spec/server_server/r0.1.3#put-matrix-federation-v1-send-txnid)
|
||||
|
||||
use std::{collections::BTreeMap, time::SystemTime};
|
||||
|
||||
use ruma_api::ruma_api;
|
||||
use ruma_events::pdu::Pdu;
|
||||
use ruma_identifiers::EventId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
ruma_api! {
|
||||
metadata {
|
||||
description: "Send transaction messages to another server",
|
||||
name: "send_transaction_message",
|
||||
method: PUT,
|
||||
path: "/_matrix/federation/v1/send/:transaction_id",
|
||||
rate_limited: false,
|
||||
requires_authentication: true,
|
||||
}
|
||||
|
||||
request {
|
||||
/// A transaction ID unique between sending and receiving homeservers.
|
||||
#[ruma_api(path)]
|
||||
pub transaction_id: String,
|
||||
|
||||
/// The server_name of the homeserver sending this transaction.
|
||||
pub origin: String,
|
||||
|
||||
/// POSIX timestamp in milliseconds on the originating homeserver when this transaction started.
|
||||
#[serde(with = "ruma_serde::time::ms_since_unix_epoch")]
|
||||
pub origin_server_ts: SystemTime,
|
||||
|
||||
/// List of persistent updates to rooms.
|
||||
///
|
||||
/// Must not be more than 50 items.
|
||||
pub pdus: Vec<Pdu>,
|
||||
|
||||
/// List of ephemeral messages.
|
||||
///
|
||||
/// Must not be more than 100 items.
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub edus: Vec<Edu>,
|
||||
}
|
||||
|
||||
response {
|
||||
/// Map of event IDs and response for each PDU given in the request.
|
||||
#[serde(with = "crate::serde::pdu_process_response")]
|
||||
pub pdus: BTreeMap<EventId, Result<(), String>>,
|
||||
}
|
||||
}
|
||||
|
||||
/// Type for passing ephemeral data to homeservers.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Edu {
|
||||
/// Type of the ephemeral message.
|
||||
pub edu_type: String,
|
||||
/// Content of ephemeral message
|
||||
pub content: JsonValue,
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user