echo_bot.rs

 1use futures::{future, Future, Sink, Stream};
 2use std::env::args;
 3use std::process::exit;
 4use tokio::runtime::current_thread::Runtime;
 5use tokio_xmpp::Client;
 6use xmpp_parsers::{Jid, Element, TryFrom};
 7use xmpp_parsers::message::{Body, Message, MessageType};
 8use xmpp_parsers::presence::{Presence, Show as PresenceShow, Type as PresenceType};
 9
10fn main() {
11    let args: Vec<String> = args().collect();
12    if args.len() != 3 {
13        println!("Usage: {} <jid> <password>", args[0]);
14        exit(1);
15    }
16    let jid = &args[1];
17    let password = &args[2];
18
19    // tokio_core context
20    let mut rt = Runtime::new().unwrap();
21    // Client instance
22    let client = Client::new(jid, password).unwrap();
23
24    // Make the two interfaces for sending and receiving independent
25    // of each other so we can move one into a closure.
26    let (sink, stream) = client.split();
27    let mut sink_state = Some(sink);
28    // Main loop, processes events
29    let done = stream.for_each(move |event| {
30        let mut sink_future = None;
31
32        if event.is_online() {
33            println!("Online!");
34
35            let presence = make_presence();
36            let sink = sink_state.take().unwrap();
37            sink_future = Some(Box::new(sink.send(presence)));
38        } else if let Some(message) = event
39            .into_stanza()
40            .and_then(|stanza| Message::try_from(stanza).ok())
41        {
42            match (message.from, message.bodies.get("")) {
43                (Some(ref from), Some(ref body)) if body.0 == "die" => {
44                    println!("Secret die command triggered by {}", from);
45                    let sink = sink_state.as_mut().unwrap();
46                    sink.close().expect("close");
47                }
48                (Some(ref from), Some(ref body)) => {
49                    if message.type_ != MessageType::Error {
50                        // This is a message we'll echo
51                        let reply = make_reply(from.clone(), &body.0);
52                        let sink = sink_state.take().unwrap();
53                        sink_future = Some(Box::new(sink.send(reply)));
54                    }
55                }
56                _ => {}
57            }
58        };
59
60        sink_future
61            .map(|future| {
62                let wait_send: Box<Future<Item = (), Error = tokio_xmpp::Error>> =
63                    Box::new(future
64                             .map(|sink| {
65                                 sink_state = Some(sink);
66                             }));
67                wait_send
68            })
69            .unwrap_or_else(|| Box::new(future::ok(())))
70    });
71
72    // Start polling `done`
73    match rt.block_on(done) {
74        Ok(_) => (),
75        Err(e) => {
76            println!("Fatal: {}", e);
77            ()
78        }
79    }
80}
81
82// Construct a <presence/>
83fn make_presence() -> Element {
84    let mut presence = Presence::new(PresenceType::None);
85    presence.show = PresenceShow::Chat;
86    presence
87        .statuses
88        .insert(String::from("en"), String::from("Echoing messages."));
89    presence.into()
90}
91
92// Construct a chat <message/>
93fn make_reply(to: Jid, body: &str) -> Element {
94    let mut message = Message::new(Some(to));
95    message.bodies.insert(String::new(), Body(body.to_owned()));
96    message.into()
97}