130 lines
2.9 KiB
Rust
130 lines
2.9 KiB
Rust
use crate::config::Config;
|
|
|
|
use crossbeam_channel::Receiver;
|
|
use log::error;
|
|
use matrix_sdk::ruma;
|
|
use std::{
|
|
sync::Arc,
|
|
time::{Duration, SystemTime},
|
|
};
|
|
|
|
enum OptionSince<T> {
|
|
Some(T),
|
|
NoneSince(SystemTime),
|
|
}
|
|
|
|
impl<T> OptionSince<T> {
|
|
fn from_result<E, F: FnOnce(E)>(result: Result<T, E>, f: F) -> Self {
|
|
match result {
|
|
Ok(val) => Self::Some(val),
|
|
Err(e) => {
|
|
f(e);
|
|
Self::NoneSince(SystemTime::now())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T> From<Option<T>> for OptionSince<T> {
|
|
fn from(opt: Option<T>) -> Self {
|
|
match opt {
|
|
Some(val) => Self::Some(val),
|
|
None => Self::NoneSince(SystemTime::now()),
|
|
}
|
|
}
|
|
}
|
|
|
|
struct Notifier {
|
|
matrix: Option<OptionSince<(matrix_sdk::Client, matrix_sdk::room::Joined)>>,
|
|
}
|
|
|
|
impl Notifier {
|
|
async fn new(config: &Config) -> Self {
|
|
Self {
|
|
matrix: if config.matrix_notify {
|
|
Some(OptionSince::from_result(init_matrix(config).await, |e| {
|
|
error!("Cannot init Matrix: {:?}", e)
|
|
}))
|
|
} else {
|
|
None
|
|
},
|
|
}
|
|
}
|
|
|
|
async fn notify(&mut self, config: &Config) {
|
|
match &self.matrix {
|
|
None => {}
|
|
Some(OptionSince::Some((_client, room))) => {
|
|
room.send(
|
|
ruma::events::room::message::RoomMessageEventContent::text_plain(
|
|
"New comment.",
|
|
),
|
|
None,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
}
|
|
Some(OptionSince::NoneSince(earlier)) => {
|
|
if SystemTime::now().duration_since(*earlier).unwrap()
|
|
> Duration::from_secs(config.matrix_retry_timeout)
|
|
{
|
|
self.matrix = Some(OptionSince::from_result(init_matrix(config).await, |e| {
|
|
error!("Cannot init Matrix: {:?}", e)
|
|
}))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn run_notifier(config: Arc<Config>, recv: Receiver<()>) {
|
|
let mut notifier = Notifier::new(&config).await;
|
|
for () in recv {
|
|
notifier.notify(&config).await;
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
enum MatrixError {
|
|
CannotConnect(matrix_sdk::ClientBuildError),
|
|
CannotLogin(matrix_sdk::Error),
|
|
CannotSync(matrix_sdk::Error),
|
|
RoomNotJoined,
|
|
UnknownRoom,
|
|
}
|
|
|
|
async fn init_matrix(
|
|
config: &Config,
|
|
) -> Result<(matrix_sdk::Client, matrix_sdk::room::Joined), MatrixError> {
|
|
let user = ruma::UserId::parse(&config.matrix_user)
|
|
.expect("Matrix username should be in format `@user:homeserver`");
|
|
let room_id = <&ruma::RoomId>::try_from(config.matrix_room.as_str())
|
|
.expect("Matrix room should be in format `#roomname:homeserver` or `!roomid:homeserver`");
|
|
|
|
let client = matrix_sdk::Client::builder()
|
|
.homeserver_url(&config.matrix_server)
|
|
.user_agent("Webcomment")
|
|
.handle_refresh_tokens()
|
|
.build()
|
|
.await
|
|
.map_err(MatrixError::CannotConnect)?;
|
|
|
|
client
|
|
.login_username(&user, &config.matrix_password)
|
|
.send()
|
|
.await
|
|
.map_err(MatrixError::CannotLogin)?;
|
|
client
|
|
.sync_once(matrix_sdk::config::SyncSettings::default())
|
|
.await
|
|
.map_err(MatrixError::CannotSync)?;
|
|
|
|
let room = client.get_room(room_id).ok_or(MatrixError::UnknownRoom)?;
|
|
|
|
if let matrix_sdk::room::Room::Joined(room) = room {
|
|
Ok((client, room))
|
|
} else {
|
|
Err(MatrixError::RoomNotJoined)
|
|
}
|
|
}
|