implement the new event system, things are still really messy

This commit is contained in:
lumi 2017-05-10 00:13:54 +02:00
parent f3b9984ff2
commit 917b14b5d2
11 changed files with 404 additions and 157 deletions

View file

@ -1,4 +1,4 @@
image: "scorpil/rust:stable" image: "scorpil/rust:nightly"
before_script: before_script:
- apt-get update -yqq - apt-get update -yqq

View file

@ -19,7 +19,8 @@ fn main() {
client.register_plugin(PresencePlugin::new()); client.register_plugin(PresencePlugin::new());
client.register_plugin(PingPlugin::new()); client.register_plugin(PingPlugin::new());
client.plugin::<PresencePlugin>().set_presence(Show::Available, None).unwrap(); client.plugin::<PresencePlugin>().set_presence(Show::Available, None).unwrap();
loop { client.main().unwrap();
/*loop {
let event = client.next_event().unwrap(); let event = client.next_event().unwrap();
if let Some(evt) = event.downcast::<MessageEvent>() { if let Some(evt) = event.downcast::<MessageEvent>() {
println!("{:?}", evt); println!("{:?}", evt);
@ -28,5 +29,5 @@ fn main() {
println!("{:?}", evt); println!("{:?}", evt);
client.plugin::<PingPlugin>().reply_ping(evt); client.plugin::<PingPlugin>().reply_ping(evt);
} }
} }*/
} }

View file

