Add webpack building (#907)

* friggin webpack tho

* probably important

* add all the stuff to the package.json

* add minify builds and a nice package.json script to run it all

* clean up

* use uglify harmony branch so we can actually run minify builds that work

* update build system

* make test better

* clean up

* fix issues with compression

* ‮

* c++ requirements in a node lib? whaaaaat?

* fix travis yml?

* put railings on voice connections

* 🖕🏻

* aaaaaa

* handle arraybuffers in the unlikely event one is sent

* support arraybuffers in resolvebuffer

* this needs to be fixed at some point

* this was fixed

* disable filename versioning if env VERSIONED is set to false

* Update ClientDataResolver.js

* Update ClientVoiceManager.js

* Update WebSocketManager.js

* Update ConvertArrayBuffer.js

* Update webpack.html

* enable compression for browser and fix ws error handler

* Update WebSocketManager.js

* everything will be okay gawdl3y

* compression is slower in browser, so rip the last three hours of my life

* Update Constants.js

* Update .gitignore
This commit is contained in:
Gus Caplan
2016-11-20 18:38:16 -06:00
committed by Schuyler Cebulskie
parent b3e795d0b0
commit 2440a4a2c8
14 changed files with 162 additions and 38 deletions

View File

@@ -23,6 +23,12 @@ class Client extends EventEmitter {
constructor(options = {}) {
super();
/**
* Whether the client is in a browser environment
* @type {boolean}
*/
this.browser = typeof window !== 'undefined';
// Obtain shard details from environment
if (!options.shardId && 'SHARD_ID' in process.env) options.shardId = Number(process.env.SHARD_ID);
if (!options.shardCount && 'SHARD_COUNT' in process.env) options.shardCount = Number(process.env.SHARD_COUNT);

View File

@@ -3,13 +3,14 @@ const fs = require('fs');
const request = require('superagent');
const Constants = require('../util/Constants');
const User = require(`../structures/User`);
const Message = require(`../structures/Message`);
const Guild = require(`../structures/Guild`);
const Channel = require(`../structures/Channel`);
const GuildMember = require(`../structures/GuildMember`);
const Emoji = require(`../structures/Emoji`);
const ReactionEmoji = require(`../structures/ReactionEmoji`);
const convertArrayBuffer = require('../util/ConvertArrayBuffer');
const User = require('../structures/User');
const Message = require('../structures/Message');
const Guild = require('../structures/Guild');
const Channel = require('../structures/Channel');
const GuildMember = require('../structures/GuildMember');
const Emoji = require('../structures/Emoji');
const ReactionEmoji = require('../structures/ReactionEmoji');
/**
* The DataResolver identifies different objects and tries to resolve a specific piece of information from them, e.g.
@@ -240,17 +241,19 @@ class ClientDataResolver {
*/
resolveBuffer(resource) {
if (resource instanceof Buffer) return Promise.resolve(resource);
if (this.client.browser && resource instanceof ArrayBuffer) return Promise.resolve(convertArrayBuffer(resource));
if (typeof resource === 'string') {
return new Promise((resolve, reject) => {
if (/^https?:\/\//.test(resource)) {
request.get(resource)
.set('Content-Type', 'blob')
.end((err, res) => {
if (err) return reject(err);
if (!(res.body instanceof Buffer)) return reject(new TypeError('Body is not a Buffer'));
return resolve(res.body);
});
const req = request.get(resource).set('Content-Type', 'blob');
if (this.client.browser) req.responseType('arraybuffer');
req.end((err, res) => {
if (err) return reject(err);
if (this.client.browser) return resolve(convertArrayBuffer(res.xhr.response));
if (!(res.body instanceof Buffer)) return reject(new TypeError('Body is not a Buffer'));
return resolve(res.body);
});
} else {
const file = path.resolve(resource);
fs.stat(file, (err, stats) => {

View File

@@ -3,14 +3,13 @@ const Collection = require('../../util/Collection');
const splitMessage = require('../../util/SplitMessage');
const parseEmoji = require('../../util/ParseEmoji');
const requireStructure = name => require(`../../structures/${name}`);
const User = requireStructure('User');
const GuildMember = requireStructure('GuildMember');
const Role = requireStructure('Role');
const Invite = requireStructure('Invite');
const Webhook = requireStructure('Webhook');
const UserProfile = requireStructure('UserProfile');
const ClientOAuth2Application = requireStructure('ClientOAuth2Application');
const User = require('../../structures/User');
const GuildMember = require('../../structures/GuildMember');
const Role = require('../../structures/Role');
const Invite = require('../../structures/Invite');
const Webhook = require('../../structures/Webhook');
const UserProfile = require('../../structures/UserProfile');
const ClientOAuth2Application = require('../../structures/ClientOAuth2Application');
class RESTMethods {
constructor(restManager) {

View File

@@ -78,6 +78,7 @@ class ClientVoiceManager {
*/
joinChannel(channel) {
return new Promise((resolve, reject) => {
if (this.client.browser) throw new Error('Voice connections are not available in browsers.');
if (this.pending.get(channel.guild.id)) throw new Error('Already connecting to this guild\'s voice server.');
if (!channel.joinable) throw new Error('You do not have permission to join this voice channel.');

View File

@@ -1,8 +1,10 @@
const WebSocket = require('ws');
const browser = typeof window !== 'undefined';
const WebSocket = browser ? window.WebSocket : require('ws'); // eslint-disable-line no-undef
const EventEmitter = require('events').EventEmitter;
const Constants = require('../../util/Constants');
const zlib = require('zlib');
const inflate = browser ? require('zlibjs').inflateSync : require('zlib').inflateSync;
const PacketManager = require('./packets/WebSocketPacketManager');
const convertArrayBuffer = require('../../util/ConvertArrayBuffer');
/**
* The WebSocket Manager of the Client
@@ -78,6 +80,7 @@ class WebSocketManager extends EventEmitter {
this.normalReady = false;
if (this.status !== Constants.Status.RECONNECTING) this.status = Constants.Status.CONNECTING;
this.ws = new WebSocket(gateway);
if (browser) this.ws.binaryType = 'arraybuffer';
this.ws.onopen = () => this.eventOpen();
this.ws.onclose = (d) => this.eventClose(d);
this.ws.onmessage = (e) => this.eventMessage(e);
@@ -193,11 +196,11 @@ class WebSocketManager extends EventEmitter {
*/
eventClose(event) {
this.emit('close', event);
this.client.clearInterval(this.client.manager.heartbeatInterval);
/**
* Emitted whenever the client websocket is disconnected
* @event Client#disconnect
*/
clearInterval(this.client.manager.heartbeatInterval);
if (!this.reconnecting) this.client.emit(Constants.Events.DISCONNECT);
if (event.code === 4004) return;
if (event.code === 4010) return;
@@ -211,10 +214,13 @@ class WebSocketManager extends EventEmitter {
* @returns {boolean}
*/
eventMessage(event) {
let packet;
let packet = event.data;
try {
if (event.binary) event.data = zlib.inflateSync(event.data).toString();
packet = JSON.parse(event.data);
if (typeof packet !== 'string') {
if (packet instanceof ArrayBuffer) packet = convertArrayBuffer(packet);
packet = inflate(packet).toString();
}
packet = JSON.parse(packet);
} catch (e) {
return this.eventError(new Error(Constants.Errors.BAD_WS_MESSAGE));
}
@@ -236,7 +242,7 @@ class WebSocketManager extends EventEmitter {
* @param {Error} error The encountered error
*/
if (this.client.listenerCount('error') > 0) this.client.emit('error', err);
this.tryReconnect();
this.ws.close();
}
_emitReady(normal = true) {

View File

@@ -1,7 +1,6 @@
const AbstractHandler = require('./AbstractHandler');
const getStructure = name => require(`../../../../structures/${name}`);
const ClientUser = getStructure('ClientUser');
const ClientUser = require('../../../../structures/ClientUser');
class ReadyHandler extends AbstractHandler {
handle(packet) {