component.rs

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