Implement MessageEvent and AnyMessageEventContent
This commit is contained in:
parent
24f720d1f1
commit
33ac5267a9
@ -6,6 +6,20 @@ use syn::{Ident, LitStr};
|
|||||||
|
|
||||||
use parse::RumaCollectionInput;
|
use parse::RumaCollectionInput;
|
||||||
|
|
||||||
|
fn marker_traits(ident: &Ident) -> TokenStream {
|
||||||
|
match ident.to_string().as_str() {
|
||||||
|
"AnyStateEventContent" => quote! {
|
||||||
|
impl ::ruma_events::RoomEventContent for #ident {}
|
||||||
|
impl ::ruma_events::StateEventContent for #ident {}
|
||||||
|
},
|
||||||
|
"AnyMessageEventContent" => quote! {
|
||||||
|
impl ::ruma_events::RoomEventContent for #ident {}
|
||||||
|
impl ::ruma_events::MessageEventContent for #ident {}
|
||||||
|
},
|
||||||
|
_ => TokenStream::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a collection from `RumaCollectionInput.
|
/// Create a collection from `RumaCollectionInput.
|
||||||
pub fn expand_collection(input: RumaCollectionInput) -> syn::Result<TokenStream> {
|
pub fn expand_collection(input: RumaCollectionInput) -> syn::Result<TokenStream> {
|
||||||
let attrs = &input.attrs;
|
let attrs = &input.attrs;
|
||||||
@ -36,7 +50,7 @@ pub fn expand_collection(input: RumaCollectionInput) -> syn::Result<TokenStream>
|
|||||||
impl ::ruma_events::EventContent for #ident {
|
impl ::ruma_events::EventContent for #ident {
|
||||||
fn event_type(&self) -> &str {
|
fn event_type(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
#( Self::#variants(content) => content.event_type()),*
|
#( Self::#variants(content) => content.event_type() ),*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,6 +77,8 @@ pub fn expand_collection(input: RumaCollectionInput) -> syn::Result<TokenStream>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let marker_trait_impls = marker_traits(ident);
|
||||||
|
|
||||||
let raw_mod = expand_raw_content_event(&input, &variants)?;
|
let raw_mod = expand_raw_content_event(&input, &variants)?;
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
@ -72,9 +88,7 @@ pub fn expand_collection(input: RumaCollectionInput) -> syn::Result<TokenStream>
|
|||||||
|
|
||||||
#event_content_impl
|
#event_content_impl
|
||||||
|
|
||||||
impl RoomEventContent for AnyStateEventContent {}
|
#marker_trait_impls
|
||||||
|
|
||||||
impl StateEventContent for AnyStateEventContent {}
|
|
||||||
|
|
||||||
#raw_mod
|
#raw_mod
|
||||||
})
|
})
|
||||||
@ -139,17 +153,18 @@ fn to_event_content_path(
|
|||||||
|
|
||||||
assert_eq!(&name[..2], "m.");
|
assert_eq!(&name[..2], "m.");
|
||||||
|
|
||||||
let event_str = name[2..].split('.').last().unwrap();
|
let path = name[2..].split('.').collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let event_str = path.last().unwrap();
|
||||||
let event = event_str
|
let event = event_str
|
||||||
.split('_')
|
.split('_')
|
||||||
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
|
|
||||||
let module = Ident::new(event_str, span);
|
|
||||||
let content_str = Ident::new(&format!("{}EventContent", event), span);
|
let content_str = Ident::new(&format!("{}EventContent", event), span);
|
||||||
|
let path = path.iter().map(|s| Ident::new(s, span));
|
||||||
syn::parse_quote! {
|
syn::parse_quote! {
|
||||||
::ruma_events::room::#module::#content_str
|
::ruma_events::#( #path )::*::#content_str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,17 +176,18 @@ fn to_raw_event_content_path(
|
|||||||
|
|
||||||
assert_eq!(&name[..2], "m.");
|
assert_eq!(&name[..2], "m.");
|
||||||
|
|
||||||
let event_str = name[2..].split('.').last().unwrap();
|
let path = name[2..].split('.').collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let event_str = path.last().unwrap();
|
||||||
let event = event_str
|
let event = event_str
|
||||||
.split('_')
|
.split('_')
|
||||||
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
|
|
||||||
let module = Ident::new(event_str, span);
|
|
||||||
let content_str = Ident::new(&format!("{}EventContent", event), span);
|
let content_str = Ident::new(&format!("{}EventContent", event), span);
|
||||||
|
let path = path.iter().map(|s| Ident::new(s, span));
|
||||||
syn::parse_quote! {
|
syn::parse_quote! {
|
||||||
::ruma_events::room::#module::raw::#content_str
|
::ruma_events::#( #path )::*::raw::#content_str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use super::SessionDescription;
|
|||||||
/// This event is sent by the callee when they wish to answer the call.
|
/// This event is sent by the callee when they wish to answer the call.
|
||||||
#[derive(Clone, Debug, Serialize, FromRaw, MessageEventContent)]
|
#[derive(Clone, Debug, Serialize, FromRaw, MessageEventContent)]
|
||||||
#[ruma_event(type = "m.call.answer")]
|
#[ruma_event(type = "m.call.answer")]
|
||||||
pub struct AnswerEventContenet {
|
pub struct AnswerEventContent {
|
||||||
/// The VoIP session description object. The session description type must be *answer*.
|
/// The VoIP session description object. The session description type must be *answer*.
|
||||||
pub answer: SessionDescription,
|
pub answer: SessionDescription,
|
||||||
|
|
||||||
|
@ -134,6 +134,7 @@ mod error;
|
|||||||
mod event_type;
|
mod event_type;
|
||||||
mod from_raw;
|
mod from_raw;
|
||||||
mod json;
|
mod json;
|
||||||
|
mod message;
|
||||||
mod state;
|
mod state;
|
||||||
#[doc(hidden)] // only public for external tests
|
#[doc(hidden)] // only public for external tests
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
491
src/message.rs
Normal file
491
src/message.rs
Normal file
@ -0,0 +1,491 @@
|
|||||||
|
//! An enum that represents any message event. A message event is represented by
|
||||||
|
//! a parameterized struct allowing more flexibility in whats being sent.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
convert::TryFrom,
|
||||||
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
|
};
|
||||||
|
|
||||||
|
use js_int::UInt;
|
||||||
|
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||||
|
use serde::{
|
||||||
|
ser::{Error, SerializeStruct},
|
||||||
|
Serialize, Serializer,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{MessageEventContent, RawEventContent, RoomEventContent, TryFromRaw, UnsignedData};
|
||||||
|
use ruma_events_macros::event_content_collection;
|
||||||
|
|
||||||
|
event_content_collection! {
|
||||||
|
/// A message event.
|
||||||
|
name: AnyMessageEventContent,
|
||||||
|
events: [
|
||||||
|
"m.call.answer",
|
||||||
|
"m.call.invite",
|
||||||
|
"m.call.hangup",
|
||||||
|
"m.call.candidates",
|
||||||
|
"m.sticker",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Message event.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MessageEvent<C: MessageEventContent>
|
||||||
|
where
|
||||||
|
C::Raw: RawEventContent,
|
||||||
|
{
|
||||||
|
/// Data specific to the event type.
|
||||||
|
pub content: C,
|
||||||
|
|
||||||
|
/// The globally unique event identifier for the user who sent the event.
|
||||||
|
pub event_id: EventId,
|
||||||
|
|
||||||
|
/// Contains the fully-qualified ID of the user who sent this event.
|
||||||
|
pub sender: UserId,
|
||||||
|
|
||||||
|
/// Timestamp in milliseconds on originating homeserver when this event was sent.
|
||||||
|
pub origin_server_ts: SystemTime,
|
||||||
|
|
||||||
|
/// The ID of the room associated with this event.
|
||||||
|
pub room_id: RoomId,
|
||||||
|
|
||||||
|
/// Additional key-value pairs not signed by the homeserver.
|
||||||
|
pub unsigned: UnsignedData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> TryFromRaw for MessageEvent<C>
|
||||||
|
where
|
||||||
|
C: MessageEventContent + TryFromRaw,
|
||||||
|
C::Raw: RawEventContent,
|
||||||
|
{
|
||||||
|
type Raw = raw_message_event::MessageEvent<C::Raw>;
|
||||||
|
type Err = C::Err;
|
||||||
|
|
||||||
|
fn try_from_raw(raw: Self::Raw) -> Result<Self, Self::Err> {
|
||||||
|
Ok(Self {
|
||||||
|
content: C::try_from_raw(raw.content)?,
|
||||||
|
event_id: raw.event_id,
|
||||||
|
sender: raw.sender,
|
||||||
|
origin_server_ts: raw.origin_server_ts,
|
||||||
|
room_id: raw.room_id,
|
||||||
|
unsigned: raw.unsigned,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: MessageEventContent> Serialize for MessageEvent<C>
|
||||||
|
where
|
||||||
|
C::Raw: RawEventContent,
|
||||||
|
{
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let event_type = self.content.event_type();
|
||||||
|
|
||||||
|
let time_since_epoch = self.origin_server_ts.duration_since(UNIX_EPOCH).unwrap();
|
||||||
|
let timestamp = match UInt::try_from(time_since_epoch.as_millis()) {
|
||||||
|
Ok(uint) => uint,
|
||||||
|
Err(err) => return Err(S::Error::custom(err)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut message = serializer.serialize_struct("MessageEvent", 7)?;
|
||||||
|
message.serialize_field("content", &self.content)?;
|
||||||
|
message.serialize_field("event_id", &self.event_id)?;
|
||||||
|
message.serialize_field("sender", &self.sender)?;
|
||||||
|
message.serialize_field("origin_server_ts", ×tamp)?;
|
||||||
|
message.serialize_field("room_id", &self.room_id)?;
|
||||||
|
message.serialize_field("type", event_type)?;
|
||||||
|
message.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod raw_message_event {
|
||||||
|
use std::{
|
||||||
|
fmt,
|
||||||
|
marker::PhantomData,
|
||||||
|
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||||
|
};
|
||||||
|
|
||||||
|
use js_int::UInt;
|
||||||
|
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||||
|
use serde::de::{self, Deserialize, Deserializer, Error as _, MapAccess, Visitor};
|
||||||
|
use serde_json::value::RawValue as RawJsonValue;
|
||||||
|
|
||||||
|
use crate::{RawEventContent, UnsignedData};
|
||||||
|
|
||||||
|
/// The raw half of a message event.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MessageEvent<C> {
|
||||||
|
/// Data specific to the event type.
|
||||||
|
pub content: C,
|
||||||
|
|
||||||
|
/// The globally unique event identifier for the user who sent the event.
|
||||||
|
pub event_id: EventId,
|
||||||
|
|
||||||
|
/// Contains the fully-qualified ID of the user who sent this event.
|
||||||
|
pub sender: UserId,
|
||||||
|
|
||||||
|
/// Timestamp in milliseconds on originating homeserver when this event was sent.
|
||||||
|
pub origin_server_ts: SystemTime,
|
||||||
|
|
||||||
|
/// The ID of the room associated with this event.
|
||||||
|
pub room_id: RoomId,
|
||||||
|
|
||||||
|
/// Additional key-value pairs not signed by the homeserver.
|
||||||
|
pub unsigned: UnsignedData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, C> Deserialize<'de> for MessageEvent<C>
|
||||||
|
where
|
||||||
|
C: RawEventContent,
|
||||||
|
{
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_map(MessageEventVisitor(std::marker::PhantomData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
#[serde(field_identifier, rename_all = "snake_case")]
|
||||||
|
enum Field {
|
||||||
|
Type,
|
||||||
|
Content,
|
||||||
|
EventId,
|
||||||
|
Sender,
|
||||||
|
OriginServerTs,
|
||||||
|
RoomId,
|
||||||
|
Unsigned,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Visits the fields of a MessageEvent<C> to handle deserialization of
|
||||||
|
/// the `content` and `prev_content` fields.
|
||||||
|
struct MessageEventVisitor<C>(PhantomData<C>);
|
||||||
|
|
||||||
|
impl<'de, C> Visitor<'de> for MessageEventVisitor<C>
|
||||||
|
where
|
||||||
|
C: RawEventContent,
|
||||||
|
{
|
||||||
|
type Value = MessageEvent<C>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(formatter, "struct implementing MessageEventContent")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut content: Option<Box<RawJsonValue>> = None;
|
||||||
|
let mut event_type: Option<String> = None;
|
||||||
|
let mut event_id: Option<EventId> = None;
|
||||||
|
let mut sender: Option<UserId> = None;
|
||||||
|
let mut origin_server_ts: Option<UInt> = None;
|
||||||
|
let mut room_id: Option<RoomId> = None;
|
||||||
|
let mut unsigned: Option<UnsignedData> = None;
|
||||||
|
|
||||||
|
while let Some(key) = map.next_key()? {
|
||||||
|
match key {
|
||||||
|
Field::Content => {
|
||||||
|
if content.is_some() {
|
||||||
|
return Err(de::Error::duplicate_field("content"));
|
||||||
|
}
|
||||||
|
content = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
Field::EventId => {
|
||||||
|
if event_id.is_some() {
|
||||||
|
return Err(de::Error::duplicate_field("event_id"));
|
||||||
|
}
|
||||||
|
event_id = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
Field::Sender => {
|
||||||
|
if sender.is_some() {
|
||||||
|
return Err(de::Error::duplicate_field("sender"));
|
||||||
|
}
|
||||||
|
sender = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
Field::OriginServerTs => {
|
||||||
|
if origin_server_ts.is_some() {
|
||||||
|
return Err(de::Error::duplicate_field("origin_server_ts"));
|
||||||
|
}
|
||||||
|
origin_server_ts = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
Field::RoomId => {
|
||||||
|
if room_id.is_some() {
|
||||||
|
return Err(de::Error::duplicate_field("room_id"));
|
||||||
|
}
|
||||||
|
room_id = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
Field::Type => {
|
||||||
|
if event_type.is_some() {
|
||||||
|
return Err(de::Error::duplicate_field("type"));
|
||||||
|
}
|
||||||
|
event_type = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
Field::Unsigned => {
|
||||||
|
if unsigned.is_some() {
|
||||||
|
return Err(de::Error::duplicate_field("unsigned"));
|
||||||
|
}
|
||||||
|
unsigned = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let event_type = event_type.ok_or_else(|| de::Error::missing_field("type"))?;
|
||||||
|
|
||||||
|
let raw = content.ok_or_else(|| de::Error::missing_field("content"))?;
|
||||||
|
let content = C::from_parts(&event_type, raw).map_err(A::Error::custom)?;
|
||||||
|
|
||||||
|
let event_id = event_id.ok_or_else(|| de::Error::missing_field("event_id"))?;
|
||||||
|
let sender = sender.ok_or_else(|| de::Error::missing_field("sender"))?;
|
||||||
|
|
||||||
|
let origin_server_ts = origin_server_ts
|
||||||
|
.map(|time| UNIX_EPOCH + Duration::from_millis(time.into()))
|
||||||
|
.ok_or_else(|| de::Error::missing_field("origin_server_ts"))?;
|
||||||
|
|
||||||
|
let room_id = room_id.ok_or_else(|| de::Error::missing_field("room_id"))?;
|
||||||
|
|
||||||
|
let unsigned = unsigned.unwrap_or_default();
|
||||||
|
|
||||||
|
Ok(MessageEvent {
|
||||||
|
content,
|
||||||
|
event_id,
|
||||||
|
sender,
|
||||||
|
origin_server_ts,
|
||||||
|
room_id,
|
||||||
|
unsigned,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::{
|
||||||
|
convert::TryFrom,
|
||||||
|
time::{Duration, UNIX_EPOCH},
|
||||||
|
};
|
||||||
|
|
||||||
|
use js_int::UInt;
|
||||||
|
use matches::assert_matches;
|
||||||
|
use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId};
|
||||||
|
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
|
||||||
|
|
||||||
|
use super::{AnyMessageEventContent, MessageEvent};
|
||||||
|
use crate::{
|
||||||
|
call::{answer::AnswerEventContent, SessionDescription, SessionDescriptionType},
|
||||||
|
room::{ImageInfo, ThumbnailInfo},
|
||||||
|
sticker::StickerEventContent,
|
||||||
|
EventJson, UnsignedData,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn message_serialize_aliases() {
|
||||||
|
let aliases_event = MessageEvent {
|
||||||
|
content: AnyMessageEventContent::Sticker(StickerEventContent {
|
||||||
|
body: "Hello".into(),
|
||||||
|
info: ImageInfo {
|
||||||
|
height: UInt::new(423),
|
||||||
|
width: UInt::new(1011),
|
||||||
|
mimetype: Some("image/png".into()),
|
||||||
|
size: UInt::new(84242),
|
||||||
|
thumbnail_info: Some(Box::new(ThumbnailInfo {
|
||||||
|
width: UInt::new(800),
|
||||||
|
height: UInt::new(334),
|
||||||
|
mimetype: Some("image/png".into()),
|
||||||
|
size: UInt::new(82595),
|
||||||
|
})),
|
||||||
|
thumbnail_url: Some("mxc://matrix.org".into()),
|
||||||
|
thumbnail_file: None,
|
||||||
|
},
|
||||||
|
url: "http://www.matrix.org".into(),
|
||||||
|
}),
|
||||||
|
event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
|
||||||
|
origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
|
||||||
|
room_id: RoomId::try_from("!roomid:room.com").unwrap(),
|
||||||
|
sender: UserId::try_from("@carl:example.com").unwrap(),
|
||||||
|
unsigned: UnsignedData::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let actual = to_json_value(&aliases_event).unwrap();
|
||||||
|
let expected = json!({
|
||||||
|
"content": {
|
||||||
|
"body": "Hello",
|
||||||
|
"info": {
|
||||||
|
"h": 423,
|
||||||
|
"mimetype": "image/png",
|
||||||
|
"size": 84242,
|
||||||
|
"thumbnail_info": {
|
||||||
|
"h": 334,
|
||||||
|
"mimetype": "image/png",
|
||||||
|
"size": 82595,
|
||||||
|
"w": 800
|
||||||
|
},
|
||||||
|
"thumbnail_url": "mxc://matrix.org",
|
||||||
|
"w": 1011
|
||||||
|
},
|
||||||
|
"url": "http://www.matrix.org"
|
||||||
|
},
|
||||||
|
"event_id": "$h29iv0s8:example.com",
|
||||||
|
"origin_server_ts": 1,
|
||||||
|
"room_id": "!roomid:room.com",
|
||||||
|
"sender": "@carl:example.com",
|
||||||
|
"type": "m.sticker",
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_message_aliases_content() {
|
||||||
|
let json_data = json!({
|
||||||
|
"answer": {
|
||||||
|
"type": "answer",
|
||||||
|
"sdp": "Hello"
|
||||||
|
},
|
||||||
|
"call_id": "foofoo",
|
||||||
|
"version": 1
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
from_json_value::<EventJson<AnyMessageEventContent>>(json_data)
|
||||||
|
.unwrap()
|
||||||
|
.deserialize_content("m.call.answer")
|
||||||
|
.unwrap(),
|
||||||
|
AnyMessageEventContent::CallAnswer(AnswerEventContent {
|
||||||
|
answer: SessionDescription {
|
||||||
|
session_type: SessionDescriptionType::Answer,
|
||||||
|
sdp,
|
||||||
|
},
|
||||||
|
call_id,
|
||||||
|
version,
|
||||||
|
}) if sdp == "Hello" && call_id == "foofoo" && version == UInt::new(1).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_message_aliases() {
|
||||||
|
let json_data = json!({
|
||||||
|
"content": {
|
||||||
|
"answer": {
|
||||||
|
"type": "answer",
|
||||||
|
"sdp": "Hello"
|
||||||
|
},
|
||||||
|
"call_id": "foofoo",
|
||||||
|
"version": 1
|
||||||
|
},
|
||||||
|
"event_id": "$h29iv0s8:example.com",
|
||||||
|
"origin_server_ts": 1,
|
||||||
|
"room_id": "!roomid:room.com",
|
||||||
|
"sender": "@carl:example.com",
|
||||||
|
"type": "m.call.answer"
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
from_json_value::<EventJson<MessageEvent<AnyMessageEventContent>>>(json_data)
|
||||||
|
.unwrap()
|
||||||
|
.deserialize()
|
||||||
|
.unwrap(),
|
||||||
|
MessageEvent {
|
||||||
|
content: AnyMessageEventContent::CallAnswer(AnswerEventContent {
|
||||||
|
answer: SessionDescription {
|
||||||
|
session_type: SessionDescriptionType::Answer,
|
||||||
|
sdp,
|
||||||
|
},
|
||||||
|
call_id,
|
||||||
|
version,
|
||||||
|
}),
|
||||||
|
event_id,
|
||||||
|
origin_server_ts,
|
||||||
|
room_id,
|
||||||
|
sender,
|
||||||
|
unsigned,
|
||||||
|
} if sdp == "Hello" && call_id == "foofoo" && version == UInt::new(1).unwrap()
|
||||||
|
&& event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
|
||||||
|
&& origin_server_ts == UNIX_EPOCH + Duration::from_millis(1)
|
||||||
|
&& room_id == RoomId::try_from("!roomid:room.com").unwrap()
|
||||||
|
&& sender == UserId::try_from("@carl:example.com").unwrap()
|
||||||
|
&& unsigned.is_empty()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_message_avatar() {
|
||||||
|
let json_data = json!({
|
||||||
|
"content": {
|
||||||
|
"body": "Hello",
|
||||||
|
"info": {
|
||||||
|
"h": 423,
|
||||||
|
"mimetype": "image/png",
|
||||||
|
"size": 84242,
|
||||||
|
"thumbnail_info": {
|
||||||
|
"h": 334,
|
||||||
|
"mimetype": "image/png",
|
||||||
|
"size": 82595,
|
||||||
|
"w": 800
|
||||||
|
},
|
||||||
|
"thumbnail_url": "mxc://matrix.org",
|
||||||
|
"w": 1011
|
||||||
|
},
|
||||||
|
"url": "http://www.matrix.org"
|
||||||
|
},
|
||||||
|
"event_id": "$h29iv0s8:example.com",
|
||||||
|
"origin_server_ts": 1,
|
||||||
|
"room_id": "!roomid:room.com",
|
||||||
|
"sender": "@carl:example.com",
|
||||||
|
"type": "m.sticker"
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
from_json_value::<EventJson<MessageEvent<AnyMessageEventContent>>>(json_data)
|
||||||
|
.unwrap()
|
||||||
|
.deserialize()
|
||||||
|
.unwrap(),
|
||||||
|
MessageEvent {
|
||||||
|
content: AnyMessageEventContent::Sticker(StickerEventContent {
|
||||||
|
body,
|
||||||
|
info: ImageInfo {
|
||||||
|
height,
|
||||||
|
width,
|
||||||
|
mimetype: Some(mimetype),
|
||||||
|
size,
|
||||||
|
thumbnail_info: Some(thumbnail_info),
|
||||||
|
thumbnail_url: Some(thumbnail_url),
|
||||||
|
thumbnail_file: None,
|
||||||
|
},
|
||||||
|
url,
|
||||||
|
}),
|
||||||
|
event_id,
|
||||||
|
origin_server_ts,
|
||||||
|
room_id,
|
||||||
|
sender,
|
||||||
|
unsigned
|
||||||
|
} if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
|
||||||
|
&& body == "Hello"
|
||||||
|
&& origin_server_ts == UNIX_EPOCH + Duration::from_millis(1)
|
||||||
|
&& room_id == RoomId::try_from("!roomid:room.com").unwrap()
|
||||||
|
&& sender == UserId::try_from("@carl:example.com").unwrap()
|
||||||
|
&& height == UInt::new(423)
|
||||||
|
&& width == UInt::new(1011)
|
||||||
|
&& mimetype == "image/png"
|
||||||
|
&& size == UInt::new(84242)
|
||||||
|
&& thumbnail_url == "mxc://matrix.org"
|
||||||
|
&& matches!(
|
||||||
|
thumbnail_info.as_ref(),
|
||||||
|
ThumbnailInfo {
|
||||||
|
width: thumb_width,
|
||||||
|
height: thumb_height,
|
||||||
|
mimetype: thumb_mimetype,
|
||||||
|
size: thumb_size,
|
||||||
|
} if *thumb_width == UInt::new(800)
|
||||||
|
&& *thumb_height == UInt::new(334)
|
||||||
|
&& *thumb_mimetype == Some("image/png".to_string())
|
||||||
|
&& *thumb_size == UInt::new(82595)
|
||||||
|
)
|
||||||
|
&& url == "http://www.matrix.org"
|
||||||
|
&& unsigned.is_empty()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user