discord-baymax-bot/node_modules/discordie/lib/index.js
2017-03-23 23:52:08 -05:00

415 lines
13 KiB
JavaScript

"use strict";
const DiscordieDispatcher = require("./core/DiscordieDispatcher");
const events = require("events");
const request = require("./core/ApiRequest");
const DiscordieError = require("./core/DiscordieError");
const Constants = require("./Constants");
const Events = Constants.Events;
const GatewaySocket = require("./networking/ws/GatewaySocket");
const Utils = require("./core/Utils");
const GuildCollection = require("./collections/GuildCollection");
const ChannelCollection = require("./collections/ChannelCollection");
const UserCollection = require("./collections/UserCollection");
const GuildMemberCollection = require("./collections/GuildMemberCollection");
const MessageCollection = require("./collections/MessageCollection");
const PresenceCollection = require("./collections/PresenceCollection");
const VoiceStateCollection = require("./collections/VoiceStateCollection");
const VoiceConnectionCollection = require("./collections/VoiceConnectionCollection");
const UnavailableGuildCollection = require("./collections/UnavailableGuildCollection");
const GuildSyncCollection = require("./collections/GuildSyncCollection");
const CallCollection = require("./collections/CallCollection");
const User = require("./models/User");
const AuthenticatedUser = require("./models/AuthenticatedUser");
const IGuildCollection = require("./interfaces/IGuildCollection");
const IChannelCollection = require("./interfaces/IChannelCollection");
const IAuthenticatedUser = require("./interfaces/IAuthenticatedUser");
const IUserCollection = require("./interfaces/IUserCollection");
const IMessageCollection = require("./interfaces/IMessageCollection");
const IDirectMessageChannelCollection = require("./interfaces/IDirectMessageChannelCollection");
const IInviteManager = require("./interfaces/IInviteManager");
const IWebhookManager = require("./interfaces/IWebhookManager");
const RequestQueueManager = require("./core/ratelimiting/RequestQueueManager");
const GatewayReconnectHandler = require("./core/GatewayReconnectHandler");
const ReadyEventScheduler = require("./core/ReadyEventScheduler");
const MessageHandlerCache = require("./core/MessageHandlerCache");
const messageHandlerCache = new WeakMap();
const rest = require("./networking/rest");
function handleAuthLoginError(e) {
this.pendingLogin = false;
this.Dispatcher.emit(
Events.DISCONNECTED,
{error: new DiscordieError("Login failed", e.error)}
);
}
function handleAuthLoginSuccess(e) {
this.pendingLogin = false;
this.token = e.token;
delete e.token;
delete e.password;
rest(this).gateway();
}
function handleGatewayError(e) {
this.pendingLogin = false;
var ev = {error: new DiscordieError("Could not get gateway", e.error)};
if (this.autoReconnect) this.autoReconnect._disconnected(ev);
this.Dispatcher.emit(Events.DISCONNECTED, ev);
}
function handleGatewaySuccess(e) {
this.pendingLogin = false;
this.gatewayEndpoint = e.gateway;
this._createPrimaryGateway();
}
function registerGatewayHandlers() {
this.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
if (e.suppress) { delete e.suppress; delete e.handled; return; }
const handlers = messageHandlerCache.get(this);
if (!handlers.processGatewayMessage(e.socket, e.type, e.data) && !e.handled) {
if (!e.socket.isPrimary) return;
return this.Dispatcher.emit(
Events.GATEWAY_UNHANDLED_MESSAGE,
{type: e.type, data: e.data}
);
}
if (e.handled) delete e.handled;
});
const onVoiceMessage = (type, e) => {
if (e.suppress) { delete e.suppress; delete e.handled; return; }
const handlers = messageHandlerCache.get(this);
if (!handlers.processVoiceMessage(e.socket, type, e.data) && !e.handled) {
return this.Dispatcher.emit(
Events.VOICESOCKET_UNHANDLED_MESSAGE,
{type: type, data: e.data}
);
}
if (e.handled) delete e.handled;
};
this.Dispatcher.on(Events.VOICE_READY, e => {
onVoiceMessage("READY", e);
});
this.Dispatcher.on(Events.VOICE_SESSION_DESCRIPTION, e => {
onVoiceMessage("SESSION_DESCRIPTION", e);
});
this.Dispatcher.on(Events.VOICE_SPEAKING, e => {
onVoiceMessage("SPEAKING", e);
});
}
const defaultOptions = {
compressMessages: true,
messageQueue: true,
};
/**
* @class
* @classdesc
* Additional constructor options:
*
* ```js
* var client = new Discordie({
* // Maximum amount of messages to store in channel cache.
* // Decreasing this will reduce memory usage over time.
* // With low values (below 50) chances of message invalidation increase:
* // accessing message properties (ex. `e.message.channel`) in callbacks
* // of long running tasks (ex. HTTP requests) becomes unsafe.
* messageCacheLimit: 1000, // < default
*
* // Guild sharding:
* // (Note that this is only intended to be used by large bots.)
* // 'shardId' is a number starting at 0 and less than 'shardCount'
* // 'shardCount' must be a number greater than 1
* shardId: 0, shardCount: 2, // sharding is disabled by default
*
* // Gateway auto-reconnect:
* // If enabled, 'DISCONNECTED' event will also contain properties
* // 'autoReconnect' boolean, set to true
* // 'delay' delay in milliseconds until next connect attempt
* autoReconnect: false, // < default
* });
* ```
*/
class Discordie {
constructor(options) {
messageHandlerCache.set(this, new MessageHandlerCache(this));
if (!options) options = defaultOptions;
const _defaultOptions = Object.assign({}, defaultOptions);
this.options = Object.assign(_defaultOptions, options);
Object.defineProperty(this, "options", {writable: false});
this.token = null;
this.bot = false;
/**
* Primary event bus.
* @returns {EventEmitter}
* @example
* client.Dispatcher.on("GATEWAY_READY", e => {
* console.log("Connected as: " + client.User.username);
* });
*/
this.Dispatcher = new DiscordieDispatcher();
this.gatewaySocket = null;
const gw = () => this.gatewaySocket;
this._readyScheduler = new ReadyEventScheduler(this, gw);
this._user = new AuthenticatedUser();
this._guilds = new GuildCollection(this, gw);
this._channels = new ChannelCollection(this, gw);
this._users = new UserCollection(this, gw);
this._members = new GuildMemberCollection(this, gw);
this._presences = new PresenceCollection(this, gw);
this._messages = new MessageCollection(this, gw);
this._voicestates = new VoiceStateCollection(this, gw);
this._calls = new CallCollection(this, gw);
if (options.messageCacheLimit) {
this._messages.setMessageLimit(options.messageCacheLimit);
}
this._queueManager = new RequestQueueManager(this);
if (!this.options.messageQueue) {
this._queueManager.disabled = true;
}
// == PUBLIC == //
/**
* Represents current user.
* @returns {IAuthenticatedUser}
*/
this.User = new IAuthenticatedUser(this);
/**
* Interface to a collection containing all "Discord Servers"
* (internally called guilds) current session is connected
* to. Does not contain unavailable guilds.
* @returns {IGuildCollection}
*/
this.Guilds = new IGuildCollection(this,
() => this._guilds.values(),
(key) => this._guilds.get(key));
/**
* Interface to a collection containing all public channels current session
* is connected to.
* @returns {IChannelCollection}
*/
this.Channels = new IChannelCollection(this,
() => this._channels.getGuildChannelIterator(),
(key) => this._channels.getGuildChannel(key));
/**
* Interface to a collection containing all users current session has
* been exposed to.
*
* Contains only online users after `READY`.
* See documentation for `IUserCollection.fetchMembers(guilds)` if you
* want to load offline members too.
* @returns {IUserCollection}
*/
this.Users = new IUserCollection(this,
() => this._users.values(),
(key) => this._users.get(key));
/**
* Interface to a collection containing all private (direct message)
* channels current session is connected to.
* @returns {IDirectMessageChannelCollection}
*/
this.DirectMessageChannels = new IDirectMessageChannelCollection(this,
() => this._channels.getPrivateChannelIterator(),
(key) => this._channels.getPrivateChannel(key));
/**
* Interface to a collection containing all cached messages.
* @returns {IMessageCollection}
*/
this.Messages = new IMessageCollection(this,
() => this._messages.getIterator(),
(key) => this._messages.get(key));
/**
* An instance of IInviteManager.
* @returns {IInviteManager}
*/
this.Invites = new IInviteManager(this);
/**
* An instance of IWebhookManager.
* @returns {IWebhookManager}
*/
this.Webhooks = new IWebhookManager(this);
/**
* An array of VoiceConnectionInfo.
* @returns {Array<VoiceConnectionInfo>}
*/
this.VoiceConnections = VoiceConnectionCollection.create(this, gw);
/**
* An array of unavailable guild's ids.
* @returns {Array<String>}
*/
this.UnavailableGuilds = UnavailableGuildCollection.create(this, gw);
this.SyncedGuilds = new GuildSyncCollection(this, gw);
this._readyScheduler._waitFor(this.UnavailableGuilds);
this._readyScheduler._addTask("GuildSync", this.SyncedGuilds);
// == EVENTS == //
this.Dispatcher.on(Events.REQUEST_AUTH_LOGIN_ERROR, handleAuthLoginError.bind(this));
this.Dispatcher.on(Events.REQUEST_AUTH_LOGIN_SUCCESS, handleAuthLoginSuccess.bind(this));
this.Dispatcher.on(Events.REQUEST_GATEWAY_ERROR, handleGatewayError.bind(this));
this.Dispatcher.on(Events.REQUEST_GATEWAY_SUCCESS, handleGatewaySuccess.bind(this));
/**
* Auto-reconnect handler.
* @returns {GatewayReconnectHandler}
*/
this.autoReconnect = new GatewayReconnectHandler(this);
if (options.autoReconnect) this.autoReconnect.enable();
// must register our gateway/voice events last to check e.handled
registerGatewayHandlers.call(this);
Utils.privatify(this);
}
/**
* Current state.
*
* Possible return values:
*
* - **`DISCONNECTED`**: Initial state. Returned if token is not available.
* - **`LOGGING_IN`**
* - **`LOGGED_IN`**: Returned if token is set, but gateway websocket is
* not connected.
* - **`CONNECTING`**
* - **`CONNECTED`**
*
* State `CONNECTED` only indicates state of gateway websocket connection,
* returns both before and after `READY`.
* @returns {String}
* @readonly
*/
get state() {
if (this.pendingLogin)
return Constants.DiscordieState.LOGGING_IN;
if (this.gatewaySocket) {
if (this.gatewaySocket.connected)
return Constants.DiscordieState.CONNECTED;
if (this.gatewaySocket.connecting)
return Constants.DiscordieState.CONNECTING;
}
if (this.token)
return Constants.DiscordieState.LOGGED_IN;
return Constants.DiscordieState.DISCONNECTED;
}
/**
* Gets a value indicating whether the gateway websocket connection is
* established.
* @returns {boolean}
* @readonly
*/
get connected() {
return this.state == Constants.DiscordieState.CONNECTED;
}
/**
* @param {Object} credentials - Can contain `email`, `password` or `token`
*/
connect(credentials) {
if (this.state == Constants.DiscordieState.CONNECTED
|| this.state == Constants.DiscordieState.CONNECTING
|| this.pendingLogin)
return;
this.pendingLogin = true;
if (credentials && credentials.hasOwnProperty("bot")) {
this.bot = credentials.bot;
}
if (credentials && credentials.token) {
this.token = credentials.token;
credentials = null;
}
if (!credentials && this.token) {
rest(this).gateway();
return;
}
rest(this).auth.login(credentials);
}
/**
* Disconnects primary gateway websocket.
*/
disconnect() {
if (this.gatewaySocket) {
this.gatewaySocket.disconnect();
this.gatewaySocket = null;
}
}
_createPrimaryGateway() {
if (!this.gatewaySocket) {
const compressMessages = this.options.compressMessages;
const shardId = this.options.shardId;
const shardCount = this.options.shardCount;
const gatewayOptions = {compressMessages, shardId, shardCount};
this.gatewaySocket = new GatewaySocket(this, gatewayOptions);
}
this.gatewaySocket.connect(this.gatewayEndpoint);
}
}
Discordie.Events = Constants.Events;
Discordie.StatusTypes = Constants.StatusTypes;
Discordie.ActivityTypes = Constants.ActivityTypes;
Discordie.States = Constants.DiscordieState;
Discordie.Permissions = Constants.Permissions;
Discordie.VerificationLevel = Constants.VerificationLevel;
Discordie.MFALevels = Constants.MFALevels;
Discordie.UserNotificationSettings = Constants.UserNotificationSettings;
Discordie.Errors = Constants.Errors;
Discordie.ChannelTypes = Constants.ChannelTypes;
Discordie.MessageTypes = Constants.MessageTypes;
module.exports = Discordie;