1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15+ use std:: fmt;
16+
1517use ruma:: {
16- events:: { AnyTimelineEvent , MessageLikeEventType , StateEventType } ,
18+ events:: {
19+ AnyTimelineEvent , AnyToDeviceEvent , MessageLikeEventType , StateEventType , ToDeviceEventType ,
20+ } ,
1721 serde:: Raw ,
1822} ;
1923use serde:: Deserialize ;
2024use tracing:: debug;
2125
2226use super :: machine:: SendEventRequest ;
2327
24- /// A Filter for Matrix events. That is used to decide if a given event can be
25- /// sent to the widget and if a widgets is allowed to send an event to to a
26- /// Matrix room or not .
28+ /// A Filter for Matrix events. It is used to decide if a given event can be
29+ /// sent to the widget and if a widget is allowed to send an event to a
30+ /// Matrix room.
2731#[ derive( Clone , Debug ) ]
2832#[ cfg_attr( test, derive( PartialEq ) ) ]
2933pub enum Filter {
3034 /// Filter for message-like events.
3135 MessageLike ( MessageLikeEventFilter ) ,
3236 /// Filter for state events.
3337 State ( StateEventFilter ) ,
38+ /// Filter for to device events.
39+ ToDevice ( ToDeviceEventFilter ) ,
3440}
3541
3642impl Filter {
@@ -41,6 +47,7 @@ impl Filter {
4147 match self {
4248 Self :: MessageLike ( filter) => filter. matches ( filter_input) ,
4349 Self :: State ( filter) => filter. matches ( filter_input) ,
50+ Self :: ToDevice ( filter) => filter. matches ( filter_input) ,
4451 }
4552 }
4653 /// Returns the event type that this filter is configured to match.
@@ -51,6 +58,7 @@ impl Filter {
5158 match self {
5259 Self :: MessageLike ( filter) => filter. filter_event_type ( ) ,
5360 Self :: State ( filter) => filter. filter_event_type ( ) ,
61+ Self :: ToDevice ( filter) => filter. event_type . to_string ( ) ,
5462 }
5563 }
5664}
@@ -123,6 +131,33 @@ impl<'a> StateEventFilter {
123131 }
124132}
125133
134+ /// Filter for to-device events.
135+ #[ derive( Clone , Debug ) ]
136+ #[ cfg_attr( test, derive( PartialEq ) ) ]
137+ pub struct ToDeviceEventFilter {
138+ /// The event type this to-device-filter filters for.
139+ pub event_type : ToDeviceEventType ,
140+ }
141+
142+ impl ToDeviceEventFilter {
143+ /// Create a new `ToDeviceEventFilter` with the given event type.
144+ pub fn new ( event_type : ToDeviceEventType ) -> Self {
145+ Self { event_type }
146+ }
147+ }
148+
149+ impl ToDeviceEventFilter {
150+ fn matches ( & self , filter_input : & FilterInput ) -> bool {
151+ matches ! ( filter_input, FilterInput :: ToDevice ( f_in) if f_in. event_type == self . event_type)
152+ }
153+ }
154+
155+ impl fmt:: Display for ToDeviceEventFilter {
156+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
157+ write ! ( f, "{}" , self . event_type)
158+ }
159+ }
160+
126161// Filter input:
127162
128163/// The input data for the filter. This can either be constructed from a
@@ -131,8 +166,13 @@ impl<'a> StateEventFilter {
131166#[ serde( untagged) ]
132167pub enum FilterInput < ' a > {
133168 #[ serde( borrow) ]
169+ // The order is important.
170+ // We first need to check if we can deserialize as a state (state_key exists)
134171 State ( FilterInputState < ' a > ) ,
172+ // only then we can check if we can deserialize as a message like.
135173 MessageLike ( FilterInputMessageLike < ' a > ) ,
174+ // ToDevice will need to be done explicitly since it looks the same as a message like.
175+ ToDevice ( FilterInputToDevice < ' a > ) ,
136176}
137177
138178impl < ' a > FilterInput < ' a > {
@@ -188,10 +228,29 @@ impl<'a> TryFrom<&'a Raw<AnyTimelineEvent>> for FilterInput<'a> {
188228 type Error = serde_json:: Error ;
189229
190230 fn try_from ( raw_event : & ' a Raw < AnyTimelineEvent > ) -> Result < Self , Self :: Error > {
231+ // FilterInput first checks if it can deserialize as a state event (state_key exists)
232+ // and then as a message like event.
191233 raw_event. deserialize_as ( )
192234 }
193235}
194236
237+ #[ derive( Debug , Deserialize ) ]
238+ pub struct FilterInputToDevice < ' a > {
239+ #[ serde( rename = "type" ) ]
240+ pub ( super ) event_type : & ' a str ,
241+ }
242+
243+ /// Create a filter input of type [`FilterInput::ToDevice`]`.
244+ impl < ' a > TryFrom < & ' a Raw < AnyToDeviceEvent > > for FilterInput < ' a > {
245+ type Error = serde_json:: Error ;
246+ fn try_from ( raw_event : Raw < AnyToDeviceEvent > ) -> Result < Self , Self :: Error > {
247+ // deserialize_as::<FilterInput> will first try state, message like and then to-device.
248+ // The `AnyToDeviceEvent` would match message like first, so we need to explicitly
249+ // deserialize as `FilterInputToDevice`.
250+ raw_event. deserialize_as :: < FilterInputToDevice > ( ) . map ( FilterInput :: ToDevice )
251+ }
252+ }
253+
195254impl < ' a > From < & ' a SendEventRequest > for FilterInput < ' a > {
196255 fn from ( request : & ' a SendEventRequest ) -> Self {
197256 match & request. state_key {
@@ -234,7 +293,9 @@ mod tests {
234293 use super :: {
235294 Filter , FilterInput , FilterInputMessageLike , MessageLikeEventFilter , StateEventFilter ,
236295 } ;
237- use crate :: widget:: filter:: MessageLikeFilterEventContent ;
296+ use crate :: widget:: filter:: {
297+ FilterInputToDevice , MessageLikeFilterEventContent , ToDeviceEventFilter ,
298+ } ;
238299
239300 fn message_event ( event_type : & str ) -> FilterInput < ' _ > {
240301 FilterInput :: MessageLike ( FilterInputMessageLike { event_type, content : Default :: default ( ) } )
@@ -443,4 +504,12 @@ mod tests {
443504 assert_eq ! ( state. state_key, "@alice:example.com" ) ;
444505 }
445506 }
507+
508+ #[ test]
509+ fn test_to_device_filter_does_match ( ) {
510+ let f = Filter :: ToDevice ( ToDeviceEventFilter :: new ( "my.custom.to.device" . into ( ) ) ) ;
511+ assert ! ( f. matches( & FilterInput :: ToDevice ( FilterInputToDevice {
512+ event_type: "my.custom.to.device" . into( ) ,
513+ } ) ) ) ;
514+ }
446515}
0 commit comments