diff --git a/src/main.rs b/src/main.rs index 0d3211b..53782cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,13 +8,7 @@ use std::{ use clap::Clap; use matrix_sdk::{ self, async_trait, - events::{ - room::{ - member::MemberEventContent, - message::{MessageEventContent, TextMessageEventContent}, - }, - StrippedStateEvent, SyncMessageEvent, - }, + events::{room::member::MemberEventContent, StrippedStateEvent}, Client, ClientConfig, EventEmitter, RoomState, Session, SyncSettings, }; use serde::Deserialize; @@ -22,39 +16,83 @@ use thiserror::Error; use tokio::time::sleep; use url::Url; -struct AutoJoinBot { +struct BadNewsBot { + client: Client, + config: Config, +} + +impl BadNewsBot { + pub fn new(config: Config) -> anyhow::Result { + let client_config = ClientConfig::new().store_path(config.state_dir.join("store")); + let client = Client::new_with_config(config.homeserver.clone(), client_config)?; + + Ok(Self { client, config }) + } + + pub async fn init(&self) -> anyhow::Result<()> { + load_or_init_session(&self).await?; + + self.client + .add_event_emitter(Box::new(AutoJoinHandler::new(self.client.clone()))) + .await; + + Ok(()) + } + + pub async fn run(&self) { + self.client.sync(SyncSettings::default()).await + } +} + +async fn load_or_init_session(bot: &BadNewsBot) -> anyhow::Result<()> { + let session_file = bot.config.state_dir.join("session.yaml"); + + if session_file.is_file() { + let reader = BufReader::new(File::open(session_file)?); + + let session: Session = serde_yaml::from_reader(reader)?; + + bot.client.restore_login(session.clone()).await?; + + println!("Reused session: {}, {}", session.user_id, session.device_id); + } else { + let response = bot + .client + .login( + &bot.config.username, + &bot.config.password, + None, + Some("autojoin bot"), + ) + .await?; + + println!("logged in as {}", bot.config.username); + + let session = Session { + access_token: response.access_token, + user_id: response.user_id, + device_id: response.device_id, + }; + + let writer = BufWriter::new(File::create(session_file)?); + serde_yaml::to_writer(writer, &session)?; + } + + Ok(()) +} + +struct AutoJoinHandler { client: Client, } -impl AutoJoinBot { - pub fn new(client: Client) -> Self { +impl AutoJoinHandler { + fn new(client: Client) -> Self { Self { client } } } #[async_trait] -impl EventEmitter for AutoJoinBot { - async fn on_room_message( - &self, - room: RoomState, - event: &SyncMessageEvent, - ) { - if let RoomState::Joined(room) = room { - if let SyncMessageEvent { - content: MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }), - sender, - .. - } = event - { - let member = room.get_member(&sender).await.unwrap().unwrap(); - let name = member - .display_name() - .unwrap_or_else(|| member.user_id().as_str()); - println!("{}: {}", name, msg_body); - } - } - } - +impl EventEmitter for AutoJoinHandler { async fn on_stripped_state_member( &self, room: RoomState, @@ -95,62 +133,6 @@ impl EventEmitter for AutoJoinBot { } } -// TODO: use nice error handling -async fn load_or_init_session( - client: &Client, - session_file: PathBuf, - username: &str, - password: &str, -) -> anyhow::Result<()> { - if session_file.is_file() { - let reader = BufReader::new(File::open(session_file)?); - - let session: Session = serde_yaml::from_reader(reader)?; - - client.restore_login(session.clone()).await?; - - println!("Reused session: {}, {}", session.user_id, session.device_id); - } else { - let response = client - .login(username, password, None, Some("autojoin bot")) - .await?; - - println!("logged in as {}", username); - - let session = Session { - access_token: response.access_token, - user_id: response.user_id, - device_id: response.device_id, - }; - - let writer = BufWriter::new(File::create(session_file)?); - serde_yaml::to_writer(writer, &session)?; - } - - Ok(()) -} - -async fn login_and_sync( - homeserver_url: Url, - username: &str, - password: &str, - state_dir: PathBuf, -) -> anyhow::Result<()> { - let client_config = ClientConfig::new().store_path(state_dir.join("store")); - - let client = Client::new_with_config(homeserver_url, client_config)?; - - load_or_init_session(&client, state_dir.join("session.yaml"), username, password).await?; - - client - .add_event_emitter(Box::new(AutoJoinBot::new(client.clone()))) - .await; - - client.sync(SyncSettings::default()).await; - - Ok(()) -} - #[derive(Error, Debug)] enum BadNewsError { #[error("problem accessing configuration file")] @@ -189,11 +171,9 @@ async fn main() -> anyhow::Result<()> { let config: Config = serde_yaml::from_reader(BufReader::new(File::open(config_file)?))?; - login_and_sync( - config.homeserver, - &config.username, - &config.password, - config.state_dir, - ) - .await + let bot = BadNewsBot::new(config)?; + bot.init().await?; + bot.run().await; + + Ok(()) }