-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
180 lines (167 loc) · 5.83 KB
/
index.js
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
const EventEmitter = require('events');
const request = require('request-promise');
/**
* Discord Webhook Manager
* @author Bsian <[email protected]>
* @note Initialise a new instance of the Webhook Manager for each webhook
*/
class WebhookManager extends EventEmitter {
/**
* Settings for Webhook Manager
* @param {string} webhookID Webhook ID
* @param {string} webhookToken Webhook Token
* @param {{content?: string, embeds?: {}[]}} format Format which the webhook should be sent in - use `'text'` as the wildcard phrase for where the logs should be placed.
* Default:
* ```js
* { content: 'text' }
* ```
* @param {number} interval Interval at which the webhooks should be sent at in milliseconds. Default: 2000
* @param {number} joinInputLengths Maximum length of joined messages - if you don't want them joined, select 0. Default: 0
*/
constructor(webhookID, webhookToken, format = { content: 'text' }, interval = 2000, joinInputLengths = 0) {
super();
if (!webhookID || !webhookToken) throw new TypeError('Expected Webhook ID and Webhook Token');
if (interval < 0 || joinInputLengths < 0) throw new TypeError('`interval` and `joinInputLengths` parameter must be greater than or equal to 0');
this.url = `https://discordapp.com/api/webhooks/${webhookID}/${webhookToken}`;
this.format = format;
this.interval = interval;
this.joinInputLengths = joinInputLengths;
/**
* @type {string[]} Array of messages
*/
this.queue = [];
/**
* @type {Date[]}
*/
this.rateLimiter = [];
this.enabled = true;
setInterval(() => { this.rateLimiter = this.rateLimiter.filter((d) => new Date(Date.now() - 2000) < d); });
setInterval(async () => {
try {
if (this.rateLimiter.length >= 30 || !this.queue.length || this.enabled) return;
const body = JSON.parse(JSON.stringify(this.format).replace(/text/g, this.escapeJSON(this.queue[0])));
try {
await request({
method: 'POST', uri: this.url, body, json: true, resolveWithFullResponse: true,
});
this.queue.shift();
} catch (error) {
if (error.statusCode !== 429 && error.statusCode !== 500) this.rateLimiter.push(new Date());
let errorMessage = `${error.response.statusCode} ${error.response.statusMessage}: ${error.error.code || error.statusCode} - ${error.error.message}`;
if (error.statusCode === 429) errorMessage += '\nRate limits are not working, please open an issue at https://github.com/bsian03/Discord-Webhook-Manager';
else if (error.statusCode === 401
|| error.statusCode === 403
|| error.statusCode === 404) {
errorMessage += '\nPlease try again with another webhook'
+ '\nFor more info regarding webhooks, please see https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks';
}
this.emit('error', [errorMessage, error]);
return;
}
this.rateLimiter.push(new Date());
} catch (error) {
this.emit('error', 'Unknown error occured', error);
}
}, this.interval);
}
/**
* Add a message to the queue
* @param {string} message Message to be added
* @returns {string[]} Current queue
*/
addToQueue(message) {
if (!this.joinInputLengths) {
const splitMessages = this.splitString(message);
splitMessages.forEach((m) => this.queue.push(m));
} else {
const splitMessages = message.split('\n').filter((a) => a);
splitMessages.forEach((m) => {
const lastInQueue = this.queue[this.queue.length - 1];
if (!lastInQueue || lastInQueue.length + m.length + 1 > this.joinInputLengths) this.queue.push(m);
else this.queue[this.queue.length - 1] += `\n${m}`;
});
}
return this.queue;
}
/**
* Removes everything in the queue
* @returns {string[]} Empty queue
*/
emptyQueue() {
this.queue = [];
return this.queue;
}
/**
* Resets the rate limit
* @returns {Date[]} Empty rate limit
*/
resetRateLimit() {
this.rateLimiter = [];
return this.rateLimiter;
}
/**
* Updates the webhook URL
* @param {string} webhookID New Webhook ID
* @param {string} webhookToken New Webhook Token
* @returns {string} New Webhook URL
*/
updateWebhook(webhookID, webhookToken) {
this.url = `https://discordapp.com/api/webhooks/${webhookID}/${webhookToken}`;
return this.url;
}
/**
* Pause webhook sending
* @returns {boolean} Enabled status
*/
pauseWebhookSending() {
this.enabled = false;
return this.enabled;
}
/**
* Start/resume webhook sending
* @returns {boolean} Enabled status
*/
startWebhookSending() {
this.enabled = true;
return this.enabled;
}
/**
* End webhook sending and clear the queue
* @returns {boolean} Enabled status
*/
stopWebhookSending() {
this.enabled = false;
this.queue = [];
return this.enabled;
}
/**
* Split a message
* @param {string} message Message to be split
* @private
*/
splitString(message) {
const msgArray = [];
let str = '';
let pos = 0;
const maxLength = this.joinInputLengths || 2000;
while (message.length > 0) {
pos = message.length > maxLength ? message.lastIndexOf('\n', maxLength) : message.length;
if (pos > maxLength) pos = maxLength;
str = message.substring(0, pos);
// eslint-disable-next-line no-param-reassign
message = message.substring(pos);
msgArray.push(str);
}
return msgArray;
}
/**
* Make message JSON compatible
* @param {string} string Message to be JSON compatible
* @private
*/
// eslint-disable-next-line class-methods-use-this
escapeJSON(string) {
return string.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n');
}
}
module.exports = WebhookManager;