mirror of
https://gitlab.com/xmpp-rs/xmpp-rs.git
synced 2024-07-12 22:21:53 +00:00
implement the new event system, things are still really messy
This commit is contained in:
parent
f3b9984ff2
commit
917b14b5d2
11 changed files with 404 additions and 157 deletions
|
@ -1,4 +1,4 @@
|
||||||
image: "scorpil/rust:stable"
|
image: "scorpil/rust:nightly"
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- apt-get update -yqq
|
- apt-get update -yqq
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
122
src/client.rs
122
src/client.rs
|
@ -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,
|
||||||
|
|
292
src/event.rs
292
src/event.rs
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
26
src/plugin_macro.rs
Normal 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),*]);
|
||||||
|
};
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue