diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d29f6f1..3038e39 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: "scorpil/rust:stable" +image: "scorpil/rust:nightly" before_script: - apt-get update -yqq diff --git a/examples/client.rs b/examples/client.rs index 193d689..de8fa51 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -19,7 +19,8 @@ fn main() { client.register_plugin(PresencePlugin::new()); client.register_plugin(PingPlugin::new()); client.plugin::().set_presence(Show::Available, None).unwrap(); - loop { + client.main().unwrap(); + /*loop { let event = client.next_event().unwrap(); if let Some(evt) = event.downcast::() { println!("{:?}", evt); @@ -28,5 +29,5 @@ fn main() { println!("{:?}", evt); client.plugin::().reply_ping(evt); } - } + }*/ } diff --git a/src/client.rs b/src/client.rs index 6313156..70741b8 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,9 +1,9 @@ +use xml; use jid::Jid; use transport::{Transport, SslTransport}; use error::Error; use ns; -use plugin::{Plugin, PluginProxyBinding}; -use event::AbstractEvent; +use plugin::{Plugin, PluginInit, PluginProxyBinding}; use connection::{Connection, C2S}; use sasl::client::Mechanism as SaslMechanism; use sasl::client::mechanisms::{Plain, Scram}; @@ -11,6 +11,7 @@ use sasl::common::{Credentials as SaslCredentials, Identity, Secret, ChannelBind use sasl::common::scram::{Sha1, Sha256}; use components::sasl_error::SaslError; use util::FromElement; +use event::{Dispatcher, Propagation, SendElement, ReceiveElement, Priority}; use base64; @@ -18,9 +19,11 @@ use minidom::Element; use xml::reader::XmlEvent as ReaderEvent; -use std::sync::mpsc::{Receiver, channel}; +use std::sync::{Mutex, Arc}; -use std::collections::HashSet; +use std::collections::{HashSet, HashMap}; + +use std::any::TypeId; /// Struct that should be moved somewhere else and cleaned up. #[derive(Debug)] @@ -74,18 +77,22 @@ impl ClientBuilder { let host = &self.host.unwrap_or(self.jid.domain.clone()); let mut transport = SslTransport::connect(host, self.port)?; C2S::init(&mut transport, &self.jid.domain, "before_sasl")?; - let (sender_out, sender_in) = channel(); - let (dispatcher_out, dispatcher_in) = channel(); + let dispatcher = Arc::new(Mutex::new(Dispatcher::new())); let mut credentials = self.credentials; credentials.channel_binding = transport.channel_bind(); + let transport = Arc::new(Mutex::new(transport)); let mut client = Client { jid: self.jid, - transport: transport, - plugins: Vec::new(), - binding: PluginProxyBinding::new(sender_out, dispatcher_out), - sender_in: sender_in, - dispatcher_in: dispatcher_in, + transport: transport.clone(), + plugins: HashMap::new(), + binding: PluginProxyBinding::new(dispatcher.clone()), + dispatcher: dispatcher, }; + client.dispatcher.lock().unwrap().register(Priority::Default, Box::new(move |evt: &SendElement| { + let mut t = transport.lock().unwrap(); + t.write_element(&evt.0).unwrap(); + Propagation::Continue + })); client.connect(credentials)?; client.bind()?; Ok(client) @@ -95,11 +102,10 @@ impl ClientBuilder { /// An XMPP client. pub struct Client { jid: Jid, - transport: SslTransport, - plugins: Vec>, + transport: Arc>, + plugins: HashMap>>, binding: PluginProxyBinding, - sender_in: Receiver, - dispatcher_in: Receiver, + dispatcher: Arc>, } impl Client { @@ -109,46 +115,55 @@ impl Client { } /// Registers a plugin. - pub fn register_plugin(&mut self, mut plugin: P) { - plugin.bind(self.binding.clone()); - self.plugins.push(Box::new(plugin)); + pub fn register_plugin(&mut self, mut plugin: P) { + let binding = self.binding.clone(); + plugin.bind(binding); + let p = Arc::new(Box::new(plugin) as Box); + { + let mut disp = self.dispatcher.lock().unwrap(); + P::init(&mut disp, p.clone()); + } + if self.plugins.insert(TypeId::of::

(), p).is_some() { + panic!("registering a plugin that's already registered"); + } } /// Returns the plugin given by the type parameter, if it exists, else panics. pub fn plugin(&self) -> &P { - for plugin in &self.plugins { - let any = plugin.as_any(); - if let Some(ret) = any.downcast_ref::

