why did I
This commit is contained in:
commit
c664e0caeb
4 changed files with 1837 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
1694
Cargo.lock
generated
Normal file
1694
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "discord-cc-bridge"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.75"
|
||||||
|
parking_lot = "0.12.1"
|
||||||
|
serde = { version = "1.0.190", features = ["derive"] }
|
||||||
|
serde_json = "1.0.107"
|
||||||
|
serenity = "0.11.7"
|
||||||
|
tokio = { version = "1.33.0", features = ["macros", "rt-multi-thread"] }
|
||||||
|
tokio-tungstenite = "0.20.1"
|
127
src/main.rs
Normal file
127
src/main.rs
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serenity::futures::stream::{SplitSink, SplitStream};
|
||||||
|
use serenity::futures::{StreamExt, TryFutureExt};
|
||||||
|
use serenity::http::{Http, StatusCode};
|
||||||
|
use serenity::model::prelude::*;
|
||||||
|
use serenity::prelude::*;
|
||||||
|
use serenity::{async_trait, futures::SinkExt};
|
||||||
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
|
use tokio_tungstenite::tungstenite::handshake::server::{ErrorResponse, Request, Response};
|
||||||
|
use tokio_tungstenite::tungstenite::Message as WsMessage;
|
||||||
|
use tokio_tungstenite::WebSocketStream;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
struct ChatMessage {
|
||||||
|
user: String,
|
||||||
|
user_id: String,
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Message> for ChatMessage {
|
||||||
|
fn from(value: Message) -> Self {
|
||||||
|
Self {
|
||||||
|
user: value
|
||||||
|
.member
|
||||||
|
.and_then(|member| member.nick)
|
||||||
|
.unwrap_or(value.author.name),
|
||||||
|
user_id: value.author.id.to_string(),
|
||||||
|
message: value.content,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Handler(
|
||||||
|
Mutex<SplitSink<WebSocketStream<TcpStream>, WsMessage>>,
|
||||||
|
ChannelId,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl EventHandler for Handler {
|
||||||
|
async fn message(&self, _ctx: Context, new_message: Message) {
|
||||||
|
if new_message.webhook_id.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if new_message.author.bot {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if new_message.channel_id != self.1 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.0
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.send(WsMessage::Text(
|
||||||
|
serde_json::to_string::<ChatMessage>(&new_message.into()).unwrap(),
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_recv(
|
||||||
|
mut recv: SplitStream<WebSocketStream<TcpStream>>,
|
||||||
|
http: Http,
|
||||||
|
webhook: Webhook,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
while let Some(msg) = recv.next().await {
|
||||||
|
if let WsMessage::Text(content) = msg? {
|
||||||
|
let message: ChatMessage = serde_json::from_str(&content)?;
|
||||||
|
webhook
|
||||||
|
.execute(&http, false, |w| {
|
||||||
|
w.content(message.message)
|
||||||
|
.username(message.user)
|
||||||
|
.avatar_url(format!(
|
||||||
|
"https://minotar.net/helm/{}/256.png",
|
||||||
|
message.user_id
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
let http = Http::new("");
|
||||||
|
let webhook = Webhook::from_url(&http, &env::var("WEBHOOK_URL").expect("webhook url")).await?;
|
||||||
|
let auth_token = env::var("AUTH_TOKEN").expect("auth token");
|
||||||
|
|
||||||
|
let channel_id = env::var("CHANNEL_ID").expect("channel id").parse()?;
|
||||||
|
|
||||||
|
let listener = TcpListener::bind(env::var("BIND_ADDR").expect("bind address")).await?;
|
||||||
|
let (stream, _) = listener.accept().await?;
|
||||||
|
let (send, recv) =
|
||||||
|
tokio_tungstenite::accept_hdr_async(stream, |req: &Request, resp: Response| {
|
||||||
|
if let Some(header) = req.headers().get("X-Token") {
|
||||||
|
if header.as_bytes() == auth_token.as_bytes() {
|
||||||
|
Ok(resp)
|
||||||
|
} else {
|
||||||
|
let mut resp = ErrorResponse::new(None);
|
||||||
|
*resp.status_mut() = StatusCode::UNAUTHORIZED;
|
||||||
|
Err(resp)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut resp = ErrorResponse::new(None);
|
||||||
|
*resp.status_mut() = StatusCode::UNAUTHORIZED;
|
||||||
|
Err(resp)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?
|
||||||
|
.split();
|
||||||
|
// Login with a bot token from the environment
|
||||||
|
let token = env::var("DISCORD_TOKEN").expect("token");
|
||||||
|
let intents = GatewayIntents::non_privileged() | GatewayIntents::MESSAGE_CONTENT;
|
||||||
|
let mut client = Client::builder(token, intents)
|
||||||
|
.event_handler(Handler(Mutex::new(send), channel_id))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// start listening for events by starting a single shard
|
||||||
|
tokio::try_join!(
|
||||||
|
client.start().map_err(|e| e.into()),
|
||||||
|
handle_recv(recv, http, webhook)
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in a new issue