echo_bot.rs

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