diff --git a/src/client.rs b/src/client.rs index a4504a0..e47616f 100644 --- a/src/client.rs +++ b/src/client.rs @@ -3,7 +3,7 @@ use jid::Jid; use transport::{Transport, SslTransport}; use error::Error; use ns; -use plugin::{Plugin, PluginInit, PluginProxyBinding}; +use plugin::{Plugin, PluginInit, PluginProxyBinding, PluginContainer, PluginRef}; use connection::{Connection, C2S}; use sasl::client::Mechanism as SaslMechanism; use sasl::client::mechanisms::{Plain, Scram}; @@ -21,9 +21,7 @@ use xml::reader::XmlEvent as ReaderEvent; use std::sync::{Mutex, Arc}; -use std::collections::{HashSet, HashMap}; - -use std::any::TypeId; +use std::collections::HashSet; /// Struct that should be moved somewhere else and cleaned up. #[derive(Debug)] @@ -81,11 +79,12 @@ impl ClientBuilder { let mut credentials = self.credentials; credentials.channel_binding = transport.channel_bind(); let transport = Arc::new(Mutex::new(transport)); + let plugin_container = Arc::new(PluginContainer::new()); let mut client = Client { jid: self.jid, transport: transport.clone(), - plugins: HashMap::new(), - binding: PluginProxyBinding::new(dispatcher.clone()), + binding: PluginProxyBinding::new(dispatcher.clone(), plugin_container.clone()), + plugin_container: plugin_container, dispatcher: dispatcher, }; client.dispatcher.register(Priority::Default, move |evt: &SendElement| { @@ -103,7 +102,7 @@ impl ClientBuilder { pub struct Client { jid: Jid, transport: Arc>, - plugins: HashMap>, + plugin_container: Arc, binding: PluginProxyBinding, dispatcher: Arc, } @@ -118,11 +117,9 @@ impl Client { pub fn register_plugin(&mut self, mut plugin: P) { let binding = self.binding.clone(); plugin.bind(binding); - let p = Arc::new(plugin) as Arc; + let p = Arc::new(plugin); P::init(&self.dispatcher, p.clone()); - if self.plugins.insert(TypeId::of::

(), p).is_some() { - panic!("registering a plugin that's already registered"); - } + self.plugin_container.register(p); } pub fn register_handler(&mut self, pri: Priority, func: F) @@ -133,12 +130,8 @@ impl Client { } /// Returns the plugin given by the type parameter, if it exists, else panics. - pub fn plugin(&self) -> &P { - self.plugins.get(&TypeId::of::

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

() - .expect("plugin downcast failure (should not happen!!)") + pub fn plugin(&self) -> PluginRef

{ + self.plugin_container.get::

().unwrap() } /// Returns the next event and flush the send queue. diff --git a/src/component.rs b/src/component.rs index 77de6c0..63125ba 100644 --- a/src/component.rs +++ b/src/component.rs @@ -3,7 +3,7 @@ use jid::Jid; use transport::{Transport, PlainTransport}; use error::Error; use ns; -use plugin::{Plugin, PluginInit, PluginProxyBinding}; +use plugin::{Plugin, PluginInit, PluginProxyBinding, PluginContainer, PluginRef}; use event::{Dispatcher, ReceiveElement, SendElement, Propagation, Priority, Event}; use connection::{Connection, Component2S}; use sha_1::{Sha1, Digest}; @@ -15,10 +15,6 @@ use xml::reader::XmlEvent as ReaderEvent; use std::fmt::Write; use std::sync::{Mutex, Arc}; -use std::collections::HashMap; - -use std::any::TypeId; - /// A builder for `Component`s. pub struct ComponentBuilder { jid: Jid, @@ -63,11 +59,12 @@ impl ComponentBuilder { Component2S::init(&mut transport, &self.jid.domain, "stream_opening")?; let dispatcher = Arc::new(Dispatcher::new()); let transport = Arc::new(Mutex::new(transport)); + let plugin_container = Arc::new(PluginContainer::new()); let mut component = Component { jid: self.jid, transport: transport.clone(), - plugins: HashMap::new(), - binding: PluginProxyBinding::new(dispatcher.clone()), + binding: PluginProxyBinding::new(dispatcher.clone(), plugin_container.clone()), + plugin_container: plugin_container, dispatcher: dispatcher, }; component.dispatcher.register(Priority::Default, move |evt: &SendElement| { @@ -84,7 +81,7 @@ impl ComponentBuilder { pub struct Component { jid: Jid, transport: Arc>, - plugins: HashMap>, + plugin_container: Arc, binding: PluginProxyBinding, dispatcher: Arc, } @@ -99,20 +96,9 @@ impl Component { pub fn register_plugin(&mut self, mut plugin: P) { let binding = self.binding.clone(); plugin.bind(binding); - let p = Arc::new(plugin) as Arc; + let p = Arc::new(plugin); P::init(&self.dispatcher, 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 { - self.plugins.get(&TypeId::of::

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