() { - return ret; - } - } - panic!("plugin does not exist!"); + self.plugins.get(&TypeId::of::

()) + .expect("the requested plugin was not registered") + .as_any() + .downcast_ref::

() + .expect("plugin downcast failure (should not happen!!)") } /// Returns the next event and flush the send queue. - pub fn next_event(&mut self) -> Result { - self.flush_send_queue()?; + pub fn main(&mut self) -> Result<(), Error> { + self.dispatcher.lock().unwrap().flush_all(); loop { - if let Ok(evt) = self.dispatcher_in.try_recv() { - return Ok(evt); + let elem = self.read_element()?; + { + let mut disp = self.dispatcher.lock().unwrap(); + disp.dispatch(ReceiveElement(elem)); + disp.flush_all(); } - let elem = self.transport.read_element()?; - for plugin in self.plugins.iter_mut() { - plugin.handle(&elem); - // TODO: handle plugin return - } - self.flush_send_queue()?; } } - /// Flushes the send queue, sending all queued up stanzas. - pub fn flush_send_queue(&mut self) -> Result<(), Error> { // TODO: not sure how great of an - // idea it is to flush in this - // manner… - while let Ok(elem) = self.sender_in.try_recv() { - self.transport.write_element(&elem)?; - } - Ok(()) + fn reset_stream(&self) { + self.transport.lock().unwrap().reset_stream() + } + + fn read_element(&self) -> Result { + self.transport.lock().unwrap().read_element() + } + + fn write_element(&self, elem: &Element) -> Result<(), Error> { + self.transport.lock().unwrap().write_element(elem) + } + + fn read_event(&self) -> Result { + self.transport.lock().unwrap().read_event() } fn connect(&mut self, mut credentials: SaslCredentials) -> Result<(), Error> { @@ -188,9 +203,9 @@ impl Client { if !auth.is_empty() { elem.append_text_node(base64::encode(&auth)); } - self.transport.write_element(&elem)?; + self.write_element(&elem)?; loop { - let n = self.transport.read_element()?; + let n = self.read_element()?; if n.is("challenge", ns::SASL) { let text = n.text(); let challenge = if text == "" { @@ -206,7 +221,7 @@ impl Client { if !response.is_empty() { elem.append_text_node(base64::encode(&response)); } - self.transport.write_element(&elem)?; + self.write_element(&elem)?; } else if n.is("success", ns::SASL) { let text = n.text(); @@ -217,8 +232,11 @@ impl Client { base64::decode(&text)? }; mechanism.success(&data).map_err(|x| Error::SaslError(Some(x)))?; - self.transport.reset_stream(); - C2S::init(&mut self.transport, &self.jid.domain, "after_sasl")?; + self.reset_stream(); + { + let mut g = self.transport.lock().unwrap(); + C2S::init(&mut *g, &self.jid.domain, "after_sasl")?; + } self.wait_for_features()?; return Ok(()); } @@ -245,9 +263,9 @@ impl Client { bind.append_child(res); } elem.append_child(bind); - self.transport.write_element(&elem)?; + self.write_element(&elem)?; loop { - let n = self.transport.read_element()?; + let n = self.read_element()?; if n.is("iq", ns::CLIENT) && n.has_child("bind", ns::BIND) { return Ok(()); } @@ -257,7 +275,7 @@ impl Client { fn wait_for_features(&mut self) -> Result { // TODO: this is very ugly loop { - let e = self.transport.read_event()?; + let e = self.read_event()?; match e { ReaderEvent::StartElement { .. } => { break; @@ -266,7 +284,7 @@ impl Client { } } loop { - let n = self.transport.read_element()?; + let n = self.read_element()?; if n.is("features", ns::STREAM) { let mut features = StreamFeatures { sasl_mechanisms: None, diff --git a/src/event.rs b/src/event.rs index c580a2b..7841ee3 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,56 +1,262 @@ -//! Provides an abstract event type which can be downcasted into a more specific one. -//! -//! # Examples -//! -//! ``` -//! use xmpp::event::{Event, AbstractEvent}; -//! -//! #[derive(Debug, PartialEq, Eq)] -//! struct EventA; -//! -//! impl Event for EventA {} -//! -//! #[derive(Debug, PartialEq, Eq)] -//! struct EventB; -//! -//! impl Event for EventB {} -//! -//! let event_a = AbstractEvent::new(EventA); -//! -//! assert_eq!(event_a.is::(), true); -//! assert_eq!(event_a.is::(), false); -//! -//! assert_eq!(event_a.downcast::(), Some(&EventA)); -//! assert_eq!(event_a.downcast::(), None); -//! ``` - +use std::marker::PhantomData; +use std::any::{TypeId, Any}; use std::fmt::Debug; +use std::collections::BTreeMap; +use std::cmp::Ordering; +use std::sync::Arc; +use std::mem; +use std::ptr; +use std::raw::TraitObject; -use std::any::Any; +use minidom::Element; -/// An abstract event. -pub struct AbstractEvent { - inner: Box, +/// A marker trait which marks all events. +pub trait Event: Any + Debug {} + +/// A trait which can be implemented when something can handle a specific kind of event. +pub trait EventHandler: Any { + /// Handle an event, returns whether to propagate the event to the remaining handlers. + fn handle(&self, event: &E) -> Propagation; } -impl AbstractEvent { - /// Creates an abstract event from a concrete event. - pub fn new(event: E) -> AbstractEvent { - AbstractEvent { - inner: Box::new(event), +struct Record(P, T); + +impl PartialEq for Record { + fn eq(&self, other: &Record) -> bool { + self.0 == other.0 + } +} + +impl Eq for Record {} + +impl PartialOrd for Record { + fn partial_cmp(&self, other: &Record) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl Ord for Record { + fn cmp(&self, other: &Record) -> Ordering { + self.0.cmp(&other.0) + } +} + +/// An enum representing whether to keep propagating an event or to stop the propagation. +pub enum Propagation { + /// Stop the propagation of the event, the remaining handlers will not get invoked. + Stop, + /// Continue propagating the event. + Continue, +} + +#[derive(Debug)] +struct GarbageEvent; + +impl Event for GarbageEvent {} + +impl EventHandler for Box where E: Event, F: 'static + Fn(&E) -> Propagation { + fn handle(&self, evt: &E) -> Propagation { + self(evt) + } +} + +/// An event dispatcher, this takes care of dispatching events to their respective handlers. +pub struct Dispatcher { + handlers: BTreeMap>>>, + queue: Vec<(TypeId, Box)>, +} + +impl Dispatcher { + /// Create a new `Dispatcher`. + pub fn new() -> Dispatcher { + Dispatcher { + handlers: BTreeMap::new(), + queue: Vec::new(), } } - /// Downcasts this abstract event into a concrete event. - pub fn downcast(&self) -> Option<&E> { - self.inner.downcast_ref::() + /// Register an event handler. + pub fn register(&mut self, priority: Priority, handler: H) where E: Event + 'static, H: EventHandler { + let handler: Box> = Box::new(handler) as Box>; + let ent = self.handlers.entry(TypeId::of::()) + .or_insert_with(|| Vec::new()); + ent.push(Record(priority, Box::new(handler) as Box)); + ent.sort(); } - /// Checks whether this abstract event is a specific concrete event. - pub fn is(&self) -> bool { - self.inner.is::() + /// Append an event to the queue. + pub fn dispatch(&mut self, event: E) where E: Event { + self.queue.push((TypeId::of::(), Box::new(event) as Box)); + } + + /// Flush all events in the queue so they can be handled by their respective handlers. + /// Returns whether there are still pending events. + pub fn flush(&mut self) -> bool { + let mut q = Vec::new(); + mem::swap(&mut self.queue, &mut q); + 'evts: for (t, evt) in q { + if let Some(handlers) = self.handlers.get_mut(&t) { + for &mut Record(_, ref mut handler) in handlers { + // GarbageEvent is a garbage type. + // The actual passed type is NEVER of this type. + let h: &mut EventHandler = unsafe { + let handler_obj: &mut TraitObject = mem::transmute(handler); + let handler_inner: *mut TraitObject = mem::transmute(handler_obj.data); + mem::transmute(*handler_inner) + }; + let e: &&GarbageEvent = unsafe { + let evt_ref: &Any = &evt; + let evt_obj: TraitObject = mem::transmute(evt_ref); + mem::transmute(evt_obj.data) + }; + match h.handle(e) { + Propagation::Stop => { continue 'evts; }, + Propagation::Continue => (), + } + } + } + } + !self.queue.is_empty() + } + + /// Flushes all events, like `flush`, but keeps doing this until there is nothing left in the + /// queue. + pub fn flush_all(&mut self) { + while self.flush() {} + } + + /// Dispatch an event to the handlers right now, without going through the queue. + pub fn dispatch_now(&mut self, event: E) where E: Event { + if let Some(handlers) = self.handlers.get_mut(&TypeId::of::()) { + for &mut Record(_, ref mut handler) in handlers { + let h = handler.downcast_mut::>>().unwrap(); + match h.handle(&event) { + Propagation::Stop => { return; }, + Propagation::Continue => (), + } + } + } } } -/// A marker trait which all events must implement. -pub trait Event: Any + Debug {} +pub struct EventProxy { + inner: Arc>, + vtable: *mut (), + _event_type: PhantomData, +} + +impl EventProxy { + /// Unsafe because T is assumed to be a TraitObject or at least have its shape. + /// If it is not, things will break. In a fascinatingly horrible manner. + /// Some people, such as myself, find it hilarious. Most people do not. + /// T is also assumed to actually support EventHandler, if it does not, refer to above + /// statement. + pub unsafe fn new>(inner: Arc>) -> EventProxy { + let box_with_vtable = &*ptr::null::() as &EventHandler; + let obj: TraitObject = mem::transmute(box_with_vtable); + EventProxy { + inner: inner, + vtable: obj.vtable, + _event_type: PhantomData, + } + } +} + +impl EventHandler for EventProxy where Box: 'static { + fn handle(&self, evt: &E) -> Propagation { + let inner = Arc::into_raw(self.inner.clone()); + let obj = TraitObject { data: unsafe { mem::transmute(inner) }, vtable: self.vtable }; + let handler: &EventHandler = unsafe { mem::transmute(obj) }; + let prop = handler.handle(evt); + unsafe { Arc::>::from_raw(mem::transmute(inner)); } + prop + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Priority { + Max, + Default, + Min, +} + +impl Default for Priority { + fn default() -> Priority { + Priority::Default + } +} + +#[derive(Debug)] +pub struct SendElement(pub Element); + +impl Event for SendElement {} + +#[derive(Debug)] +pub struct ReceiveElement(pub Element); + +impl Event for ReceiveElement {} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic(expected = "success")] + fn test() { + let mut disp = Dispatcher::new(); + + struct MyHandler; + struct EvilHandler; + struct EventFilter; + + #[derive(Debug)] + struct MyEvent { + should_be_42: u32, + } + + impl Event for MyEvent {} + + impl EventHandler for MyHandler { + fn handle(&self, evt: &MyEvent) -> Propagation { + if evt.should_be_42 == 42 { + panic!("success"); + } + else { + panic!("not 42"); + } + } + } + + impl EventHandler for EvilHandler { + fn handle(&self, _: &MyEvent) -> Propagation { + panic!("should not be called"); + } + } + + impl EventHandler for EventFilter { + fn handle(&self, evt: &MyEvent) -> Propagation { + if evt.should_be_42 == 42 { + Propagation::Continue + } + else { + Propagation::Stop + } + } + } + + disp.register(Priority::Max, EventFilter); + disp.register(Priority::Min, EvilHandler); + disp.register(Priority::Default, MyHandler); + disp.register(Priority::Min, EvilHandler); + + disp.dispatch(MyEvent { + should_be_42: 39, + }); + + disp.dispatch(MyEvent { + should_be_42: 42, + }); + + disp.flush(); + } +} diff --git a/src/lib.rs b/src/lib.rs index 6a2715f..c3e933f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(raw)] + extern crate xml; extern crate openssl; extern crate minidom; @@ -10,8 +12,9 @@ pub mod ns; pub mod transport; pub mod error; pub mod client; -pub mod component; +//pub mod component; pub mod plugin; +#[macro_use] pub mod plugin_macro; pub mod event; pub mod plugins; pub mod connection; diff --git a/src/plugin.rs b/src/plugin.rs index 21c0114..2ccb460 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,10 +1,10 @@ //! Provides the plugin infrastructure. -use event::{Event, AbstractEvent}; +use event::{Event, EventHandler, Dispatcher, SendElement, Priority}; use std::any::Any; -use std::sync::mpsc::Sender; +use std::sync::{Arc, Mutex}; use std::mem; @@ -12,14 +12,12 @@ use minidom::Element; #[derive(Clone)] pub struct PluginProxyBinding { - sender: Sender, - dispatcher: Sender, + dispatcher: Arc>, } impl PluginProxyBinding { - pub fn new(sender: Sender, dispatcher: Sender) -> PluginProxyBinding { + pub fn new(dispatcher: Arc>) -> PluginProxyBinding { PluginProxyBinding { - sender: sender, dispatcher: dispatcher, } } @@ -58,46 +56,44 @@ impl PluginProxy { /// Dispatches an event. pub fn dispatch(&self, event: E) { self.with_binding(move |binding| { - binding.dispatcher.send(AbstractEvent::new(event)) - .unwrap(); // TODO: may want to return the error + // TODO: proper error handling + binding.dispatcher.lock().unwrap().dispatch(event); + }); + } + + /// Registers an event handler. + pub fn register_handler(&self, priority: Priority, handler: H) where E: Event, H: EventHandler { + self.with_binding(move |binding| { + // TODO: proper error handling + binding.dispatcher.lock().unwrap().register(priority, handler); }); } /// Sends a stanza. pub fn send(&self, elem: Element) { - self.with_binding(move |binding| { - binding.sender.send(elem).unwrap(); // TODO: as above, may want to return the error - }); + self.dispatch(SendElement(elem)); } } -/// A plugin handler return value. -/// -/// The `Continue` variant means to do nothing, the `Unload` variant means to unload the plugin. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum PluginReturn { - Continue, - Unload, -} - /// A trait whch all plugins should implement. pub trait Plugin: Any + PluginAny { /// Gets a mutable reference to the inner `PluginProxy`. fn get_proxy(&mut self) -> &mut PluginProxy; - /// Handles a received stanza. - fn handle(&mut self, elem: &Element) -> PluginReturn; - #[doc(hidden)] fn bind(&mut self, inner: PluginProxyBinding) { self.get_proxy().bind(inner); } } +pub trait PluginInit { + fn init(dispatcher: &mut Dispatcher, me: Arc>); +} + pub trait PluginAny { fn as_any(&self) -> &Any; } -impl PluginAny for T { +impl PluginAny for T { fn as_any(&self) -> &Any { self } } diff --git a/src/plugin_macro.rs b/src/plugin_macro.rs new file mode 100644 index 0000000..36599cc --- /dev/null +++ b/src/plugin_macro.rs @@ -0,0 +1,26 @@ +#[macro_export] +macro_rules! impl_plugin { + ($plugin:ty, $proxy:ident, [$($evt:ty => $pri:expr),*]) => { + impl $crate::plugin::Plugin for $plugin { + fn get_proxy(&mut self) -> &mut $crate::plugin::PluginProxy { + &mut self.$proxy + } + } + + #[allow(unused_variables)] + impl $crate::plugin::PluginInit for $plugin { + fn init( dispatcher: &mut $crate::event::Dispatcher + , me: ::std::sync::Arc>) { + $( + dispatcher.register($pri, unsafe { + $crate::event::EventProxy::new::<$plugin>(me.clone()) + }); + )* + } + } + }; + + ($plugin:ty, $proxy:ident, [$($evt:ty => $pri:expr),*,]) => { + impl_plugin!($plugin, $proxy, [$($evt => $pri),*]); + }; +} diff --git a/src/plugins/messaging.rs b/src/plugins/messaging.rs index af840c8..1fe9d54 100644 --- a/src/plugins/messaging.rs +++ b/src/plugins/messaging.rs @@ -1,5 +1,5 @@ -use plugin::{Plugin, PluginReturn, PluginProxy}; -use event::Event; +use plugin::{PluginProxy}; +use event::{Event, EventHandler, ReceiveElement, Priority, Propagation}; use minidom::Element; use error::Error; use jid::Jid; @@ -36,12 +36,13 @@ impl MessagingPlugin { } } -impl Plugin for MessagingPlugin { - fn get_proxy(&mut self) -> &mut PluginProxy { - &mut self.proxy - } +impl_plugin!(MessagingPlugin, proxy, [ + ReceiveElement => Priority::Default, +]); - fn handle(&mut self, elem: &Element) -> PluginReturn { +impl EventHandler for MessagingPlugin { + fn handle(&self, evt: &ReceiveElement) -> Propagation { + let elem = &evt.0; if elem.is("message", ns::CLIENT) && elem.attr("type") == Some("chat") { if let Some(body) = elem.get_child("body", ns::CLIENT) { self.proxy.dispatch(MessageEvent { // TODO: safety!!! @@ -51,6 +52,6 @@ impl Plugin for MessagingPlugin { }); } } - PluginReturn::Continue + Propagation::Continue } } diff --git a/src/plugins/ping.rs b/src/plugins/ping.rs index e9a457c..3421d7d 100644 --- a/src/plugins/ping.rs +++ b/src/plugins/ping.rs @@ -1,5 +1,5 @@ -use plugin::{Plugin, PluginReturn, PluginProxy}; -use event::Event; +use plugin::PluginProxy; +use event::{Event, EventHandler, Priority, Propagation, ReceiveElement}; use minidom::Element; use error::Error; use jid::Jid; @@ -45,12 +45,13 @@ impl PingPlugin { } } -impl Plugin for PingPlugin { - fn get_proxy(&mut self) -> &mut PluginProxy { - &mut self.proxy - } +impl_plugin!(PingPlugin, proxy, [ + ReceiveElement => Priority::Default, +]); - fn handle(&mut self, elem: &Element) -> PluginReturn { +impl EventHandler for PingPlugin { + fn handle(&self, evt: &ReceiveElement) -> Propagation { + let elem = &evt.0; if elem.is("iq", ns::CLIENT) && elem.attr("type") == Some("get") { if elem.has_child("ping", ns::PING) { self.proxy.dispatch(PingEvent { // TODO: safety!!! @@ -60,6 +61,6 @@ impl Plugin for PingPlugin { }); } } - PluginReturn::Continue + Propagation::Continue } } diff --git a/src/plugins/presence.rs b/src/plugins/presence.rs index 70a6773..147ac28 100644 --- a/src/plugins/presence.rs +++ b/src/plugins/presence.rs @@ -1,5 +1,5 @@ use error::Error; -use plugin::{Plugin, PluginProxy, PluginReturn}; +use plugin::PluginProxy; use minidom::Element; @@ -94,12 +94,4 @@ impl PresencePlugin { } } -impl Plugin for PresencePlugin { - fn get_proxy(&mut self) -> &mut PluginProxy { - &mut self.proxy - } - - fn handle(&mut self, _elem: &Element) -> PluginReturn { - PluginReturn::Continue - } -} +impl_plugin!(PresencePlugin, proxy, []); diff --git a/src/plugins/stanza.rs b/src/plugins/stanza.rs index d0d7f8b..d30f0ad 100644 --- a/src/plugins/stanza.rs +++ b/src/plugins/stanza.rs @@ -1,8 +1,8 @@ use std::fmt::Debug; use std::any::Any; -use plugin::{Plugin, PluginReturn, PluginProxy}; -use event::Event; +use plugin::PluginProxy; +use event::{Event, EventHandler, ReceiveElement, Propagation, Priority}; use minidom::Element; use jid::Jid; use ns; @@ -52,12 +52,14 @@ impl StanzaPlugin { } } -impl Plugin for StanzaPlugin { - fn get_proxy(&mut self) -> &mut PluginProxy { - &mut self.proxy - } +impl_plugin!(StanzaPlugin, proxy, [ + ReceiveElement => Priority::Default, +]); + +impl EventHandler for StanzaPlugin { + fn handle(&self, evt: &ReceiveElement) -> Propagation { + let elem = &evt.0; - fn handle(&mut self, elem: &Element) -> PluginReturn { let from = match elem.attr("from") { Some(from) => Some(from.parse().unwrap()), None => None }; let to = match elem.attr("to") { Some(to) => Some(to.parse().unwrap()), None => None }; let id = match elem.attr("id") { Some(id) => Some(id.parse().unwrap()), None => None }; @@ -89,6 +91,7 @@ impl Plugin for StanzaPlugin { payloads: payloads, }); } - PluginReturn::Continue + + Propagation::Continue } }