xmpp: handle SIGINT (^C) in hello_bot example

Maxime “pep” Buquet created

Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>

Change summary

xmpp/Cargo.toml            |   2 
xmpp/ChangeLog             |   2 
xmpp/examples/hello_bot.rs | 101 +++++++++++++++++++++++----------------
3 files changed, 62 insertions(+), 43 deletions(-)

Detailed changes

xmpp/Cargo.toml 🔗

@@ -16,7 +16,7 @@ edition = "2021"
 [dependencies]
 chrono = "0.4"
 futures = "0.3"
-tokio = { version = "1", features = ["fs"] }
+tokio = { version = "1", features = ["fs", "signal"] }
 log = "0.4"
 reqwest = { version = "0.12", features = ["stream"], default-features = false }
 tokio-util = { version = "0.7", features = ["codec"] }

xmpp/ChangeLog 🔗

@@ -22,6 +22,8 @@ XXXX-YY-ZZ [ RELEASER <admin@localhost> ]
         Event::RoomPrivateMessageCorrection signal XEP-0308 message corrections; they're
         not checked how old the corrected entry is, which has security concerns (!496)
       - Agent::new helper method.
+      - Handle SIGINT, SIGTERM and SIGKILL in hello_bot example to avoid leaving
+        hibernating resources around.
     * Fixes:
       - Use tokio::sync::RwLock not std::sync::RwLock (!432)
       - Agent::wait_for_events now return Vec<Event> and sets inner tokio_xmpp Client

xmpp/examples/hello_bot.rs 🔗

@@ -7,9 +7,11 @@
 use xmpp::{
     jid::BareJid,
     muc::room::{JoinRoomSettings, RoomMessageSettings},
-    ClientBuilder, ClientFeature, ClientType, Event, RoomNick,
+    Agent, ClientBuilder, ClientFeature, ClientType, Event, RoomNick,
 };
 
+use tokio::signal::ctrl_c;
+
 use std::env::args;
 use std::str::FromStr;
 
@@ -56,49 +58,64 @@ async fn main() -> Result<(), Option<()>> {
     log::info!("Connecting...");
 
     loop {
-        for event in client.wait_for_events().await {
-            match event {
-                Event::Online => {
-                    log::info!("Online.");
-                    for room in &rooms {
-                        log::info!("Joining room {} from CLI argument…", room);
-                        client
-                            .join_room(JoinRoomSettings {
-                                room: room.clone(),
-                                nick: None,
-                                password: None,
-                                status: Some(("en", "Yet another bot!")),
-                            })
-                            .await;
-                    }
-                }
-                Event::Disconnected(e) => {
-                    log::info!("Disconnected: {}.", e);
-                }
-                Event::ChatMessage(_id, jid, body, time_info) => {
-                    log::info!(
-                        "{} {}: {}",
-                        time_info.received.time().format("%H:%M"),
-                        jid,
-                        body.0
-                    );
-                }
-                Event::RoomJoined(jid) => {
-                    log::info!("Joined room {}.", jid);
-                    client
-                        .send_room_message(RoomMessageSettings::new(jid, "Hello world!"))
-                        .await;
-                }
-                Event::RoomMessage(_id, jid, nick, body, time_info) => {
-                    println!(
-                        "Message in room {} from {} at {}: {}",
-                        jid, nick, time_info.received, body.0
-                    );
-                }
-                _ => {
-                    log::debug!("Unimplemented event:\n{:#?}", event);
+        tokio::select! {
+            events = client.wait_for_events() => {
+                for event in events {
+                    let _ = handle_events(&mut client, event, &rooms);
                 }
+            },
+            _ = ctrl_c() => {
+                log::info!("Disconnecting...");
+                let _ = client.disconnect().await;
+                break;
+            },
+        }
+    }
+
+    Ok(())
+}
+
+async fn handle_events(client: &mut Agent, event: Event, rooms: &Vec<BareJid>) {
+    match event {
+        Event::Online => {
+            log::info!("Online.");
+            for room in rooms {
+                log::info!("Joining room {} from CLI argument…", room);
+                client
+                    .join_room(JoinRoomSettings {
+                        room: room.clone(),
+                        nick: None,
+                        password: None,
+                        status: Some(("en", "Yet another bot!")),
+                    })
+                    .await;
             }
         }
+        Event::Disconnected(e) => {
+            log::info!("Disconnected: {}.", e);
+        }
+        Event::ChatMessage(_id, jid, body, time_info) => {
+            log::info!(
+                "{} {}: {}",
+                time_info.received.time().format("%H:%M"),
+                jid,
+                body.0
+            );
+        }
+        Event::RoomJoined(jid) => {
+            log::info!("Joined room {}.", jid);
+            client
+                .send_room_message(RoomMessageSettings::new(jid, "Hello world!"))
+                .await;
+        }
+        Event::RoomMessage(_id, jid, nick, body, time_info) => {
+            println!(
+                "Message in room {} from {} at {}: {}",
+                jid, nick, time_info.received, body.0
+            );
+        }
+        _ => {
+            log::debug!("Unimplemented event:\n{:#?}", event);
+        }
     }
 }