Skip to main content

example_command_bot/
main.rs

1#![recursion_limit = "256"]
2
3use std::{env, process::exit};
4
5use matrix_sdk::{
6    Client, Room, RoomState,
7    config::SyncSettings,
8    ruma::events::room::message::{
9        MessageType, OriginalSyncRoomMessageEvent, RoomMessageEventContent,
10    },
11};
12
13async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: Room) {
14    if room.state() != RoomState::Joined {
15        return;
16    }
17    let MessageType::Text(text_content) = event.content.msgtype else {
18        return;
19    };
20
21    if text_content.body.contains("!party") {
22        let content = RoomMessageEventContent::text_plain("🎉🎊🥳 let's PARTY!! 🥳🎊🎉");
23
24        println!("sending");
25
26        // send our message to the room we found the "!party" command in
27        room.send(content).await.unwrap();
28
29        println!("message sent");
30    }
31}
32
33async fn login_and_sync(
34    homeserver_url: String,
35    username: String,
36    password: String,
37) -> anyhow::Result<()> {
38    // Note that when encryption is enabled, you should use a persistent store
39    // to be able to restore the session with a working encryption setup.
40    // See the `persist_session` example.
41    let client = Client::builder().homeserver_url(homeserver_url).build().await.unwrap();
42    client
43        .matrix_auth()
44        .login_username(&username, &password)
45        .initial_device_display_name("command bot")
46        .await?;
47
48    println!("logged in as {username}");
49
50    // An initial sync to set up state and so our bot doesn't respond to old
51    // messages.
52    let response = client.sync_once(SyncSettings::default()).await.unwrap();
53    // add our CommandBot to be notified of incoming messages, we do this after
54    // the initial sync to avoid responding to messages before the bot was
55    // running.
56    client.add_event_handler(on_room_message);
57
58    // since we called `sync_once` before we entered our sync loop we must pass
59    // that sync token to `sync`
60    let settings = SyncSettings::default().token(response.next_batch);
61    // this keeps state from the server streaming in to CommandBot via the
62    // EventHandler trait
63    client.sync(settings).await?;
64
65    Ok(())
66}
67
68#[tokio::main]
69async fn main() -> anyhow::Result<()> {
70    tracing_subscriber::fmt::init();
71
72    let (Some(homeserver_url), Some(username), Some(password)) =
73        (env::args().nth(1), env::args().nth(2), env::args().nth(3))
74    else {
75        eprintln!("Usage: {} <homeserver_url> <username> <password>", env::args().next().unwrap());
76        exit(1)
77    };
78
79    login_and_sync(homeserver_url, username, password).await?;
80    Ok(())
81}