Skip to content

Commit c398e89

Browse files
authored
chore: 🤝 handler tweaks (#96)
this branch is front-running some other changes i'll be making. these are some small (_sometimes subjective_) nits to polish up the handler code. most importantly, this saves some redundant clones and removes needless `pub` directives from some internal interfaces. * handler: 🤝 `MessageInfo::new()` takes references this constructor does not need to take ownership of these structures. so, to reduce frivolous cloning, change the signature so that the parameters borrow the message and context. * handler: 📑 document `Handler::new() * handler: `MessageInfo` is `Debug` * handler: ❓ `should_send` takes references likewise, this can avoid a frivolous clone if we accept a reference to the context, and avoid performing the same `MessageInfo` validations twice. * handler: 🌯 remove frivolous block * handler: 🔐 internal interfaces don't need `pub` visibility these aren't used outside of this file, so we should not designate them as public interfaces.
1 parent 087419d commit c398e89

File tree

1 file changed

+38
-32
lines changed

1 file changed

+38
-32
lines changed

src/handler.rs

+38-32
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use serenity::{
1111
model::{
1212
channel::{GuildChannel, Message},
1313
id::{GuildId, UserId},
14+
user::User,
1415
},
1516
};
1617
use tokio::time::{Duration, Instant};
@@ -37,6 +38,7 @@ pub struct Handler {
3738
}
3839

3940
impl Handler {
41+
/// Constructs a new [`Handler`].
4042
pub fn new(rate_limit: Duration, reply_limit: usize, dry_run: bool) -> Self {
4143
Handler {
4244
rate_limit,
@@ -45,28 +47,26 @@ impl Handler {
4547
dry_run,
4648
}
4749
}
50+
4851
/// Check whether the bot can proceed with honoring this request,
4952
/// performing preflight checks on server and channel configuration,
5053
/// avoiding self-sends, and honoring ratelimits.
51-
async fn should_send(&self, ctx: Context, message: Message) -> bool {
52-
tracing::trace!("parsing message: {:#?}", message);
53-
let message_info = match MessageInfo::new(message.clone(), ctx.clone()) {
54-
Ok(m) => m,
55-
Err(e) => {
56-
tracing::error!(%e, "failed to parse message");
57-
return false;
58-
}
59-
};
54+
async fn should_send(
55+
&self,
56+
ctx: &Context,
57+
MessageInfo {
58+
user_id,
59+
guild_channel,
60+
..
61+
}: &MessageInfo,
62+
) -> bool {
6063
let self_id = ctx.cache.current_user().id;
6164

6265
// Stop if we're not allowed to respond in this channel
63-
if let Ok(self_permissions) = message_info
64-
.guild_channel
65-
.permissions_for_user(&ctx, self_id)
66-
{
66+
if let Ok(self_permissions) = guild_channel.permissions_for_user(&ctx, self_id) {
6767
if !self_permissions.send_messages() {
6868
tracing::debug!(
69-
?message_info.guild_channel,
69+
?guild_channel,
7070
"not allowed to send messages in this channel"
7171
);
7272
return false;
@@ -78,7 +78,7 @@ impl Handler {
7878
// TODO: add check for channel id, bailing out if channel doesn't match
7979

8080
// Don't trigger on messages we ourselves send
81-
if message_info.user_id == self_id {
81+
if *user_id == self_id {
8282
tracing::trace!("detected message from ourselves");
8383
return false;
8484
}
@@ -91,6 +91,7 @@ impl Handler {
9191
/// Representation of a Discord message, containing only the fields
9292
/// relevant for processing a faucet request.
9393
// TODO: consider using `serenity::model::channel::Message` instead.
94+
#[derive(Debug)]
9495
pub struct MessageInfo {
9596
/// Discord user ID of the sender of the message.
9697
pub user_id: UserId,
@@ -103,10 +104,18 @@ pub struct MessageInfo {
103104
}
104105

105106
impl MessageInfo {
106-
pub fn new(message: Message, ctx: Context) -> anyhow::Result<MessageInfo> {
107+
fn new(
108+
message @ Message {
109+
author: User { id, name, .. },
110+
channel_id,
111+
guild_id,
112+
..
113+
}: &Message,
114+
ctx: &Context,
115+
) -> anyhow::Result<MessageInfo> {
107116
// Get the guild id of this message. In Discord nomenclature,
108117
// a "guild" is the overarching server that contains channels.
109-
let guild_id = match message.guild_id {
118+
let guild_id = match guild_id {
110119
Some(guild_id) => guild_id,
111120
None => {
112121
// Assuming Galileo is targeting the Penumbra Labs Discord server,
@@ -117,7 +126,7 @@ impl MessageInfo {
117126
};
118127

119128
// Get the channel of this message.
120-
let guild_channel = match ctx.cache.guild_channel(message.channel_id) {
129+
let guild_channel = match ctx.cache.guild_channel(channel_id) {
121130
Some(guild_channel) => guild_channel,
122131
None => {
123132
// As above, assuming Galileo is targeting the Penumbra Labs Discord server,
@@ -127,12 +136,10 @@ impl MessageInfo {
127136
}
128137
};
129138

130-
let user_id = message.author.id;
131-
let user_name = message.author.name.clone();
132139
Ok(MessageInfo {
133-
user_id,
134-
user_name,
135-
guild_id,
140+
user_id: *id,
141+
user_name: name.clone(),
142+
guild_id: *guild_id,
136143
guild_channel,
137144
})
138145
}
@@ -144,7 +151,7 @@ struct SendHistory {
144151
}
145152

146153
impl SendHistory {
147-
pub fn new() -> Self {
154+
fn new() -> Self {
148155
SendHistory {
149156
discord_users: VecDeque::new(),
150157
penumbra_addresses: VecDeque::new(),
@@ -153,7 +160,7 @@ impl SendHistory {
153160

154161
/// Returns whether the given user is rate limited, and if so, when the rate limit will expire along with
155162
/// the number of times the user has been notified of the rate limit.
156-
pub fn is_rate_limited(
163+
fn is_rate_limited(
157164
&mut self,
158165
user_id: UserId,
159166
addresses: &[AddressOrAlmost],
@@ -184,7 +191,7 @@ impl SendHistory {
184191
})
185192
}
186193

187-
pub fn record_request(&mut self, user_id: UserId, addresses: &[AddressOrAlmost]) {
194+
fn record_request(&mut self, user_id: UserId, addresses: &[AddressOrAlmost]) {
188195
self.discord_users.push_back((user_id, Instant::now(), 1));
189196
self.penumbra_addresses
190197
.extend(addresses.iter().map(|address_or_almost| {
@@ -196,7 +203,7 @@ impl SendHistory {
196203
}));
197204
}
198205

199-
pub fn prune(&mut self, rate_limit: Duration) {
206+
fn prune(&mut self, rate_limit: Duration) {
200207
tracing::trace!("pruning discord user send history");
201208
while let Some((user, last_fulfilled, _)) = self.discord_users.front() {
202209
if last_fulfilled.elapsed() >= rate_limit {
@@ -220,7 +227,7 @@ impl SendHistory {
220227
tracing::trace!("finished pruning penumbra address send history");
221228
}
222229

223-
pub fn record_failure(&mut self, user_id: UserId, addresses: &[AddressOrAlmost]) {
230+
fn record_failure(&mut self, user_id: UserId, addresses: &[AddressOrAlmost]) {
224231
// If the request failed, we set the notification count to zero, so that the rate
225232
// limit will not apply to future requests
226233
if let Some((_, _, notified)) = self
@@ -254,17 +261,16 @@ impl EventHandler for Handler {
254261
/// window, then Galileo will respond instructing the user to wait longer.
255262
async fn message(&self, ctx: Context, message: Message) {
256263
// Check whether we should proceed.
257-
if !self.should_send(ctx.clone(), message.clone()).await {
264+
let message_info = MessageInfo::new(&message, &ctx).unwrap();
265+
if !self.should_send(&ctx, &message_info).await {
258266
return;
259267
}
260268

261-
let message_info = MessageInfo::new(message.clone(), ctx.clone()).unwrap();
262-
263269
// Prune the send history of all expired rate limit timeouts
264270
self.send_history.lock().unwrap().prune(self.rate_limit);
265271

266272
// Check if the message contains a penumbra address and create a request for it if so
267-
let (response, request) = if let Some(parsed) = { Request::try_new(&message) } {
273+
let (response, request) = if let Some(parsed) = Request::try_new(&message) {
268274
parsed
269275
} else {
270276
tracing::trace!("no addresses found in message");

0 commit comments

Comments
 (0)