botlist.me.js
Version:
Official node.js API wrapper of Botlist.me
105 lines (96 loc) • 3.77 kB
JavaScript
const EventEmitter = require('events');
const { Server, createServer } = require('http');
const querystring = require('querystring');
class BotlistMeWebhook extends EventEmitter {
/**
* Creates a new BotlistMeWebhook Instance.
* @param {number} port The port to run the webhook on.
* @param {string} [path='/botlistmewebhook'] The path for the webhook request.
* @param {string} [auth] The string for Authorization you set on the bot page for verification.
* @param {http.Server} [server] An existing http server to connect with.
*/
constructor(port, path, auth, server) {
if (!port && !server) throw new Error('Neither port nor server provided');
super();
this.port = port || 0;
this.path = path || '/botlistmewebhook';
this.auth = auth;
this._server = null;
this.attached = false;
if (server && !(server instanceof Server)) throw Error('The server is not an instance of http.Server');
if (server) {
this._attachWebhook(server);
} else {
this._startWebhook();
}
}
_emitListening() {
/**
* Event to notify that the webhook is listening
* @event BotlistMeWebhook#ready
* @param {string} hostname The hostname of the webhook server
* @param {number} port The port the webhook server is running on
* @param {string} path The path for the webhook
*/
// Get the user's public IP via an API for hostname later?
this.emit('ready', { hostname: '0.0.0.0', port: this.port, path: this.path });
}
_startWebhook() {
this._server = createServer(this._handleRequest.bind(this));
this._server.listen(this.port, this._emitListening.bind(this));
}
_attachWebhook(server) {
this._server = server;
this._listeners = server.listeners('request');
server.removeAllListeners('request');
server.on('request', this._handleRequest.bind(this));
server.on('listening', this._emitListening.bind(this));
this.attached = true;
}
_handleRequest(req, res) {
if (req.url === this.path && req.method === 'POST') {
if (this.auth && this.auth !== req.headers.authorization) return this._returnResponse(res, 403);
if (req.headers['content-type'] !== 'application/json') return this._returnResponse(res, 400);
let data = '';
req.on('data', chunk => {
data += chunk;
});
req.on('end', () => {
if (data) {
try {
data = JSON.parse(data);
if (data.query === '') data.query = undefined;
if (data.query) data.query = querystring.parse(data.query.substr(1));
} catch (e) {
return this._returnResponse(res, 400);
}
/**
* Event that fires when the webhook has received a vote.
* @event BotlistMeWebhook#vote
* @param {string} bot Id of the bot that was voted for.
* @param {string} user Id of the user that voted.
* @param {string} type Type of the vote. Is always "upvote" except when using the test button it's "test".
*/
this.emit('vote', data);
return this._returnResponse(res, 200, 'Webhook successfully received');
} else {
return this._returnResponse(res, 400);
}
});
} else {
if (this.attached) {
for (const listener of this._listeners) {
listener.call(this._server, req, res);
}
return undefined;
}
return this._returnResponse(res, 404);
}
return undefined;
}
_returnResponse(res, statusCode, data) {
res.statusCode = statusCode;
res.end(data);
}
}
module.exports = BotlistMeWebhook;