/*
* Copyright (C) 2025 Jonni Liljamo <jonni@liljamo.com>
*
* This file is licensed under GPL-3.0-or-later, see NOTICE and LICENSE for
* more information.
*/
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use serde_json::json;
use crate::config::ServiceConfig;
use super::Service;
#[derive(Clone, Deserialize, Serialize)]
pub struct MatrixConfig {
pub instance: String,
pub token: String,
pub room: String,
}
#[typetag::serde(name = "matrix")]
impl ServiceConfig for MatrixConfig {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
pub struct MatrixService {
client: reqwest::Client,
config: MatrixConfig,
}
impl MatrixService {
pub fn new(client: reqwest::Client, config: MatrixConfig) -> Self {
Self { client, config }
}
fn gen_txn_id(&self) -> String {
format!(
"{}_{}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or(std::time::Duration::new(0, 0))
.as_nanos()
)
}
}
#[async_trait]
impl Service for MatrixService {
async fn send(&self, title: &str, message: &str) -> Result<(), Box<dyn std::error::Error>> {
let body = json!({
"msgtype": "m.notice",
"body": format!("**{}**\n\n{}", title, message),
"format": "org.matrix.custom.html",
"formatted_body": format!("<p><strong>{}</strong></p>\n<p>{}</p>\n", title, message),
});
let _ = self
.client
.put(format!(
"{}/_matrix/client/v3/rooms/{}/send/m.room.message/{}",
self.config.instance,
self.config.room,
self.gen_txn_id()
))
.query(&[("access_token", &self.config.token)])
.body(body.to_string())
.send()
.await?;
Ok(())
}
}