169 lines
4.8 KiB
Rust
169 lines
4.8 KiB
Rust
use std::{
|
|
cell::RefCell,
|
|
str::FromStr,
|
|
sync::{Arc, Mutex},
|
|
};
|
|
|
|
use discord::create_discord_client;
|
|
use matrix::create_matrix_client;
|
|
use matrix_sdk::{
|
|
ruma::{
|
|
events::{room::message::MessageEventContent, AnyMessageEventContent},
|
|
RoomId,
|
|
},
|
|
SyncSettings,
|
|
};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
mod discord;
|
|
mod matrix;
|
|
mod message_ast;
|
|
|
|
use message_ast::MessageContent;
|
|
use serenity::model::id::ChannelId;
|
|
use tokio::sync::mpsc;
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub enum MessageReference {
|
|
Discord(u64, u64),
|
|
Matrix(String, String),
|
|
}
|
|
|
|
pub struct SentMessage {
|
|
pub source: MessageReference,
|
|
pub content: MessageContent,
|
|
}
|
|
|
|
struct Bridgers {
|
|
discord: Mutex<RefCell<Option<discord::Context>>>,
|
|
matrix: Mutex<RefCell<Option<matrix::Client>>>,
|
|
}
|
|
|
|
impl Bridgers {
|
|
fn new() -> Self {
|
|
Self {
|
|
discord: Mutex::new(RefCell::new(None)),
|
|
matrix: Mutex::new(RefCell::new(None)),
|
|
}
|
|
}
|
|
|
|
async fn send_message(
|
|
&self,
|
|
source: MessageReference,
|
|
content: MessageContent,
|
|
) -> Vec<MessageReference> {
|
|
let mut created_messages = Vec::new();
|
|
|
|
if let Some(discord) = self.discord.lock().unwrap().borrow().as_ref() {
|
|
// We probably want a function that returns an Option<ChannelId> taking the source
|
|
match &source {
|
|
MessageReference::Matrix(_room_id, _event_id) => {
|
|
let channel_id = ChannelId(885690775193661463); // TODO: Look up linked channel
|
|
let discord_message = channel_id
|
|
.send_message(&discord.http, |m| {
|
|
m.content(message_ast::format_discord(&content))
|
|
})
|
|
.await
|
|
.expect("Failed to send discord message");
|
|
|
|
created_messages.push(MessageReference::from(&discord_message));
|
|
}
|
|
_ => {}
|
|
};
|
|
}
|
|
|
|
if let Some(matrix) = self.matrix.lock().unwrap().borrow().as_ref() {
|
|
match &source {
|
|
MessageReference::Discord(_, _) => {
|
|
let room_id = RoomId::from_str("asdfghj").unwrap(); // TODO: Get a room id
|
|
if let Some(room) = matrix.get_joined_room(&room_id) {
|
|
let event = room
|
|
.send(
|
|
AnyMessageEventContent::RoomMessage(
|
|
MessageEventContent::text_plain(message_ast::format_discord(
|
|
&content, // TODO: Format as HTML
|
|
)),
|
|
),
|
|
None,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
created_messages.push(MessageReference::from((&room_id, &event.event_id)));
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
created_messages
|
|
}
|
|
}
|
|
|
|
async fn setup_discord(
|
|
token: String,
|
|
bridgers: Arc<Bridgers>,
|
|
discord_tx: mpsc::UnboundedSender<SentMessage>,
|
|
) {
|
|
let (discord_ctx_tx, mut discord_ctx_rx) = mpsc::unbounded_channel::<discord::Context>();
|
|
tokio::spawn(async move {
|
|
let mut discord = create_discord_client(discord_ctx_tx, discord_tx, &token).await;
|
|
discord.start().await.unwrap();
|
|
});
|
|
|
|
// Hack to grab the Context object when discord is ready
|
|
tokio::spawn(async move {
|
|
while let Some(discord) = discord_ctx_rx.recv().await {
|
|
bridgers.discord.lock().unwrap().replace(Some(discord));
|
|
}
|
|
});
|
|
}
|
|
|
|
async fn setup_matrix(
|
|
homeserver_url: String,
|
|
username: String,
|
|
password: String,
|
|
bridgers: Arc<Bridgers>,
|
|
message_tx: mpsc::UnboundedSender<SentMessage>,
|
|
) {
|
|
let client = create_matrix_client(homeserver_url, username, password, message_tx).await;
|
|
let settings = SyncSettings::default().token(client.sync_token().await.unwrap());
|
|
|
|
bridgers
|
|
.matrix
|
|
.lock()
|
|
.unwrap()
|
|
.replace(Some(client.clone()));
|
|
|
|
tokio::spawn(async move {
|
|
client.sync(settings).await;
|
|
});
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
let bridgers = Arc::new(Bridgers::new());
|
|
|
|
let (message_tx, mut message_rx) = tokio::sync::mpsc::unbounded_channel::<SentMessage>();
|
|
|
|
setup_discord(
|
|
"token".to_string(),
|
|
Arc::clone(&bridgers),
|
|
message_tx.clone(),
|
|
)
|
|
.await;
|
|
|
|
setup_matrix(
|
|
"https://matrix.org".to_string(),
|
|
"username".to_string(),
|
|
"password".to_string(),
|
|
Arc::clone(&bridgers),
|
|
message_tx.clone(),
|
|
)
|
|
.await;
|
|
|
|
while let Some(message) = message_rx.recv().await {
|
|
let _ = bridgers.send_message(message.source, message.content).await;
|
|
}
|
|
}
|