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, 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
 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(Dispatcher::new());
 65        let transport = Arc::new(Mutex::new(transport));
 66        let mut component = Component {
 67            jid: self.jid,
 68            transport: transport.clone(),
 69            plugins: HashMap::new(),
 70            binding: PluginProxyBinding::new(dispatcher.clone()),
 71            dispatcher: dispatcher,
 72        };
 73        component.dispatcher.register(Priority::Default, move |evt: &SendElement| {
 74            let mut t = transport.lock().unwrap();
 75            t.write_element(&evt.0).unwrap();
 76            Propagation::Continue
 77        });
 78        component.connect(self.secret)?;
 79        Ok(component)
 80    }
 81}
 82
 83/// An XMPP component.
 84pub struct Component {
 85    jid: Jid,
 86    transport: Arc<Mutex<PlainTransport>>,
 87    plugins: HashMap<TypeId, Arc<Plugin>>,
 88    binding: PluginProxyBinding,
 89    dispatcher: Arc<Dispatcher>,
 90}
 91
 92impl Component {
 93    /// Returns a reference to the `Jid` associated with this `Component`.
 94    pub fn jid(&self) -> &Jid {
 95        &self.jid
 96    }
 97
 98    /// Registers a plugin.
 99    pub fn register_plugin<P: Plugin + PluginInit + 'static>(&mut self, mut plugin: P) {
100        let binding = self.binding.clone();
101        plugin.bind(binding);
102        let p = Arc::new(plugin) as Arc<Plugin>;
103        P::init(&self.dispatcher, p.clone());
104        if self.plugins.insert(TypeId::of::<P>(), p).is_some() {
105            panic!("registering a plugin that's already registered");
106        }
107    }
108
109    /// Returns the plugin given by the type parameter, if it exists, else panics.
110    pub fn plugin<P: Plugin>(&self) -> &P {
111        self.plugins.get(&TypeId::of::<P>())
112                    .expect("the requested plugin was not registered")
113                    .as_any()
114                    .downcast_ref::<P>()
115                    .expect("plugin downcast failure (should not happen!!)")
116    }
117
118    pub fn register_handler<E, F>(&mut self, pri: Priority, func: F)
119        where
120            E: Event,
121            F: Fn(&E) -> Propagation + 'static {
122        self.dispatcher.register(pri, func);
123    }
124
125    /// Returns the next event and flush the send queue.
126    pub fn main(&mut self) -> Result<(), Error> {
127        self.dispatcher.flush_all();
128        loop {
129            let elem = self.read_element()?;
130            self.dispatcher.dispatch(ReceiveElement(elem));
131            self.dispatcher.flush_all();
132        }
133    }
134
135    fn read_element(&self) -> Result<Element, Error> {
136        self.transport.lock().unwrap().read_element()
137    }
138
139    fn write_element(&self, elem: &Element) -> Result<(), Error> {
140        self.transport.lock().unwrap().write_element(elem)
141    }
142
143    fn read_event(&self) -> Result<xml::reader::XmlEvent, Error> {
144        self.transport.lock().unwrap().read_event()
145    }
146
147    fn connect(&mut self, secret: String) -> Result<(), Error> {
148        let mut sid = String::new();
149        loop {
150            let e = self.read_event()?;
151            match e {
152                ReaderEvent::StartElement { attributes, .. } => {
153                    for attribute in attributes {
154                        if attribute.name.namespace == None && attribute.name.local_name == "id" {
155                            sid = attribute.value;
156                        }
157                    }
158                    break;
159                },
160                _ => (),
161            }
162        }
163        let concatenated = format!("{}{}", sid, secret);
164        let mut hasher = Sha1::default();
165        hasher.input(concatenated.as_bytes());
166        let mut handshake = String::new();
167        for byte in hasher.result() {
168            write!(handshake, "{:02x}", byte)?;
169        }
170        let mut elem = Element::builder("handshake")
171                               .ns(ns::COMPONENT_ACCEPT)
172                               .build();
173        elem.append_text_node(handshake);
174        self.write_element(&elem)?;
175        loop {
176            let n = self.read_element()?;
177            if n.is("handshake", ns::COMPONENT_ACCEPT) {
178                return Ok(());
179            }
180        }
181    }
182}