Created
July 23, 2019 17:28
-
-
Save resynth1943/cdb0837be09369037720f535720a710b to your computer and use it in GitHub Desktop.
Discord - Ratelimiting made easy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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