Skip to content

Commit b9d0f9c

Browse files
authored
Merge pull request #9 from roobscoob/message-sending
Message Sending
2 parents 0a257fe + 7c3d3b8 commit b9d0f9c

File tree

17 files changed

+1986
-306
lines changed

17 files changed

+1986
-306
lines changed

Cargo.lock

Lines changed: 1706 additions & 90 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/chat/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@ version = "0.1.0"
44
edition = "2021"
55

66
[dependencies]
7-
gpui = { git = "https://github.com/zed-industries/zed.git", version = "0.1.0" }
7+
gpui = { git = "https://github.com/huacnlee/zed.git", branch = "export-platform-window", default-features = false, features = [
8+
"http_client",
9+
"font-kit",
10+
] }
811
tokio = "1.41.1"

src/chat/src/channel.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ use tokio::sync::broadcast;
22

33
use crate::message::Message;
44

5-
pub trait Channel {
5+
pub trait Channel: Clone {
66
type Message: Message;
77

88
fn get_receiver(&self) -> broadcast::Receiver<Self::Message>;
9-
}
9+
10+
fn send_message(&self, content: String, nonce: String) -> Self::Message;
11+
}

src/chat/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
pub mod message;
21
pub mod channel;
2+
pub mod message;

src/chat/src/message.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
use gpui::{Element};
1+
use gpui::Element;
22

33
pub trait Message: Clone {
44
fn get_author(&self) -> &impl MessageAuthor;
55
fn get_content(&self) -> impl Element;
66
fn get_identifier(&self) -> String;
7+
fn get_nonce(&self) -> Option<&String>;
78
}
89

910
pub trait MessageAuthor {
1011
fn get_display_name(&self) -> impl Element;
1112
fn get_icon(&self) -> String;
12-
}
13+
}

src/discord/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ version = "0.1.0"
44
edition = "2021"
55

66
[dependencies]
7-
gpui = { git = "https://github.com/zed-industries/zed.git", version = "0.1.0" }
7+
gpui = { git = "https://github.com/huacnlee/zed.git", branch = "export-platform-window", default-features = false, features = [
8+
"http_client",
9+
"font-kit",
10+
] }
811
scope-chat = { version = "0.1.0", path = "../chat" }
912
serenity = { git = "https://github.com/scopeclient/serenity", version = "0.13.0" }
1013
tokio = "1.41.1"

src/discord/src/channel/mod.rs

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,33 @@ use std::sync::Arc;
33
use scope_chat::channel::Channel;
44
use tokio::sync::{broadcast, RwLock};
55

6-
use crate::{client::DiscordClient, message::DiscordMessage, snowflake::Snowflake};
6+
use crate::{
7+
client::DiscordClient,
8+
message::{
9+
author::{DiscordMessageAuthor, DisplayName},
10+
content::DiscordMessageContent,
11+
DiscordMessage,
12+
},
13+
snowflake::Snowflake,
14+
};
715

816
pub struct DiscordChannel {
917
channel_id: Snowflake,
1018
receiver: broadcast::Receiver<DiscordMessage>,
19+
client: Arc<DiscordClient>,
1120
}
1221

