1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
use std::{collections::HashMap, num::NonZeroUsize, str::FromStr};
use tokio::sync::mpsc::channel;
use twilight_http::Client;
use twilight_model::id::{Id, marker::{ChannelMarker, MessageMarker, UserMarker}};
use twilight_model::util::Timestamp;
use crate::listener::{Listener, ClientEvent};
pub struct System {
pub name: String,
pub config: crate::config::System,
pub message_dedup_cache: lru::LruCache<Id<MessageMarker>, Timestamp>,
pub clients: HashMap<String, Client>,
}
impl System {
pub fn new(system_name: String, system_config: crate::config::System) -> Self {
System {
name: system_name,
config: system_config,
message_dedup_cache: lru::LruCache::new(NonZeroUsize::new(100).unwrap()),
clients: HashMap::new(),
}
}
pub async fn start_clients(&mut self) {
println!("Starting clients for system {}", self.name);
let (tx, mut rx) = channel::<ClientEvent>(100);
let reference_user_id : Id<UserMarker> = Id::from_str(self.config.reference_user_id.as_str())
.expect(format!("Invalid user ID: {}", self.config.reference_user_id).as_str());
for member in self.config.members.iter() {
let client = twilight_http::Client::new(member.discord_token.clone());
self.clients.insert(member.name.clone(), client);
let tx = tx.clone();
let member = member.clone();
tokio::spawn(async move {
let mut listener = Listener::new(member, reference_user_id);
listener.start_listening(tx).await;
});
}
loop {
match rx.recv().await {
Some(event) => match event {
ClientEvent::Message { event_time, message_id, channel_id, content, author: _ } => {
if self.is_new_message(message_id, event_time) {
self.handle_message(message_id, channel_id, content).await;
}
},
ClientEvent::Error(_err) => {
println!("Client ran into an error for system {}", self.name);
return
},
},
None => {
return
},
}
}
}
fn is_new_message(&mut self, message_id: Id<MessageMarker>, timestamp: Timestamp) -> bool {
let last_seen_timestamp = self.message_dedup_cache.get(&message_id);
let current_timestamp = timestamp;
if last_seen_timestamp.is_none() || last_seen_timestamp.unwrap().as_micros() < current_timestamp.as_micros() {
self.message_dedup_cache.put(message_id, timestamp);
true
} else {
false
}
}
async fn handle_message(&mut self, message_id: Id<MessageMarker>, channel_id: Id<ChannelMarker>, content: String) {
// Check for command
// Check for prefix
for member in self.config.members.iter() {
if let Some(captures) = member.message_pattern.captures(content.as_str()) {
let client = self.clients.get(&member.name).expect("No client for member");
let content = captures.name("content").expect("No capture group").as_str();
if let Ok(_) = client.create_message(channel_id)
.content(content).expect("Cannot set content").await {
client.delete_message(channel_id, message_id).await.expect("Could not delete message");
}
}
}
}
}
|