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 |   struct variants | ||||||
|   * This change removes the types `EventMatchCondition`, `RoomMemberCountCondition` and |   * This change removes the types `EventMatchCondition`, `RoomMemberCountCondition` and | ||||||
|     `SenderNotificationPermissionCondition` |     `SenderNotificationPermissionCondition` | ||||||
|  | * Add PDU types: `pdu::{Pdu, PduStub}` | ||||||
| 
 | 
 | ||||||
| Improvements: | Improvements: | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -147,6 +147,7 @@ pub mod forwarded_room_key; | |||||||
| pub mod fully_read; | pub mod fully_read; | ||||||
| pub mod ignored_user_list; | pub mod ignored_user_list; | ||||||
| pub mod key; | pub mod key; | ||||||
|  | pub mod pdu; | ||||||
| pub mod presence; | pub mod presence; | ||||||
| pub mod push_rules; | pub mod push_rules; | ||||||
| pub mod receipt; | 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] | # [unreleased] | ||||||
| 
 | 
 | ||||||
|  | Breaking Changes: | ||||||
|  | 
 | ||||||
|  | * Replace `RoomV3Pdu` with `ruma_events::pdu::{Pdu, PduStub}`. | ||||||
|  | 
 | ||||||
| Improvements: | Improvements: | ||||||
| 
 | 
 | ||||||
| * Add endpoints: | * Add endpoints: | ||||||
| @ -15,6 +19,7 @@ Improvements: | |||||||
|         create_join_event_template::v1 |         create_join_event_template::v1 | ||||||
|     }, |     }, | ||||||
|     query::get_room_information::v1, |     query::get_room_information::v1, | ||||||
|  |     transactions::send_transaction_message::v1, | ||||||
|     version::get_server_version::v1 |     version::get_server_version::v1 | ||||||
|   ``` |   ``` | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,69 +2,10 @@ | |||||||
| 
 | 
 | ||||||
| #![warn(missing_docs)] | #![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; | mod serde; | ||||||
| 
 | 
 | ||||||
| pub mod directory; | pub mod directory; | ||||||
| pub mod discovery; | pub mod discovery; | ||||||
| pub mod membership; | pub mod membership; | ||||||
| pub mod query; | pub mod query; | ||||||
| 
 | pub mod transactions; | ||||||
| /// 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, |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -2,11 +2,9 @@ | |||||||
| 
 | 
 | ||||||
| pub mod v1; | pub mod v1; | ||||||
| 
 | 
 | ||||||
| use ruma_events::EventJson; | use ruma_events::{pdu::Pdu, EventJson}; | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
| 
 | 
 | ||||||
| use crate::RoomV3Pdu; |  | ||||||
| 
 |  | ||||||
| /// Full state of the room.
 | /// Full state of the room.
 | ||||||
| #[derive(Clone, Debug, Deserialize, Serialize)] | #[derive(Clone, Debug, Deserialize, Serialize)] | ||||||
| pub struct RoomState { | pub struct RoomState { | ||||||
| @ -14,7 +12,7 @@ pub struct RoomState { | |||||||
|     pub origin: String, |     pub origin: String, | ||||||
|     /// The full set of authorization events that make up the state of the room,
 |     /// The full set of authorization events that make up the state of the room,
 | ||||||
|     /// and their authorization events, recursively.
 |     /// and their authorization events, recursively.
 | ||||||
|     pub auth_chain: Vec<EventJson<RoomV3Pdu>>, |     pub auth_chain: Vec<EventJson<Pdu>>, | ||||||
|     /// The room state.
 |     /// 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)
 | //! [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_api::ruma_api; | ||||||
| use ruma_events::EventType; | use ruma_events::pdu::PduStub; | ||||||
| use ruma_identifiers::{EventId, RoomId, UserId}; | use ruma_identifiers::{EventId, RoomId}; | ||||||
| use serde_json::Value as JsonValue; |  | ||||||
| 
 | 
 | ||||||
| use super::RoomState; | use super::RoomState; | ||||||
| use crate::{EventHash, RoomV3Pdu}; |  | ||||||
| 
 | 
 | ||||||
| ruma_api! { | ruma_api! { | ||||||
|     metadata { |     metadata { | ||||||
| @ -29,44 +24,9 @@ ruma_api! { | |||||||
|         #[ruma_api(path)] |         #[ruma_api(path)] | ||||||
|         pub event_id: EventId, |         pub event_id: EventId, | ||||||
| 
 | 
 | ||||||
|         /// The user id of the user who sent this event.
 |         /// PDU type without event and room IDs.
 | ||||||
|         pub sender: UserId, |         #[ruma_api(body)] | ||||||
|         /// The `server_name` of the homeserver that created this event.
 |         pub pdu_stub: PduStub, | ||||||
|         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>>, |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     response { |     response { | ||||||
| @ -76,29 +36,3 @@ ruma_api! { | |||||||
|         pub room_state: RoomState, |         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 js_int::UInt; | ||||||
| use ruma_api::ruma_api; | use ruma_api::ruma_api; | ||||||
| use ruma_events::EventJson; | use ruma_events::{pdu::Pdu, EventJson}; | ||||||
| use ruma_identifiers::{RoomId, UserId}; | use ruma_identifiers::{RoomId, UserId}; | ||||||
| 
 | 
 | ||||||
| use crate::RoomV3Pdu; |  | ||||||
| 
 |  | ||||||
| ruma_api! { | ruma_api! { | ||||||
|     metadata { |     metadata { | ||||||
|         description: "Send a request for a join event template to a resident server.", |         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.
 |         /// The version of the room where the server is trying to join.
 | ||||||
|         pub room_version: Option<UInt>, |         pub room_version: Option<UInt>, | ||||||
|         /// An unsigned template event.
 |         /// An unsigned template event.
 | ||||||
|         pub event: EventJson<RoomV3Pdu>, |         pub event: EventJson<Pdu>, | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
| //! Modules for custom serde de/-serialization implementations.
 | //! Modules for custom serde de/-serialization implementations.
 | ||||||
| 
 | 
 | ||||||
|  | pub mod pdu_process_response; | ||||||
| pub mod room_state; | 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