component.rs

  1use xml;
  2use jid::Jid;
  3use transport::{Transport, PlainTransport};
  4use error::Error;
  5use ns;
  6use plugin::{Plugin, PluginInit, PluginProxyBinding, PluginContainer, PluginRef};
  7use event::{Dispatcher, ReceiveElement, SendElement, Propagation, Priority, Event};
  8use connection::{Connection, Component2S};
  9use sha_1::{Sha1, Digest};
 10
 11use minidom::Element;
 12
 13use xml::reader::XmlEvent as ReaderEvent;
 14
 15use std::fmt::Write;
 16use std::sync::{Mutex, Arc};
 17
 18/// A builder for `Component`s.
 19pub struct ComponentBuilder {
 20    jid: Jid,
 21    secret: String,
 22    host: Option<String>,
 23    port: u16,
 24}
 25
 26impl ComponentBuilder {
 27    /// Creates a new builder for an XMPP component that will connect to `jid` with default parameters.
 28    pub fn new(jid: Jid) -> ComponentBuilder {
 29        ComponentBuilder {
 30            jid: jid,
 31            secret: "".to_owned(),
 32            host: None,
 33            port: 5347,
 34        }
 35    }
 36
 37    /// Sets the host to connect to.
 38    pub fn host(mut self, host: String) -> ComponentBuilder {
 39        self.host = Some(host);
 40        self
 41    }
 42
 43    /// Sets the port to connect to.
 44    pub fn port(mut self, port: u16) -> ComponentBuilder {
 45        self.port = port;
 46        self
 47    }
 48
 49    /// Sets the password to use.
 50    pub fn password<P: Into<String>>(mut self, password: P) -> ComponentBuilder {
 51        self.secret = password.into();
 52        self
 53    }
 54
 55    /// Connects to the server and returns a `Component` when succesful.
 56    pub fn connect(self) -> Result<Component, Error> {
 57        let host = &self.host.unwrap_or(self.jid.domain.clone());
 58        let mut transport = PlainTransport::connect(host, self.port)?;
 59        Component2S::init(&mut transport, &self.jid.domain, "stream_opening")?;
 60        let dispatcher = Arc::new(Dispatcher::new());
 61        let transport = Arc::new(Mutex::new(transport));
 62        let plugin_container = Arc::new(PluginContainer::new());
 63        let mut component = Component {
 64            jid: self.jid.clone(),
 65            transport: transport.clone(),
 66            binding: PluginProxyBinding::new(dispatcher.clone(), plugin_container.clone(), self.jid),
 67            plugin_container: plugin_container,
 68            dispatcher: dispatcher,
 69        };
 70        component.dispatcher.register(Priority::Default, move |evt: &SendElement| {
 71            let mut t = transport.lock().unwrap();
 72            t.write_element(&evt.0).unwrap();
 73            Propagation::Continue
 74        });
 75        component.connect(self.secret)?;
 76        Ok(component)
 77    }
 78}
 79
 80/// An XMPP component.
 81pub struct Component {
 82    jid: Jid,
 83    transport: Arc<Mutex<PlainTransport>>,
 84    plugin_container: Arc<PluginContainer>,
 85    binding: PluginProxyBinding,
 86    dispatcher: Arc<Dispatcher>,
 87}
 88
 89impl Component {
 90    /// Returns a reference to the `Jid` associated with this `Component`.
 91    pub fn jid(&self) -> &Jid {
 92        &self.jid
 93    }
 94
 95    /// Registers a plugin.
 96    pub fn register_plugin<P: Plugin + PluginInit + 'static>(&mut self, mut plugin: P) {
 97        let binding = self.binding.clone();
 98        plugin.bind(binding);
 99        let p = Arc::new(plugin);
100        P::init(&self.dispatcher, p.clone());
101        self.plugin_container.register(p);
102    }
103
104    pub fn register_handler<E, F>(&mut self, pri: Priority, func: F)
105        where
106            E: Event,
107            F: Fn(&E) -> Propagation + 'static {
108        self.dispatcher.register(pri, func);
109    }
110
111    /// Returns the plugin given by the type parameter, if it exists, else panics.
112    pub fn plugin<P: Plugin>(&self) -> PluginRef<P> {
113        self.plugin_container.get::<P>().unwrap()
114    }
115
116    /// Returns the next event and flush the send queue.
117    pub fn main(&mut self) -> Result<(), Error> {
118        self.dispatcher.flush_all();
119        loop {
120            let elem = self.read_element()?;
121            self.dispatcher.dispatch(ReceiveElement(elem));
122            self.dispatcher.flush_all();
123        }
124    }
125
126    fn read_element(&self) -> Result<Element, Error> {
127        self.transport.lock().unwrap().read_element()
128    }
129
130    fn write_element(&self, elem: &Element) -> Result<(), Error> {
131        self.transport.lock().unwrap().write_element(elem)
132    }
133
134    fn read_event(&self) -> Result<xml::reader::XmlEvent, Error> {
135        self.transport.lock().unwrap().read_event()
136    }
137
138    fn connect(&mut self, secret: String) -> Result<(), Error> {
139        let mut sid = String::new();
140        loop {
141            let e = self.read_event()?;
142            match e {
143                ReaderEvent::StartElement { attributes, .. } => {
144                    for attribute in attributes {
145                        if attribute.name.namespace == None && attribute.name.local_name == "id" {
146                            sid = attribute.value;
147                        }
148                    }
149                    break;
150                },
151                _ => (),
152            }
153        }
154        let concatenated = format!("{}{}", sid, secret);
155        let mut hasher = Sha1::default();
156        hasher.input(concatenated.as_bytes());
157        let mut handshake = String::new();
158        for byte in hasher.result() {
159            write!(handshake, "{:02x}", byte)?;
160        }
161        let mut elem = Element::builder("handshake")
162                               .ns(ns::COMPONENT_ACCEPT)
163                               .build();
164        elem.append_text_node(handshake);
165        self.write_element(&elem)?;
166        loop {
167            let n = self.read_element()?;
168            if n.is("handshake", ns::COMPONENT_ACCEPT) {
169                return Ok(());
170            }
171        }
172    }
173}