UNPKG

dbots

Version:

Discord bot list poster and stats retriever

324 lines (323 loc) 14.1 kB
"use strict"; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Poster = void 0; var Constants_1 = require("../Utils/Constants"); var EnsurePromise_1 = require("../Utils/EnsurePromise"); var DBotsError_1 = require("../Utils/DBotsError"); var ClientFiller_1 = require("./ClientFiller"); var Service_1 = require("./Service"); var promise_allsettled_1 = __importDefault(require("promise.allsettled")); var DBotsError = DBotsError_1.errors.Error, TypeError = DBotsError_1.errors.TypeError; /** A class that posts server count to listing site(s). */ var Poster = /** @class */ (function () { // #endregion /** * @constructor * @param options The options needed to construct the poster */ function Poster(options) { var _a, _b; if (!options || typeof options !== 'object') throw new DBotsError('INVALID_POSTER_OPTIONS'); this.client = options.client; this._clientFiller = null; this.customServices = options.customServices || []; this.apiKeys = options.apiKeys || {}; this.options = options; if (typeof options.useSharding !== 'boolean') options.useSharding = true; if (!this.client && !options.clientID) throw new DBotsError('NO_CLIENT_OR_ID'); if (this.client && !options.clientID) Object.assign(options, { clientID: (_a = this.clientFiller) === null || _a === void 0 ? void 0 : _a.clientID, shard: (_b = this.clientFiller) === null || _b === void 0 ? void 0 : _b.shard }); if (!options.useSharding) options.shard = undefined; this.handlers = {}; for (var _i = 0, SupportedEvents_1 = Constants_1.SupportedEvents; _i < SupportedEvents_1.length; _i++) { var event_1 = SupportedEvents_1[_i]; this.handlers[event_1] = []; } } Object.defineProperty(Poster.prototype, "clientFiller", { /** The client filler used in the poster */ get: function () { return (this._clientFiller || (this.options.clientLibrary && this.client ? (this._clientFiller = (0, ClientFiller_1.getClientFiller)(this.options.clientLibrary, this.client)) : undefined)); }, enumerable: false, configurable: true }); /** * Retrieves the current server count of the client/shard. * @returns Amount of servers the client/shard is in */ Poster.prototype.getServerCount = function () { var _a; if (this.options.serverCount) // @ts-expect-error return (0, EnsurePromise_1.ensurePromise)(this.options.serverCount); if (!this.client) throw new DBotsError('NO_CLIENT', 'server'); if (!this.options.clientLibrary) throw new DBotsError('UNKNOWN_CLIENT', 'server'); return Promise.resolve(((_a = this.clientFiller) === null || _a === void 0 ? void 0 : _a.serverCount) || 0); }; /** * Retrieves the current user count of the client/shard. * @returns Amount of users the client/shard is connected with */ Poster.prototype.getUserCount = function () { var _a; if (this.options.userCount) // @ts-expect-error return (0, EnsurePromise_1.ensurePromise)(this.options.userCount); if (!this.client) throw new DBotsError('NO_CLIENT', 'user'); if (!this.options.clientLibrary) throw new DBotsError('UNKNOWN_CLIENT', 'user'); return Promise.resolve(((_a = this.clientFiller) === null || _a === void 0 ? void 0 : _a.userCount) || 0); }; /** * Retrieves the current voice connection count of the client/shard. * @returns Number of active voice connections */ Poster.prototype.getVoiceConnections = function () { var _a; if (this.options.voiceConnections) // @ts-expect-error return (0, EnsurePromise_1.ensurePromise)(this.options.voiceConnections); if (!this.client) throw new DBotsError('NO_CLIENT', 'voice connection'); if (!this.options.clientLibrary) throw new DBotsError('UNKNOWN_CLIENT', 'voice connection'); return Promise.resolve(((_a = this.clientFiller) === null || _a === void 0 ? void 0 : _a.voiceConnections) || 0); }; /** * Creates an interval that posts to all services. * @param interval The time (in ms) to reach to post to all {@link Service}s again * @returns The interval that is responsible for posting * @emits Poster#autopostSuccess * @emits Poster#autopostFail */ Poster.prototype.startInterval = function (interval) { var _this_1 = this; if (interval === void 0) { interval = 1800000; } this._interval && clearTimeout(this._interval); this._interval = setInterval(function () { return _this_1.post() .then(function (result) { _this_1.runHandlers('autopostSuccess', result); return result; }) .catch(function (error) { return _this_1.runHandlers('autopostFail', error); }); }, interval); return this._interval; }; /** Destroys the current interval. */ Poster.prototype.stopInterval = function () { if (this._interval) clearTimeout(this._interval); }; /** * Gets a service, autofilling its API key if the poster has it. * @param service The service to get */ Poster.prototype.getService = function (service) { var _this_1 = this; var serviceClass = Service_1.Service.get(service, this.customServices); if (!serviceClass) return undefined; var keyName = serviceClass.aliases.find(function (key) { return Object.keys(_this_1.apiKeys).includes(key); }); if (keyName) return new serviceClass(this.apiKeys[keyName]); else return serviceClass; }; /** * Posts the current clients server count to a service. * @param service The service to post to * @see Poster#postManual * @returns The result(s) of the post * @emits Poster#postSuccess * @emits Poster#postFail */ Poster.prototype.post = function (service) { if (service === void 0) { service = 'all'; } var _this = this; return new Promise(function (resolve, reject) { return Promise.all([ _this.getServerCount(), _this.getUserCount(), _this.getVoiceConnections() ]) .then(function (_a) { var serverCount = _a[0], userCount = _a[1], voiceConnections = _a[2]; _this .postManual(service, { serverCount: serverCount, userCount: userCount, voiceConnections: voiceConnections }) .then(resolve) .catch(reject); }) .catch(reject); }); }; /** * Manually posts a server count to a service. * @param service The service to post to * @param counts An object containing the tallies of servers, users and voice connections * @returns The result(s) of the post */ Poster.prototype.postManual = function (service, counts) { var _this_1 = this; var serverCount = counts.serverCount, userCount = counts.userCount, voiceConnections = counts.voiceConnections; if (!service) service = 'all'; if (!this.apiKeys && !this.options.post) return Promise.reject(new DBotsError('NO_API_KEYS')); if (service === 'custom') // @ts-expect-error return (0, EnsurePromise_1.ensurePromise)( // @ts-expect-error this.options.post, this.options.clientID, serverCount, this.options.shard); if (service === 'all') { var services = Object.keys(this.apiKeys); if (this.options.post) services.push('custom'); return promise_allsettled_1.default .call(Promise, services.map(function (k) { return _this_1.postManual(k, { serverCount: serverCount, userCount: userCount, voiceConnections: voiceConnections }); })) .then(function (requests) { var _a, _b; var rejected = [], hostnames = []; for (var _i = 0, requests_1 = requests; _i < requests_1.length; _i++) { var r = requests_1[_i]; if (r.status == 'rejected') { rejected.push(r); // @ts-expect-error if ((_b = (_a = r.reason) === null || _a === void 0 ? void 0 : _a.config) === null || _b === void 0 ? void 0 : _b.url) { // @ts-expect-error var hostname = new URL(r.reason.config.url).hostname; if (hostname && !hostnames.includes(hostname)) hostnames.push(hostname); } else hostnames.push('???'); } } if (rejected.length > 0) { var msg = "".concat(rejected.length, " request").concat(rejected.length == 1 ? '' : 's', " have been rejected.\n"); if (hostnames.length > 0) msg += "Failing hostnames: ".concat(hostnames.join(', '), "\n"); msg += 'Please check the error from the following responses.\n'; msg += rejected .map(function (rej) { var reason = rej.reason || rej; return reason && typeof reason == 'object' && !(reason instanceof Error) ? JSON.stringify(reason, null, 2) : reason.toString(); }) .join('\n'); throw new DBotsError('GENERIC', msg); } else { // @ts-expect-error return requests.map(function (r) { return r.value; }); } }); } if (!Object.keys(this.apiKeys).includes(service)) return Promise.reject(new DBotsError('SERVICE_NO_KEY', service)); var serviceClass = Service_1.Service.get(service, this.customServices); if (!serviceClass) return Promise.reject(new TypeError('INVALID_SERVICE', service)); return new Promise(function (resolve, reject) { serviceClass .post({ token: _this_1.apiKeys[service], clientID: _this_1.options.clientID || '', shard: _this_1.options.shard, serverCount: serverCount, userCount: userCount, voiceConnections: voiceConnections }) .then(function (result) { _this_1.runHandlers('postSuccess', result); resolve(result); }) .catch(function (error) { _this_1.runHandlers('postFail', error); reject(error); }); }); }; /** * Adds an handler for an event. * @param event The name of the event to add the handler to * @param handler The function that is run with the event * @returns The array of handlers currently set for that event */ Poster.prototype.addHandler = function (event, handler) { if (!Constants_1.SupportedEvents.includes(event)) throw new TypeError('UNSUPPORTED_EVENT', 'add'); if (typeof handler != 'function') throw new DBotsError('HANDLER_INVALID'); this.handlers[event].push(handler); return this.handlers[event]; }; /** * Removes an handler for an event. * @param event The name of the event to remove the handler from * @param handler The function that is run with the event * @returns The array of handlers currently set for that event */ Poster.prototype.removeHandler = function (event, handler) { if (!Constants_1.SupportedEvents.includes(event)) throw new TypeError('UNSUPPORTED_EVENT', 'remove'); if (typeof handler != 'function') throw new DBotsError('HANDLER_INVALID'); var index = this.handlers[event].indexOf(handler); if (index >= 0) this.handlers[event].splice(index, 1); return this.handlers[event]; }; /** * Manually triggers an event with custom arguments. * @param {CustomEvent} event The name of the event to run the handlers for * @param {...any} args The arguments to pass to the handlers */ Poster.prototype.runHandlers = function (event) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } if (!Constants_1.SupportedEvents.includes(event)) throw new TypeError('UNSUPPORTED_EVENT', 'run'); for (var _a = 0, _b = this.handlers[event]; _a < _b.length; _a++) { var handler = _b[_a]; EnsurePromise_1.ensurePromise.apply(void 0, __spreadArray([handler], args, false)); } }; return Poster; }()); exports.Poster = Poster;