dircord/src/main.rs

174 lines
4.6 KiB
Rust
Raw Normal View History

2021-12-27 13:49:54 -06:00
use std::{env, sync::Arc, fs::File, io::Read};
2021-12-26 15:13:09 -06:00
2021-12-26 16:05:53 -06:00
use serenity::{
async_trait,
2021-12-27 11:24:31 -06:00
futures::StreamExt,
2021-12-26 16:05:53 -06:00
http::Http,
model::{
channel::Message,
id::{ChannelId, UserId},
2021-12-27 14:46:12 -06:00
prelude::Ready, webhook::Webhook,
2021-12-26 16:05:53 -06:00
},
prelude::*,
2021-12-27 11:24:31 -06:00
Client as DiscordClient,
};
use irc::{
client::{data::Config, Client as IrcClient, Sender},
proto::Command,
2021-12-26 16:05:53 -06:00
};
2021-12-26 15:13:09 -06:00
2021-12-27 13:49:54 -06:00
use toml::Value;
2021-12-26 15:13:09 -06:00
struct Handler;
#[async_trait]
impl EventHandler for Handler {
async fn message(&self, ctx: Context, msg: Message) {
let nick = {
if let Some(member) = msg.member {
match member.nick {
Some(n) => n,
2021-12-26 16:05:53 -06:00
None => msg.author.name,
2021-12-26 15:13:09 -06:00
}
} else {
msg.author.name
}
};
2021-12-27 13:28:35 -06:00
let (user_id, sender) = {
2021-12-26 15:35:49 -06:00
let data = ctx.data.read().await;
2021-12-26 16:05:53 -06:00
let user_id = data.get::<UserIdKey>().unwrap().to_owned();
2021-12-27 13:28:35 -06:00
let sender = data.get::<SenderKey>().unwrap().to_owned();
2021-12-26 15:35:49 -06:00
2021-12-27 13:28:35 -06:00
(user_id, sender)
2021-12-26 15:35:49 -06:00
};
2021-12-27 13:28:35 -06:00
if user_id != msg.author.id && !msg.author.bot {
send_irc_message(&sender, &format!("<{}> {}", nick, msg.content))
.await
.unwrap();
}
2021-12-26 16:05:53 -06:00
}
async fn ready(&self, ctx: Context, info: Ready) {
let id = info.user.id;
let mut data = ctx.data.write().await;
data.insert::<UserIdKey>(id);
2021-12-26 15:13:09 -06:00
}
2021-12-26 14:04:47 -06:00
}
2021-12-26 15:13:09 -06:00
2021-12-26 15:35:49 -06:00
struct HttpKey;
struct ChannelIdKey;
2021-12-26 16:05:53 -06:00
struct UserIdKey;
2021-12-27 11:24:31 -06:00
struct SenderKey;
2021-12-26 15:35:49 -06:00
impl TypeMapKey for HttpKey {
type Value = Arc<Http>;
}
impl TypeMapKey for ChannelIdKey {
type Value = ChannelId;
}
2021-12-26 16:05:53 -06:00
impl TypeMapKey for UserIdKey {
type Value = UserId;
}
2021-12-27 11:24:31 -06:00
impl TypeMapKey for SenderKey {
type Value = Sender;
}
2021-12-26 15:13:09 -06:00
#[tokio::main]
async fn main() -> anyhow::Result<()> {
2021-12-27 13:49:54 -06:00
let filename = env::args().nth(1).expect("No filename was provided!");
let mut data = String::new();
File::open(filename)?.read_to_string(&mut data)?;
let value = data.parse::<Value>()?;
let token = value["token"].as_str().expect("No token provided!").to_string();
2021-12-27 16:41:27 -06:00
let webhook = value.get("webhook").map(|v| v.as_str().map(|s| s.to_string())).flatten();
2021-12-26 15:13:09 -06:00
2021-12-27 11:24:31 -06:00
let mut discord_client = DiscordClient::builder(&token)
.event_handler(Handler)
.await?;
2021-12-26 15:13:09 -06:00
let channel_id = ChannelId(831255708875751477);
2021-12-27 11:24:31 -06:00
let config = Config {
nickname: Some("dircord".to_string()),
server: Some("192.168.1.28".to_owned()),
port: Some(6667),
channels: vec!["#no-normies".to_string()],
use_tls: Some(false),
umodes: Some("+B".to_string()),
..Config::default()
};
2021-12-27 13:28:35 -06:00
let irc_client = IrcClient::from_config(config).await?;
2021-12-27 11:24:31 -06:00
let http = discord_client.cache_and_http.http.clone();
2021-12-26 15:35:49 -06:00
{
2021-12-27 11:24:31 -06:00
let mut data = discord_client.data.write().await;
data.insert::<SenderKey>(irc_client.sender());
2021-12-26 15:35:49 -06:00
}
2021-12-27 16:44:34 -06:00
let webhook = parse_webhook_url(http.clone(), webhook).await.expect("Invalid webhook URL");
2021-12-27 14:46:12 -06:00
2021-12-27 11:24:31 -06:00
tokio::spawn(async move {
2021-12-27 16:41:27 -06:00
irc_loop(irc_client, http, channel_id, webhook).await.unwrap();
2021-12-27 11:24:31 -06:00
});
discord_client.start().await?;
2021-12-26 15:13:09 -06:00
Ok(())
}
2021-12-27 13:28:35 -06:00
async fn send_irc_message(sender: &Sender, content: &str) -> anyhow::Result<()> {
sender.send_privmsg("#no-normies", content)?;
Ok(())
}
2021-12-27 11:24:31 -06:00
async fn irc_loop(
mut client: IrcClient,
http: Arc<Http>,
channel_id: ChannelId,
2021-12-27 16:41:27 -06:00
webhook: Option<Webhook>
2021-12-27 11:24:31 -06:00
) -> anyhow::Result<()> {
client.identify()?;
let mut stream = client.stream()?;
while let Some(orig_message) = stream.next().await.transpose()? {
print!("{}", orig_message);
2021-12-27 13:28:35 -06:00
if let Command::PRIVMSG(_, ref message) = orig_message.command {
2021-12-27 11:24:31 -06:00
let nickname = orig_message.source_nickname().unwrap();
2021-12-27 16:41:27 -06:00
if let Some(ref webhook) = webhook {
webhook.execute(&http, false, |w| {
w.username(nickname);
w.content(message);
w
}).await?;
} else {
channel_id
.say(&http, format!("{}: {}", nickname, message))
.await?;
}
2021-12-27 11:24:31 -06:00
}
}
Ok(())
2021-12-26 16:05:53 -06:00
}
2021-12-27 14:46:12 -06:00
2021-12-27 16:44:34 -06:00
async fn parse_webhook_url(http: Arc<Http>, url: Option<String>) -> anyhow::Result<Option<Webhook>> {
2021-12-27 14:46:12 -06:00
if let Some(url) = url {
let url = url.trim_start_matches("https://discord.com/api/webhooks/");
let split = url.split("/").collect::<Vec<&str>>();
2021-12-27 16:44:34 -06:00
let id = split[0].parse::<u64>()?;
2021-12-27 14:46:12 -06:00
let token = split[1].to_string();
2021-12-27 16:44:34 -06:00
let webhook = http.get_webhook_with_token(id, &token).await?;
Ok(Some(webhook))
2021-12-27 14:46:12 -06:00
} else {
2021-12-27 16:44:34 -06:00
Ok(None)
2021-12-27 14:46:12 -06:00
}
}