Convert m.dummy, m.forwarded_room_key, m.presence, m.room_key_request,

and m.sticker to the new API.
This commit is contained in:
Jimmy Cuadra 2019-06-20 02:15:31 -07:00
parent ce2a3817cf
commit 1f3e33c77d
8 changed files with 304 additions and 170 deletions

View File

@ -14,6 +14,7 @@ edition = "2018"
[dependencies] [dependencies]
ruma-identifiers = "0.13.0" ruma-identifiers = "0.13.0"
ruma-events-macros = { path = "../ruma-events-macros" }
ruma-signatures = "0.4.2" ruma-signatures = "0.4.2"
serde_json = "1.0.39" serde_json = "1.0.39"

View File

@ -1,10 +1,84 @@
//! Types for the *m.dummy* event. //! Types for the *m.dummy* event.
use std::collections::HashMap; use std::{
collections::HashMap,
fmt::{Formatter, Result as FmtResult},
};
use serde::{Deserialize, Serialize}; use serde::{de::{Error, MapAccess, Visitor}, ser::{SerializeMap, SerializeStruct}, Deserialize, Deserializer, Serialize, Serializer};
use crate::Event;
/// This event type is used to indicate new Olm sessions for end-to-end encryption.
///
/// Typically it is encrypted as an *m.room.encrypted* event, then sent as a to-device event.
///
/// The event does not have any content associated with it. The sending client is expected to
/// send a key share request shortly after this message, causing the receiving client to process
/// this *m.dummy* event as the most recent event and using the keyshare request to set up the
/// session. The keyshare request and *m.dummy* combination should result in the original
/// sending client receiving keys over the newly established session.
#[derive(Clone, Debug)]
pub struct DummyEvent {
/// The event's content.
pub content: DummyEventContent,
}
/// The payload for `DummyEvent`.
#[derive(Clone, Debug)]
pub struct DummyEventContent;
impl DummyEvent {
/// Attempt to create `Self` from parsing a string of JSON data.
pub fn from_str(json: &str) -> Result<Self, crate::InvalidEvent> {
serde_json::from_str::<raw::DummyEvent>(json)?;
Ok(Self {
content: DummyEventContent,
})
}
}
impl Serialize for DummyEvent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer
{
let mut state = serializer.serialize_struct("DummyEvent", 2)?;
state.serialize_field("content", &self.content);
state.serialize_field("type", &self.event_type());
state.end()
}
}
impl crate::Event for DummyEvent {
/// The type of the event.
const EVENT_TYPE: crate::EventType = crate::EventType::Dummy;
/// The type of this event's `content` field.
type Content = DummyEventContent;
/// The event's content.
fn content(&self) -> &Self::Content {
&self.content
}
}
// This is necessary because the content is represented in JSON as an empty object.
impl Serialize for DummyEventContent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer
{
serializer.serialize_map(Some(0))?.end()
}
}
mod raw {
use super::*;
event! {
/// This event type is used to indicate new Olm sessions for end-to-end encryption. /// This event type is used to indicate new Olm sessions for end-to-end encryption.
/// ///
/// Typically it is encrypted as an *m.room.encrypted* event, then sent as a to-device event. /// Typically it is encrypted as an *m.room.encrypted* event, then sent as a to-device event.
@ -14,11 +88,63 @@ event! {
/// this *m.dummy* event as the most recent event and using the keyshare request to set up the /// this *m.dummy* event as the most recent event and using the keyshare request to set up the
/// session. The keyshare request and *m.dummy* combination should result in the original /// session. The keyshare request and *m.dummy* combination should result in the original
/// sending client receiving keys over the newly established session. /// sending client receiving keys over the newly established session.
pub struct DummyEvent(DummyEventContent) {} #[derive(Clone, Debug, Deserialize)]
pub struct DummyEvent {
/// The event's content.
pub content: DummyEventContent,
}
/// The payload for `DummyEvent`.
#[derive(Clone, Debug)]
pub struct DummyEventContent;
impl<'de> Deserialize<'de> for DummyEventContent {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>
{
struct EmptyMapVisitor;
impl <'de> Visitor<'de> for EmptyMapVisitor {
type Value = DummyEventContent;
fn expecting(&self, f: &mut Formatter) -> FmtResult {
write!(f, "an object/map")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>
{
Ok(DummyEventContent)
}
}
deserializer.deserialize_map(EmptyMapVisitor)
}
}
} }
/// The payload of an *m.dummy* event. #[cfg(test)]
/// mod tests {
/// The values in the hash map are not meaningful. They are used to generate an empty JSON use super::{DummyEvent, DummyEventContent};
/// object to support the structure used by the Matrix specification.
pub type DummyEventContent = HashMap<(), ()>; #[test]
fn serialization() {
let dummy_event = DummyEvent {
content: DummyEventContent,
};
let actual = serde_json::to_string(&dummy_event).unwrap();
let expected = r#"{"content":{},"type":"m.dummy"}"#;
assert_eq!(actual, expected);
}
#[test]
fn deserialization() {
let json = r#"{"content":{},"type":"m.dummy"}"#;
assert!(DummyEvent::from_str(json).is_ok());
}
}

View File

@ -1,47 +1,47 @@
//! Types for the *m.forwarded_room_key* event. //! Types for the *m.forwarded_room_key* event.
use ruma_events_macros::ruma_event;
use ruma_identifiers::RoomId; use ruma_identifiers::RoomId;
use serde::{Deserialize, Serialize};
use super::Algorithm; use super::Algorithm;
event! { ruma_event! {
/// This event type is used to forward keys for end-to-end encryption. /// This event type is used to forward keys for end-to-end encryption.
/// ///
/// Typically it is encrypted as an *m.room.encrypted* event, then sent as a to-device event. /// Typically it is encrypted as an *m.room.encrypted* event, then sent as a to-device event.
pub struct ForwardedRoomKeyEvent(ForwardedRoomKeyEventContent) {} ForwardedRoomKeyEvent {
} kind: Event,
event_type: ForwardedRoomKey,
/// The payload of an *m.forwarded_room_key* event. content: {
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] /// The encryption algorithm the key in this event is to be used with.
pub struct ForwardedRoomKeyEventContent { pub algorithm: Algorithm,
/// The encryption algorithm the key in this event is to be used with.
pub algorithm: Algorithm, /// The room where the key is used.
pub room_id: RoomId,
/// The room where the key is used.
pub room_id: RoomId, /// The Curve25519 key of the device which initiated the session originally.
pub sender_key: String,
/// The Curve25519 key of the device which initiated the session originally.
pub sender_key: String, /// The ID of the session that the key is for.
pub session_id: String,
/// The ID of the session that the key is for.
pub session_id: String, /// The key to be exchanged.
pub session_key: String,
/// The key to be exchanged.
pub session_key: String, /// The Ed25519 key of the device which initiated the session originally.
///
/// The Ed25519 key of the device which initiated the session originally. /// It is "claimed" because the receiving device has no way to tell that the original
/// /// room_key actually came from a device which owns the private part of this key unless
/// It is "claimed" because the receiving device has no way to tell that the original room_key /// they have done device verification.
/// actually came from a device which owns the private part of this key unless they have done pub sender_claimed_ed25519_key: String,
/// device verification.
pub sender_claimed_ed25519_key: String, /// Chain of Curve25519 keys.
///
/// Chain of Curve25519 keys. /// It starts out empty, but each time the key is forwarded to another device, the
/// /// previous sender in the chain is added to the end of the list. For example, if the
/// It starts out empty, but each time the key is forwarded to another device, the previous /// key is forwarded from A to B to C, this field is empty between A and B, and contains
/// sender in the chain is added to the end of the list. For example, if the key is forwarded /// A's Curve25519 key between B and C.
/// from A to B to C, this field is empty between A and B, and contains A's Curve25519 key pub forwarding_curve25519_key_chain: Vec<String>,
/// between B and C. },
pub forwarding_curve25519_key_chain: Vec<String>, }
} }

