use std::borrow::Borrow;
use tracing::Instrument;
use matrix_sdk::{
Room, RoomState,
ruma::{
OwnedEventId,
events::{
relation::{Reply, Thread},
room::message::{
MessageType, OriginalSyncRoomMessageEvent, Relation, Relation::Replacement,
RoomMessageEventContent,
},
},
},
};
use matrix_sdk::ruma::api::client::message::send_message_event;
use crate::{CallbackError, MessageResponseType};
#[derive(Clone)]
pub struct Messaging {
matrix_link: super::MatrixLink,
}
impl Messaging {
pub(super) fn new(matrix_link: super::MatrixLink) -> Self {
Self { matrix_link }
}
pub async fn send_text_markdown(
&self,
room: &Room,
message: String,
response_type: MessageResponseType,
) -> Result<send_message_event::v3::Response, matrix_sdk::Error> {
let mut content = RoomMessageEventContent::text_markdown(message);
self.send_event(room, &mut content, response_type).await
}
pub async fn send_notice_markdown(
&self,
room: &Room,
message: String,
response_type: MessageResponseType,
) -> Result<send_message_event::v3::Response, matrix_sdk::Error> {
let mut content: RoomMessageEventContent =
RoomMessageEventContent::notice_markdown(message);
self.send_event(room, &mut content, response_type).await
}
#[tracing::instrument(name="send_event", skip_all, fields(room_id = room.room_id().as_str(), response_type = response_type.as_str()))]
pub async fn send_event(
&self,
room: &Room,
content: &mut RoomMessageEventContent,
response_type: MessageResponseType,
) -> Result<send_message_event::v3::Response, matrix_sdk::Error> {
let start_time = std::time::Instant::now();
tracing::debug!("Sending event..",);
match response_type {
MessageResponseType::InRoom => {}
MessageResponseType::Reply(event_id) => {
content.relates_to = Some(Relation::Reply(Reply::with_event_id(event_id)))
}
MessageResponseType::InThread(thread_info) => {
content.relates_to = Some(Relation::Thread(Thread::plain(
thread_info.root_event_id,
thread_info.last_event_id,
)))
}
};
let result = room.send(content.clone()).await;
let duration = start_time.elapsed();
tracing::debug!(?duration, "Event sent",);
result.map(|r| r.response)
}
pub async fn redact_event(
&self,
room: &Room,
target_event_id: OwnedEventId,
reason: Option<String>,
) -> matrix_sdk::HttpResult<matrix_sdk::ruma::api::client::redact::redact_event::v3::Response>
{
room.redact(target_event_id.borrow(), reason.as_deref(), None)
.await
}
pub fn on_actionable_room_message<F, Fut>(&self, callback: F)
where
F: FnOnce(OriginalSyncRoomMessageEvent, Room) -> Fut + Send + 'static + Clone + Sync,
Fut: std::future::Future<Output = Result<(), CallbackError>> + Send + 'static,
{
let own_user_id = self.matrix_link.user_id().to_owned();
self.matrix_link.client().add_event_handler(
move |ev: OriginalSyncRoomMessageEvent, room: Room| async move {
let event_span = tracing::error_span!(
"on_actionable_room_message",
event_id = ev.event_id.as_str(),
room_id = room.room_id().as_str(),
sender_id = ev.sender.as_str()
);
{
let _enter = event_span.enter();
tracing::trace!(
"Sync room message event handler (on_actionable_room_message) for event: {:?}",
ev,
);
if room.state() != RoomState::Joined {
return;
}
if let MessageType::Notice(_) = &ev.content.msgtype {
tracing::trace!("Ignoring notice message type");
return;
}
if let Some(Replacement(_)) = &ev.content.relates_to {
tracing::trace!("Ignoring message edit");
return;
}
if ev.sender == own_user_id {
tracing::debug!("Ignoring own message");
return;
}
}
tokio::spawn(async move {
if let Err(err) = callback(ev, room).await {
tracing::error!(?err, "Error in callback");
}
}.instrument(event_span));
},
);
}
}