zlib stream compression (#2028)

This commit is contained in:
Gus Caplan
2017-10-25 11:30:03 -05:00
committed by Amish Shah
parent 0277d1de78
commit 0589b7d7f1
7 changed files with 48 additions and 30 deletions

View File

@@ -1,6 +1,9 @@
const { browser } = require('./util/Constants');
const zlib = require('zlib');
const querystring = require('querystring');
try {
var erlpack = require('erlpack');
if (!erlpack.pack) erlpack = null;
} catch (err) {} // eslint-disable-line no-empty
if (browser) {
exports.WebSocket = window.WebSocket; // eslint-disable-line no-undef
@@ -12,25 +15,14 @@ if (browser) {
}
}
try {
var erlpack = require('erlpack');
if (!erlpack.pack) erlpack = null;
} catch (err) {} // eslint-disable-line no-empty
exports.encoding = erlpack ? 'etf' : 'json';
exports.pack = erlpack ? erlpack.pack : JSON.stringify;
exports.unpack = data => {
if (Array.isArray(data)) data = Buffer.concat(data);
if (!browser && data instanceof ArrayBuffer) data = Buffer.from(new Uint8Array(data));
if (erlpack && typeof data !== 'string') {
return erlpack.unpack(data);
} else if (data instanceof ArrayBuffer || (!browser && data instanceof Buffer)) {
data = zlib.inflateSync(data).toString();
}
return JSON.parse(data);
if (!erlpack || data[0] === '{') return JSON.parse(data);
if (!(data instanceof Buffer)) data = Buffer.from(new Uint8Array(data));
return erlpack.unpack(data);
};
exports.create = (gateway, query = {}, ...args) => {

View File

@@ -1,7 +1,13 @@
const EventEmitter = require('events');
const { DefaultOptions, Events, OPCodes, Status, WSCodes } = require('../../util/Constants');
const { Events, OPCodes, Status, WSCodes } = require('../../util/Constants');
const PacketManager = require('./packets/WebSocketPacketManager');
const WebSocket = require('../../WebSocket');
try {
var zlib = require('zlib-sync');
if (!zlib.Inflate) zlib = require('pako');
} catch (err) {
zlib = require('pako');
}
/**
* Abstracts a WebSocket connection with decoding/encoding for the Discord gateway.
@@ -67,13 +73,13 @@ class WebSocketConnection extends EventEmitter {
time: 60e3,
resetTimer: null,
};
this.connect(gateway);
/**
* Events that are disabled (will not be processed)
* @type {Object}
*/
this.disabledEvents = {};
for (const event of this.client.options.disabledEvents) this.disabledEvents[event] = true;
/**
* The sequence on WebSocket close
@@ -86,7 +92,9 @@ class WebSocketConnection extends EventEmitter {
* @type {boolean}
*/
this.expectingClose = false;
for (const event of this.client.options.disabledEvents) this.disabledEvents[event] = true;
this.inflate = null;
this.connect(gateway);
}
/**
@@ -206,10 +214,18 @@ class WebSocketConnection extends EventEmitter {
this.debug(`Tried to connect to an invalid gateway: ${gateway}`);
return false;
}
this.inflate = new zlib.Inflate({
chunkSize: 65535,
flush: zlib.Z_SYNC_FLUSH,
to: WebSocket.encoding === 'json' ? 'string' : '',
});
this.expectingClose = false;
this.gateway = gateway;
this.debug(`Connecting to ${gateway}`);
const ws = this.ws = WebSocket.create(gateway, { v: DefaultOptions.ws.version });
const ws = this.ws = WebSocket.create(gateway, {
v: this.client.options.ws.version,
compress: 'zlib-stream',
});
ws.onmessage = this.onMessage.bind(this);
ws.onopen = this.onOpen.bind(this);
ws.onerror = this.onError.bind(this);
@@ -241,18 +257,25 @@ class WebSocketConnection extends EventEmitter {
/**
* Called whenever a message is received.
* @param {Event} event Event received
* @returns {boolean}
*/
onMessage(event) {
let data;
onMessage({ data }) {
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
const l = data.length;
const flush = l >= 4 &&
data[l - 4] === 0x00 &&
data[l - 3] === 0x00 &&
data[l - 2] === 0xFF &&
data[l - 1] === 0xFF;
this.inflate.push(data, flush && zlib.Z_SYNC_FLUSH);
if (!flush) return;
try {
data = WebSocket.unpack(event.data);
const packet = WebSocket.unpack(this.inflate.result);
this.onPacket(packet);
if (this.client.listenerCount('raw')) this.client.emit('raw', data);
} catch (err) {
this.client.emit('debug', err);
}
const ret = this.onPacket(data);
this.client.emit('raw', data);
return ret;
}
/**

View File

@@ -57,7 +57,7 @@ exports.DefaultOptions = {
*/
ws: {
large_threshold: 250,
compress: !browser,
compress: false,
properties: {
$os: browser ? 'browser' : process.platform,
$browser: 'discord.js',