component.rs

  1use jid::Jid;
  2use transport::{Transport, PlainTransport};
  3use error::Error;
  4use ns;
  5use plugin::{Plugin, PluginInit, PluginProxyBinding, PluginContainer, PluginRef};
  6use event::{Dispatcher, ReceiveElement, SendElement, Propagation, Priority, Event};
  7use connection::{Connection, Component2S};
  8use sha_1::{Sha1, Digest};
  9
 10use minidom::Element;
 11
 12use quick_xml::events::Event as XmlEvent;
 13
 14use std::str;
 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 connect(&mut self, secret: String) -> Result<(), Error> {
135        let mut sid = String::new();
136        loop {
137            let mut transport = self.transport.lock().unwrap();
138            let e = transport.read_event()?;
139            match e {
140                XmlEvent::Start(ref e) => {
141                    let mut attributes = e.attributes()
142                        .map(|o| {
143                            let o = o?;
144                            let key = str::from_utf8(o.key)?;
145                            let value = str::from_utf8(&o.value)?;
146                            Ok((key, value))
147                            }
148                        )
149                        .collect::<Result<Vec<(&str, &str)>, Error>>()?;
150                    for &(name, value) in &attributes {
151                        if name == "id" {
152                            sid = value.to_owned();
153                        }
154                    }
155                },
156                _ => (),
157            }
158            break
159        }
160        let concatenated = format!("{}{}", sid, secret);
161        let mut hasher = Sha1::default();
162        hasher.input(concatenated.as_bytes());
163        let mut handshake = String::new();
164        for byte in hasher.result() {
165            write!(handshake, "{:02x}", byte)?;
166        }
167        let mut elem = Element::builder("handshake")
168                               .ns(ns::COMPONENT_ACCEPT)
169                               .build();
170        elem.append_text_node(handshake);
171        self.write_element(&elem)?;
172        loop {
173            let n = self.read_element()?;
174            if n.is("handshake", ns::COMPONENT_ACCEPT) {
175                return Ok(());
176            }
177        }
178    }
179}