Errors Standardization (#1246)

* errors and stuff

* more errors

* all the errors

* fix build
This commit is contained in:
Gus Caplan
2017-06-25 12:48:05 -05:00
committed by Amish Shah
parent 602fe06f88
commit 63e54982f4
28 changed files with 258 additions and 102 deletions

View File

@@ -19,6 +19,7 @@ const Invite = require('../structures/Invite');
const OAuth2Application = require('../structures/OAuth2Application');
const ShardClientUtil = require('../sharding/ShardClientUtil');
const VoiceBroadcast = require('./voice/VoiceBroadcast');
const { Error, TypeError, RangeError } = require('../errors');
/**
* The main hub for interacting with the Discord API, and the starting point for any bot.
@@ -287,7 +288,7 @@ class Client extends EventEmitter {
*/
login(token) {
return new Promise((resolve, reject) => {
if (typeof token !== 'string') throw new Error(Constants.Errors.INVALID_TOKEN);
if (typeof token !== 'string') throw new Error('TOKEN_INVALID');
token = token.replace(/^Bot\s*/i, '');
this.manager.connectToWebSocket(token, resolve, reject);
});
@@ -375,7 +376,9 @@ class Client extends EventEmitter {
* or -1 if the message cache lifetime is unlimited
*/
sweepMessages(lifetime = this.options.messageCacheLifetime) {
if (typeof lifetime !== 'number' || isNaN(lifetime)) throw new TypeError('The lifetime must be a number.');
if (typeof lifetime !== 'number' || isNaN(lifetime)) {
throw new TypeError('CLIENT_INVALID_OPTION', 'Lifetime', 'a number');
}
if (lifetime <= 0) {
this.emit('debug', 'Didn\'t sweep messages - lifetime is unlimited');
return -1;
@@ -524,41 +527,40 @@ class Client extends EventEmitter {
*/
_validateOptions(options = this.options) {
if (typeof options.shardCount !== 'number' || isNaN(options.shardCount)) {
throw new TypeError('The shardCount option must be a number.');
throw new TypeError('CLIENT_INVALID_OPTION', 'shardCount', 'a number');
}
if (typeof options.shardId !== 'number' || isNaN(options.shardId)) {
throw new TypeError('The shardId option must be a number.');
throw new TypeError('CLIENT_INVALID_OPTION', 'shardId', 'a number');
}
if (options.shardCount < 0) throw new RangeError('The shardCount option must be at least 0.');
if (options.shardId < 0) throw new RangeError('The shardId option must be at least 0.');
if (options.shardCount < 0) throw new RangeError('CLIENT_INVALID_OPTION', 'shardCount', 'at least 0');
if (options.shardId < 0) throw new RangeError('CLIENT_INVALID_OPTION', 'shardId', 'at least 0');
if (options.shardId !== 0 && options.shardId >= options.shardCount) {
throw new RangeError('The shardId option must be less than shardCount.');
throw new RangeError('CLIENT_INVALID_OPTION', 'shardId', 'less than shardCount');
}
if (typeof options.messageCacheMaxSize !== 'number' || isNaN(options.messageCacheMaxSize)) {
throw new TypeError('The messageCacheMaxSize option must be a number.');
throw new TypeError('CLIENT_INVALID_OPTION', 'messageCacheMaxSize', 'a number');
}
if (typeof options.messageCacheLifetime !== 'number' || isNaN(options.messageCacheLifetime)) {
throw new TypeError('The messageCacheLifetime option must be a number.');
throw new TypeError('CLIENT_INVALID_OPTION', 'The messageCacheLifetime', 'a number');
}
if (typeof options.messageSweepInterval !== 'number' || isNaN(options.messageSweepInterval)) {
throw new TypeError('The messageSweepInterval option must be a number.');
throw new TypeError('CLIENT_INVALID_OPTION', 'messageSweepInterval', 'a number');
}
if (typeof options.fetchAllMembers !== 'boolean') {
throw new TypeError('The fetchAllMembers option must be a boolean.');
throw new TypeError('CLIENT_INVALID_OPTION', 'fetchAllMembers', 'a boolean');
}
if (typeof options.disableEveryone !== 'boolean') {
throw new TypeError('The disableEveryone option must be a boolean.');
throw new TypeError('CLIENT_INVALID_OPTION', 'disableEveryone', 'a boolean');
}
if (typeof options.restWsBridgeTimeout !== 'number' || isNaN(options.restWsBridgeTimeout)) {
throw new TypeError('The restWsBridgeTimeout option must be a number.');
throw new TypeError('CLIENT_INVALID_OPTION', 'restWsBridgeTimeout', 'a number');
}
if (typeof options.internalSharding !== 'boolean') {
throw new TypeError('The internalSharding option must be a boolean.');
throw new TypeError('CLIENT_INVALID_OPTION', 'internalSharding', 'a boolean');
}
if (options.internalSharding && ('shardCount' in options || 'shardId' in options)) {
throw new TypeError('You cannot specify shardCount/shardId if you are using internal sharding.');
if (!(options.disabledEvents instanceof Array)) {
throw new TypeError('CLIENT_INVALID_OPTION', 'disabledEvents', 'an Array');
}
if (!(options.disabledEvents instanceof Array)) throw new TypeError('The disabledEvents option must be an Array.');
}
}

View File

@@ -10,6 +10,7 @@ const Channel = require('../structures/Channel');
const GuildMember = require('../structures/GuildMember');
const Emoji = require('../structures/Emoji');
const ReactionEmoji = require('../structures/ReactionEmoji');
const { Error, TypeError } = require('../errors');
/**
* The DataResolver identifies different objects and tries to resolve a specific piece of information from them, e.g.
@@ -194,14 +195,14 @@ class ClientDataResolver {
snekfetch.get(resource)
.end((err, res) => {
if (err) return reject(err);
if (!(res.body instanceof Buffer)) return reject(new TypeError('The response body isn\'t a Buffer.'));
if (!(res.body instanceof Buffer)) return reject(new TypeError('REQ_BODY_TYPE'));
return resolve(res.body);
});
} else {
const file = path.resolve(resource);
fs.stat(file, (err, stats) => {
if (err) return reject(err);
if (!stats || !stats.isFile()) return reject(new Error(`The file could not be found: ${file}`));
if (!stats || !stats.isFile()) return reject(new Error('FILE_NOT_FOUND', file));
fs.readFile(file, (err2, data) => {
if (err2) reject(err2); else resolve(data);
});
@@ -211,7 +212,7 @@ class ClientDataResolver {
});
}
return Promise.reject(new TypeError('The resource must be a string or Buffer.'));
return Promise.reject(new TypeError('REQ_RESOURCE_TYPE'));
}
/**

View File

@@ -1,5 +1,6 @@
const Constants = require('../util/Constants');
const WebSocketConnection = require('./websocket/WebSocketConnection');
const { Error } = require('../errors');
/**
* Manages the state and background tasks of the client.
@@ -37,16 +38,16 @@ class ClientManager {
connectToWebSocket(token, resolve, reject) {
this.client.emit(Constants.Events.DEBUG, `Authenticated using token ${token}`);
this.client.token = token;
const timeout = this.client.setTimeout(() => reject(new Error(Constants.Errors.TOOK_TOO_LONG)), 1000 * 300);
const timeout = this.client.setTimeout(() => reject(new Error('INVALID_TOKEN')), 1000 * 300);
this.client.api.gateway.get().then(res => {
const protocolVersion = Constants.DefaultOptions.ws.version;
const gateway = `${res.url}/?v=${protocolVersion}&encoding=${WebSocketConnection.ENCODING}`;
this.client.emit(Constants.Events.DEBUG, `Using gateway ${gateway}`);
this.client.ws.connect(gateway);
this.client.ws.connection.once('close', event => {
if (event.code === 4004) reject(new Error(Constants.Errors.BAD_LOGIN));
if (event.code === 4010) reject(new Error(Constants.Errors.INVALID_SHARD));
if (event.code === 4011) reject(new Error(Constants.Errors.SHARDING_REQUIRED));
if (event.code === 4004) reject(new Error('TOKEN_INVALID'));
if (event.code === 4010) reject(new Error('SHARDING_INVALID'));
if (event.code === 4011) reject(new Error('SHARDING_REQUIRED'));
});
this.client.once(Constants.Events.READY, () => {
resolve(token);

View File

@@ -1,6 +1,6 @@
const querystring = require('querystring');
const snekfetch = require('snekfetch');
const Constants = require('../../util/Constants');
const { Error } = require('../../errors');
class APIRequest {
constructor(rest, method, path, options) {
@@ -28,7 +28,7 @@ class APIRequest {
} else if (this.client.token) {
return this.client.token;
}
throw new Error(Constants.Errors.NO_TOKEN);
throw new Error('TOKEN_MISSING');
}
gen() {

View File

@@ -3,7 +3,7 @@ const SequentialRequestHandler = require('./RequestHandlers/Sequential');
const BurstRequestHandler = require('./RequestHandlers/Burst');
const APIRequest = require('./APIRequest');
const mountApi = require('./APIRouter');
const Constants = require('../../util/Constants');
const { Error } = require('../../errors');
class RESTManager {
constructor(client) {
@@ -39,7 +39,7 @@ class RESTManager {
case 'burst':
return BurstRequestHandler;
default:
throw new Error(Constants.Errors.INVALID_RATE_LIMIT_METHOD);
throw new Error('RATELIMIT_INVALID_METHOD');
}
}

View File

@@ -1,5 +1,6 @@
const Collection = require('../../util/Collection');
const VoiceConnection = require('./VoiceConnection');
const { Error } = require('../../errors');
/**
* Manages all the voice stuff for the client.
@@ -44,11 +45,7 @@ class ClientVoiceManager {
joinChannel(channel) {
return new Promise((resolve, reject) => {
if (!channel.joinable) {
if (channel.full) {
throw new Error('You do not have permission to join this voice channel; it is full.');
} else {
throw new Error('You do not have permission to join this voice channel.');
}
throw new Error('VOICE_JOIN_CHANNEL', channel.full);
}
let connection = this.connections.get(channel.guild.id);

View File

@@ -6,6 +6,7 @@ const AudioPlayer = require('./player/AudioPlayer');
const VoiceReceiver = require('./receiver/VoiceReceiver');
const EventEmitter = require('events').EventEmitter;
const Prism = require('prism-media');
const { Error } = require('../../errors');
/**
* Represents a connection to a guild's voice server.
@@ -341,8 +342,8 @@ class VoiceConnection extends EventEmitter {
*/
connect() {
if (this.status !== Constants.VoiceStatus.RECONNECTING) {
if (this.sockets.ws) throw new Error('There is already an existing WebSocket connection.');
if (this.sockets.udp) throw new Error('There is already an existing UDP connection.');
if (this.sockets.ws) throw new Error('WS_CONNECTION_EXISTS');
if (this.sockets.udp) throw new Error('UDP_CONNECTION_EXISTS');
}
if (this.sockets.ws) this.sockets.ws.shutdown();

View File

@@ -2,6 +2,7 @@ const udp = require('dgram');
const dns = require('dns');
const Constants = require('../../util/Constants');
const EventEmitter = require('events').EventEmitter;
const { Error } = require('../../errors');
/**
* Represents a UDP client for a Voice Connection.
@@ -89,8 +90,8 @@ class VoiceConnectionUDPClient extends EventEmitter {
*/
send(packet) {
return new Promise((resolve, reject) => {
if (!this.socket) throw new Error('Tried to send a UDP packet, but there is no socket available.');
if (!this.discordAddress || !this.discordPort) throw new Error('Malformed UDP address or port.');
if (!this.socket) throw new Error('UDP_SEND_FAIL');
if (!this.discordAddress || !this.discordPort) throw new Error('UDP_ADDRESS_MALFORMED');
this.socket.send(packet, 0, packet.length, this.discordPort, this.discordAddress, error => {
if (error) reject(error); else resolve(packet);
});

View File

@@ -1,6 +1,7 @@
const Constants = require('../../util/Constants');
const SecretKey = require('./util/SecretKey');
const EventEmitter = require('events').EventEmitter;
const { Error } = require('../../errors');
let WebSocket;
try {
@@ -88,9 +89,7 @@ class VoiceWebSocket extends EventEmitter {
*/
send(data) {
return new Promise((resolve, reject) => {
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
throw new Error(`Voice websocket not open to send ${data}.`);
}
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) throw new Error('WS_NOT_OPEN', data);
this.ws.send(data, null, error => {
if (error) reject(error); else resolve(data);
});

View File

@@ -1,3 +1,5 @@
const { Error } = require('../../../errors');
const list = [
require('./NodeOpusEngine'),
require('./OpusScriptEngine'),
@@ -30,5 +32,5 @@ exports.fetch = engineOptions => {
exports.guaranteeOpusEngine = () => {
if (typeof opusEngineFound === 'undefined') opusEngineFound = Boolean(exports.fetch());
if (!opusEngineFound) throw new Error('Couldn\'t find an Opus engine.');
if (!opusEngineFound) throw new Error('OPUS_ENGINE_MISSING');
};

View File

@@ -2,6 +2,7 @@ const EventEmitter = require('events').EventEmitter;
const secretbox = require('../util/Secretbox');
const Readable = require('./VoiceReadable');
const OpusEncoders = require('../opus/OpusEngineList');
const { Error } = require('../../../errors');
const nonce = Buffer.alloc(24);
nonce.fill(0);
@@ -122,8 +123,8 @@ class VoiceReceiver extends EventEmitter {
*/
createOpusStream(user) {
user = this.voiceConnection.voiceManager.client.resolver.resolveUser(user);
if (!user) throw new Error('Couldn\'t resolve the user to create Opus stream.');
if (this.opusStreams.get(user.id)) throw new Error('There is already an existing stream for that user.');
if (!user) throw new Error('VOICE_USER_MISSING');
if (this.opusStreams.get(user.id)) throw new Error('VOICE_STREAM_EXISTS');
const stream = new Readable();
this.opusStreams.set(user.id, stream);
return stream;
@@ -137,8 +138,8 @@ class VoiceReceiver extends EventEmitter {
*/
createPCMStream(user) {
user = this.voiceConnection.voiceManager.client.resolver.resolveUser(user);
if (!user) throw new Error('Couldn\'t resolve the user to create PCM stream.');
if (this.pcmStreams.get(user.id)) throw new Error('There is already an existing stream for that user.');
if (!user) throw new Error('VOICE_USER_MISSING');
if (this.pcmStreams.get(user.id)) throw new Error('VOICE_STREAM_EXISTS');
const stream = new Readable();
this.pcmStreams.set(user.id, stream);
return stream;