detritus-client
Version:
A Typescript NodeJS library to interact with Discord's API, both Rest and Gateway.
133 lines (132 loc) • 4.49 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CommandRatelimiter = exports.CommandRatelimit = exports.KEY_SPLITTER = void 0;
const detritus_utils_1 = require("detritus-utils");
const basecollection_1 = require("../collections/basecollection");
const constants_1 = require("../constants");
const interaction_1 = require("../interaction");
exports.KEY_SPLITTER = ':';
/**
* Command Ratelimit Options and Cache
* @category Command Ratelimit
*/
class CommandRatelimit {
constructor(options = {}, command) {
this.duration = 5000;
this.limit = 5;
this.type = constants_1.CommandRatelimitTypes.USER;
options = Object.assign({}, options);
this.command = command || this.command;
this.duration = options.duration || this.duration;
this.limit = options.limit || this.limit;
if (options.type) {
if (typeof (options.type) === 'string') {
this.type = options.type.toLowerCase();
}
else {
this.type = options.type;
}
}
if (typeof (this.type) === 'string' && !constants_1.COMMAND_RATELIMIT_TYPES.includes(this.type)) {
// maybe error instead?
this.type = constants_1.CommandRatelimitTypes.USER;
}
this.key = options.key || this.key;
}
get uniqueKey() {
if (this.key) {
return 'KEY' + exports.KEY_SPLITTER + this.key;
}
if (this.command) {
if (this.command instanceof interaction_1.InteractionCommand) {
return 'INTERACTION-COMMAND' + exports.KEY_SPLITTER + this.command.fullName;
}
else {
return 'COMMAND' + exports.KEY_SPLITTER + this.command.fullName;
}
}
return '';
}
createKey(context) {
let key;
if (typeof (this.type) === 'function') {
key = this.type(context);
}
else {
switch (this.type) {
case constants_1.CommandRatelimitTypes.CHANNEL:
{
key = context.channelId || '';
}
;
break;
case constants_1.CommandRatelimitTypes.GUILD:
{
key = context.guildId || context.channelId || '';
}
;
break;
case constants_1.CommandRatelimitTypes.USER:
{
key = context.userId;
}
;
break;
default:
{
key = context.userId;
this.type = constants_1.CommandRatelimitTypes.USER;
}
;
}
const uniqueKey = this.uniqueKey;
if (uniqueKey) {
key += exports.KEY_SPLITTER + this.type + exports.KEY_SPLITTER + uniqueKey;
}
else {
key += exports.KEY_SPLITTER + this.type;
}
}
return key;
}
}
exports.CommandRatelimit = CommandRatelimit;
class CommandRatelimiter {
constructor() {
this.cache = new basecollection_1.BaseCollection();
}
getExceeded(context, ratelimits, now = Date.now()) {
const exceeded = [];
for (const ratelimit of ratelimits) {
const item = this.getOrCreate(context, ratelimit);
if (ratelimit.limit <= item.usages++) {
const remaining = (item.start + ratelimit.duration) - now;
exceeded.push({ item, ratelimit, remaining });
}
}
return exceeded;
}
getOrCreate(context, ratelimit) {
const key = ratelimit.createKey(context);
let item;
if (this.cache.has(key)) {
item = this.cache.get(key);
}
else {
const timeout = new detritus_utils_1.Timers.Timeout();
timeout.start(ratelimit.duration, () => {
this.cache.delete(key);
});
item = {
key,
replied: false,
start: Date.now(),
timeout,
usages: 0,
};
this.cache.set(key, item);
}
return item;
}
}
exports.CommandRatelimiter = CommandRatelimiter;