@ -1,9 +1,9 @@
use xml;
use jid::Jid; use jid::Jid;
use transport::{Transport, SslTransport}; use transport::{Transport, SslTransport};
use error::Error; use error::Error;
use ns; use ns;
use plugin::{Plugin, PluginProxyBinding}; use plugin::{Plugin, PluginInit, PluginProxyBinding};
use event::AbstractEvent;
use connection::{Connection, C2S}; use connection::{Connection, C2S};
use sasl::client::Mechanism as SaslMechanism; use sasl::client::Mechanism as SaslMechanism;
use sasl::client::mechanisms::{Plain, Scram}; 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 sasl::common::scram::{Sha1, Sha256};
use components::sasl_error::SaslError; use components::sasl_error::SaslError;
use util::FromElement; use util::FromElement;
use event::{Dispatcher, Propagation, SendElement, ReceiveElement, Priority};
use base64; use base64;
@ -18,9 +19,11 @@ use minidom::Element;
use xml::reader::XmlEvent as ReaderEvent; 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. /// Struct that should be moved somewhere else and cleaned up.
#[derive(Debug)] #[derive(Debug)]
@ -74,18 +77,22 @@ impl ClientBuilder {
let host = &self.host.unwrap_or(self.jid.domain.clone()); let host = &self.host.unwrap_or(self.jid.domain.clone());
let mut transport = SslTransport::connect(host, self.port)?; let mut transport = SslTransport::connect(host, self.port)?;
C2S::init(&mut transport, &self.jid.domain, "before_sasl")?; C2S::init(&mut transport, &self.jid.domain, "before_sasl")?;
let (sender_out, sender_in) = channel(); let dispatcher = Arc::new(Mutex::new(Dispatcher::new()));
let (dispatcher_out, dispatcher_in) = channel();
let mut credentials = self.credentials; let mut credentials = self.credentials;
credentials.channel_binding = transport.channel_bind(); credentials.channel_binding = transport.channel_bind();
let transport = Arc::new(Mutex::new(transport));
let mut client = Client { let mut client = Client {
jid: self.jid, jid: self.jid,
transport: transport, transport: transport.clone(),
plugins: Vec::new(), plugins: HashMap::new(),
binding: PluginProxyBinding::new(sender_out, dispatcher_out), binding: PluginProxyBinding::new(dispatcher.clone()),
sender_in: sender_in, dispatcher: dispatcher,
dispatcher_in: dispatcher_in,
}; };
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.connect(credentials)?;
client.bind()?; client.bind()?;
Ok(client) Ok(client)
@ -95,11 +102,10 @@ impl ClientBuilder {
/// An XMPP client. /// An XMPP client.
pub struct Client { pub struct Client {
jid: Jid, jid: Jid,
transport: SslTransport, transport: Arc<Mutex<SslTransport>>,
plugins: Vec<Box<Plugin>>, plugins: HashMap<TypeId, Arc<Box<Plugin>>>,
binding: PluginProxyBinding, binding: PluginProxyBinding,
sender_in: Receiver<Element>, dispatcher: Arc<Mutex<Dispatcher>>,
dispatcher_in: Receiver<AbstractEvent>,
} }
impl Client { impl Client {
@ -109,46 +115,55 @@ impl Client {
} }
/// Registers a plugin. /// Registers a plugin.
pub fn register_plugin<P: Plugin + 'static>(&mut self, mut plugin: P) { pub fn register_plugin<P: Plugin + PluginInit + 'static>(&mut self, mut plugin: P) {
plugin.bind(self.binding.clone()); let binding = self.binding.clone();
self.plugins.push(Box::new(plugin)); plugin.bind(binding);
let p = Arc::new(Box::new(plugin) as Box<Plugin>);
{
let mut disp = self.dispatcher.lock().unwrap();
P::init(&mut disp, p.clone());
}
if self.plugins.insert(TypeId::of::<P>(), p).is_some() {
panic!("registering a plugin that's already registered");
}
} }
/// Returns the plugin given by the type parameter, if it exists, else panics. /// Returns the plugin given by the type parameter, if it exists, else panics.
pub fn plugin<P: Plugin>(&self) -> &P { pub fn plugin<P: Plugin>(&self) -> &P {
for plugin in &self.plugins { self.plugins.get(&TypeId::of::<P>())
let any = plugin.as_any(); .expect("the requested plugin was not registered")
if let Some(ret) = any.downcast_ref::<P>() { .as_any()
return ret; .downcast_ref::<P>()
} .expect("plugin downcast failure (should not happen!!)")
}
panic!("plugin does not exist!");
} }
/// Returns the next event and flush the send queue. /// Returns the next event and flush the send queue.
pub fn next_event(&mut self) -> Result<AbstractEvent, Error> { pub fn main(&mut self) -> Result<(), Error> {
self.flush_send_queue()?; self.dispatcher.lock().unwrap().flush_all();
loop { loop {
if let Ok(evt) = self.dispatcher_in.try_recv() { let elem = self.read_element()?;
return Ok(evt); {
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. fn reset_stream(&self) {
pub fn flush_send_queue(&mut self) -> Result<(), Error> { // TODO: not sure how great of an self.transport.lock().unwrap().reset_stream()
// idea it is to flush in this }
// manner…
while let Ok(elem) = self.sender_in.try_recv() { fn read_element(&self) -> Result<Element, Error> {
self.transport.write_element(&elem)?; self.transport.lock().unwrap().read_element()
} }
Ok(())
fn write_element(&self, elem: &Element) -> Result<(), Error> {
self.transport.lock().unwrap().write_element(elem)
}
fn read_event(&self) -> Result<xml::reader::XmlEvent, Error> {
self.transport.lock().unwrap().read_event()
} }
fn connect(&mut self, mut credentials: SaslCredentials) -> Result<(), Error> { fn connect(&mut self, mut credentials: SaslCredentials) -> Result<(), Error> {
@ -188,9 +203,9 @@ impl Client {
if !auth.is_empty() { if !auth.is_empty() {
elem.append_text_node(base64::encode(&auth)); elem.append_text_node(base64::encode(&auth));
} }
self.transport.write_element(&elem)?; self.write_element(&elem)?;
loop { loop {
let n = self.transport.read_element()?; let n = self.read_element()?;
if n.is("challenge", ns::SASL) { if n.is("challenge", ns::SASL) {
let text = n.text(); let text = n.text();
let challenge = if text == "" { let challenge = if text == "" {
@ -206,7 +221,7 @@ impl Client {
if !response.is_empty() { if !response.is_empty() {
elem.append_text_node(base64::encode(&response)); elem.append_text_node(base64::encode(&response));
} }
self.transport.write_element(&elem)?; self.write_element(&elem)?;
} }
else if n.is("success", ns::SASL) { else if n.is("success", ns::SASL) {
let text = n.text(); let text = n.text();
@ -217,8 +232,11 @@ impl Client {
base64::decode(&text)? base64::decode(&text)?
}; };
mechanism.success(&data).map_err(|x| Error::SaslError(Some(x)))?; mechanism.success(&data).map_err(|x| Error::SaslError(Some(x)))?;
self.transport.reset_stream(); self.reset_stream();
C2S::init(&mut self.transport, &self.jid.domain, "after_sasl")?; {
let mut g = self.transport.lock().unwrap();
C2S::init(&mut *g, &self.jid.domain, "after_sasl")?;
}
self.wait_for_features()?; self.wait_for_features()?;
return Ok(()); return Ok(());
} }
@ -245,9 +263,9 @@ impl Client {
bind.append_child(res); bind.append_child(res);
} }
elem.append_child(bind); elem.append_child(bind);
self.transport.write_element(&elem)?; self.write_element(&elem)?;
loop { loop {
let n = self.transport.read_element()?; let n = self.read_element()?;
if n.is("iq", ns::CLIENT) && n.has_child("bind", ns::BIND) { if n.is("iq", ns::CLIENT) && n.has_child("bind", ns::BIND) {
return Ok(()); return Ok(());
} }
@ -257,7 +275,7 @@ impl Client {
fn wait_for_features(&mut self) -> Result<StreamFeatures, Error> { fn wait_for_features(&mut self) -> Result<StreamFeatures, Error> {
// TODO: this is very ugly // TODO: this is very ugly
loop { loop {
let e = self.transport.read_event()?; let e = self.read_event()?;
match e { match e {
ReaderEvent::StartElement { .. } => { ReaderEvent::StartElement { .. } => {
break; break;
@ -266,7 +284,7 @@ impl Client {
} }
} }
loop { loop {
let n = self.transport.read_element()?; let n = self.read_element()?;
if n.is("features", ns::STREAM) { if n.is("features", ns::STREAM) {
let mut features = StreamFeatures { let mut features = StreamFeatures {
sasl_mechanisms: None, sasl_mechanisms: None,

View file

@ -1,56 +1,262 @@
//! Provides an abstract event type which can be downcasted into a more specific one. use std::marker::PhantomData;
//! use std::any::{TypeId, Any};
//! # 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::<EventA>(), true);
//! assert_eq!(event_a.is::<EventB>(), false);
//!
//! assert_eq!(event_a.downcast::<EventA>(), Some(&EventA));
//! assert_eq!(event_a.downcast::<EventB>(), None);
//! ```
use std::fmt::Debug; 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. /// A marker trait which marks all events.
pub struct AbstractEvent { pub trait Event: Any + Debug {}
inner: Box<Any>,
/// A trait which can be implemented when something can handle a specific kind of event.
pub trait EventHandler<E: Event>: Any {
/// Handle an event, returns whether to propagate the event to the remaining handlers.
fn handle(&self, event: &E) -> Propagation;
} }
impl AbstractEvent { struct Record<P, T>(P, T);
/// Creates an abstract event from a concrete event.
pub fn new<E: Event>(event: E) -> AbstractEvent { impl<P: PartialEq, T> PartialEq for Record<P, T> {
AbstractEvent { fn eq(&self, other: &Record<P, T>) -> bool {
inner: Box::new(event), self.0 == other.0
}
}
impl<P: Eq, T> Eq for Record<P, T> {}
impl<P: PartialOrd, T> PartialOrd for Record<P, T> {
fn partial_cmp(&self, other: &Record<P, T>) -> Option<Ordering> {
self.0.partial_cmp(&other.0)
}
}
impl<P: Ord, T> Ord for Record<P, T> {
fn cmp(&self, other: &Record<P, T>) -> 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<E, F> EventHandler<E> for Box<F> 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<TypeId, Vec<Record<Priority, Box<Any>>>>,
queue: Vec<(TypeId, Box<Any>)>,
}
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. /// Register an event handler.
pub fn downcast<E: Event + 'static>(&self) -> Option<&E> { pub fn register<E, H>(&mut self, priority: Priority, handler: H) where E: Event + 'static, H: EventHandler<E> {
self.inner.downcast_ref::<E>() let handler: Box<EventHandler<E>> = Box::new(handler) as Box<EventHandler<E>>;
let ent = self.handlers.entry(TypeId::of::<E>())
.or_insert_with(|| Vec::new());
ent.push(Record(priority, Box::new(handler) as Box<Any>));
ent.sort();
} }
/// Checks whether this abstract event is a specific concrete event. /// Append an event to the queue.
pub fn is<E: Event + 'static>(&self) -> bool { pub fn dispatch<E>(&mut self, event: E) where E: Event {
self.inner.is::<E>() self.queue.push((TypeId::of::<E>(), Box::new(event) as Box<Any>));
}
/// 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<GarbageEvent> = 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<E>(&mut self, event: E) where E: Event {
if let Some(handlers) = self.handlers.get_mut(&TypeId::of::<E>()) {
for &mut Record(_, ref mut handler) in handlers {
let h = handler.downcast_mut::<Box<EventHandler<E>>>().unwrap();
match h.handle(&event) {
Propagation::Stop => { return; },
Propagation::Continue => (),
}
}
}
} }
} }
/// A marker trait which all events must implement. pub struct EventProxy<T: ?Sized, E: Event> {
pub trait Event: Any + Debug {} inner: Arc<Box<T>>,
vtable: *mut (),
_event_type: PhantomData<E>,
}
impl<T: ?Sized, E: Event> EventProxy<T, E> {
/// 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<E>, if it does not, refer to above
/// statement.
pub unsafe fn new<H: EventHandler<E>>(inner: Arc<Box<T>>) -> EventProxy<T, E> {
let box_with_vtable = &*ptr::null::<H>() as &EventHandler<E>;
let obj: TraitObject = mem::transmute(box_with_vtable);
EventProxy {
inner: inner,
vtable: obj.vtable,
_event_type: PhantomData,
}
}
}
impl<T: ?Sized, E: Event> EventHandler<E> for EventProxy<T, E> where Box<T>: '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<E> = unsafe { mem::transmute(obj) };
let prop = handler.handle(evt);
unsafe { Arc::<Box<T>>::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<MyEvent> for MyHandler {
fn handle(&self, evt: &MyEvent) -> Propagation {
if evt.should_be_42 == 42 {
panic!("success");
}
else {
panic!("not 42");
}
}
}
impl EventHandler<MyEvent> for EvilHandler {
fn handle(&self, _: &MyEvent) -> Propagation {
panic!("should not be called");
}
}
impl EventHandler<MyEvent> 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();
}
}

View file

@ -1,3 +1,5 @@
#![feature(raw)]
extern crate xml; extern crate xml;
extern crate openssl; extern crate openssl;
extern crate minidom; extern crate minidom;
@ -10,8 +12,9 @@ pub mod ns;
pub mod transport; pub mod transport;
pub mod error; pub mod error;
pub mod client; pub mod client;
pub mod component; //pub mod component;
pub mod plugin; pub mod plugin;
#[macro_use] pub mod plugin_macro;
pub mod event; pub mod event;
pub mod plugins; pub mod plugins;
pub mod connection; pub mod connection;

View file

@ -1,10 +1,10 @@
//! Provides the plugin infrastructure. //! Provides the plugin infrastructure.
use event::{Event, AbstractEvent}; use event::{Event, EventHandler, Dispatcher, SendElement, Priority};
use std::any::Any; use std::any::Any;
use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex};
use std::mem; use std::mem;
@ -12,14 +12,12 @@ use minidom::Element;
#[derive(Clone)] #[derive(Clone)]
pub struct PluginProxyBinding { pub struct PluginProxyBinding {
sender: Sender<Element>, dispatcher: Arc<Mutex<Dispatcher>>,
dispatcher: Sender<AbstractEvent>,
} }
impl PluginProxyBinding { impl PluginProxyBinding {
pub fn new(sender: Sender<Element>, dispatcher: Sender<AbstractEvent>) -> PluginProxyBinding { pub fn new(dispatcher: Arc<Mutex<Dispatcher>>) -> PluginProxyBinding {
PluginProxyBinding { PluginProxyBinding {
sender: sender,
dispatcher: dispatcher, dispatcher: dispatcher,
} }
} }
@ -58,46 +56,44 @@ impl PluginProxy {
/// Dispatches an event. /// Dispatches an event.
pub fn dispatch<E: Event>(&self, event: E) { pub fn dispatch<E: Event>(&self, event: E) {
self.with_binding(move |binding| { self.with_binding(move |binding| {
binding.dispatcher.send(AbstractEvent::new(event)) // TODO: proper error handling
.unwrap(); // TODO: may want to return the error binding.dispatcher.lock().unwrap().dispatch(event);
});
}
/// Registers an event handler.
pub fn register_handler<E, H>(&self, priority: Priority, handler: H) where E: Event, H: EventHandler<E> {
self.with_binding(move |binding| {
// TODO: proper error handling
binding.dispatcher.lock().unwrap().register(priority, handler);
}); });
} }
/// Sends a stanza. /// Sends a stanza.
pub fn send(&self, elem: Element) { pub fn send(&self, elem: Element) {
self.with_binding(move |binding| { self.dispatch(SendElement(elem));
binding.sender.send(elem).unwrap(); // TODO: as above, may want to return the error
});
} }
} }
/// 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. /// A trait whch all plugins should implement.
pub trait Plugin: Any + PluginAny { pub trait Plugin: Any + PluginAny {
/// Gets a mutable reference to the inner `PluginProxy`. /// Gets a mutable reference to the inner `PluginProxy`.
fn get_proxy(&mut self) -> &mut PluginProxy; fn get_proxy(&mut self) -> &mut PluginProxy;
/// Handles a received stanza.
fn handle(&mut self, elem: &Element) -> PluginReturn;
#[doc(hidden)] #[doc(hidden)]
fn bind(&mut self, inner: PluginProxyBinding) { fn bind(&mut self, inner: PluginProxyBinding) {
self.get_proxy().bind(inner); self.get_proxy().bind(inner);
} }
} }
pub trait PluginInit {
fn init(dispatcher: &mut Dispatcher, me: Arc<Box<Plugin>>);
}
pub trait PluginAny { pub trait PluginAny {
fn as_any(&self) -> &Any; fn as_any(&self) -> &Any;
} }
impl<T: Any + Sized> PluginAny for T { impl<T: Any + Sized + Plugin> PluginAny for T {
fn as_any(&self) -> &Any { self } fn as_any(&self) -> &Any { self }
} }

26
src/plugin_macro.rs Normal file
View file

@ -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<Box<$crate::plugin::Plugin>>) {
$(
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),*]);
};
}

View file

@ -1,5 +1,5 @@
use plugin::{Plugin, PluginReturn, PluginProxy}; use plugin::{PluginProxy};
use event::Event; use event::{Event, EventHandler, ReceiveElement, Priority, Propagation};
use minidom::Element; use minidom::Element;
use error::Error; use error::Error;
use jid::Jid; use jid::Jid;
@ -36,12 +36,13 @@ impl MessagingPlugin {
} }
} }
impl Plugin for MessagingPlugin { impl_plugin!(MessagingPlugin, proxy, [
fn get_proxy(&mut self) -> &mut PluginProxy { ReceiveElement => Priority::Default,
&mut self.proxy ]);
}
fn handle(&mut self, elem: &Element) -> PluginReturn { impl EventHandler<ReceiveElement> for MessagingPlugin {
fn handle(&self, evt: &ReceiveElement) -> Propagation {
let elem = &evt.0;
if elem.is("message", ns::CLIENT) && elem.attr("type") == Some("chat") { if elem.is("message", ns::CLIENT) && elem.attr("type") == Some("chat") {
if let Some(body) = elem.get_child("body", ns::CLIENT) { if let Some(body) = elem.get_child("body", ns::CLIENT) {
self.proxy.dispatch(MessageEvent { // TODO: safety!!! self.proxy.dispatch(MessageEvent { // TODO: safety!!!
@ -51,6 +52,6 @@ impl Plugin for MessagingPlugin {
}); });
} }
} }
PluginReturn::Continue Propagation::Continue
} }
} }

View file

@ -1,5 +1,5 @@
use plugin::{Plugin, PluginReturn, PluginProxy}; use plugin::PluginProxy;
use event::Event; use event::{Event, EventHandler, Priority, Propagation, ReceiveElement};
use minidom::Element; use minidom::Element;
use error::Error; use error::Error;
use jid::Jid; use jid::Jid;
@ -45,12 +45,13 @@ impl PingPlugin {
} }
} }
impl Plugin for PingPlugin { impl_plugin!(PingPlugin, proxy, [
fn get_proxy(&mut self) -> &mut PluginProxy { ReceiveElement => Priority::Default,
&mut self.proxy ]);
}
fn handle(&mut self, elem: &Element) -> PluginReturn { impl EventHandler<ReceiveElement> 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.is("iq", ns::CLIENT) && elem.attr("type") == Some("get") {
if elem.has_child("ping", ns::PING) { if elem.has_child("ping", ns::PING) {
self.proxy.dispatch(PingEvent { // TODO: safety!!! self.proxy.dispatch(PingEvent { // TODO: safety!!!
@ -60,6 +61,6 @@ impl Plugin for PingPlugin {
}); });
} }
} }
PluginReturn::Continue Propagation::Continue
} }
} }

View file

@ -1,5 +1,5 @@
use error::Error; use error::Error;
use plugin::{Plugin, PluginProxy, PluginReturn}; use plugin::PluginProxy;
use minidom::Element; use minidom::Element;
@ -94,12 +94,4 @@ impl PresencePlugin {
} }
} }
impl Plugin for PresencePlugin { impl_plugin!(PresencePlugin, proxy, []);
fn get_proxy(&mut self) -> &mut PluginProxy {
&mut self.proxy
}
fn handle(&mut self, _elem: &Element) -> PluginReturn {
PluginReturn::Continue
}
}

View file

@ -1,8 +1,8 @@
use std::fmt::Debug; use std::fmt::Debug;
use std::any::Any; use std::any::Any;
use plugin::{Plugin, PluginReturn, PluginProxy}; use plugin::PluginProxy;
use event::Event; use event::{Event, EventHandler, ReceiveElement, Propagation, Priority};
use minidom::Element; use minidom::Element;
use jid::Jid; use jid::Jid;
use ns; use ns;
@ -52,12 +52,14 @@ impl StanzaPlugin {
} }
} }
impl Plugin for StanzaPlugin { impl_plugin!(StanzaPlugin, proxy, [
fn get_proxy(&mut self) -> &mut PluginProxy { ReceiveElement => Priority::Default,
&mut self.proxy ]);
}
impl EventHandler<ReceiveElement> 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 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 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 }; let id = match elem.attr("id") { Some(id) => Some(id.parse().unwrap()), None => None };
@ -89,6 +91,7 @@ impl Plugin for StanzaPlugin {
payloads: payloads, payloads: payloads,
}); });
} }
PluginReturn::Continue
Propagation::Continue
} }
} }