Implement EventContent for CustomEventConent and include in Any*EventContent enums

This commit is contained in:
Devin R 2020-06-16 17:27:39 -04:00 committed by Jonas Platte
parent 8195496cfd
commit 7c934e1b8f
3 changed files with 214 additions and 8 deletions

View File

@ -27,8 +27,10 @@ pub fn expand_content_enum(input: ContentEnumInput) -> syn::Result<TokenStream>
pub enum #ident { pub enum #ident {
#( #(
#[doc = #event_type_str] #[doc = #event_type_str]
#variants(#content) #variants(#content),
),* )*
#[doc = "Represents any event not defined in the Matrix spec."]
Custom(::ruma_events::custom::CustomEventContent)
} }
}; };
@ -36,7 +38,8 @@ pub fn expand_content_enum(input: ContentEnumInput) -> 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(), )*
#ident::Custom(content) => content.event_type(),
} }
} }
@ -51,7 +54,10 @@ pub fn expand_content_enum(input: ContentEnumInput) -> syn::Result<TokenStream>
Ok(#ident::#variants(content)) Ok(#ident::#variants(content))
}, },
)* )*
ev => Err(::serde::de::Error::custom(format!("event not supported {}", ev))), ev_type => {
let content = ::ruma_events::custom::CustomEventContent::from_parts(ev_type, input)?;
Ok(#ident::Custom(content))
},
} }
} }
} }

View File

@ -4,11 +4,9 @@ use std::time::SystemTime;
use ruma_identifiers::{EventId, RoomId, UserId}; use ruma_identifiers::{EventId, RoomId, UserId};
use serde::Serialize; use serde::Serialize;
use serde_json::Value as JsonValue; use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue};
use crate::UnsignedData; use crate::{EventContent, UnsignedData};
// TODO: (De)serialization
/// A custom event's type and `content` JSON object. /// A custom event's type and `content` JSON object.
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug, Serialize)]
@ -18,9 +16,21 @@ pub struct CustomEventContent {
pub event_type: String, pub event_type: String,
/// The actual `content` JSON object. /// The actual `content` JSON object.
#[serde(flatten)]
pub json: JsonValue, pub json: JsonValue,
} }
impl EventContent for CustomEventContent {
fn event_type(&self) -> &str {
&self.event_type
}
fn from_parts(event_type: &str, content: Box<RawJsonValue>) -> Result<Self, serde_json::Error> {
let json = serde_json::from_str(content.get())?;
Ok(Self { event_type: event_type.to_string(), json })
}
}
/// A custom event not covered by the Matrix specification. /// A custom event not covered by the Matrix specification.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct CustomBasicEvent { pub struct CustomBasicEvent {

190
ruma-events/tests/custom.rs Normal file
View File

@ -0,0 +1,190 @@
use std::{
convert::TryFrom,
time::{Duration, UNIX_EPOCH},
};
use matches::assert_matches;
use ruma_events::{
custom::CustomEventContent, AnyMessageEventContent, AnyStateEventContent, EventJson,
MessageEvent, StateEvent, StateEventStub, UnsignedData,
};
use ruma_identifiers::{EventId, RoomId, UserId};
use serde_json::{
from_value as from_json_value, json, to_value as to_json_value, Value as JsonValue,
};
fn custom_state_event() -> JsonValue {
json!({
"content": {
"m.relates_to": {
"event_id": "$MDitXXXXXX",
"key": "👍",
"rel_type": "m.annotation"
}
},
"event_id": "$h29iv0s8:example.com",
"origin_server_ts": 10,
"room_id": "!room:room.com",
"sender": "@carl:example.com",
"state_key": "",
"type": "m.reaction",
"unsigned": {
"age": 85
}
})
}
#[test]
fn serialize_custom_message_event() {
let aliases_event = MessageEvent {
content: AnyMessageEventContent::Custom(CustomEventContent {
json: json!({
"body": " * edited message",
"m.new_content": {
"body": "edited message",
"msgtype": "m.text"
},
"m.relates_to": {
"event_id": "some event id",
"rel_type": "m.replace"
},
"msgtype": "m.text"
}),
event_type: "m.room.message".to_string(),
}),
event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
origin_server_ts: UNIX_EPOCH + Duration::from_millis(10),
room_id: RoomId::try_from("!room: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": " * edited message",
"m.new_content": {
"body": "edited message",
"msgtype": "m.text"
},
"m.relates_to": {
"event_id": "some event id",
"rel_type": "m.replace"
},
"msgtype": "m.text"
},
"event_id": "$h29iv0s8:example.com",
"origin_server_ts": 10,
"sender": "@carl:example.com",
"room_id": "!room:room.com",
"type": "m.room.message",
});
assert_eq!(actual, expected);
}
#[test]
fn serialize_custom_state_event() {
let aliases_event = StateEvent {
content: AnyStateEventContent::Custom(CustomEventContent {
json: json!({
"custom": 10
}),
event_type: "m.made.up".to_string(),
}),
event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
origin_server_ts: UNIX_EPOCH + Duration::from_millis(10),
prev_content: None,
room_id: RoomId::try_from("!roomid:room.com").unwrap(),
sender: UserId::try_from("@carl:example.com").unwrap(),
state_key: "".to_string(),
unsigned: UnsignedData::default(),
};
let actual = to_json_value(&aliases_event).unwrap();
let expected = json!({
"content": {
"custom": 10
},
"event_id": "$h29iv0s8:example.com",
"origin_server_ts": 10,
"room_id": "!roomid:room.com",
"sender": "@carl:example.com",
"state_key": "",
"type": "m.made.up",
});
assert_eq!(actual, expected);
}
#[test]
fn deserialize_custom_state_event() {
let json_data = custom_state_event();
let expected_content = json!({
"m.relates_to": {
"event_id": "$MDitXXXXXX",
"key": "👍",
"rel_type": "m.annotation"
}
});
assert_matches!(
from_json_value::<EventJson<StateEvent<AnyStateEventContent>>>(json_data)
.unwrap()
.deserialize()
.unwrap(),
StateEvent {
content: AnyStateEventContent::Custom(CustomEventContent {
json, event_type,
}),
event_id,
origin_server_ts,
sender,
room_id,
prev_content: None,
state_key,
unsigned,
} if json == expected_content && event_type == "m.reaction"
&& event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
&& origin_server_ts == UNIX_EPOCH + Duration::from_millis(10)
&& sender == UserId::try_from("@carl:example.com").unwrap()
&& room_id == RoomId::try_from("!room:room.com").unwrap()
&& state_key == ""
&& !unsigned.is_empty()
);
}
#[test]
fn deserialize_custom_state_stub_event() {
let json_data = custom_state_event();
let expected_content = json!({
"m.relates_to": {
"event_id": "$MDitXXXXXX",
"key": "👍",
"rel_type": "m.annotation"
}
});
assert_matches!(
from_json_value::<StateEventStub<AnyStateEventContent>>(json_data)
.unwrap(),
StateEventStub {
content: AnyStateEventContent::Custom(CustomEventContent {
json, event_type,
}),
event_id,
origin_server_ts,
sender,
prev_content: None,
state_key,
unsigned,
} if json == expected_content && event_type == "m.reaction"
&& event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
&& origin_server_ts == UNIX_EPOCH + Duration::from_millis(10)
&& sender == UserId::try_from("@carl:example.com").unwrap()
&& state_key == ""
&& !unsigned.is_empty()
);
}