1322
impl DiscordChannel {
14-
pub async fn new(client: &mut Arc<RwLock<DiscordClient>>, channel_id: Snowflake) -> Self {
23+
pub async fn new(client: Arc<DiscordClient>, channel_id: Snowflake) -> Self {
1524
let (sender, receiver) = broadcast::channel(10);
1625

17-
client.write().await.add_channel_message_sender(channel_id, sender).await;
26+
client.add_channel_message_sender(channel_id, sender).await;
1827

19-
DiscordChannel { channel_id, receiver }
28+
DiscordChannel {
29+
channel_id,
30+
receiver,
31+
client,
32+
}
2033
}
2134
}
2235

@@ -26,4 +39,32 @@ impl Channel for DiscordChannel {
2639
fn get_receiver(&self) -> broadcast::Receiver<Self::Message> {
2740
self.receiver.resubscribe()
2841
}
42+
43+
fn send_message(&self, content: String, nonce: String) -> DiscordMessage {
44+
let client = self.client.clone();
45+
let channel_id = self.channel_id;
46+
let sent_content = content.clone();
47+
let sent_nonce = nonce.clone();
48+
49+
tokio::spawn(async move {
50+
client.send_message(channel_id, sent_content, sent_nonce).await;
51+
});
52+
53+
DiscordMessage {
54+
content: DiscordMessageContent { content, is_pending: true },
55+
author: self.client.user().clone(),
56+
id: Snowflake { content: 0 },
57+
nonce: Some(nonce),
58+
}
59+
}
60+
}
61+
62+
impl Clone for DiscordChannel {
63+
fn clone(&self) -> Self {
64+
Self {
65+
channel_id: self.channel_id.clone(),
66+
receiver: self.receiver.resubscribe(),
67+
client: self.client.clone(),
68+
}
69+
}
2970
}

src/discord/src/client.rs

Lines changed: 69 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
use std::{collections::HashMap, rc::Rc, sync::Arc};
1+
use std::{
2+
collections::HashMap,
3+
fs::File,
4+
rc::Rc,
5+
sync::{Arc, OnceLock},
6+
};
27

38
use serenity::{
4-
all::{Context, EventHandler, GatewayIntents, Message},
9+
all::{ChannelId, Context, CreateMessage, Event, EventHandler, GatewayIntents, Message, Nonce, RawEventHandler},
510
async_trait,
611
futures::SinkExt,
712
};
13+
use std::io::Write;
814
use tokio::sync::{broadcast, Mutex, RwLock};
915

1016
use crate::{
@@ -18,49 +24,84 @@ use crate::{
1824

1925
#[derive(Default)]
2026
pub struct DiscordClient {
21-
channel_message_event_handlers: HashMap<Snowflake, Vec<broadcast::Sender<DiscordMessage>>>,
27+
channel_message_event_handlers: RwLock<HashMap<Snowflake, Vec<broadcast::Sender<DiscordMessage>>>>,
28+
client: OnceLock<serenity::Client>,
29+
user: OnceLock<DiscordMessageAuthor>,
2230
}
2331

2432
impl DiscordClient {
25-
pub fn new(token: String) -> Arc<RwLock<DiscordClient>> {
26-
let client = Arc::new(RwLock::new(DiscordClient::default()));
27-
let remote = RemoteDiscordClient(client.clone());
33+
pub async fn new(token: String) -> Arc<DiscordClient> {
34+
let client = Arc::new(DiscordClient::default());
2835

29-
tokio::spawn(async {
30-
let mut client = serenity::Client::builder(token, GatewayIntents::all()).event_handler(remote).await.expect("Error creating client");
36+
let mut discord = serenity::Client::builder(token, GatewayIntents::all())
37+
.event_handler_arc(client.clone())
38+
.raw_event_handler(RawClient(client.clone()))
39+
.await
40+
.expect("Error creating client");
3141

32-
if let Err(why) = client.start().await {
33-
panic!("Client error: {why:?}");
34-
}
35-
});
42+
if let Err(why) = discord.start().await {
43+
panic!("Client error: {why:?}");
44+
}
45+
46+
let _ = client.client.set(discord);
3647

3748
client
3849
}
3950

40-
pub async fn add_channel_message_sender(&mut self, channel: Snowflake, sender: broadcast::Sender<DiscordMessage>) {
41-
self.channel_message_event_handlers.entry(channel).or_default().push(sender);
51+
fn discord(&self) -> &serenity::Client {
52+
self.client.get().unwrap()
53+
}
54+
55+
pub fn user(&self) -> &DiscordMessageAuthor {
56+
self.user.get().unwrap()
57+
}
58+
59+
pub async fn add_channel_message_sender(&self, channel: Snowflake, sender: broadcast::Sender<DiscordMessage>) {
60+
self.channel_message_event_handlers.write().await.entry(channel).or_default().push(sender);
61+
}
62+
63+
pub async fn send_message(&self, channel_id: Snowflake, content: String, nonce: String) {
64+
ChannelId::new(channel_id.content)
65+
.send_message(
66+
self.discord().http.clone(),
67+
CreateMessage::new().content(content).enforce_nonce(true).nonce(serenity::all::Nonce::String(nonce)),
68+
)
69+
.await
70+
.unwrap();
4271
}
4372
}
4473

45-
struct RemoteDiscordClient(Arc<RwLock<DiscordClient>>);
74+
struct RawClient(Arc<DiscordClient>);
4675

4776
#[async_trait]
48-
impl EventHandler for RemoteDiscordClient {
49-
async fn ready(&self, ctx: Context, data_about_bot: serenity::model::prelude::Ready) {
50-
println!("Ready! {:?}", data_about_bot);
77+
impl RawEventHandler for RawClient {
78+
async fn raw_event(&self, ctx: Context, ev: serenity::model::prelude::Event) {
79+
if let Event::Unknown(unk) = ev {
80+
if unk.kind == "READY" {
81+
let user = unk.value.as_object().unwrap().get("user").unwrap().as_object().unwrap();
82+
83+
self.0.user.get_or_init(|| DiscordMessageAuthor {
84+
display_name: DisplayName(user.get("username").unwrap().as_str().unwrap().to_owned()),
85+
icon: format!(
86+
"https://cdn.discordapp.com/avatars/{}/{}",
87+
user.get("id").unwrap().as_str().unwrap(),
88+
user.get("avatar").unwrap().as_str().unwrap()
89+
),
90+
});
91+
}
92+
}
5193
}
94+
}
5295

96+
#[async_trait]
97+
impl EventHandler for DiscordClient {
5398
async fn message(&self, _: Context, msg: Message) {
54-
println!("Got message: {:?} {:?}", msg.channel_id, msg.content);
55-
5699
let snowflake = Snowflake {
57100
content: msg.channel_id.get(),
58101
};
59102

60-
if let Some(vec) = self.0.read().await.channel_message_event_handlers.get(&snowflake) {
103+
if let Some(vec) = self.channel_message_event_handlers.read().await.get(&snowflake) {
61104
for sender in vec {
62-
println!("Sending to sender!");
63-
64105
let _ = sender.send(DiscordMessage {
65106
id: snowflake,
66107
author: DiscordMessageAuthor {
@@ -69,7 +110,12 @@ impl EventHandler for RemoteDiscordClient {
69110
},
70111
content: DiscordMessageContent {
71112
content: msg.content.clone(),
113+
is_pending: false,
72114
},
115+
nonce: msg.nonce.clone().map(|n| match n {
116+
Nonce::Number(n) => n.to_string(),
117+
Nonce::String(s) => s,
118+
}),
73119
});
74120
}
75121
}

src/discord/src/message/content.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
use gpui::{IntoElement, Render, RenderOnce, WindowContext};
1+
use gpui::{div, IntoElement, ParentElement, Render, RenderOnce, Styled, WindowContext};
22

33
#[derive(Clone, IntoElement)]
44
pub struct DiscordMessageContent {
55
pub content: String,
6+
pub is_pending: bool,
67
}
78

89
impl RenderOnce for DiscordMessageContent {
910
fn render(self, _: &mut WindowContext) -> impl IntoElement {
10-
self.content.clone()
11+
div().opacity(if self.is_pending { 0.25 } else { 1.0 }).child(self.content.clone())
1112
}
1213
}

src/discord/src/message/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub struct DiscordMessage {
1313
pub content: DiscordMessageContent,
1414
pub author: DiscordMessageAuthor,
1515
pub id: Snowflake,
16+
pub nonce: Option<String>,
1617
}
1718

1819
impl Message for DiscordMessage {
@@ -27,4 +28,8 @@ impl Message for DiscordMessage {
2728
fn get_identifier(&self) -> String {
2829
self.id.to_string()
2930
}
31+
32+
fn get_nonce(&self) -> Option<&String> {
33+
self.nonce.as_ref()
34+
}
3035
}

0 commit comments

Comments
 (0)