diff --git a/ruma-events/src/enums.rs b/ruma-events/src/enums.rs index 298d3e93..de0ab6b1 100644 --- a/ruma-events/src/enums.rs +++ b/ruma-events/src/enums.rs @@ -36,6 +36,7 @@ event_enum! { "m.call.invite", "m.call.hangup", "m.call.candidates", + "m.reaction", "m.room.encrypted", "m.room.message", "m.room.message.feedback", diff --git a/ruma-events/src/lib.rs b/ruma-events/src/lib.rs index ac5dddb6..b0d10578 100644 --- a/ruma-events/src/lib.rs +++ b/ruma-events/src/lib.rs @@ -170,6 +170,7 @@ pub mod pdu; pub mod policy; pub mod presence; pub mod push_rules; +pub mod reaction; pub mod receipt; pub mod room; pub mod room_key; diff --git a/ruma-events/src/reaction.rs b/ruma-events/src/reaction.rs new file mode 100644 index 00000000..56759c2b --- /dev/null +++ b/ruma-events/src/reaction.rs @@ -0,0 +1,67 @@ +//! Types for the *m.reaction* event. + +use std::convert::TryFrom; + +use crate::{ + room::relationships::{Annotation, RelatesToJsonRepr, RelationJsonRepr}, + MessageEvent, +}; +use ruma_events_macros::MessageEventContent; +use ruma_identifiers::EventId; +use serde::{Deserialize, Serialize}; + +/// A reaction to another event. +pub type ReactionEvent = MessageEvent; + +/// The payload for a `ReactionEvent`. +#[derive(Clone, Debug, Deserialize, Serialize, MessageEventContent)] +#[ruma_event(type = "m.reaction")] +pub struct ReactionEventContent { + /// Information about the related event. + #[serde(rename = "m.relates_to")] + pub relation: Relation, +} + +/// The relation that contains info which event the reaction is applying to. +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(try_from = "RelatesToJsonRepr", into = "RelatesToJsonRepr")] +pub struct Relation { + /// The event that is being reacted to. + pub event_id: EventId, + + /// A string that holds the emoji reaction. + pub emoji: String, +} + +impl From for RelatesToJsonRepr { + fn from(relation: Relation) -> Self { + RelatesToJsonRepr::Relation(RelationJsonRepr::Annotation(Annotation { + event_id: relation.event_id, + key: relation.emoji, + })) + } +} + +impl TryFrom for Relation { + type Error = &'static str; + + fn try_from(value: RelatesToJsonRepr) -> Result { + if let RelatesToJsonRepr::Relation(RelationJsonRepr::Annotation(a)) = value { + Ok(Relation { event_id: a.event_id, emoji: a.key }) + } else { + Err("Expected a relation with a rel_type of `annotation`") + } + } +} + +impl ReactionEventContent { + /// Create a new reaction. + /// + /// # Arguments + /// + /// * `event_id` - The id of the event we are reacting to. + /// * `emoji` - The emoji that indicates the reaction that is being applied. + pub fn new(event_id: EventId, emoji: String) -> Self { + ReactionEventContent { relation: Relation { event_id, emoji } } + } +}