initial commit
This commit is contained in:
257
node_modules/websocket/lib/W3CWebSocket.js
generated
vendored
Normal file
257
node_modules/websocket/lib/W3CWebSocket.js
generated
vendored
Normal file
@@ -0,0 +1,257 @@
|
||||
/************************************************************************
|
||||
* Copyright 2010-2015 Brian McKelvey.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***********************************************************************/
|
||||
|
||||
var WebSocketClient = require('./WebSocketClient');
|
||||
var toBuffer = require('typedarray-to-buffer');
|
||||
var yaeti = require('yaeti');
|
||||
|
||||
|
||||
const CONNECTING = 0;
|
||||
const OPEN = 1;
|
||||
const CLOSING = 2;
|
||||
const CLOSED = 3;
|
||||
|
||||
|
||||
module.exports = W3CWebSocket;
|
||||
|
||||
|
||||
function W3CWebSocket(url, protocols, origin, headers, requestOptions, clientConfig) {
|
||||
// Make this an EventTarget.
|
||||
yaeti.EventTarget.call(this);
|
||||
|
||||
// Sanitize clientConfig.
|
||||
clientConfig = clientConfig || {};
|
||||
clientConfig.assembleFragments = true; // Required in the W3C API.
|
||||
|
||||
var self = this;
|
||||
|
||||
this._url = url;
|
||||
this._readyState = CONNECTING;
|
||||
this._protocol = undefined;
|
||||
this._extensions = '';
|
||||
this._bufferedAmount = 0; // Hack, always 0.
|
||||
this._binaryType = 'arraybuffer'; // TODO: Should be 'blob' by default, but Node has no Blob.
|
||||
|
||||
// The WebSocketConnection instance.
|
||||
this._connection = undefined;
|
||||
|
||||
// WebSocketClient instance.
|
||||
this._client = new WebSocketClient(clientConfig);
|
||||
|
||||
this._client.on('connect', function(connection) {
|
||||
onConnect.call(self, connection);
|
||||
});
|
||||
|
||||
this._client.on('connectFailed', function() {
|
||||
onConnectFailed.call(self);
|
||||
});
|
||||
|
||||
this._client.connect(url, protocols, origin, headers, requestOptions);
|
||||
}
|
||||
|
||||
|
||||
// Expose W3C read only attributes.
|
||||
Object.defineProperties(W3CWebSocket.prototype, {
|
||||
url: { get: function() { return this._url; } },
|
||||
readyState: { get: function() { return this._readyState; } },
|
||||
protocol: { get: function() { return this._protocol; } },
|
||||
extensions: { get: function() { return this._extensions; } },
|
||||
bufferedAmount: { get: function() { return this._bufferedAmount; } }
|
||||
});
|
||||
|
||||
|
||||
// Expose W3C write/read attributes.
|
||||
Object.defineProperties(W3CWebSocket.prototype, {
|
||||
binaryType: {
|
||||
get: function() {
|
||||
return this._binaryType;
|
||||
},
|
||||
set: function(type) {
|
||||
// TODO: Just 'arraybuffer' supported.
|
||||
if (type !== 'arraybuffer') {
|
||||
throw new SyntaxError('just "arraybuffer" type allowed for "binaryType" attribute');
|
||||
}
|
||||
this._binaryType = type;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Expose W3C readyState constants into the WebSocket instance as W3C states.
|
||||
[['CONNECTING',CONNECTING], ['OPEN',OPEN], ['CLOSING',CLOSING], ['CLOSED',CLOSED]].forEach(function(property) {
|
||||
Object.defineProperty(W3CWebSocket.prototype, property[0], {
|
||||
get: function() { return property[1]; }
|
||||
});
|
||||
});
|
||||
|
||||
// Also expone W3C readyState constants into the WebSocket class (not defined by the W3C,
|
||||
// but there are so many libs relying on them).
|
||||
[['CONNECTING',CONNECTING], ['OPEN',OPEN], ['CLOSING',CLOSING], ['CLOSED',CLOSED]].forEach(function(property) {
|
||||
Object.defineProperty(W3CWebSocket, property[0], {
|
||||
get: function() { return property[1]; }
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
W3CWebSocket.prototype.send = function(data) {
|
||||
if (this._readyState !== OPEN) {
|
||||
throw new Error('cannot call send() while not connected');
|
||||
}
|
||||
|
||||
// Text.
|
||||
if (typeof data === 'string' || data instanceof String) {
|
||||
this._connection.sendUTF(data);
|
||||
}
|
||||
// Binary.
|
||||
else {
|
||||
// Node Buffer.
|
||||
if (data instanceof Buffer) {
|
||||
this._connection.sendBytes(data);
|
||||
}
|
||||
// If ArrayBuffer or ArrayBufferView convert it to Node Buffer.
|
||||
else if (data.byteLength || data.byteLength === 0) {
|
||||
data = toBuffer(data);
|
||||
this._connection.sendBytes(data);
|
||||
}
|
||||
else {
|
||||
throw new Error('unknown binary data:', data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
W3CWebSocket.prototype.close = function(code, reason) {
|
||||
switch(this._readyState) {
|
||||
case CONNECTING:
|
||||
// NOTE: We don't have the WebSocketConnection instance yet so no
|
||||
// way to close the TCP connection.
|
||||
// Artificially invoke the onConnectFailed event.
|
||||
onConnectFailed.call(this);
|
||||
// And close if it connects after a while.
|
||||
this._client.on('connect', function(connection) {
|
||||
if (code) {
|
||||
connection.close(code, reason);
|
||||
} else {
|
||||
connection.close();
|
||||
}
|
||||
});
|
||||
break;
|
||||
case OPEN:
|
||||
this._readyState = CLOSING;
|
||||
if (code) {
|
||||
this._connection.close(code, reason);
|
||||
} else {
|
||||
this._connection.close();
|
||||
}
|
||||
break;
|
||||
case CLOSING:
|
||||
case CLOSED:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Private API.
|
||||
*/
|
||||
|
||||
|
||||
function createCloseEvent(code, reason) {
|
||||
var event = new yaeti.Event('close');
|
||||
|
||||
event.code = code;
|
||||
event.reason = reason;
|
||||
event.wasClean = (typeof code === 'undefined' || code === 1000);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
function createMessageEvent(data) {
|
||||
var event = new yaeti.Event('message');
|
||||
|
||||
event.data = data;
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
function onConnect(connection) {
|
||||
var self = this;
|
||||
|
||||
this._readyState = OPEN;
|
||||
this._connection = connection;
|
||||
this._protocol = connection.protocol;
|
||||
this._extensions = connection.extensions;
|
||||
|
||||
this._connection.on('close', function(code, reason) {
|
||||
onClose.call(self, code, reason);
|
||||
});
|
||||
|
||||
this._connection.on('message', function(msg) {
|
||||
onMessage.call(self, msg);
|
||||
});
|
||||
|
||||
this.dispatchEvent(new yaeti.Event('open'));
|
||||
}
|
||||
|
||||
|
||||
function onConnectFailed() {
|
||||
destroy.call(this);
|
||||
this._readyState = CLOSED;
|
||||
|
||||
try {
|
||||
this.dispatchEvent(new yaeti.Event('error'));
|
||||
} finally {
|
||||
this.dispatchEvent(createCloseEvent(1006, 'connection failed'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function onClose(code, reason) {
|
||||
destroy.call(this);
|
||||
this._readyState = CLOSED;
|
||||
|
||||
this.dispatchEvent(createCloseEvent(code, reason || ''));
|
||||
}
|
||||
|
||||
|
||||
function onMessage(message) {
|
||||
if (message.utf8Data) {
|
||||
this.dispatchEvent(createMessageEvent(message.utf8Data));
|
||||
}
|
||||
else if (message.binaryData) {
|
||||
// Must convert from Node Buffer to ArrayBuffer.
|
||||
// TODO: or to a Blob (which does not exist in Node!).
|
||||
if (this.binaryType === 'arraybuffer') {
|
||||
var buffer = message.binaryData;
|
||||
var arraybuffer = new ArrayBuffer(buffer.length);
|
||||
var view = new Uint8Array(arraybuffer);
|
||||
for (var i=0, len=buffer.length; i<len; ++i) {
|
||||
view[i] = buffer[i];
|
||||
}
|
||||
this.dispatchEvent(createMessageEvent(arraybuffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function destroy() {
|
||||
this._client.removeAllListeners();
|
||||
if (this._connection) {
|
||||
this._connection.removeAllListeners();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user