@fairwords/websocket 1.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/websocket-tests.yml +16 -0
- package/.jshintrc +88 -0
- package/CHANGELOG.md +291 -0
- package/Jenkinsfile +7 -0
- package/LICENSE +177 -0
- package/Makefile +5 -0
- package/README.md +255 -0
- package/gulpfile.js +14 -0
- package/index.js +1 -0
- package/lib/Deprecation.js +32 -0
- package/lib/W3CWebSocket.js +257 -0
- package/lib/WebSocketClient.js +361 -0
- package/lib/WebSocketConnection.js +896 -0
- package/lib/WebSocketFrame.js +280 -0
- package/lib/WebSocketRequest.js +541 -0
- package/lib/WebSocketRouter.js +157 -0
- package/lib/WebSocketRouterRequest.js +54 -0
- package/lib/WebSocketServer.js +256 -0
- package/lib/browser.js +54 -0
- package/lib/utils.js +66 -0
- package/lib/version.js +1 -0
- package/lib/websocket.js +11 -0
- package/package.json +58 -0
- package/vendor/FastBufferList.js +191 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/************************************************************************
|
|
2
|
+
* Copyright 2010-2015 Brian McKelvey.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
***********************************************************************/
|
|
16
|
+
|
|
17
|
+
var util = require('util');
|
|
18
|
+
var EventEmitter = require('events').EventEmitter;
|
|
19
|
+
|
|
20
|
+
function WebSocketRouterRequest(webSocketRequest, resolvedProtocol) {
|
|
21
|
+
// Superclass Constructor
|
|
22
|
+
EventEmitter.call(this);
|
|
23
|
+
|
|
24
|
+
this.webSocketRequest = webSocketRequest;
|
|
25
|
+
if (resolvedProtocol === '____no_protocol____') {
|
|
26
|
+
this.protocol = null;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
this.protocol = resolvedProtocol;
|
|
30
|
+
}
|
|
31
|
+
this.origin = webSocketRequest.origin;
|
|
32
|
+
this.resource = webSocketRequest.resource;
|
|
33
|
+
this.resourceURL = webSocketRequest.resourceURL;
|
|
34
|
+
this.httpRequest = webSocketRequest.httpRequest;
|
|
35
|
+
this.remoteAddress = webSocketRequest.remoteAddress;
|
|
36
|
+
this.webSocketVersion = webSocketRequest.webSocketVersion;
|
|
37
|
+
this.requestedExtensions = webSocketRequest.requestedExtensions;
|
|
38
|
+
this.cookies = webSocketRequest.cookies;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
util.inherits(WebSocketRouterRequest, EventEmitter);
|
|
42
|
+
|
|
43
|
+
WebSocketRouterRequest.prototype.accept = function(origin, cookies) {
|
|
44
|
+
var connection = this.webSocketRequest.accept(this.protocol, origin, cookies);
|
|
45
|
+
this.emit('requestAccepted', connection);
|
|
46
|
+
return connection;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
WebSocketRouterRequest.prototype.reject = function(status, reason, extraHeaders) {
|
|
50
|
+
this.webSocketRequest.reject(status, reason, extraHeaders);
|
|
51
|
+
this.emit('requestRejected', this);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
module.exports = WebSocketRouterRequest;
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/************************************************************************
|
|
2
|
+
* Copyright 2010-2015 Brian McKelvey.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
***********************************************************************/
|
|
16
|
+
|
|
17
|
+
var extend = require('./utils').extend;
|
|
18
|
+
var utils = require('./utils');
|
|
19
|
+
var util = require('util');
|
|
20
|
+
var debug = require('debug')('websocket:server');
|
|
21
|
+
var EventEmitter = require('events').EventEmitter;
|
|
22
|
+
var WebSocketRequest = require('./WebSocketRequest');
|
|
23
|
+
|
|
24
|
+
var WebSocketServer = function WebSocketServer(config) {
|
|
25
|
+
// Superclass Constructor
|
|
26
|
+
EventEmitter.call(this);
|
|
27
|
+
|
|
28
|
+
this._handlers = {
|
|
29
|
+
upgrade: this.handleUpgrade.bind(this),
|
|
30
|
+
requestAccepted: this.handleRequestAccepted.bind(this),
|
|
31
|
+
requestResolved: this.handleRequestResolved.bind(this)
|
|
32
|
+
};
|
|
33
|
+
this.connections = [];
|
|
34
|
+
this.pendingRequests = [];
|
|
35
|
+
if (config) {
|
|
36
|
+
this.mount(config);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
util.inherits(WebSocketServer, EventEmitter);
|
|
41
|
+
|
|
42
|
+
WebSocketServer.prototype.mount = function(config) {
|
|
43
|
+
this.config = {
|
|
44
|
+
// The http server instance to attach to. Required.
|
|
45
|
+
httpServer: null,
|
|
46
|
+
|
|
47
|
+
// 64KiB max frame size.
|
|
48
|
+
maxReceivedFrameSize: 0x10000,
|
|
49
|
+
|
|
50
|
+
// 1MiB max message size, only applicable if
|
|
51
|
+
// assembleFragments is true
|
|
52
|
+
maxReceivedMessageSize: 0x100000,
|
|
53
|
+
|
|
54
|
+
// Outgoing messages larger than fragmentationThreshold will be
|
|
55
|
+
// split into multiple fragments.
|
|
56
|
+
fragmentOutgoingMessages: true,
|
|
57
|
+
|
|
58
|
+
// Outgoing frames are fragmented if they exceed this threshold.
|
|
59
|
+
// Default is 16KiB
|
|
60
|
+
fragmentationThreshold: 0x4000,
|
|
61
|
+
|
|
62
|
+
// If true, the server will automatically send a ping to all
|
|
63
|
+
// clients every 'keepaliveInterval' milliseconds. The timer is
|
|
64
|
+
// reset on any received data from the client.
|
|
65
|
+
keepalive: true,
|
|
66
|
+
|
|
67
|
+
// The interval to send keepalive pings to connected clients if the
|
|
68
|
+
// connection is idle. Any received data will reset the counter.
|
|
69
|
+
keepaliveInterval: 20000,
|
|
70
|
+
|
|
71
|
+
// If true, the server will consider any connection that has not
|
|
72
|
+
// received any data within the amount of time specified by
|
|
73
|
+
// 'keepaliveGracePeriod' after a keepalive ping has been sent to
|
|
74
|
+
// be dead, and will drop the connection.
|
|
75
|
+
// Ignored if keepalive is false.
|
|
76
|
+
dropConnectionOnKeepaliveTimeout: true,
|
|
77
|
+
|
|
78
|
+
// The amount of time to wait after sending a keepalive ping before
|
|
79
|
+
// closing the connection if the connected peer does not respond.
|
|
80
|
+
// Ignored if keepalive is false.
|
|
81
|
+
keepaliveGracePeriod: 10000,
|
|
82
|
+
|
|
83
|
+
// Whether to use native TCP keep-alive instead of WebSockets ping
|
|
84
|
+
// and pong packets. Native TCP keep-alive sends smaller packets
|
|
85
|
+
// on the wire and so uses bandwidth more efficiently. This may
|
|
86
|
+
// be more important when talking to mobile devices.
|
|
87
|
+
// If this value is set to true, then these values will be ignored:
|
|
88
|
+
// keepaliveGracePeriod
|
|
89
|
+
// dropConnectionOnKeepaliveTimeout
|
|
90
|
+
useNativeKeepalive: false,
|
|
91
|
+
|
|
92
|
+
// If true, fragmented messages will be automatically assembled
|
|
93
|
+
// and the full message will be emitted via a 'message' event.
|
|
94
|
+
// If false, each frame will be emitted via a 'frame' event and
|
|
95
|
+
// the application will be responsible for aggregating multiple
|
|
96
|
+
// fragmented frames. Single-frame messages will emit a 'message'
|
|
97
|
+
// event in addition to the 'frame' event.
|
|
98
|
+
// Most users will want to leave this set to 'true'
|
|
99
|
+
assembleFragments: true,
|
|
100
|
+
|
|
101
|
+
// If this is true, websocket connections will be accepted
|
|
102
|
+
// regardless of the path and protocol specified by the client.
|
|
103
|
+
// The protocol accepted will be the first that was requested
|
|
104
|
+
// by the client. Clients from any origin will be accepted.
|
|
105
|
+
// This should only be used in the simplest of cases. You should
|
|
106
|
+
// probably leave this set to 'false' and inspect the request
|
|
107
|
+
// object to make sure it's acceptable before accepting it.
|
|
108
|
+
autoAcceptConnections: false,
|
|
109
|
+
|
|
110
|
+
// Whether or not the X-Forwarded-For header should be respected.
|
|
111
|
+
// It's important to set this to 'true' when accepting connections
|
|
112
|
+
// from untrusted clients, as a malicious client could spoof its
|
|
113
|
+
// IP address by simply setting this header. It's meant to be added
|
|
114
|
+
// by a trusted proxy or other intermediary within your own
|
|
115
|
+
// infrastructure.
|
|
116
|
+
// See: http://en.wikipedia.org/wiki/X-Forwarded-For
|
|
117
|
+
ignoreXForwardedFor: false,
|
|
118
|
+
|
|
119
|
+
// If this is true, 'cookie' headers are parsed and exposed as WebSocketRequest.cookies
|
|
120
|
+
parseCookies: true,
|
|
121
|
+
|
|
122
|
+
// If this is true, 'sec-websocket-extensions' headers are parsed and exposed as WebSocketRequest.requestedExtensions
|
|
123
|
+
parseExtensions: true,
|
|
124
|
+
|
|
125
|
+
// The Nagle Algorithm makes more efficient use of network resources
|
|
126
|
+
// by introducing a small delay before sending small packets so that
|
|
127
|
+
// multiple messages can be batched together before going onto the
|
|
128
|
+
// wire. This however comes at the cost of latency, so the default
|
|
129
|
+
// is to disable it. If you don't need low latency and are streaming
|
|
130
|
+
// lots of small messages, you can change this to 'false'
|
|
131
|
+
disableNagleAlgorithm: true,
|
|
132
|
+
|
|
133
|
+
// The number of milliseconds to wait after sending a close frame
|
|
134
|
+
// for an acknowledgement to come back before giving up and just
|
|
135
|
+
// closing the socket.
|
|
136
|
+
closeTimeout: 5000
|
|
137
|
+
};
|
|
138
|
+
extend(this.config, config);
|
|
139
|
+
|
|
140
|
+
if (this.config.httpServer) {
|
|
141
|
+
if (!Array.isArray(this.config.httpServer)) {
|
|
142
|
+
this.config.httpServer = [this.config.httpServer];
|
|
143
|
+
}
|
|
144
|
+
var upgradeHandler = this._handlers.upgrade;
|
|
145
|
+
this.config.httpServer.forEach(function(httpServer) {
|
|
146
|
+
httpServer.on('upgrade', upgradeHandler);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
throw new Error('You must specify an httpServer on which to mount the WebSocket server.');
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
WebSocketServer.prototype.unmount = function() {
|
|
155
|
+
var upgradeHandler = this._handlers.upgrade;
|
|
156
|
+
this.config.httpServer.forEach(function(httpServer) {
|
|
157
|
+
httpServer.removeListener('upgrade', upgradeHandler);
|
|
158
|
+
});
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
WebSocketServer.prototype.closeAllConnections = function() {
|
|
162
|
+
this.connections.forEach(function(connection) {
|
|
163
|
+
connection.close();
|
|
164
|
+
});
|
|
165
|
+
this.pendingRequests.forEach(function(request) {
|
|
166
|
+
process.nextTick(function() {
|
|
167
|
+
request.reject(503); // HTTP 503 Service Unavailable
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
WebSocketServer.prototype.broadcast = function(data) {
|
|
173
|
+
if (Buffer.isBuffer(data)) {
|
|
174
|
+
this.broadcastBytes(data);
|
|
175
|
+
}
|
|
176
|
+
else if (typeof(data.toString) === 'function') {
|
|
177
|
+
this.broadcastUTF(data);
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
WebSocketServer.prototype.broadcastUTF = function(utfData) {
|
|
182
|
+
this.connections.forEach(function(connection) {
|
|
183
|
+
connection.sendUTF(utfData);
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
WebSocketServer.prototype.broadcastBytes = function(binaryData) {
|
|
188
|
+
this.connections.forEach(function(connection) {
|
|
189
|
+
connection.sendBytes(binaryData);
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
WebSocketServer.prototype.shutDown = function() {
|
|
194
|
+
this.unmount();
|
|
195
|
+
this.closeAllConnections();
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
WebSocketServer.prototype.handleUpgrade = function(request, socket) {
|
|
199
|
+
var self = this;
|
|
200
|
+
var wsRequest = new WebSocketRequest(socket, request, this.config);
|
|
201
|
+
try {
|
|
202
|
+
wsRequest.readHandshake();
|
|
203
|
+
}
|
|
204
|
+
catch(e) {
|
|
205
|
+
wsRequest.reject(
|
|
206
|
+
e.httpCode ? e.httpCode : 400,
|
|
207
|
+
e.message,
|
|
208
|
+
e.headers
|
|
209
|
+
);
|
|
210
|
+
debug('Invalid handshake: %s', e.message);
|
|
211
|
+
this.emit('upgradeError', e);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
this.pendingRequests.push(wsRequest);
|
|
216
|
+
|
|
217
|
+
wsRequest.once('requestAccepted', this._handlers.requestAccepted);
|
|
218
|
+
wsRequest.once('requestResolved', this._handlers.requestResolved);
|
|
219
|
+
socket.once('close', function () {
|
|
220
|
+
self._handlers.requestResolved(wsRequest);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
if (!this.config.autoAcceptConnections && utils.eventEmitterListenerCount(this, 'request') > 0) {
|
|
224
|
+
this.emit('request', wsRequest);
|
|
225
|
+
}
|
|
226
|
+
else if (this.config.autoAcceptConnections) {
|
|
227
|
+
wsRequest.accept(wsRequest.requestedProtocols[0], wsRequest.origin);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
wsRequest.reject(404, 'No handler is configured to accept the connection.');
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
WebSocketServer.prototype.handleRequestAccepted = function(connection) {
|
|
235
|
+
var self = this;
|
|
236
|
+
connection.once('close', function(closeReason, description) {
|
|
237
|
+
self.handleConnectionClose(connection, closeReason, description);
|
|
238
|
+
});
|
|
239
|
+
this.connections.push(connection);
|
|
240
|
+
this.emit('connect', connection);
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
WebSocketServer.prototype.handleConnectionClose = function(connection, closeReason, description) {
|
|
244
|
+
var index = this.connections.indexOf(connection);
|
|
245
|
+
if (index !== -1) {
|
|
246
|
+
this.connections.splice(index, 1);
|
|
247
|
+
}
|
|
248
|
+
this.emit('close', connection, closeReason, description);
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
WebSocketServer.prototype.handleRequestResolved = function(request) {
|
|
252
|
+
var index = this.pendingRequests.indexOf(request);
|
|
253
|
+
if (index !== -1) { this.pendingRequests.splice(index, 1); }
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
module.exports = WebSocketServer;
|
package/lib/browser.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
var _globalThis;
|
|
2
|
+
if (typeof globalThis === 'object') {
|
|
3
|
+
_globalThis = globalThis;
|
|
4
|
+
} else {
|
|
5
|
+
try {
|
|
6
|
+
_globalThis = require('es5-ext/global');
|
|
7
|
+
} catch (error) {
|
|
8
|
+
} finally {
|
|
9
|
+
if (!_globalThis && typeof window !== 'undefined') { _globalThis = window; }
|
|
10
|
+
if (!_globalThis) { throw new Error('Could not determine global this'); }
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
var NativeWebSocket = _globalThis.WebSocket || _globalThis.MozWebSocket;
|
|
15
|
+
var websocket_version = require('./version');
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Expose a W3C WebSocket class with just one or two arguments.
|
|
20
|
+
*/
|
|
21
|
+
function W3CWebSocket(uri, protocols) {
|
|
22
|
+
var native_instance;
|
|
23
|
+
|
|
24
|
+
if (protocols) {
|
|
25
|
+
native_instance = new NativeWebSocket(uri, protocols);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
native_instance = new NativeWebSocket(uri);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 'native_instance' is an instance of nativeWebSocket (the browser's WebSocket
|
|
33
|
+
* class). Since it is an Object it will be returned as it is when creating an
|
|
34
|
+
* instance of W3CWebSocket via 'new W3CWebSocket()'.
|
|
35
|
+
*
|
|
36
|
+
* ECMAScript 5: http://bclary.com/2004/11/07/#a-13.2.2
|
|
37
|
+
*/
|
|
38
|
+
return native_instance;
|
|
39
|
+
}
|
|
40
|
+
if (NativeWebSocket) {
|
|
41
|
+
['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'].forEach(function(prop) {
|
|
42
|
+
Object.defineProperty(W3CWebSocket, prop, {
|
|
43
|
+
get: function() { return NativeWebSocket[prop]; }
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Module exports.
|
|
50
|
+
*/
|
|
51
|
+
module.exports = {
|
|
52
|
+
'w3cwebsocket' : NativeWebSocket ? W3CWebSocket : null,
|
|
53
|
+
'version' : websocket_version
|
|
54
|
+
};
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
var noop = exports.noop = function(){};
|
|
2
|
+
|
|
3
|
+
exports.extend = function extend(dest, source) {
|
|
4
|
+
for (var prop in source) {
|
|
5
|
+
dest[prop] = source[prop];
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
exports.eventEmitterListenerCount =
|
|
10
|
+
require('events').EventEmitter.listenerCount ||
|
|
11
|
+
function(emitter, type) { return emitter.listeners(type).length; };
|
|
12
|
+
|
|
13
|
+
exports.bufferAllocUnsafe = Buffer.allocUnsafe ?
|
|
14
|
+
Buffer.allocUnsafe :
|
|
15
|
+
function oldBufferAllocUnsafe(size) { return new Buffer(size); };
|
|
16
|
+
|
|
17
|
+
exports.bufferFromString = Buffer.from ?
|
|
18
|
+
Buffer.from :
|
|
19
|
+
function oldBufferFromString(string, encoding) {
|
|
20
|
+
return new Buffer(string, encoding);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
exports.BufferingLogger = function createBufferingLogger(identifier, uniqueID) {
|
|
24
|
+
var logFunction = require('debug')(identifier);
|
|
25
|
+
if (logFunction.enabled) {
|
|
26
|
+
var logger = new BufferingLogger(identifier, uniqueID, logFunction);
|
|
27
|
+
var debug = logger.log.bind(logger);
|
|
28
|
+
debug.printOutput = logger.printOutput.bind(logger);
|
|
29
|
+
debug.enabled = logFunction.enabled;
|
|
30
|
+
return debug;
|
|
31
|
+
}
|
|
32
|
+
logFunction.printOutput = noop;
|
|
33
|
+
return logFunction;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function BufferingLogger(identifier, uniqueID, logFunction) {
|
|
37
|
+
this.logFunction = logFunction;
|
|
38
|
+
this.identifier = identifier;
|
|
39
|
+
this.uniqueID = uniqueID;
|
|
40
|
+
this.buffer = [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
BufferingLogger.prototype.log = function() {
|
|
44
|
+
this.buffer.push([ new Date(), Array.prototype.slice.call(arguments) ]);
|
|
45
|
+
return this;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
BufferingLogger.prototype.clear = function() {
|
|
49
|
+
this.buffer = [];
|
|
50
|
+
return this;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
BufferingLogger.prototype.printOutput = function(logFunction) {
|
|
54
|
+
if (!logFunction) { logFunction = this.logFunction; }
|
|
55
|
+
var uniqueID = this.uniqueID;
|
|
56
|
+
this.buffer.forEach(function(entry) {
|
|
57
|
+
var date = entry[0].toLocaleString();
|
|
58
|
+
var args = entry[1].slice();
|
|
59
|
+
var formatString = args[0];
|
|
60
|
+
if (formatString !== (void 0) && formatString !== null) {
|
|
61
|
+
formatString = '%s - %s - ' + formatString.toString();
|
|
62
|
+
args.splice(0, 1, formatString, date, uniqueID);
|
|
63
|
+
logFunction.apply(global, args);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
};
|
package/lib/version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('../package.json').version;
|
package/lib/websocket.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
'server' : require('./WebSocketServer'),
|
|
3
|
+
'client' : require('./WebSocketClient'),
|
|
4
|
+
'router' : require('./WebSocketRouter'),
|
|
5
|
+
'frame' : require('./WebSocketFrame'),
|
|
6
|
+
'request' : require('./WebSocketRequest'),
|
|
7
|
+
'connection' : require('./WebSocketConnection'),
|
|
8
|
+
'w3cwebsocket' : require('./W3CWebSocket'),
|
|
9
|
+
'deprecation' : require('./Deprecation'),
|
|
10
|
+
'version' : require('./version')
|
|
11
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fairwords/websocket",
|
|
3
|
+
"description": "Websocket Client & Server Library implementing the WebSocket protocol as specified in RFC 6455.",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"websocket",
|
|
6
|
+
"websockets",
|
|
7
|
+
"socket",
|
|
8
|
+
"networking",
|
|
9
|
+
"comet",
|
|
10
|
+
"push",
|
|
11
|
+
"RFC-6455",
|
|
12
|
+
"realtime",
|
|
13
|
+
"server",
|
|
14
|
+
"client"
|
|
15
|
+
],
|
|
16
|
+
"author": "Brian McKelvey <theturtle32@gmail.com> (https://github.com/theturtle32)",
|
|
17
|
+
"contributors": [
|
|
18
|
+
"Iñaki Baz Castillo <ibc@aliax.net> (http://dev.sipdoc.net)"
|
|
19
|
+
],
|
|
20
|
+
"version": "1.0.35",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/theturtle32/WebSocket-Node.git"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/theturtle32/WebSocket-Node",
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=4.0.0"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"bufferutil": "^4.0.1",
|
|
31
|
+
"debug": "^2.2.0",
|
|
32
|
+
"es5-ext": "^0.10.50",
|
|
33
|
+
"typedarray-to-buffer": "^3.1.5",
|
|
34
|
+
"utf-8-validate": "^5.0.2",
|
|
35
|
+
"yaeti": "^0.0.6"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"buffer-equal": "^1.0.0",
|
|
39
|
+
"gulp": "^4.0.2",
|
|
40
|
+
"gulp-jshint": "^2.0.4",
|
|
41
|
+
"jshint-stylish": "^2.2.1",
|
|
42
|
+
"jshint": "^2.0.0",
|
|
43
|
+
"tape": "^4.9.1"
|
|
44
|
+
},
|
|
45
|
+
"config": {
|
|
46
|
+
"verbose": false
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"test": "tape test/unit/*.js",
|
|
50
|
+
"gulp": "gulp"
|
|
51
|
+
},
|
|
52
|
+
"main": "index",
|
|
53
|
+
"directories": {
|
|
54
|
+
"lib": "./lib"
|
|
55
|
+
},
|
|
56
|
+
"browser": "lib/browser.js",
|
|
57
|
+
"license": "Apache-2.0"
|
|
58
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// This file was copied from https://github.com/substack/node-bufferlist
|
|
2
|
+
// and modified to be able to copy bytes from the bufferlist directly into
|
|
3
|
+
// a pre-existing fixed-size buffer without an additional memory allocation.
|
|
4
|
+
|
|
5
|
+
// bufferlist.js
|
|
6
|
+
// Treat a linked list of buffers as a single variable-size buffer.
|
|
7
|
+
var Buffer = require('buffer').Buffer;
|
|
8
|
+
var EventEmitter = require('events').EventEmitter;
|
|
9
|
+
var bufferAllocUnsafe = require('../lib/utils').bufferAllocUnsafe;
|
|
10
|
+
|
|
11
|
+
module.exports = BufferList;
|
|
12
|
+
module.exports.BufferList = BufferList; // backwards compatibility
|
|
13
|
+
|
|
14
|
+
function BufferList(opts) {
|
|
15
|
+
if (!(this instanceof BufferList)) return new BufferList(opts);
|
|
16
|
+
EventEmitter.call(this);
|
|
17
|
+
var self = this;
|
|
18
|
+
|
|
19
|
+
if (typeof(opts) == 'undefined') opts = {};
|
|
20
|
+
|
|
21
|
+
// default encoding to use for take(). Leaving as 'undefined'
|
|
22
|
+
// makes take() return a Buffer instead.
|
|
23
|
+
self.encoding = opts.encoding;
|
|
24
|
+
|
|
25
|
+
var head = { next : null, buffer : null };
|
|
26
|
+
var last = { next : null, buffer : null };
|
|
27
|
+
|
|
28
|
+
// length can get negative when advanced past the end
|
|
29
|
+
// and this is the desired behavior
|
|
30
|
+
var length = 0;
|
|
31
|
+
self.__defineGetter__('length', function () {
|
|
32
|
+
return length;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// keep an offset of the head to decide when to head = head.next
|
|
36
|
+
var offset = 0;
|
|
37
|
+
|
|
38
|
+
// Write to the bufferlist. Emits 'write'. Always returns true.
|
|
39
|
+
self.write = function (buf) {
|
|
40
|
+
if (!head.buffer) {
|
|
41
|
+
head.buffer = buf;
|
|
42
|
+
last = head;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
last.next = { next : null, buffer : buf };
|
|
46
|
+
last = last.next;
|
|
47
|
+
}
|
|
48
|
+
length += buf.length;
|
|
49
|
+
self.emit('write', buf);
|
|
50
|
+
return true;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
self.end = function (buf) {
|
|
54
|
+
if (Buffer.isBuffer(buf)) self.write(buf);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Push buffers to the end of the linked list. (deprecated)
|
|
58
|
+
// Return this (self).
|
|
59
|
+
self.push = function () {
|
|
60
|
+
var args = [].concat.apply([], arguments);
|
|
61
|
+
args.forEach(self.write);
|
|
62
|
+
return self;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// For each buffer, perform some action.
|
|
66
|
+
// If fn's result is a true value, cut out early.
|
|
67
|
+
// Returns this (self).
|
|
68
|
+
self.forEach = function (fn) {
|
|
69
|
+
if (!head.buffer) return bufferAllocUnsafe(0);
|
|
70
|
+
|
|
71
|
+
if (head.buffer.length - offset <= 0) return self;
|
|
72
|
+
var firstBuf = head.buffer.slice(offset);
|
|
73
|
+
|
|
74
|
+
var b = { buffer : firstBuf, next : head.next };
|
|
75
|
+
|
|
76
|
+
while (b && b.buffer) {
|
|
77
|
+
var r = fn(b.buffer);
|
|
78
|
+
if (r) break;
|
|
79
|
+
b = b.next;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return self;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Create a single Buffer out of all the chunks or some subset specified by
|
|
86
|
+
// start and one-past the end (like slice) in bytes.
|
|
87
|
+
self.join = function (start, end) {
|
|
88
|
+
if (!head.buffer) return bufferAllocUnsafe(0);
|
|
89
|
+
if (start == undefined) start = 0;
|
|
90
|
+
if (end == undefined) end = self.length;
|
|
91
|
+
|
|
92
|
+
var big = bufferAllocUnsafe(end - start);
|
|
93
|
+
var ix = 0;
|
|
94
|
+
self.forEach(function (buffer) {
|
|
95
|
+
if (start < (ix + buffer.length) && ix < end) {
|
|
96
|
+
// at least partially contained in the range
|
|
97
|
+
buffer.copy(
|
|
98
|
+
big,
|
|
99
|
+
Math.max(0, ix - start),
|
|
100
|
+
Math.max(0, start - ix),
|
|
101
|
+
Math.min(buffer.length, end - ix)
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
ix += buffer.length;
|
|
105
|
+
if (ix > end) return true; // stop processing past end
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return big;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
self.joinInto = function (targetBuffer, targetStart, sourceStart, sourceEnd) {
|
|
112
|
+
if (!head.buffer) return new bufferAllocUnsafe(0);
|
|
113
|
+
if (sourceStart == undefined) sourceStart = 0;
|
|
114
|
+
if (sourceEnd == undefined) sourceEnd = self.length;
|
|
115
|
+
|
|
116
|
+
var big = targetBuffer;
|
|
117
|
+
if (big.length - targetStart < sourceEnd - sourceStart) {
|
|
118
|
+
throw new Error("Insufficient space available in target Buffer.");
|
|
119
|
+
}
|
|
120
|
+
var ix = 0;
|
|
121
|
+
self.forEach(function (buffer) {
|
|
122
|
+
if (sourceStart < (ix + buffer.length) && ix < sourceEnd) {
|
|
123
|
+
// at least partially contained in the range
|
|
124
|
+
buffer.copy(
|
|
125
|
+
big,
|
|
126
|
+
Math.max(targetStart, targetStart + ix - sourceStart),
|
|
127
|
+
Math.max(0, sourceStart - ix),
|
|
128
|
+
Math.min(buffer.length, sourceEnd - ix)
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
ix += buffer.length;
|
|
132
|
+
if (ix > sourceEnd) return true; // stop processing past end
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return big;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// Advance the buffer stream by n bytes.
|
|
139
|
+
// If n the aggregate advance offset passes the end of the buffer list,
|
|
140
|
+
// operations such as .take() will return empty strings until enough data is
|
|
141
|
+
// pushed.
|
|
142
|
+
// Returns this (self).
|
|
143
|
+
self.advance = function (n) {
|
|
144
|
+
offset += n;
|
|
145
|
+
length -= n;
|
|
146
|
+
while (head.buffer && offset >= head.buffer.length) {
|
|
147
|
+
offset -= head.buffer.length;
|
|
148
|
+
head = head.next
|
|
149
|
+
? head.next
|
|
150
|
+
: { buffer : null, next : null }
|
|
151
|
+
;
|
|
152
|
+
}
|
|
153
|
+
if (head.buffer === null) last = { next : null, buffer : null };
|
|
154
|
+
self.emit('advance', n);
|
|
155
|
+
return self;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// Take n bytes from the start of the buffers.
|
|
159
|
+
// Returns a string.
|
|
160
|
+
// If there are less than n bytes in all the buffers or n is undefined,
|
|
161
|
+
// returns the entire concatenated buffer string.
|
|
162
|
+
self.take = function (n, encoding) {
|
|
163
|
+
if (n == undefined) n = self.length;
|
|
164
|
+
else if (typeof n !== 'number') {
|
|
165
|
+
encoding = n;
|
|
166
|
+
n = self.length;
|
|
167
|
+
}
|
|
168
|
+
var b = head;
|
|
169
|
+
if (!encoding) encoding = self.encoding;
|
|
170
|
+
if (encoding) {
|
|
171
|
+
var acc = '';
|
|
172
|
+
self.forEach(function (buffer) {
|
|
173
|
+
if (n <= 0) return true;
|
|
174
|
+
acc += buffer.toString(
|
|
175
|
+
encoding, 0, Math.min(n,buffer.length)
|
|
176
|
+
);
|
|
177
|
+
n -= buffer.length;
|
|
178
|
+
});
|
|
179
|
+
return acc;
|
|
180
|
+
} else {
|
|
181
|
+
// If no 'encoding' is specified, then return a Buffer.
|
|
182
|
+
return self.join(0, n);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// The entire concatenated buffer as a string.
|
|
187
|
+
self.toString = function () {
|
|
188
|
+
return self.take('binary');
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
require('util').inherits(BufferList, EventEmitter);
|