() - .expect("plugin downcast failure (should not happen!!)") + self.plugin_container.register(p); } pub fn register_handler(&mut self, pri: Priority, func: F) @@ -122,6 +108,11 @@ impl Component { self.dispatcher.register(pri, func); } + /// Returns the plugin given by the type parameter, if it exists, else panics. + pub fn plugin(&self) -> PluginRef

{ + self.plugin_container.get::

().unwrap() + } + /// Returns the next event and flush the send queue. pub fn main(&mut self) -> Result<(), Error> { self.dispatcher.flush_all(); diff --git a/src/plugin.rs b/src/plugin.rs index ac495ba..e91544e 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -2,23 +2,81 @@ use event::{Event, Dispatcher, SendElement, Priority, Propagation}; -use std::any::Any; +use std::any::{Any, TypeId}; -use std::sync::Arc; +use std::collections::HashMap; + +use std::sync::{RwLock, Arc}; + +use std::marker::PhantomData; + +use std::ops::Deref; + +use std::convert::AsRef; use std::mem; use minidom::Element; +pub struct PluginContainer { + plugins: RwLock>>, +} + +impl PluginContainer { + pub fn new() -> PluginContainer { + PluginContainer { + plugins: RwLock::new(HashMap::new()), + } + } + + pub fn register(&self, plugin: Arc

) { + let mut guard = self.plugins.write().unwrap(); + if guard.insert(TypeId::of::

(), plugin as Arc).is_some() { + panic!("registering a plugin that's already registered"); + } + } + + pub fn get(&self) -> Option> { + let guard = self.plugins.read().unwrap(); + let arc = guard.get(&TypeId::of::

()); + arc.map(|arc| PluginRef { + inner: arc.clone(), + _marker: PhantomData + }) + } +} + +#[derive(Clone)] +pub struct PluginRef { + inner: Arc, + _marker: PhantomData

, +} + +impl Deref for PluginRef

{ + type Target = P; + + fn deref(&self) -> &P { + self.inner.as_any().downcast_ref::

().expect("plugin downcast failure") + } +} + +impl AsRef

for PluginRef

{ + fn as_ref(&self) -> &P { + self.inner.as_any().downcast_ref::

().expect("plugin downcast failure") + } +} + #[derive(Clone)] pub struct PluginProxyBinding { dispatcher: Arc, + plugin_container: Arc, } impl PluginProxyBinding { - pub fn new(dispatcher: Arc) -> PluginProxyBinding { + pub fn new(dispatcher: Arc, plugin_container: Arc) -> PluginProxyBinding { PluginProxyBinding { dispatcher: dispatcher, + plugin_container: plugin_container, } } } @@ -72,6 +130,13 @@ impl PluginProxy { }); } + /// Tries to get another plugin. + pub fn plugin(&self) -> Option> { + self.with_binding(|binding| { + binding.plugin_container.get::

() + }) + } + /// Sends a stanza. pub fn send(&self, elem: Element) { self.dispatch(SendElement(elem));