echo_bot.rs

  1extern crate futures;
  2extern crate tokio_core;
  3extern crate tokio_xmpp;
  4extern crate jid;
  5extern crate xml;
  6
  7use std::env::args;
  8use std::process::exit;
  9use tokio_core::reactor::Core;
 10use futures::{Future, Stream, Sink, future};
 11use tokio_xmpp::Client;
 12
 13fn main() {
 14    let args: Vec<String> = args().collect();
 15    if args.len() != 3 {
 16        println!("Usage: {} <jid> <password>", args[0]);
 17        exit(1);
 18    }
 19    let jid = &args[1];
 20    let password = &args[2];
 21
 22    // tokio_core context
 23    let mut core = Core::new().unwrap();
 24    // Client instance
 25    let client = Client::new(jid, password, core.handle()).unwrap();
 26
 27    // Make the two interfaces for sending and receiving independent
 28    // of each other so we can move one into a closure.
 29    let (sink, stream) = client.split();
 30    // Wrap sink in Option so that we can take() it for the send(self)
 31    // to consume and return it back when ready.
 32    let mut sink = Some(sink);
 33    let mut send = move |stanza| {
 34        sink = Some(
 35            sink.take().
 36                expect("sink")
 37                .send(stanza)
 38                .wait()
 39                .expect("sink.send")
 40        );
 41    };
 42    // Main loop, processes events
 43    let done = stream.for_each(|event| {
 44        if event.is_online() {
 45            println!("Online!");
 46
 47            let presence = make_presence();
 48            send(presence);
 49        } else if let Some(stanza) = event.as_stanza() {
 50            if stanza.name == "message" &&
 51                stanza.get_attribute("type", None) != Some("error") {
 52                    // This is a message we'll echo
 53                    let from = stanza.get_attribute("from", None);
 54                    let body = stanza.get_child("body", Some("jabber:client"))
 55                        .map(|el| el.content_str());
 56
 57                    match (from.as_ref(), body) {
 58                        (Some(from), Some(body)) => {
 59                            let reply = make_reply(from, body);
 60                            send(reply);
 61                        },
 62                        _ => (),
 63                    };
 64                }
 65        }
 66
 67        Box::new(future::ok(()))
 68    });
 69
 70    // Start polling `done`
 71    match core.run(done) {
 72        Ok(_) => (),
 73        Err(e) => {
 74            println!("Fatal: {}", e);
 75            ()
 76        }
 77    }
 78}
 79
 80// Construct a <presence/>
 81fn make_presence() -> xml::Element {
 82    let mut presence = xml::Element::new("presence".to_owned(), None, vec![]);
 83    presence.tag(xml::Element::new("status".to_owned(), None, vec![]))
 84        .text("chat".to_owned());
 85    presence.tag(xml::Element::new("show".to_owned(), None, vec![]))
 86        .text("Echoing messages".to_owned());
 87    presence
 88}
 89
 90// Construct a chat <message/>
 91fn make_reply(to: &str, body: String) -> xml::Element {
 92    let mut message = xml::Element::new(
 93        "message".to_owned(),
 94        None,
 95        vec![("type".to_owned(), None, "chat".to_owned()),
 96             ("to".to_owned(), None, to.to_owned())]
 97    );
 98    message.tag(xml::Element::new("body".to_owned(), None, vec![]))
 99        .text(body);
100    message
101}