extern crate rand; use crate::message::*; pub use crate::output::*; use serde::Deserialize; use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; use rand::distributions::Alphanumeric; use rand::Rng; use reqwest::header; use reqwest::{Client, Url}; #[derive(Debug)] struct MatrixClient { http_client: Client, homeserver_uri: String, token: String, } impl MatrixClient { fn new(homeserver_uri: &str, token: &str) -> Self { Self { http_client: Client::new(), homeserver_uri: homeserver_uri.to_owned(), token: token.to_owned(), } } // fn get( // &self, // path: &str, // params: &HashMap<&str, String>, // ) -> Result { // let mut path = self.homeserver_uri.clone() + path; // let mut first = true; // for (k, v) in params { // path += &format!( // "{}{}={}", // if first { "?" } else { "&" }, // utf8_percent_encode(k.as_ref(), DEFAULT_ENCODE_SET), // utf8_percent_encode(v.as_ref(), DEFAULT_ENCODE_SET) // ); // first = false; // } // self.http_client // .get(Url::parse(&path).unwrap()) // .header(header::AUTHORIZATION, format!("Bearer {}", self.token)) // .send() // } fn put(&self, path: &str, body: String) -> reqwest::Response { let path = self.homeserver_uri.clone() + path; self.http_client .put(Url::parse(&path).expect(&format!("Invalid path: {}", path))) .header(header::AUTHORIZATION, format!("Bearer {}", self.token)) .header(header::CONTENT_TYPE, "application/json") .body(body) .send() .unwrap() } } #[derive(Debug)] pub struct Matrix { client: MatrixClient, config: MatrixConfig, } #[derive(Debug, Deserialize)] struct MatrixConfig { homeserver_url: String, token: String, room_id: String, } impl Output for Matrix { fn new(config: serde_yaml::Value) -> Result> { let config: MatrixConfig = serde_yaml::from_value(config)?; Ok(Matrix { client: MatrixClient::new(&config.homeserver_url, &config.token), config: config, }) } fn process_message(&mut self, message: Message) { use serde_json::json; let msg_type = match message.level { Level::Debug | Level::Notice => "m.notice", _ => "m.text", }; let decorator = match message.level { Level::Debug | Level::Notice => ("", ""), Level::Anomaly => ("", ""), Level::Issue => ("", ""), Level::Critical => ("", ""), }; let text = match message.level { Level::Critical => format!("@room {}", message.text), _ => message.text, }; let body = json!({ "body": format!("[{}->{}]: {}", message.emitter, message.msg_type, text), "formatted_body": format!("[{}->{}]: {}{}{}", message.emitter, message.msg_type, decorator.0, text, decorator.1), "msgtype": msg_type, "format": "org.matrix.custom.html", }) .to_string(); let mut res = self.client.put( &format!( "/_matrix/client/r0/rooms/{}/send/m.room.message/{}", utf8_percent_encode(&self.config.room_id, DEFAULT_ENCODE_SET), utf8_percent_encode( &rand::thread_rng() .sample_iter(&Alphanumeric) .take(32) .collect::(), DEFAULT_ENCODE_SET ), ), body, ); if res.status().as_u16() != 200 { log::warn!("Could not send Matrix message: {}", res.text().unwrap()); } } }