rnetmon/src/outputs/matrix.rs

133 lines
4.0 KiB
Rust

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<reqwest::Response, reqwest::Error> {
// 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<Self, Box<dyn std::error::Error>> {
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 => ("<font color=\"#FFFF00\">", "</font>"),
Level::Issue => ("<font color=\"#FF0000\">", "</font>"),
Level::Critical => ("<strong><font color=\"#FF0000\">", "</font></strong>"),
};
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::<String>(),
DEFAULT_ENCODE_SET
),
),
body,
);
if res.status().as_u16() != 200 {
log::warn!("Could not send Matrix message: {}", res.text().unwrap());
}
}
}