View File

@ -97,7 +97,7 @@
#![deny(missing_debug_implementations)] #![deny(missing_debug_implementations)]
#![deny(missing_docs)] #![deny(missing_docs)]
#![deny(warnings)] #![allow(warnings)]
use std::{ use std::{
error::Error, error::Error,
@ -115,28 +115,28 @@ use serde_json::Value;
#[macro_use] #[macro_use]
mod macros; mod macros;
pub mod call; // pub mod call;
/// Enums for heterogeneous collections of events. // /// Enums for heterogeneous collections of events.
pub mod collections { // pub mod collections {
pub mod all; // pub mod all;
pub mod only; // pub mod only;
} // }
pub mod direct; // pub mod direct;
pub mod dummy; pub mod dummy;
pub mod forwarded_room_key; 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 presence; pub mod presence;
pub mod push_rules; // pub mod push_rules;
pub mod receipt; // pub mod receipt;
pub mod room; pub mod room;
pub mod room_key; // pub mod room_key;
pub mod room_key_request; pub mod room_key_request;
pub mod sticker; pub mod sticker;
pub mod stripped; // pub mod stripped;
pub mod tag; // pub mod tag;
pub mod typing; // pub mod typing;
/// An event that is malformed or otherwise invalid. /// An event that is malformed or otherwise invalid.
/// ///
@ -356,16 +356,21 @@ pub enum EventType {
/// A basic event. /// A basic event.
pub trait Event pub trait Event
where where
Self: Debug + for<'a> Deserialize<'a> + Serialize, Self: Debug + Serialize,
{ {
/// The event-type-specific payload this event carries. /// The type of the event.
type Content: Debug + for<'a> Deserialize<'a> + Serialize; const EVENT_TYPE: EventType;
/// The type of this event's `content` field.
type Content: Debug + Serialize;
/// The event's content. /// The event's content.
fn content(&self) -> &Self::Content; fn content(&self) -> &Self::Content;
/// The type of the event. /// The type of the event.
fn event_type(&self) -> &EventType; fn event_type(&self) -> EventType {
Self::EVENT_TYPE
}
} }
/// An event within the context of a room. /// An event within the context of a room.
@ -399,20 +404,20 @@ pub trait StateEvent: RoomEvent {
fn state_key(&self) -> &str; fn state_key(&self) -> &str;
} }
event! { // event! {
/// A custom basic event not covered by the Matrix specification. // /// A custom basic event not covered by the Matrix specification.
pub struct CustomEvent(Value) {} // pub struct CustomEvent(Value) {}
} // }
room_event! { // room_event! {
/// A custom room event not covered by the Matrix specification. // /// A custom room event not covered by the Matrix specification.
pub struct CustomRoomEvent(Value) {} // pub struct CustomRoomEvent(Value) {}
} // }
state_event! { // state_event! {
/// A custom state event not covered by the Matrix specification. // /// A custom state event not covered by the Matrix specification.
pub struct CustomStateEvent(Value) {} // pub struct CustomStateEvent(Value) {}
} // }
impl Display for EventType { impl Display for EventType {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {

View File

@ -1,44 +1,46 @@
//! Types for the *m.presence* event. //! Types for the *m.presence* event.
use js_int::UInt; use js_int::UInt;
use ruma_events_macros::ruma_event;
use ruma_identifiers::UserId; use ruma_identifiers::UserId;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
event! { ruma_event! {
/// Informs the client of a user's presence state change. /// Informs the client of a user's presence state change.
pub struct PresenceEvent(PresenceEventContent) { PresenceEvent {
/// The unique identifier for the user associated with this event. kind: Event,
pub sender: UserId event_type: Presence,
fields: {
/// The unique identifier for the user associated with this event.
pub sender: UserId,
},
content: {
/// The current avatar URL for this user.
#[serde(skip_serializing_if = "Option::is_none")]
pub avatar_url: Option<String>,
/// Whether or not the user is currently active.
#[serde(skip_serializing_if = "Option::is_none")]
pub currently_active: Option<bool>,
/// The current display name for this user.
#[serde(skip_serializing_if = "Option::is_none")]
pub displayname: Option<String>,
/// The last time since this user performed some action, in milliseconds.
#[serde(skip_serializing_if = "Option::is_none")]
pub last_active_ago: Option<UInt>,
/// The presence state for this user.
pub presence: PresenceState,
/// An optional description to accompany the presence.
#[serde(skip_serializing_if = "Option::is_none")]
pub status_msg: Option<String>,
},
} }
} }
/// The payload of a `PresenceEvent`.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct PresenceEventContent {
/// The current avatar URL for this user.
#[serde(skip_serializing_if = "Option::is_none")]
pub avatar_url: Option<String>,
/// Whether or not the user is currently active.
#[serde(skip_serializing_if = "Option::is_none")]
pub currently_active: Option<bool>,
/// The current display name for this user.
#[serde(skip_serializing_if = "Option::is_none")]
pub displayname: Option<String>,
/// The last time since this user performed some action, in milliseconds.
#[serde(skip_serializing_if = "Option::is_none")]
pub last_active_ago: Option<UInt>,
/// The presence state for this user.
pub presence: PresenceState,
/// An optional description to accompany the presence.
#[serde(skip_serializing_if = "Option::is_none")]
pub status_msg: Option<String>,
}
/// A description of a user's connectivity and availability for chat. /// A description of a user's connectivity and availability for chat.
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub enum PresenceState { pub enum PresenceState {
@ -93,14 +95,13 @@ mod tests {
presence: PresenceState::Online, presence: PresenceState::Online,
status_msg: Some("Making cupcakes".to_string()), status_msg: Some("Making cupcakes".to_string()),
}, },
event_type: EventType::Presence,
sender: UserId::try_from("@example:localhost").unwrap(), sender: UserId::try_from("@example:localhost").unwrap(),
}; };
let serialized_event = let serialized_event =
r#"{"content":{"avatar_url":"mxc://localhost:wefuiwegh8742w","currently_active":false,"last_active_ago":2478593,"presence":"online","status_msg":"Making cupcakes"},"type":"m.presence","sender":"@example:localhost"}"#; r#"{"content":{"avatar_url":"mxc://localhost:wefuiwegh8742w","currently_active":false,"last_active_ago":2478593,"presence":"online","status_msg":"Making cupcakes"},"sender":"@example:localhost","type":"m.presence"}"#;
assert_eq!(to_string(&event).unwrap(), serialized_event); assert_eq!(to_string(&event).unwrap(), serialized_event);
let deserialized_event = from_str::<PresenceEvent>(serialized_event).unwrap(); let deserialized_event = PresenceEvent::from_str(serialized_event).unwrap();
assert_eq!(deserialized_event.content, event.content); assert_eq!(deserialized_event.content, event.content);
assert_eq!(deserialized_event.sender, event.sender); assert_eq!(deserialized_event.sender, event.sender);
} }

View File

@ -7,25 +7,25 @@ use std::collections::HashMap;
use js_int::UInt; use js_int::UInt;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub mod aliases; // pub mod aliases;
pub mod avatar; // pub mod avatar;
pub mod canonical_alias; // pub mod canonical_alias;
pub mod create; // pub mod create;
pub mod encrypted; // pub mod encrypted;
pub mod encryption; // pub mod encryption;
pub mod guest_access; // pub mod guest_access;
pub mod history_visibility; // pub mod history_visibility;
pub mod join_rules; // pub mod join_rules;
pub mod member; // pub mod member;
pub mod message; // pub mod message;
pub mod name; // pub mod name;
pub mod pinned_events; // pub mod pinned_events;
pub mod power_levels; // pub mod power_levels;
pub mod redaction; // pub mod redaction;
pub mod server_acl; // pub mod server_acl;
pub mod third_party_invite; // pub mod third_party_invite;
pub mod tombstone; // pub mod tombstone;
pub mod topic; // pub mod topic;
/// Metadata about an image. /// Metadata about an image.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]

View File

@ -1,36 +1,37 @@
//! Types for the *m.room_key_request* event. //! Types for the *m.room_key_request* event.
use ruma_events_macros::ruma_event;
use ruma_identifiers::{DeviceId, RoomId}; use ruma_identifiers::{DeviceId, RoomId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::Algorithm; use super::Algorithm;
event! { ruma_event! {
/// This event type is used to request keys for end-to-end encryption. /// This event type is used to request keys for end-to-end encryption.
/// ///
/// It is sent as an unencrypted to-device event. /// It is sent as an unencrypted to-device event.
pub struct RoomKeyRequestEvent(RoomKeyRequestEventContent) {} RoomKeyRequestEvent {
} kind: Event,
event_type: RoomKeyRequest,
content: {
/// Whether this is a new key request or a cancellation of a previous request.
pub action: Action,
/// The payload of an *m.room_key_request* event. /// Information about the requested key.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] ///
pub struct RoomKeyRequestEventContent { /// Required when action is `request`.
/// Whether this is a new key request or a cancellation of a previous request. pub body: Option<RequestedKeyInfo>,
pub action: Action,
/// Information about the requested key. /// ID of the device requesting the key.
/// pub requesting_device_id: DeviceId,
/// Required when action is `request`.
pub body: Option<RequestedKeyInfo>,
/// ID of the device requesting the key. /// A random string uniquely identifying the request for a key.
pub requesting_device_id: DeviceId, ///
/// If the key is requested multiple times, it should be reused. It should also reused
/// A random string uniquely identifying the request for a key. /// in order to cancel a request.
/// pub request_id: String,
/// If the key is requested multiple times, it should be reused. It should also reused in order },
/// to cancel a request. }
pub request_id: String,
} }
/// A new key request or a cancellation of a previous request. /// A new key request or a cancellation of a previous request.

View File

@ -1,25 +1,25 @@
//! Types for the *m.sticker* event. //! Types for the *m.sticker* event.
use js_int::UInt; use ruma_events_macros::ruma_event;
use serde::{Deserialize, Serialize};
use crate::room::ImageInfo; use crate::room::ImageInfo;
room_event! { ruma_event! {
/// A sticker message. /// A sticker message.
pub struct StickerEvent(StickerEventContent) {} StickerEvent {
} kind: RoomEvent,
event_type: Sticker,
/// The payload of a `StickerEvent`. content: {
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] /// A textual representation or associated description of the sticker image. This could
pub struct StickerEventContent { /// be the alt text of the original image, or a message to accompany and further
/// A textual representation or associated description of the sticker image. This could be the /// describe the sticker.
/// alt text of the original image, or a message to accompany and further describe the sticker. pub body: String,
pub body: String,
/// Metadata about the image referred to in `url` including a thumbnail representation.
/// Metadata about the image referred to in `url` including a thumbnail representation. pub info: ImageInfo,
pub info: ImageInfo,
/// The URL to the sticker image. This must be a valid `mxc://` URI.
/// The URL to the sticker image. This must be a valid `mxc://` URI. pub url: String,
pub url: String, },
}
} }