abstract plugin logic into PluginContainer

This commit is contained in:
lumi 2017-05-27 20:33:56 +02:00
parent 1b6b67b332
commit 6efc77b423
3 changed files with 90 additions and 41 deletions

View file

@ -3,7 +3,7 @@ use jid::Jid;
use transport::{Transport, SslTransport}; use transport::{Transport, SslTransport};
use error::Error; use error::Error;
use ns; use ns;
use plugin::{Plugin, PluginInit, PluginProxyBinding}; use plugin::{Plugin, PluginInit, PluginProxyBinding, PluginContainer, PluginRef};
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};
@ -21,9 +21,7 @@ use xml::reader::XmlEvent as ReaderEvent;
use std::sync::{Mutex, Arc}; use std::sync::{Mutex, Arc};
use std::collections::{HashSet, HashMap}; use std::collections::HashSet;
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)]
@ -81,11 +79,12 @@ impl ClientBuilder {
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 transport = Arc::new(Mutex::new(transport));
let plugin_container = Arc::new(PluginContainer::new());
let mut client = Client { let mut client = Client {
jid: self.jid, jid: self.jid,
transport: transport.clone(), transport: transport.clone(),
plugins: HashMap::new(), binding: PluginProxyBinding::new(dispatcher.clone(), plugin_container.clone()),
binding: PluginProxyBinding::new(dispatcher.clone()), plugin_container: plugin_container,
dispatcher: dispatcher, dispatcher: dispatcher,
}; };
client.dispatcher.register(Priority::Default, move |evt: &SendElement| { client.dispatcher.register(Priority::Default, move |evt: &SendElement| {
@ -103,7 +102,7 @@ impl ClientBuilder {
pub struct Client { pub struct Client {
jid: Jid, jid: Jid,
transport: Arc<Mutex<SslTransport>>, transport: Arc<Mutex<SslTransport>>,
plugins: HashMap<TypeId, Arc<Plugin>>, plugin_container: Arc<PluginContainer>,
binding: PluginProxyBinding, binding: PluginProxyBinding,
dispatcher: Arc<Dispatcher>, dispatcher: Arc<Dispatcher>,
} }
@ -118,11 +117,9 @@ impl Client {
pub fn register_plugin<P: Plugin + PluginInit + 'static>(&mut self, mut plugin: P) { pub fn register_plugin<P: Plugin + PluginInit + 'static>(&mut self, mut plugin: P) {
let binding = self.binding.clone(); let binding = self.binding.clone();
plugin.bind(binding); plugin.bind(binding);
let p = Arc::new(plugin) as Arc<Plugin>; let p = Arc::new(plugin);
P::init(&self.dispatcher, p.clone()); P::init(&self.dispatcher, p.clone());
if self.plugins.insert(TypeId::of::<P>(), p).is_some() { self.plugin_container.register(p);
panic!("registering a plugin that's already registered");
}
} }
pub fn register_handler<E, F>(&mut self, pri: Priority, func: F) pub fn register_handler<E, F>(&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. /// 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) -> PluginRef<P> {
self.plugins.get(&TypeId::of::<P>()) self.plugin_container.get::<P>().unwrap()
.expect("the requested plugin was not registered")
.as_any()
.downcast_ref::<P>()
.expect("plugin downcast failure (should not happen!!)")
} }
/// Returns the next event and flush the send queue. /// Returns the next event and flush the send queue.

View file

@ -3,7 +3,7 @@ use jid::Jid;
use transport::{Transport, PlainTransport}; use transport::{Transport, PlainTransport};
use error::Error; use error::Error;
use ns; use ns;
use plugin::{Plugin, PluginInit, PluginProxyBinding}; use plugin::{Plugin, PluginInit, PluginProxyBinding, PluginContainer, PluginRef};
use event::{Dispatcher, ReceiveElement, SendElement, Propagation, Priority, Event}; use event::{Dispatcher, ReceiveElement, SendElement, Propagation, Priority, Event};
use connection::{Connection, Component2S}; use connection::{Connection, Component2S};
use sha_1::{Sha1, Digest}; use sha_1::{Sha1, Digest};
@ -15,10 +15,6 @@ use xml::reader::XmlEvent as ReaderEvent;
use std::fmt::Write; use std::fmt::Write;
use std::sync::{Mutex, Arc}; use std::sync::{Mutex, Arc};
use std::collections::HashMap;
use std::any::TypeId;
/// A builder for `Component`s. /// A builder for `Component`s.
pub struct ComponentBuilder { pub struct ComponentBuilder {
jid: Jid, jid: Jid,
@ -63,11 +59,12 @@ impl ComponentBuilder {
Component2S::init(&mut transport, &self.jid.domain, "stream_opening")?; Component2S::init(&mut transport, &self.jid.domain, "stream_opening")?;
let dispatcher = Arc::new(Dispatcher::new()); let dispatcher = Arc::new(Dispatcher::new());
let transport = Arc::new(Mutex::new(transport)); let transport = Arc::new(Mutex::new(transport));
let plugin_container = Arc::new(PluginContainer::new());
let mut component = Component { let mut component = Component {
jid: self.jid, jid: self.jid,
transport: transport.clone(), transport: transport.clone(),
plugins: HashMap::new(), binding: PluginProxyBinding::new(dispatcher.clone(), plugin_container.clone()),
binding: PluginProxyBinding::new(dispatcher.clone()), plugin_container: plugin_container,
dispatcher: dispatcher, dispatcher: dispatcher,
}; };
component.dispatcher.register(Priority::Default, move |evt: &SendElement| { component.dispatcher.register(Priority::Default, move |evt: &SendElement| {
@ -84,7 +81,7 @@ impl ComponentBuilder {
pub struct Component { pub struct Component {
jid: Jid, jid: Jid,
transport: Arc<Mutex<PlainTransport>>, transport: Arc<Mutex<PlainTransport>>,
plugins: HashMap<TypeId, Arc<Plugin>>, plugin_container: Arc<PluginContainer>,
binding: PluginProxyBinding, binding: PluginProxyBinding,
dispatcher: Arc<Dispatcher>, dispatcher: Arc<Dispatcher>,
} }
@ -99,20 +96,9 @@ impl Component {
pub fn register_plugin<P: Plugin + PluginInit + 'static>(&mut self, mut plugin: P) { pub fn register_plugin<P: Plugin + PluginInit + 'static>(&mut self, mut plugin: P) {
let binding = self.binding.clone(); let binding = self.binding.clone();
plugin.bind(binding); plugin.bind(binding);
let p = Arc::new(plugin) as Arc<Plugin>; let p = Arc::new(plugin);
P::init(&self.dispatcher, p.clone()); P::init(&self.dispatcher, p.clone());
if self.plugins.insert(TypeId::of::<P>(), p).is_some() { self.plugin_container.register(p);
panic!("registering a plugin that's already registered");
}
}
/// Returns the plugin given by the type parameter, if it exists, else panics.
pub fn plugin<P: Plugin>(&self) -> &P {
self.plugins.get(&TypeId::of::<P>())
.expect("the requested plugin was not registered")
.as_any()
.downcast_ref::<P>()
.expect("plugin downcast failure (should not happen!!)")
} }
pub fn register_handler<E, F>(&mut self, pri: Priority, func: F) pub fn register_handler<E, F>(&mut self, pri: Priority, func: F)
@ -122,6 +108,11 @@ impl Component {
self.dispatcher.register(pri, func); self.dispatcher.register(pri, func);
} }
/// Returns the plugin given by the type parameter, if it exists, else panics.
pub fn plugin<P: Plugin>(&self) -> PluginRef<P> {
self.plugin_container.get::<P>().unwrap()
}
/// Returns the next event and flush the send queue. /// Returns the next event and flush the send queue.
pub fn main(&mut self) -> Result<(), Error> { pub fn main(&mut self) -> Result<(), Error> {
self.dispatcher.flush_all(); self.dispatcher.flush_all();

View file

@ -2,23 +2,81 @@
use event::{Event, Dispatcher, SendElement, Priority, Propagation}; 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 std::mem;
use minidom::Element; use minidom::Element;
pub struct PluginContainer {
plugins: RwLock<HashMap<TypeId, Arc<Plugin>>>,
}
impl PluginContainer {
pub fn new() -> PluginContainer {
PluginContainer {
plugins: RwLock::new(HashMap::new()),
}
}
pub fn register<P: Plugin + 'static>(&self, plugin: Arc<P>) {
let mut guard = self.plugins.write().unwrap();
if guard.insert(TypeId::of::<P>(), plugin as Arc<Plugin>).is_some() {
panic!("registering a plugin that's already registered");
}
}
pub fn get<P: Plugin>(&self) -> Option<PluginRef<P>> {
let guard = self.plugins.read().unwrap();
let arc = guard.get(&TypeId::of::<P>());
arc.map(|arc| PluginRef {
inner: arc.clone(),
_marker: PhantomData
})
}
}
#[derive(Clone)]
pub struct PluginRef<P: Plugin> {
inner: Arc<Plugin>,
_marker: PhantomData<P>,
}
impl<P: Plugin> Deref for PluginRef<P> {
type Target = P;
fn deref(&self) -> &P {
self.inner.as_any().downcast_ref::<P>().expect("plugin downcast failure")
}
}
impl<P: Plugin> AsRef<P> for PluginRef<P> {
fn as_ref(&self) -> &P {
self.inner.as_any().downcast_ref::<P>().expect("plugin downcast failure")
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct PluginProxyBinding { pub struct PluginProxyBinding {
dispatcher: Arc<Dispatcher>, dispatcher: Arc<Dispatcher>,
plugin_container: Arc<PluginContainer>,
} }
impl PluginProxyBinding { impl PluginProxyBinding {
pub fn new(dispatcher: Arc<Dispatcher>) -> PluginProxyBinding { pub fn new(dispatcher: Arc<Dispatcher>, plugin_container: Arc<PluginContainer>) -> PluginProxyBinding {
PluginProxyBinding { PluginProxyBinding {
dispatcher: dispatcher, dispatcher: dispatcher,
plugin_container: plugin_container,
} }
} }
} }
@ -72,6 +130,13 @@ impl PluginProxy {
}); });
} }
/// Tries to get another plugin.
pub fn plugin<P: Plugin>(&self) -> Option<PluginRef<P>> {
self.with_binding(|binding| {
binding.plugin_container.get::<P>()
})
}
/// Sends a stanza. /// Sends a stanza.
pub fn send(&self, elem: Element) { pub fn send(&self, elem: Element) {
self.dispatch(SendElement(elem)); self.dispatch(SendElement(elem));