phoebe/src/matrix.rs

209 lines
6.5 KiB
Rust
Raw Normal View History

2021-08-12 09:47:38 +00:00
use matrix_sdk::{
async_trait,
2021-09-12 23:06:11 +00:00
room::{Joined, Room},
2021-08-12 09:47:38 +00:00
ruma::{
events::{
2021-09-10 04:44:00 +00:00
room::{
2021-09-12 23:06:11 +00:00
message::{
FormattedBody, MessageEventContent, MessageFormat, MessageType, Relation,
},
2021-09-10 04:44:00 +00:00
redaction::RedactionEventContent,
},
AnyMessageEventContent, AnySyncRoomEvent, SyncMessageEvent,
2021-08-12 09:47:38 +00:00
},
EventId, UserId,
2021-08-12 09:47:38 +00:00
},
2021-09-10 04:44:00 +00:00
ClientConfig, EventHandler, SyncSettings,
2021-08-12 09:47:38 +00:00
};
pub use matrix_sdk::{ruma::RoomId, Client};
2021-08-12 09:47:38 +00:00
2021-09-12 02:59:13 +00:00
use log::info;
2021-09-10 04:44:00 +00:00
use tokio::sync::mpsc;
use url::Url;
2021-08-12 09:47:38 +00:00
2021-09-12 02:59:13 +00:00
use crate::{
2021-09-12 23:06:11 +00:00
message_ast::{
convert_matrix, convert_plain, format_discord, format_matrix, MessageComponent,
MessageContent,
},
2021-09-13 02:08:35 +00:00
messages::{MessageAuthor, MessageEvent, MessageReference, SentMessage},
2021-09-12 02:59:13 +00:00
};
2021-09-10 04:44:00 +00:00
impl From<(&RoomId, &EventId)> for MessageReference {
fn from((room_id, event_id): (&RoomId, &EventId)) -> Self {
let room_string = room_id.as_str().to_string();
let event_string = event_id.as_str().to_string();
2021-08-12 09:47:38 +00:00
Self::Matrix(room_string, event_string)
}
}
2021-09-10 04:44:00 +00:00
fn _find_content(event: &AnySyncRoomEvent) -> Option<AnyMessageEventContent> {
match event {
AnySyncRoomEvent::Message(message) => Some(message.content()),
AnySyncRoomEvent::RedactedMessage(message) => {
if let Some(ref redaction_event) = message.unsigned().redacted_because {
Some(AnyMessageEventContent::RoomRedaction(
redaction_event.content.clone(),
))
} else {
Some(AnyMessageEventContent::RoomRedaction(
RedactionEventContent::new(),
))
}
}
AnySyncRoomEvent::RedactedState(state) => {
if let Some(ref redaction_event) = state.unsigned().redacted_because {
Some(AnyMessageEventContent::RoomRedaction(
redaction_event.content.clone(),
))
} else {
Some(AnyMessageEventContent::RoomRedaction(
RedactionEventContent::new(),
))
}
}
_ => None,
}
}
struct MatrixHandler {
2021-09-13 02:08:35 +00:00
message_tx: mpsc::UnboundedSender<MessageEvent>,
2021-09-12 02:59:13 +00:00
current_user_id: UserId,
2021-09-10 04:44:00 +00:00
}
2021-08-12 09:47:38 +00:00
2021-09-12 23:06:11 +00:00
impl MatrixHandler {
async fn get_message_author(&self, room: &Joined, user_id: &UserId) -> Option<MessageAuthor> {
if let Ok(Some(sender)) = room.get_member(user_id).await {
Some(MessageAuthor {
display_name: sender
.display_name()
.unwrap_or_else(|| sender.name())
.to_string(),
})
} else {
None
}
}
fn get_content(&self, body: &str, formatted_body: &Option<FormattedBody>) -> MessageContent {
if let Some(html) = formatted_body
.as_ref()
.filter(|f| f.format == MessageFormat::Html)
.map(|f| &f.body)
{
convert_matrix(html)
} else {
convert_plain(body)
}
}
}
2021-08-12 09:47:38 +00:00
#[async_trait]
impl EventHandler for MatrixHandler {
async fn on_room_message(&self, room: Room, event: &SyncMessageEvent<MessageEventContent>) {
2021-09-12 02:59:13 +00:00
if event.sender == self.current_user_id {
return;
}
2021-09-10 04:44:00 +00:00
2021-09-12 02:59:13 +00:00
if let Room::Joined(room) = room {
let message_ref = MessageReference::from((room.room_id(), &event.event_id));
2021-09-10 04:44:00 +00:00
2021-09-12 02:59:13 +00:00
let message_type =
if let Some(Relation::Replacement(replacement)) = &event.content.relates_to {
&replacement.new_content.msgtype
2021-09-10 04:44:00 +00:00
} else {
2021-09-12 02:59:13 +00:00
&event.content.msgtype
2021-09-10 04:44:00 +00:00
};
2021-09-12 02:59:13 +00:00
match message_type {
MessageType::Text(text) => {
2021-09-12 23:06:11 +00:00
let content = self.get_content(&text.body, &text.formatted);
if let Some(author) = self.get_message_author(&room, &event.sender).await {
2021-09-13 02:08:35 +00:00
let _ = self.message_tx.send(MessageEvent::Send(SentMessage {
2021-09-12 02:59:13 +00:00
source: message_ref,
content,
2021-09-12 23:06:11 +00:00
author,
2021-09-13 02:08:35 +00:00
}));
2021-09-12 23:06:11 +00:00
}
}
MessageType::Emote(emote) => {
let mut content = self.get_content(&emote.body, &emote.formatted);
content.insert(0, MessageComponent::Plain("* ".to_string()));
if let Some(author) = self.get_message_author(&room, &event.sender).await {
2021-09-13 02:08:35 +00:00
let _ = self.message_tx.send(MessageEvent::Send(SentMessage {
2021-09-12 23:06:11 +00:00
source: message_ref,
content,
author,
2021-09-13 02:08:35 +00:00
}));
2021-09-12 02:59:13 +00:00
}
}
// TODO: Handle reactions, uploads (audio, video, image, file), and any other types of event
2021-09-12 02:59:13 +00:00
_ => {}
};
2021-09-12 23:06:11 +00:00
let _ = room.read_receipt(&event.event_id).await;
2021-09-12 02:59:13 +00:00
}
2021-08-12 09:47:38 +00:00
}
}
2021-09-10 04:44:00 +00:00
pub async fn forward_to_matrix(
client: &Client,
room_id: RoomId,
message: &SentMessage,
) -> Option<MessageReference> {
if let Some(room) = client.get_joined_room(&room_id) {
let event = room
.send(
AnyMessageEventContent::RoomMessage(MessageEventContent::text_html(
format_discord(&message.content),
format_matrix(&message.content),
)),
None,
)
.await
.ok()?;
return Some(MessageReference::from((&room_id, &event.event_id)));
}
None
}
2021-09-10 04:44:00 +00:00
pub async fn create_matrix_client(
homeserver_url: String,
username: String,
password: String,
2021-09-13 02:08:35 +00:00
message_tx: mpsc::UnboundedSender<MessageEvent>,
2021-09-10 04:44:00 +00:00
) -> Client {
let client_config = ClientConfig::new().store_path("./data/matrix_state");
2021-09-10 04:44:00 +00:00
let homeserver_url =
Url::parse(&homeserver_url).expect("Failed to parse the matrix homeserver URL");
let client = Client::new_with_config(homeserver_url, client_config).unwrap();
2021-09-12 02:59:13 +00:00
info!("Matrix logging in…");
2021-09-10 04:44:00 +00:00
client
.login(&username, &password, None, Some("phoebe"))
.await
.expect("Failed to log in");
2021-09-12 02:59:13 +00:00
info!("Matrix starting…");
2021-09-10 04:44:00 +00:00
client.sync_once(SyncSettings::default()).await.unwrap();
2021-09-12 02:59:13 +00:00
let current_user_id = client.user_id().await.unwrap();
let event_handler = MatrixHandler {
message_tx,
current_user_id,
};
2021-09-10 04:44:00 +00:00
client.set_event_handler(Box::new(event_handler)).await;
client
}