twitter_stream_message/message/
event.rs

1use std::fmt;
2
3use serde::de::{
4    Deserialize,
5    Deserializer,
6    Error,
7    IgnoredAny,
8    MapAccess,
9    Visitor,
10};
11
12use {List, Tweet, User};
13use types::{DateTime, JsonValue};
14use util;
15
16/// Represents notifications about non-Tweet events are also sent over a stream.
17///
18/// # Reference
19///
20/// 1. [Streaming message types — Twitter Developers][1]
21///
22/// [1]: https://dev.twitter.com/streaming/overview/messages-types#Events_event
23#[derive(Clone, Debug, PartialEq)]
24pub struct Event<'a> {
25    pub created_at: DateTime,
26
27    /// An object which indicates the name of the event and contains
28    /// an optional object which represents the target of the event.
29    pub event: EventKind<'a>,
30
31    pub target: User<'a>,
32
33    pub source: User<'a>,
34}
35
36macro_rules! impl_event {
37    (
38        $(#[$attr:meta])*
39        pub enum $T:ident<$lifetime:tt> {
40            $(
41                $(#[$c_attr:meta])*
42                $Container:ident($c_tag:expr, $Content:ty)
43            ),*;
44            $(
45                $(#[$l_attr:meta])*
46                $Label:ident($l_tag:expr)
47            ),*;
48            $(#[$cu_attr:meta])*
49            $Custom:ident(_, _),
50        }
51    ) => {
52        $(#[$attr])*
53        pub enum $T<$lifetime> {
54            $(
55                $(#[$c_attr])*
56                $Container($Content),
57            )*
58            $(
59                $(#[$l_attr])*
60                $Label,
61            )*
62            $(#[$cu_attr])*
63            $Custom(::std::borrow::Cow<$lifetime, str>, Option<JsonValue>),
64        }
65
66        impl<'de: 'a, 'a> Deserialize<'de> for Event<'a> {
67            fn deserialize<D: Deserializer<'de>>(d: D)
68                -> Result<Self, D::Error>
69            {
70                d.deserialize_map(EventVisitor)
71            }
72        }
73
74        struct EventVisitor;
75
76        impl<'a> Visitor<'a> for EventVisitor {
77            type Value = Event<'a>;
78
79            fn visit_map<A: MapAccess<'a>>(self, mut a: A)
80                -> Result<Event<'a>, A::Error>
81            {
82                use util::CowStr;
83
84                #[derive(Default)]
85                struct EventBuffer<'a> {
86                    created_at: Option<DateTime>,
87                    event: Option<EventKind<'a>>,
88                    target: Option<User<'a>>,
89                    source: Option<User<'a>>,
90                }
91
92                let mut event = EventBuffer::default();
93                let mut event_kind: Option<CowStr> = None;
94                let mut target_obj: Option<JsonValue> = None;
95
96                while let Some(k) = a.next_key::<CowStr>()? {
97                    match &*k {
98                        "created_at" => {
99                            let val = a.next_value::<CowStr>()?;
100                            let dt = util::parse_datetime(&*val)
101                                .map_err(A::Error::custom)?;
102                            event.created_at = Some(dt);
103                        },
104                        "event" => {
105                            let e = a.next_value::<CowStr>()?;
106                            event.event = if let Some(t) = target_obj.take() {
107                                match &*e {
108                                    $($c_tag => {
109                                        let c = <$Content>::deserialize(t)
110                                            .map_err(A::Error::custom)?;
111                                        $T::$Container(c)
112                                    },)*
113                                    $($l_tag => $T::$Label,)*
114                                    _ => $T::$Custom(e.0, Some(t)),
115                                }.into()
116                            } else {
117                                match &*e {
118                                    $($c_tag)|* => {
119                                        event_kind = Some(e);
120                                        None
121                                    },
122                                    $($l_tag => Some($T::$Label),)*
123                                    _ => Some($T::Custom(e.0, None)),
124                                }
125                            };
126                        },
127                        "target" => event.target = Some(a.next_value()?),
128                        "source" => event.source = Some(a.next_value()?),
129                        "target_object" => if let Some(e) = event_kind.take() {
130                            event.event = match &*e {
131                                $($c_tag => $T::$Container(a.next_value()?),)*
132                                $($l_tag => { a.next_value::<IgnoredAny>()?; $T::$Label },)*
133                                _ => $T::$Custom(e.0, a.next_value()?),
134                            }.into();
135                        } else if event.event.is_none() {
136                            target_obj = Some(a.next_value()?);
137                        } else {
138                            a.next_value::<IgnoredAny>()?;
139                        },
140                        _ => { a.next_value::<IgnoredAny>()?; },
141                    }
142
143                    if let EventBuffer {
144                        created_at: Some(created_at),
145                        event: Some(event),
146                        target: Some(target),
147                        source: Some(source),
148                    } = event
149                    {
150                        while a.next_entry::<IgnoredAny, IgnoredAny>()?
151                            .is_some() {}
152                        return Ok(Event { created_at, event, target, source });
153                    }
154                }
155
156                Err(A::Error::missing_field(match event {
157                    EventBuffer { created_at: None, .. } => "created_at",
158                    EventBuffer { target: None, .. } => "target",
159                    EventBuffer { source: None, .. } => "source",
160                    EventBuffer { event: None, .. } => if target_obj.is_some() {
161                        "event"
162                    } else {
163                        "target_object"
164                    },
165                    EventBuffer {
166                        created_at: Some(_),
167                        target: Some(_),
168                        source: Some(_),
169                        event: Some(_),
170                    } => unreachable!(),
171                }))
172            }
173
174            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
175                write!(f, "a map")
176            }
177        }
178    };
179}
180
181impl_event! {
182    /// An object which indicates the name of an event. It may contain an
183    /// object called "target object" which represents the target of the event.
184    ///
185    /// The meaning of `target` and `source` field of an `Event` will
186    /// be different based on the name of the event, as described below.
187    ///
188    /// | Description                         | Event Name             | `source`           | `target`       |
189    /// | ----------------------------------- | ---------------------- | ------------------ | -------------- |
190    /// | User deauthorizes stream            | `AccessRevoked`        | Deauthorizing user | App owner      |
191    /// | User blocks someone                 | `Block`                | Current user       | Blocked user   |
192    /// | User removes a block                | `Unblock`              | Current user       | Unblocked user |
193    /// | User favorites a Tweet              | `Favorite`             | Current user       | Tweet author   |
194    /// | User's Tweet is favorited           | `Favorite`             | Favoriting user    | Current user   |
195    /// | User unfavorites a Tweet            | `Unfavorite`           | Current user       | Tweet author   |
196    /// | User's Tweet is unfavorited         | `Unfavorite`           | Unfavoriting user  | Current user   |
197    /// | User follows someone                | `Follow`               | Current user       | Followed user  |
198    /// | User is followed                    | `Follow`               | Following user     | Current user   |
199    /// | User unfollows someone              | `Unfollow`             | Current user       | Followed user  |
200    /// | User creates a list                 | `ListCreated`          | Current user       | Current user   |
201    /// | User deletes a list                 | `ListDestroyed`        | Current user       | Current user   |
202    /// | User edits a list                   | `ListUpdated`          | Current user       | Current user   |
203    /// | User adds someone to a list         | `ListMemberAdded`      | Current user       | Added user     |
204    /// | User is added to a list             | `ListMemberAdded`      | Adding user        | Current user   |
205    /// | User removes someone from a list    | `ListMemberRemoved`    | Current user       | Removed user   |
206    /// | User is removed from a list         | `ListMemberRemoved`    | Removing user      | Current user   |
207    /// | User subscribes to a list           | `ListUserSubscribed`   | Current user       | List owner     |
208    /// | User's list is subscribed to        | `ListUserSubscribed`   | Subscribing user   | Current user   |
209    /// | User unsubscribes from a list       | `ListUserUnsubscribed` | Current user       | List owner     |
210    /// | User's list is unsubscribed from    | `ListUserUnsubscribed` | Unsubscribing user | Current user   |
211    /// | User's Tweet is quoted              | `QuotedTweet`          | quoting User       | Current User   |
212    /// | User updates their profile          | `UserUpdate`           | Current user       | Current user   |
213    /// | User updates their protected status | `UserUpdate`           | Current user       | Current user   |
214    #[derive(Clone, Debug, PartialEq)]
215    pub enum EventKind<'a> {
216        Favorite("favorite", Box<Tweet<'a>>),
217        Unfavorite("unfavorite", Box<Tweet<'a>>),
218        ListCreated("list_created", Box<List<'a>>),
219        ListDestroyed("list_destroyed", Box<List<'a>>),
220        ListUpdated("list_updated", Box<List<'a>>),
221        ListMemberAdded("list_member_added", Box<List<'a>>),
222        ListMemberRemoved("list_member_removed", Box<List<'a>>),
223        ListUserSubscribed("list_user_subscribed", Box<List<'a>>),
224        ListUserUnsubscribed("list_user_unsubscribed", Box<List<'a>>),
225        QuotedTweet("quoted_tweet", Box<Tweet<'a>>);
226        AccessRevoked("access_revoked"),
227        Block("block"),
228        Unblock("unblock"),
229        Follow("follow"),
230        Unfollow("unfollow"),
231        UserUpdate("user_update");
232        /// An event this library does not know. The first value is raw event name
233        /// and the second is the target object.
234        Custom(_, _),
235    }
236}