We have a collaborative session
please prepare you laptop
matrix-rust-sdk
cargo run -p example-getting-started -- <homeserver_url> <username> <password>
Use your favorite Matrix client, invite the bot into a channel (or create a DM) and post !party
. See what happens.
Let's look at the code.
The CLI setup
async fn main() -> anyhow::Result<()> { tracing_subscriber::fmt::init(); let (homeserver_url, username, password) = match (env::args().nth(1), env::args().nth(2), env::args().nth(3)) { (Some(a), Some(b), Some(c)) => (a, b, c), _ => { eprintln!( "Usage: {} <homeserver_url> <username> <password>", env::args().next().unwrap() ); exit(1) } }; login_and_sync(homeserver_url, &username, &password).await?; Ok(()) }
examples/getting_started/src/main.rs
The actual SDK setup:
async fn login_and_sync( homeserver_url: String, username: &str, password: &str, ) -> anyhow::Result<()> { // first, we set up the client. We use the convenient client builder to set our // custom homeserver URL on it #[allow(unused_mut)] let mut client_builder = Client::builder().homeserver_url(homeserver_url); // Matrix-SDK has support for pluggable, configurable state and crypto-store // support we use the default sled-store (enabled by default on native // architectures), to configure a local cache and store for our crypto keys let home = dirs::data_dir().expect("no home directory found").join("getting_started"); client_builder = client_builder.sled_store(home, None)?; // alright, let's make that into a client let client = client_builder.build().await?; // then let's log that client in client .login_username(username, password) .initial_device_display_name("getting started bot") .send() .await?; // it worked! println!("logged in as {username}");
examples/getting_started/src/main.rs
Attaching the message handlers
client.add_event_handler(on_stripped_state_member).await; client.sync_once(SyncSettings::default()).await.unwrap(); client.add_event_handler(on_room_message).await; let settings = SyncSettings::default().token(client.sync_token().await.unwrap()); client.sync(settings).await; // this essentially loops until we kill the bot Ok(()) }
examples/getting_started/src/main.rs
The autojoin handler
async fn on_stripped_state_member( room_member: StrippedRoomMemberEvent, client: Client, room: Room, ) { if room_member.state_key != client.user_id().unwrap() { return; } if let Room::Invited(room) = room { println!("Autojoining room {}", room.room_id()); let mut delay = 2; while let Err(err) = room.accept_invitation().await { // retry autojoin due to synapse sending invites, before the // invited user can join for more information see // https://github.com/matrix-org/synapse/issues/4345 eprintln!("Failed to join room {} ({err:?}), retrying in {delay}s", room.room_id()); sleep(Duration::from_secs(delay)).await; delay *= 2; if delay > 3600 { eprintln!("Can't join room {} ({err:?})", room.room_id()); break; } } println!("Successfully joined room {}", room.room_id()); } }
examples/getting_started/src/main.rs
The message posting handler
async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: Room) { if let Room::Joined(room) = room { let msg_body = match event.content.msgtype { MessageType::Text(TextMessageEventContent { body, .. }) => body, _ => return, }; if msg_body.contains("!party") { let content = RoomMessageEventContent::text_plain("🎉🎊🥳 let's PARTY!! 🥳🎊🎉"); println!("sending"); room.send(content, None).await.unwrap(); println!("message sent"); } } }
examples/getting_started/src/main.rs
how about…
ping
say:
and posts the remainder in a new message