Skip to content

Instantly share code, notes, and snippets.

@resynth1943
Created July 23, 2019 17:28
Show Gist options
  • Save resynth1943/cdb0837be09369037720f535720a710b to your computer and use it in GitHub Desktop.
Save resynth1943/cdb0837be09369037720f535720a710b to your computer and use it in GitHub Desktop.
Discord - Ratelimiting made easy
import { Bucket } from './ratelimiting';
import { User } from 'discord.js';
// Create your ratelimit bucket here. This is where we'll be storing everyone who uses a command.
const ratelimitBucket = new Bucket<User>(/* enter your timeout here in milliseconds. */ 5000);
// This obviously won't work, but you need to enter this code (or your variant) into your command handler.
onCommand((message: Message) => {
// Enter the member into the bucket, so we can keep track of them. If the user is already in the bucket, this does nothing.
this.enterMember(message.author);
if (ratelimitBucket.check(message.author)) {
reply(`You need to wait ${ratelimitBucket.remaining(message.author)} ms before you use another command.`);
return;
}
// Otherwise, the user is good to go.
});
interface QueueMember<MemberType> {
member: MemberType;
end: number;
}
export class Bucket<MemberType> {
private readonly queue: QueueMember<MemberType>[] = [];
public constructor(public timeout: number) { }
public has(member: MemberType): boolean {
return this.queue.some(x => x.member === member);
}
public enterMember(member: MemberType): void {
if (this.has(member)) {
return;
}
const end = Date.now() + this.timeout;
this.push(member, end);
}
public check(member: MemberType): boolean {
const queueMember = this.findQueueMember(member);
if (!queueMember) {
// That member isn't currently in the queue. Return false to signal that they're allowed.
return false;
}
// The member does exist, and we need to check if they can pass.
const { end } = queueMember;
const hasElapsed = Date.now() > end;
if (hasElapsed) {
this.removeMember(member);
}
return hasElapsed;
}
public remaining(member: MemberType): number | void {
const queueMember = this.findQueueMember(member);
if (queueMember) {
return queueMember.end;
}
}
protected removeMember(member: MemberType): void {
const index = this.queue.findIndex(x => x.member === member);
if (index !== -1) {
// The member is present in the queue. Remove it.
this.queue.splice(index, 1);
}
}
protected push(member: MemberType, end: number): void {
this.queue.push({
member,
end
});
}
protected findQueueMember(member: MemberType): void | QueueMember<MemberType> {
return this.queue.find(x => x.member === member);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment