Uploaded the base of the project the working demo of CH1 Multiplayer Game Development with HTML5
This commit is contained in:
+11
@@ -0,0 +1,11 @@
|
||||
npm-debug.log
|
||||
node_modules
|
||||
.*.swp
|
||||
.lock-*
|
||||
build
|
||||
|
||||
bench
|
||||
doc
|
||||
examples
|
||||
test
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
language: node_js
|
||||
npm_args: --ws:native
|
||||
node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
ALL_TESTS = $(shell find test/ -name '*.test.js')
|
||||
ALL_INTEGRATION = $(shell find test/ -name '*.integration.js')
|
||||
|
||||
all:
|
||||
node-gyp configure build
|
||||
|
||||
clean:
|
||||
node-gyp clean
|
||||
|
||||
run-tests:
|
||||
@./node_modules/.bin/mocha \
|
||||
-t 5000 \
|
||||
-s 2400 \
|
||||
$(TESTFLAGS) \
|
||||
$(TESTS)
|
||||
|
||||
run-integrationtests:
|
||||
@./node_modules/.bin/mocha \
|
||||
-t 5000 \
|
||||
-s 6000 \
|
||||
$(TESTFLAGS) \
|
||||
$(TESTS)
|
||||
|
||||
test:
|
||||
@$(MAKE) NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_PATH=lib TESTS="$(ALL_TESTS)" run-tests
|
||||
|
||||
integrationtest:
|
||||
@$(MAKE) NODE_TLS_REJECT_UNAUTHORIZED=0 NODE_PATH=lib TESTS="$(ALL_INTEGRATION)" run-integrationtests
|
||||
|
||||
benchmark:
|
||||
@node bench/sender.benchmark.js
|
||||
@node bench/parser.benchmark.js
|
||||
|
||||
autobahn:
|
||||
@NODE_PATH=lib node test/autobahn.js
|
||||
|
||||
autobahn-server:
|
||||
@NODE_PATH=lib node test/autobahn-server.js
|
||||
|
||||
.PHONY: test
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
# ws: a node.js websocket library
|
||||
|
||||
[](https://travis-ci.org/einaros/ws)
|
||||
|
||||
`ws` is a simple to use WebSocket implementation, up-to-date against RFC-6455,
|
||||
and [probably the fastest WebSocket library for node.js][archive].
|
||||
|
||||
Passes the quite extensive Autobahn test suite. See http://einaros.github.com/ws
|
||||
for the full reports.
|
||||
|
||||
## Protocol support
|
||||
|
||||
* **Hixie draft 76** (Old and deprecated, but still in use by Safari and Opera.
|
||||
Added to ws version 0.4.2, but server only. Can be disabled by setting the
|
||||
`disableHixie` option to true.)
|
||||
* **HyBi drafts 07-12** (Use the option `protocolVersion: 8`)
|
||||
* **HyBi drafts 13-17** (Current default, alternatively option `protocolVersion: 13`)
|
||||
|
||||
### Installing
|
||||
|
||||
```
|
||||
npm install --save ws
|
||||
```
|
||||
|
||||
### Sending and receiving text data
|
||||
|
||||
```js
|
||||
var WebSocket = require('ws');
|
||||
var ws = new WebSocket('ws://www.host.com/path');
|
||||
|
||||
ws.on('open', function open() {
|
||||
ws.send('something');
|
||||
});
|
||||
|
||||
ws.on('message', function(data, flags) {
|
||||
// flags.binary will be set if a binary data is received.
|
||||
// flags.masked will be set if the data was masked.
|
||||
});
|
||||
```
|
||||
|
||||
### Sending binary data
|
||||
|
||||
```js
|
||||
var WebSocket = require('ws');
|
||||
var ws = new WebSocket('ws://www.host.com/path');
|
||||
|
||||
ws.on('open', function open() {
|
||||
var array = new Float32Array(5);
|
||||
|
||||
for (var i = 0; i < array.length; ++i) {
|
||||
array[i] = i / 2;
|
||||
}
|
||||
|
||||
ws.send(array, { binary: true, mask: true });
|
||||
});
|
||||
```
|
||||
|
||||
Setting `mask`, as done for the send options above, will cause the data to be
|
||||
masked according to the WebSocket protocol. The same option applies for text
|
||||
data.
|
||||
|
||||
### Server example
|
||||
|
||||
```js
|
||||
var WebSocketServer = require('ws').Server
|
||||
, wss = new WebSocketServer({ port: 8080 });
|
||||
|
||||
wss.on('connection', function connection(ws) {
|
||||
ws.on('message', function incoming(message) {
|
||||
console.log('received: %s', message);
|
||||
});
|
||||
|
||||
ws.send('something');
|
||||
});
|
||||
```
|
||||
|
||||
### Server sending broadcast data
|
||||
|
||||
```js
|
||||
var WebSocketServer = require('ws').Server
|
||||
, wss = new WebSocketServer({ port: 8080 });
|
||||
|
||||
wss.broadcast = function broadcast(data) {
|
||||
wss.clients.forEach(function each(client) {
|
||||
client.send(data);
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
### Error handling best practices
|
||||
|
||||
```js
|
||||
// If the WebSocket is closed before the following send is attempted
|
||||
ws.send('something');
|
||||
|
||||
// Errors (both immediate and async write errors) can be detected in an optional
|
||||
// callback. The callback is also the only way of being notified that data has
|
||||
// actually been sent.
|
||||
ws.send('something', function ack(error) {
|
||||
// if error is not defined, the send has been completed,
|
||||
// otherwise the error object will indicate what failed.
|
||||
});
|
||||
|
||||
// Immediate errors can also be handled with try/catch-blocks, but **note** that
|
||||
// since sends are inherently asynchronous, socket write failures will *not* be
|
||||
// captured when this technique is used.
|
||||
try { ws.send('something'); }
|
||||
catch (e) { /* handle error */ }
|
||||
```
|
||||
|
||||
### echo.websocket.org demo
|
||||
|
||||
```js
|
||||
var WebSocket = require('ws');
|
||||
var ws = new WebSocket('ws://echo.websocket.org/', {
|
||||
protocolVersion: 8,
|
||||
origin: 'http://websocket.org'
|
||||
});
|
||||
|
||||
ws.on('open', function open() {
|
||||
console.log('connected');
|
||||
ws.send(Date.now().toString(), {mask: true});
|
||||
});
|
||||
|
||||
ws.on('close', function close() {
|
||||
console.log('disconnected');
|
||||
});
|
||||
|
||||
ws.on('message', function message(data, flags) {
|
||||
console.log('Roundtrip time: ' + (Date.now() - parseInt(data)) + 'ms', flags);
|
||||
|
||||
setTimeout(function timeout() {
|
||||
ws.send(Date.now().toString(), {mask: true});
|
||||
}, 500);
|
||||
});
|
||||
```
|
||||
|
||||
### Other examples
|
||||
|
||||
For a full example with a browser client communicating with a ws server, see the
|
||||
examples folder.
|
||||
|
||||
Note that the usage together with Express 3.0 is quite different from Express
|
||||
2.x. The difference is expressed in the two different serverstats-examples.
|
||||
|
||||
Otherwise, see the test cases.
|
||||
|
||||
### Running the tests
|
||||
|
||||
```
|
||||
make test
|
||||
```
|
||||
|
||||
## API Docs
|
||||
|
||||
See the doc/ directory for Node.js-like docs for the ws classes.
|
||||
|
||||
## Changelog
|
||||
|
||||
We're using the GitHub `releases` for changelog entries.
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
[archive]: http://web.archive.org/web/20130314230536/http://hobbycoding.posterous.com/the-fastest-websocket-module-for-nodejs
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var WS = module.exports = require('./lib/WebSocket');
|
||||
|
||||
WS.Server = require('./lib/WebSocketServer');
|
||||
WS.Sender = require('./lib/Sender');
|
||||
WS.Receiver = require('./lib/Receiver');
|
||||
|
||||
/**
|
||||
* Create a new WebSocket server.
|
||||
*
|
||||
* @param {Object} options Server options
|
||||
* @param {Function} fn Optional connection listener.
|
||||
* @returns {WS.Server}
|
||||
* @api public
|
||||
*/
|
||||
WS.createServer = function createServer(options, fn) {
|
||||
var server = new WS.Server(options);
|
||||
|
||||
if (typeof fn === 'function') {
|
||||
server.on('connection', fn);
|
||||
}
|
||||
|
||||
return server;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new WebSocket connection.
|
||||
*
|
||||
* @param {String} address The URL/address we need to connect to.
|
||||
* @param {Function} fn Open listener.
|
||||
* @returns {WS}
|
||||
* @api public
|
||||
*/
|
||||
WS.connect = WS.createConnection = function connect(address, fn) {
|
||||
var client = new WS(address);
|
||||
|
||||
if (typeof fn === 'function') {
|
||||
client.on('open', fn);
|
||||
}
|
||||
|
||||
return client;
|
||||
};
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var util = require('util');
|
||||
|
||||
function BufferPool(initialSize, growStrategy, shrinkStrategy) {
|
||||
if (typeof initialSize === 'function') {
|
||||
shrinkStrategy = growStrategy;
|
||||
growStrategy = initialSize;
|
||||
initialSize = 0;
|
||||
}
|
||||
else if (typeof initialSize === 'undefined') {
|
||||
initialSize = 0;
|
||||
}
|
||||
this._growStrategy = (growStrategy || function(db, size) {
|
||||
return db.used + size;
|
||||
}).bind(null, this);
|
||||
this._shrinkStrategy = (shrinkStrategy || function(db) {
|
||||
return initialSize;
|
||||
}).bind(null, this);
|
||||
this._buffer = initialSize ? new Buffer(initialSize) : null;
|
||||
this._offset = 0;
|
||||
this._used = 0;
|
||||
this._changeFactor = 0;
|
||||
this.__defineGetter__('size', function(){
|
||||
return this._buffer == null ? 0 : this._buffer.length;
|
||||
});
|
||||
this.__defineGetter__('used', function(){
|
||||
return this._used;
|
||||
});
|
||||
}
|
||||
|
||||
BufferPool.prototype.get = function(length) {
|
||||
if (this._buffer == null || this._offset + length > this._buffer.length) {
|
||||
var newBuf = new Buffer(this._growStrategy(length));
|
||||
this._buffer = newBuf;
|
||||
this._offset = 0;
|
||||
}
|
||||
this._used += length;
|
||||
var buf = this._buffer.slice(this._offset, this._offset + length);
|
||||
this._offset += length;
|
||||
return buf;
|
||||
}
|
||||
|
||||
BufferPool.prototype.reset = function(forceNewBuffer) {
|
||||
var len = this._shrinkStrategy();
|
||||
if (len < this.size) this._changeFactor -= 1;
|
||||
if (forceNewBuffer || this._changeFactor < -2) {
|
||||
this._changeFactor = 0;
|
||||
this._buffer = len ? new Buffer(len) : null;
|
||||
}
|
||||
this._offset = 0;
|
||||
this._used = 0;
|
||||
}
|
||||
|
||||
module.exports = BufferPool;
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
module.exports.BufferUtil = {
|
||||
merge: function(mergedBuffer, buffers) {
|
||||
var offset = 0;
|
||||
for (var i = 0, l = buffers.length; i < l; ++i) {
|
||||
var buf = buffers[i];
|
||||
buf.copy(mergedBuffer, offset);
|
||||
offset += buf.length;
|
||||
}
|
||||
},
|
||||
mask: function(source, mask, output, offset, length) {
|
||||
var maskNum = mask.readUInt32LE(0, true);
|
||||
var i = 0;
|
||||
for (; i < length - 3; i += 4) {
|
||||
var num = maskNum ^ source.readUInt32LE(i, true);
|
||||
if (num < 0) num = 4294967296 + num;
|
||||
output.writeUInt32LE(num, offset + i, true);
|
||||
}
|
||||
switch (length % 4) {
|
||||
case 3: output[offset + i + 2] = source[i + 2] ^ mask[2];
|
||||
case 2: output[offset + i + 1] = source[i + 1] ^ mask[1];
|
||||
case 1: output[offset + i] = source[i] ^ mask[0];
|
||||
case 0:;
|
||||
}
|
||||
},
|
||||
unmask: function(data, mask) {
|
||||
var maskNum = mask.readUInt32LE(0, true);
|
||||
var length = data.length;
|
||||
var i = 0;
|
||||
for (; i < length - 3; i += 4) {
|
||||
var num = maskNum ^ data.readUInt32LE(i, true);
|
||||
if (num < 0) num = 4294967296 + num;
|
||||
data.writeUInt32LE(num, i, true);
|
||||
}
|
||||
switch (length % 4) {
|
||||
case 3: data[i + 2] = data[i + 2] ^ mask[2];
|
||||
case 2: data[i + 1] = data[i + 1] ^ mask[1];
|
||||
case 1: data[i] = data[i] ^ mask[0];
|
||||
case 0:;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
try {
|
||||
module.exports = require('bufferutil');
|
||||
} catch (e) {
|
||||
module.exports = require('./BufferUtil.fallback');
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
isValidErrorCode: function(code) {
|
||||
return (code >= 1000 && code <= 1011 && code != 1004 && code != 1005 && code != 1006) ||
|
||||
(code >= 3000 && code <= 4999);
|
||||
},
|
||||
1000: 'normal',
|
||||
1001: 'going away',
|
||||
1002: 'protocol error',
|
||||
1003: 'unsupported data',
|
||||
1004: 'reserved',
|
||||
1005: 'reserved for extensions',
|
||||
1006: 'reserved for extensions',
|
||||
1007: 'inconsistent or invalid data',
|
||||
1008: 'policy violation',
|
||||
1009: 'message too big',
|
||||
1010: 'extension handshake missing',
|
||||
1011: 'an unexpected condition prevented the request from being fulfilled',
|
||||
};
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
|
||||
var util = require('util');
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
*/
|
||||
|
||||
exports.parse = parse;
|
||||
exports.format = format;
|
||||
|
||||
/**
|
||||
* Parse extensions header value
|
||||
*/
|
||||
|
||||
function parse(value) {
|
||||
value = value || '';
|
||||
|
||||
var extensions = {};
|
||||
|
||||
value.split(',').forEach(function(v) {
|
||||
var params = v.split(';');
|
||||
var token = params.shift().trim();
|
||||
var paramsList = extensions[token] = extensions[token] || [];
|
||||
var parsedParams = {};
|
||||
|
||||
params.forEach(function(param) {
|
||||
var parts = param.trim().split('=');
|
||||
var key = parts[0];
|
||||
var value = parts[1];
|
||||
if (typeof value === 'undefined') {
|
||||
value = true;
|
||||
} else {
|
||||
// unquote value
|
||||
if (value[0] === '"') {
|
||||
value = value.slice(1);
|
||||
}
|
||||
if (value[value.length - 1] === '"') {
|
||||
value = value.slice(0, value.length - 1);
|
||||
}
|
||||
}
|
||||
(parsedParams[key] = parsedParams[key] || []).push(value);
|
||||
});
|
||||
|
||||
paramsList.push(parsedParams);
|
||||
});
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format extensions header value
|
||||
*/
|
||||
|
||||
function format(value) {
|
||||
return Object.keys(value).map(function(token) {
|
||||
var paramsList = value[token];
|
||||
if (!util.isArray(paramsList)) {
|
||||
paramsList = [paramsList];
|
||||
}
|
||||
return paramsList.map(function(params) {
|
||||
return [token].concat(Object.keys(params).map(function(k) {
|
||||
var p = params[k];
|
||||
if (!util.isArray(p)) p = [p];
|
||||
return p.map(function(v) {
|
||||
return v === true ? k : k + '=' + v;
|
||||
}).join('; ');
|
||||
})).join('; ');
|
||||
}).join(', ');
|
||||
}).join(', ');
|
||||
}
|
||||
+289
@@ -0,0 +1,289 @@
|
||||
|
||||
var zlib = require('zlib');
|
||||
|
||||
var AVAILABLE_WINDOW_BITS = [8, 9, 10, 11, 12, 13, 14, 15];
|
||||
var DEFAULT_WINDOW_BITS = 15;
|
||||
var DEFAULT_MEM_LEVEL = 8;
|
||||
|
||||
PerMessageDeflate.extensionName = 'permessage-deflate';
|
||||
|
||||
/**
|
||||
* Per-message Compression Extensions implementation
|
||||
*/
|
||||
|
||||
function PerMessageDeflate(options, isServer) {
|
||||
this._options = options || {};
|
||||
this._isServer = !!isServer;
|
||||
this._inflate = null;
|
||||
this._deflate = null;
|
||||
this.params = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create extension parameters offer
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.offer = function() {
|
||||
var params = {};
|
||||
if (this._options.serverNoContextTakeover) {
|
||||
params.server_no_context_takeover = true;
|
||||
}
|
||||
if (this._options.clientNoContextTakeover) {
|
||||
params.client_no_context_takeover = true;
|
||||
}
|
||||
if (this._options.serverMaxWindowBits) {
|
||||
params.server_max_window_bits = this._options.serverMaxWindowBits;
|
||||
}
|
||||
if (this._options.clientMaxWindowBits) {
|
||||
params.client_max_window_bits = this._options.clientMaxWindowBits;
|
||||
} else if (this._options.clientMaxWindowBits == null) {
|
||||
params.client_max_window_bits = true;
|
||||
}
|
||||
return params;
|
||||
};
|
||||
|
||||
/**
|
||||
* Accept extension offer
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.accept = function(paramsList) {
|
||||
paramsList = this.normalizeParams(paramsList);
|
||||
|
||||
var params;
|
||||
if (this._isServer) {
|
||||
params = this.acceptAsServer(paramsList);
|
||||
} else {
|
||||
params = this.acceptAsClient(paramsList);
|
||||
}
|
||||
|
||||
this.params = params;
|
||||
return params;
|
||||
};
|
||||
|
||||
/**
|
||||
* Accept extension offer from client
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.acceptAsServer = function(paramsList) {
|
||||
var accepted = {};
|
||||
var result = paramsList.some(function(params) {
|
||||
accepted = {};
|
||||
if (this._options.serverNoContextTakeover === false && params.server_no_context_takeover) {
|
||||
return;
|
||||
}
|
||||
if (this._options.serverMaxWindowBits === false && params.server_max_window_bits) {
|
||||
return;
|
||||
}
|
||||
if (typeof this._options.serverMaxWindowBits === 'number' &&
|
||||
typeof params.server_max_window_bits === 'number' &&
|
||||
this._options.serverMaxWindowBits > params.server_max_window_bits) {
|
||||
return;
|
||||
}
|
||||
if (typeof this._options.clientMaxWindowBits === 'number' && !params.client_max_window_bits) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._options.serverNoContextTakeover || params.server_no_context_takeover) {
|
||||
accepted.server_no_context_takeover = true;
|
||||
}
|
||||
if (this._options.clientNoContextTakeover) {
|
||||
accepted.client_no_context_takeover = true;
|
||||
}
|
||||
if (this._options.clientNoContextTakeover !== false && params.client_no_context_takeover) {
|
||||
accepted.client_no_context_takeover = true;
|
||||
}
|
||||
if (typeof this._options.serverMaxWindowBits === 'number') {
|
||||
accepted.server_max_window_bits = this._options.serverMaxWindowBits;
|
||||
} else if (typeof params.server_max_window_bits === 'number') {
|
||||
accepted.server_max_window_bits = params.server_max_window_bits;
|
||||
}
|
||||
if (typeof this._options.clientMaxWindowBits === 'number') {
|
||||
accepted.client_max_window_bits = this._options.clientMaxWindowBits;
|
||||
} else if (this._options.clientMaxWindowBits !== false && typeof params.client_max_window_bits === 'number') {
|
||||
accepted.client_max_window_bits = params.client_max_window_bits;
|
||||
}
|
||||
return true;
|
||||
}, this);
|
||||
|
||||
if (!result) {
|
||||
throw new Error('Doesn\'t support the offered configuration');
|
||||
}
|
||||
|
||||
return accepted;
|
||||
};
|
||||
|
||||
/**
|
||||
* Accept extension response from server
|
||||
*
|
||||
* @api privaye
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.acceptAsClient = function(paramsList) {
|
||||
var params = paramsList[0];
|
||||
if (this._options.clientNoContextTakeover != null) {
|
||||
if (this._options.clientNoContextTakeover === false && params.client_no_context_takeover) {
|
||||
throw new Error('Invalid value for "client_no_context_takeover"');
|
||||
}
|
||||
}
|
||||
if (this._options.clientMaxWindowBits != null) {
|
||||
if (this._options.clientMaxWindowBits === false && params.client_max_window_bits) {
|
||||
throw new Error('Invalid value for "client_max_window_bits"');
|
||||
}
|
||||
if (typeof this._options.clientMaxWindowBits === 'number' &&
|
||||
(!params.client_max_window_bits || params.client_max_window_bits > this._options.clientMaxWindowBits)) {
|
||||
throw new Error('Invalid value for "client_max_window_bits"');
|
||||
}
|
||||
}
|
||||
return params;
|
||||
};
|
||||
|
||||
/**
|
||||
* Normalize extensions parameters
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.normalizeParams = function(paramsList) {
|
||||
return paramsList.map(function(params) {
|
||||
Object.keys(params).forEach(function(key) {
|
||||
var value = params[key];
|
||||
if (value.length > 1) {
|
||||
throw new Error('Multiple extension parameters for ' + key);
|
||||
}
|
||||
|
||||
value = value[0];
|
||||
|
||||
switch (key) {
|
||||
case 'server_no_context_takeover':
|
||||
case 'client_no_context_takeover':
|
||||
if (value !== true) {
|
||||
throw new Error('invalid extension parameter value for ' + key + ' (' + value + ')');
|
||||
}
|
||||
params[key] = true;
|
||||
break;
|
||||
case 'server_max_window_bits':
|
||||
case 'client_max_window_bits':
|
||||
if (typeof value === 'string') {
|
||||
value = parseInt(value, 10);
|
||||
if (!~AVAILABLE_WINDOW_BITS.indexOf(value)) {
|
||||
throw new Error('invalid extension parameter value for ' + key + ' (' + value + ')');
|
||||
}
|
||||
}
|
||||
if (!this._isServer && value === true) {
|
||||
throw new Error('Missing extension parameter value for ' + key);
|
||||
}
|
||||
params[key] = value;
|
||||
break;
|
||||
default:
|
||||
throw new Error('Not defined extension parameter (' + key + ')');
|
||||
}
|
||||
}, this);
|
||||
return params;
|
||||
}, this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Decompress message
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.decompress = function (data, fin, callback) {
|
||||
var endpoint = this._isServer ? 'client' : 'server';
|
||||
|
||||
if (!this._inflate) {
|
||||
var maxWindowBits = this.params[endpoint + '_max_window_bits'];
|
||||
this._inflate = zlib.createInflateRaw({
|
||||
windowBits: 'number' === typeof maxWindowBits ? maxWindowBits : DEFAULT_WINDOW_BITS
|
||||
});
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var buffers = [];
|
||||
|
||||
this._inflate.on('error', onError).on('data', onData);
|
||||
this._inflate.write(data);
|
||||
if (fin) {
|
||||
this._inflate.write(new Buffer([0x00, 0x00, 0xff, 0xff]));
|
||||
}
|
||||
this._inflate.flush(function() {
|
||||
cleanup();
|
||||
callback(null, Buffer.concat(buffers));
|
||||
});
|
||||
|
||||
function onError(err) {
|
||||
cleanup();
|
||||
callback(err);
|
||||
}
|
||||
|
||||
function onData(data) {
|
||||
buffers.push(data);
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
self._inflate.removeListener('error', onError);
|
||||
self._inflate.removeListener('data', onData);
|
||||
if (fin && self.params[endpoint + '_no_context_takeover']) {
|
||||
self._inflate = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Compress message
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.compress = function (data, fin, callback) {
|
||||
var endpoint = this._isServer ? 'server' : 'client';
|
||||
|
||||
if (!this._deflate) {
|
||||
var maxWindowBits = this.params[endpoint + '_max_window_bits'];
|
||||
this._deflate = zlib.createDeflateRaw({
|
||||
flush: zlib.Z_SYNC_FLUSH,
|
||||
windowBits: 'number' === typeof maxWindowBits ? maxWindowBits : DEFAULT_WINDOW_BITS,
|
||||
memLevel: this._options.memLevel || DEFAULT_MEM_LEVEL
|
||||
});
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var buffers = [];
|
||||
|
||||
this._deflate.on('error', onError).on('data', onData);
|
||||
this._deflate.write(data);
|
||||
this._deflate.flush(function() {
|
||||
cleanup();
|
||||
var data = Buffer.concat(buffers);
|
||||
if (fin) {
|
||||
data = data.slice(0, data.length - 4);
|
||||
}
|
||||
callback(null, data);
|
||||
});
|
||||
|
||||
function onError(err) {
|
||||
cleanup();
|
||||
callback(err);
|
||||
}
|
||||
|
||||
function onData(data) {
|
||||
buffers.push(data);
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
self._deflate.removeListener('error', onError);
|
||||
self._deflate.removeListener('data', onData);
|
||||
if (fin && self.params[endpoint + '_no_context_takeover']) {
|
||||
self._deflate = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = PerMessageDeflate;
|
||||
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var util = require('util');
|
||||
|
||||
/**
|
||||
* State constants
|
||||
*/
|
||||
|
||||
var EMPTY = 0
|
||||
, BODY = 1;
|
||||
var BINARYLENGTH = 2
|
||||
, BINARYBODY = 3;
|
||||
|
||||
/**
|
||||
* Hixie Receiver implementation
|
||||
*/
|
||||
|
||||
function Receiver () {
|
||||
this.state = EMPTY;
|
||||
this.buffers = [];
|
||||
this.messageEnd = -1;
|
||||
this.spanLength = 0;
|
||||
this.dead = false;
|
||||
|
||||
this.onerror = function() {};
|
||||
this.ontext = function() {};
|
||||
this.onbinary = function() {};
|
||||
this.onclose = function() {};
|
||||
this.onping = function() {};
|
||||
this.onpong = function() {};
|
||||
}
|
||||
|
||||
module.exports = Receiver;
|
||||
|
||||
/**
|
||||
* Add new data to the parser.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Receiver.prototype.add = function(data) {
|
||||
var self = this;
|
||||
function doAdd() {
|
||||
if (self.state === EMPTY) {
|
||||
if (data.length == 2 && data[0] == 0xFF && data[1] == 0x00) {
|
||||
self.reset();
|
||||
self.onclose();
|
||||
return;
|
||||
}
|
||||
if (data[0] === 0x80) {
|
||||
self.messageEnd = 0;
|
||||
self.state = BINARYLENGTH;
|
||||
data = data.slice(1);
|
||||
} else {
|
||||
|
||||
if (data[0] !== 0x00) {
|
||||
self.error('payload must start with 0x00 byte', true);
|
||||
return;
|
||||
}
|
||||
data = data.slice(1);
|
||||
self.state = BODY;
|
||||
|
||||
}
|
||||
}
|
||||
if (self.state === BINARYLENGTH) {
|
||||
var i = 0;
|
||||
while ((i < data.length) && (data[i] & 0x80)) {
|
||||
self.messageEnd = 128 * self.messageEnd + (data[i] & 0x7f);
|
||||
++i;
|
||||
}
|
||||
if (i < data.length) {
|
||||
self.messageEnd = 128 * self.messageEnd + (data[i] & 0x7f);
|
||||
self.state = BINARYBODY;
|
||||
++i;
|
||||
}
|
||||
if (i > 0)
|
||||
data = data.slice(i);
|
||||
}
|
||||
if (self.state === BINARYBODY) {
|
||||
var dataleft = self.messageEnd - self.spanLength;
|
||||
if (data.length >= dataleft) {
|
||||
// consume the whole buffer to finish the frame
|
||||
self.buffers.push(data);
|
||||
self.spanLength += dataleft;
|
||||
self.messageEnd = dataleft;
|
||||
return self.parse();
|
||||
}
|
||||
// frame's not done even if we consume it all
|
||||
self.buffers.push(data);
|
||||
self.spanLength += data.length;
|
||||
return;
|
||||
}
|
||||
self.buffers.push(data);
|
||||
if ((self.messageEnd = bufferIndex(data, 0xFF)) != -1) {
|
||||
self.spanLength += self.messageEnd;
|
||||
return self.parse();
|
||||
}
|
||||
else self.spanLength += data.length;
|
||||
}
|
||||
while(data) data = doAdd();
|
||||
};
|
||||
|
||||
/**
|
||||
* Releases all resources used by the receiver.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Receiver.prototype.cleanup = function() {
|
||||
this.dead = true;
|
||||
this.state = EMPTY;
|
||||
this.buffers = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Process buffered data.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Receiver.prototype.parse = function() {
|
||||
var output = new Buffer(this.spanLength);
|
||||
var outputIndex = 0;
|
||||
for (var bi = 0, bl = this.buffers.length; bi < bl - 1; ++bi) {
|
||||
var buffer = this.buffers[bi];
|
||||
buffer.copy(output, outputIndex);
|
||||
outputIndex += buffer.length;
|
||||
}
|
||||
var lastBuffer = this.buffers[this.buffers.length - 1];
|
||||
if (this.messageEnd > 0) lastBuffer.copy(output, outputIndex, 0, this.messageEnd);
|
||||
if (this.state !== BODY) --this.messageEnd;
|
||||
var tail = null;
|
||||
if (this.messageEnd < lastBuffer.length - 1) {
|
||||
tail = lastBuffer.slice(this.messageEnd + 1);
|
||||
}
|
||||
this.reset();
|
||||
this.ontext(output.toString('utf8'));
|
||||
return tail;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles an error
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.error = function (reason, terminate) {
|
||||
this.reset();
|
||||
this.onerror(reason, terminate);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset parser state
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.reset = function (reason) {
|
||||
if (this.dead) return;
|
||||
this.state = EMPTY;
|
||||
this.buffers = [];
|
||||
this.messageEnd = -1;
|
||||
this.spanLength = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal api
|
||||
*/
|
||||
|
||||
function bufferIndex(buffer, byte) {
|
||||
for (var i = 0, l = buffer.length; i < l; ++i) {
|
||||
if (buffer[i] === byte) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
+698
@@ -0,0 +1,698 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var util = require('util')
|
||||
, Validation = require('./Validation').Validation
|
||||
, ErrorCodes = require('./ErrorCodes')
|
||||
, BufferPool = require('./BufferPool')
|
||||
, bufferUtil = require('./BufferUtil').BufferUtil
|
||||
, PerMessageDeflate = require('./PerMessageDeflate');
|
||||
|
||||
/**
|
||||
* HyBi Receiver implementation
|
||||
*/
|
||||
|
||||
function Receiver (extensions) {
|
||||
// memory pool for fragmented messages
|
||||
var fragmentedPoolPrevUsed = -1;
|
||||
this.fragmentedBufferPool = new BufferPool(1024, function(db, length) {
|
||||
return db.used + length;
|
||||
}, function(db) {
|
||||
return fragmentedPoolPrevUsed = fragmentedPoolPrevUsed >= 0 ?
|
||||
(fragmentedPoolPrevUsed + db.used) / 2 :
|
||||
db.used;
|
||||
});
|
||||
|
||||
// memory pool for unfragmented messages
|
||||
var unfragmentedPoolPrevUsed = -1;
|
||||
this.unfragmentedBufferPool = new BufferPool(1024, function(db, length) {
|
||||
return db.used + length;
|
||||
}, function(db) {
|
||||
return unfragmentedPoolPrevUsed = unfragmentedPoolPrevUsed >= 0 ?
|
||||
(unfragmentedPoolPrevUsed + db.used) / 2 :
|
||||
db.used;
|
||||
});
|
||||
|
||||
this.extensions = extensions || {};
|
||||
this.state = {
|
||||
activeFragmentedOperation: null,
|
||||
lastFragment: false,
|
||||
masked: false,
|
||||
opcode: 0,
|
||||
fragmentedOperation: false
|
||||
};
|
||||
this.overflow = [];
|
||||
this.headerBuffer = new Buffer(10);
|
||||
this.expectOffset = 0;
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
this.currentMessage = [];
|
||||
this.messageHandlers = [];
|
||||
this.expectHeader(2, this.processPacket);
|
||||
this.dead = false;
|
||||
this.processing = false;
|
||||
|
||||
this.onerror = function() {};
|
||||
this.ontext = function() {};
|
||||
this.onbinary = function() {};
|
||||
this.onclose = function() {};
|
||||
this.onping = function() {};
|
||||
this.onpong = function() {};
|
||||
}
|
||||
|
||||
module.exports = Receiver;
|
||||
|
||||
/**
|
||||
* Add new data to the parser.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Receiver.prototype.add = function(data) {
|
||||
var dataLength = data.length;
|
||||
if (dataLength == 0) return;
|
||||
if (this.expectBuffer == null) {
|
||||
this.overflow.push(data);
|
||||
return;
|
||||
}
|
||||
var toRead = Math.min(dataLength, this.expectBuffer.length - this.expectOffset);
|
||||
fastCopy(toRead, data, this.expectBuffer, this.expectOffset);
|
||||
this.expectOffset += toRead;
|
||||
if (toRead < dataLength) {
|
||||
this.overflow.push(data.slice(toRead));
|
||||
}
|
||||
while (this.expectBuffer && this.expectOffset == this.expectBuffer.length) {
|
||||
var bufferForHandler = this.expectBuffer;
|
||||
this.expectBuffer = null;
|
||||
this.expectOffset = 0;
|
||||
this.expectHandler.call(this, bufferForHandler);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Releases all resources used by the receiver.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Receiver.prototype.cleanup = function() {
|
||||
this.dead = true;
|
||||
this.overflow = null;
|
||||
this.headerBuffer = null;
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
this.unfragmentedBufferPool = null;
|
||||
this.fragmentedBufferPool = null;
|
||||
this.state = null;
|
||||
this.currentMessage = null;
|
||||
this.onerror = null;
|
||||
this.ontext = null;
|
||||
this.onbinary = null;
|
||||
this.onclose = null;
|
||||
this.onping = null;
|
||||
this.onpong = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Waits for a certain amount of header bytes to be available, then fires a callback.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.expectHeader = function(length, handler) {
|
||||
if (length == 0) {
|
||||
handler(null);
|
||||
return;
|
||||
}
|
||||
this.expectBuffer = this.headerBuffer.slice(this.expectOffset, this.expectOffset + length);
|
||||
this.expectHandler = handler;
|
||||
var toRead = length;
|
||||
while (toRead > 0 && this.overflow.length > 0) {
|
||||
var fromOverflow = this.overflow.pop();
|
||||
if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead));
|
||||
var read = Math.min(fromOverflow.length, toRead);
|
||||
fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset);
|
||||
this.expectOffset += read;
|
||||
toRead -= read;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Waits for a certain amount of data bytes to be available, then fires a callback.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.expectData = function(length, handler) {
|
||||
if (length == 0) {
|
||||
handler(null);
|
||||
return;
|
||||
}
|
||||
this.expectBuffer = this.allocateFromPool(length, this.state.fragmentedOperation);
|
||||
this.expectHandler = handler;
|
||||
var toRead = length;
|
||||
while (toRead > 0 && this.overflow.length > 0) {
|
||||
var fromOverflow = this.overflow.pop();
|
||||
if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead));
|
||||
var read = Math.min(fromOverflow.length, toRead);
|
||||
fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset);
|
||||
this.expectOffset += read;
|
||||
toRead -= read;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocates memory from the buffer pool.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.allocateFromPool = function(length, isFragmented) {
|
||||
return (isFragmented ? this.fragmentedBufferPool : this.unfragmentedBufferPool).get(length);
|
||||
};
|
||||
|
||||
/**
|
||||
* Start processing a new packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.processPacket = function (data) {
|
||||
if (this.extensions[PerMessageDeflate.extensionName]) {
|
||||
if ((data[0] & 0x30) != 0) {
|
||||
this.error('reserved fields (2, 3) must be empty', 1002);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ((data[0] & 0x70) != 0) {
|
||||
this.error('reserved fields must be empty', 1002);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.state.lastFragment = (data[0] & 0x80) == 0x80;
|
||||
this.state.masked = (data[1] & 0x80) == 0x80;
|
||||
var compressed = (data[0] & 0x40) == 0x40;
|
||||
var opcode = data[0] & 0xf;
|
||||
if (opcode === 0) {
|
||||
if (compressed) {
|
||||
this.error('continuation frame cannot have the Per-message Compressed bits', 1002);
|
||||
return;
|
||||
}
|
||||
// continuation frame
|
||||
this.state.fragmentedOperation = true;
|
||||
this.state.opcode = this.state.activeFragmentedOperation;
|
||||
if (!(this.state.opcode == 1 || this.state.opcode == 2)) {
|
||||
this.error('continuation frame cannot follow current opcode', 1002);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (opcode < 3 && this.state.activeFragmentedOperation != null) {
|
||||
this.error('data frames after the initial data frame must have opcode 0', 1002);
|
||||
return;
|
||||
}
|
||||
if (opcode >= 8 && compressed) {
|
||||
this.error('control frames cannot have the Per-message Compressed bits', 1002);
|
||||
return;
|
||||
}
|
||||
this.state.compressed = compressed;
|
||||
this.state.opcode = opcode;
|
||||
if (this.state.lastFragment === false) {
|
||||
this.state.fragmentedOperation = true;
|
||||
this.state.activeFragmentedOperation = opcode;
|
||||
}
|
||||
else this.state.fragmentedOperation = false;
|
||||
}
|
||||
var handler = opcodes[this.state.opcode];
|
||||
if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode, 1002);
|
||||
else {
|
||||
handler.start.call(this, data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Endprocessing a packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.endPacket = function() {
|
||||
if (!this.state.fragmentedOperation) this.unfragmentedBufferPool.reset(true);
|
||||
else if (this.state.lastFragment) this.fragmentedBufferPool.reset(false);
|
||||
this.expectOffset = 0;
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
if (this.state.lastFragment && this.state.opcode === this.state.activeFragmentedOperation) {
|
||||
// end current fragmented operation
|
||||
this.state.activeFragmentedOperation = null;
|
||||
}
|
||||
this.state.lastFragment = false;
|
||||
this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0;
|
||||
this.state.masked = false;
|
||||
this.expectHeader(2, this.processPacket);
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset the parser state.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.reset = function() {
|
||||
if (this.dead) return;
|
||||
this.state = {
|
||||
activeFragmentedOperation: null,
|
||||
lastFragment: false,
|
||||
masked: false,
|
||||
opcode: 0,
|
||||
fragmentedOperation: false
|
||||
};
|
||||
this.fragmentedBufferPool.reset(true);
|
||||
this.unfragmentedBufferPool.reset(true);
|
||||
this.expectOffset = 0;
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
this.overflow = [];
|
||||
this.currentMessage = [];
|
||||
this.messageHandlers = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Unmask received data.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.unmask = function (mask, buf, binary) {
|
||||
if (mask != null && buf != null) bufferUtil.unmask(buf, mask);
|
||||
if (binary) return buf;
|
||||
return buf != null ? buf.toString('utf8') : '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Concatenates a list of buffers.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.concatBuffers = function(buffers) {
|
||||
var length = 0;
|
||||
for (var i = 0, l = buffers.length; i < l; ++i) length += buffers[i].length;
|
||||
var mergedBuffer = new Buffer(length);
|
||||
bufferUtil.merge(mergedBuffer, buffers);
|
||||
return mergedBuffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles an error
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.error = function (reason, protocolErrorCode) {
|
||||
this.reset();
|
||||
this.onerror(reason, protocolErrorCode);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute message handler buffers
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.flush = function() {
|
||||
if (this.processing || this.dead) return;
|
||||
|
||||
var handler = this.messageHandlers.shift();
|
||||
if (!handler) return;
|
||||
|
||||
this.processing = true;
|
||||
var self = this;
|
||||
|
||||
handler(function() {
|
||||
self.processing = false;
|
||||
self.flush();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply extensions to message
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.applyExtensions = function(messageBuffer, fin, compressed, callback) {
|
||||
var self = this;
|
||||
if (compressed) {
|
||||
this.extensions[PerMessageDeflate.extensionName].decompress(messageBuffer, fin, function(err, buffer) {
|
||||
if (self.dead) return;
|
||||
if (err) {
|
||||
callback(new Error('invalid compressed data'));
|
||||
return;
|
||||
}
|
||||
callback(null, buffer);
|
||||
});
|
||||
} else {
|
||||
callback(null, messageBuffer);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Buffer utilities
|
||||
*/
|
||||
|
||||
function readUInt16BE(start) {
|
||||
return (this[start]<<8) +
|
||||
this[start+1];
|
||||
}
|
||||
|
||||
function readUInt32BE(start) {
|
||||
return (this[start]<<24) +
|
||||
(this[start+1]<<16) +
|
||||
(this[start+2]<<8) +
|
||||
this[start+3];
|
||||
}
|
||||
|
||||
function fastCopy(length, srcBuffer, dstBuffer, dstOffset) {
|
||||
switch (length) {
|
||||
default: srcBuffer.copy(dstBuffer, dstOffset, 0, length); break;
|
||||
case 16: dstBuffer[dstOffset+15] = srcBuffer[15];
|
||||
case 15: dstBuffer[dstOffset+14] = srcBuffer[14];
|
||||
case 14: dstBuffer[dstOffset+13] = srcBuffer[13];
|
||||
case 13: dstBuffer[dstOffset+12] = srcBuffer[12];
|
||||
case 12: dstBuffer[dstOffset+11] = srcBuffer[11];
|
||||
case 11: dstBuffer[dstOffset+10] = srcBuffer[10];
|
||||
case 10: dstBuffer[dstOffset+9] = srcBuffer[9];
|
||||
case 9: dstBuffer[dstOffset+8] = srcBuffer[8];
|
||||
case 8: dstBuffer[dstOffset+7] = srcBuffer[7];
|
||||
case 7: dstBuffer[dstOffset+6] = srcBuffer[6];
|
||||
case 6: dstBuffer[dstOffset+5] = srcBuffer[5];
|
||||
case 5: dstBuffer[dstOffset+4] = srcBuffer[4];
|
||||
case 4: dstBuffer[dstOffset+3] = srcBuffer[3];
|
||||
case 3: dstBuffer[dstOffset+2] = srcBuffer[2];
|
||||
case 2: dstBuffer[dstOffset+1] = srcBuffer[1];
|
||||
case 1: dstBuffer[dstOffset] = srcBuffer[0];
|
||||
}
|
||||
}
|
||||
|
||||
function clone(obj) {
|
||||
var cloned = {};
|
||||
for (var k in obj) {
|
||||
if (obj.hasOwnProperty(k)) {
|
||||
cloned[k] = obj[k];
|
||||
}
|
||||
}
|
||||
return cloned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opcode handlers
|
||||
*/
|
||||
|
||||
var opcodes = {
|
||||
// text
|
||||
'1': {
|
||||
start: function(data) {
|
||||
var self = this;
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength < 126) {
|
||||
opcodes['1'].getData.call(self, firstLength);
|
||||
}
|
||||
else if (firstLength == 126) {
|
||||
self.expectHeader(2, function(data) {
|
||||
opcodes['1'].getData.call(self, readUInt16BE.call(data, 0));
|
||||
});
|
||||
}
|
||||
else if (firstLength == 127) {
|
||||
self.expectHeader(8, function(data) {
|
||||
if (readUInt32BE.call(data, 0) != 0) {
|
||||
self.error('packets with length spanning more than 32 bit is currently not supported', 1008);
|
||||
return;
|
||||
}
|
||||
opcodes['1'].getData.call(self, readUInt32BE.call(data, 4));
|
||||
});
|
||||
}
|
||||
},
|
||||
getData: function(length) {
|
||||
var self = this;
|
||||
if (self.state.masked) {
|
||||
self.expectHeader(4, function(data) {
|
||||
var mask = data;
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['1'].finish.call(self, mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['1'].finish.call(self, null, data);
|
||||
});
|
||||
}
|
||||
},
|
||||
finish: function(mask, data) {
|
||||
var self = this;
|
||||
var packet = this.unmask(mask, data, true) || new Buffer(0);
|
||||
var state = clone(this.state);
|
||||
this.messageHandlers.push(function(callback) {
|
||||
self.applyExtensions(packet, state.lastFragment, state.compressed, function(err, buffer) {
|
||||
if (err) return self.error(err.message, 1007);
|
||||
if (buffer != null) self.currentMessage.push(buffer);
|
||||
|
||||
if (state.lastFragment) {
|
||||
var messageBuffer = self.concatBuffers(self.currentMessage);
|
||||
self.currentMessage = [];
|
||||
if (!Validation.isValidUTF8(messageBuffer)) {
|
||||
self.error('invalid utf8 sequence', 1007);
|
||||
return;
|
||||
}
|
||||
self.ontext(messageBuffer.toString('utf8'), {masked: state.masked, buffer: messageBuffer});
|
||||
}
|
||||
callback();
|
||||
});
|
||||
});
|
||||
this.flush();
|
||||
this.endPacket();
|
||||
}
|
||||
},
|
||||
// binary
|
||||
'2': {
|
||||
start: function(data) {
|
||||
var self = this;
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength < 126) {
|
||||
opcodes['2'].getData.call(self, firstLength);
|
||||
}
|
||||
else if (firstLength == 126) {
|
||||
self.expectHeader(2, function(data) {
|
||||
opcodes['2'].getData.call(self, readUInt16BE.call(data, 0));
|
||||
});
|
||||
}
|
||||
else if (firstLength == 127) {
|
||||
self.expectHeader(8, function(data) {
|
||||
if (readUInt32BE.call(data, 0) != 0) {
|
||||
self.error('packets with length spanning more than 32 bit is currently not supported', 1008);
|
||||
return;
|
||||
}
|
||||
opcodes['2'].getData.call(self, readUInt32BE.call(data, 4, true));
|
||||
});
|
||||
}
|
||||
},
|
||||
getData: function(length) {
|
||||
var self = this;
|
||||
if (self.state.masked) {
|
||||
self.expectHeader(4, function(data) {
|
||||
var mask = data;
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['2'].finish.call(self, mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['2'].finish.call(self, null, data);
|
||||
});
|
||||
}
|
||||
},
|
||||
finish: function(mask, data) {
|
||||
var self = this;
|
||||
var packet = this.unmask(mask, data, true) || new Buffer(0);
|
||||
var state = clone(this.state);
|
||||
this.messageHandlers.push(function(callback) {
|
||||
self.applyExtensions(packet, state.lastFragment, state.compressed, function(err, buffer) {
|
||||
if (err) return self.error(err.message, 1007);
|
||||
if (buffer != null) self.currentMessage.push(buffer);
|
||||
if (state.lastFragment) {
|
||||
var messageBuffer = self.concatBuffers(self.currentMessage);
|
||||
self.currentMessage = [];
|
||||
self.onbinary(messageBuffer, {masked: state.masked, buffer: messageBuffer});
|
||||
}
|
||||
callback();
|
||||
});
|
||||
});
|
||||
this.flush();
|
||||
this.endPacket();
|
||||
}
|
||||
},
|
||||
// close
|
||||
'8': {
|
||||
start: function(data) {
|
||||
var self = this;
|
||||
if (self.state.lastFragment == false) {
|
||||
self.error('fragmented close is not supported', 1002);
|
||||
return;
|
||||
}
|
||||
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength < 126) {
|
||||
opcodes['8'].getData.call(self, firstLength);
|
||||
}
|
||||
else {
|
||||
self.error('control frames cannot have more than 125 bytes of data', 1002);
|
||||
}
|
||||
},
|
||||
getData: function(length) {
|
||||
var self = this;
|
||||
if (self.state.masked) {
|
||||
self.expectHeader(4, function(data) {
|
||||
var mask = data;
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['8'].finish.call(self, mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['8'].finish.call(self, null, data);
|
||||
});
|
||||
}
|
||||
},
|
||||
finish: function(mask, data) {
|
||||
var self = this;
|
||||
data = self.unmask(mask, data, true);
|
||||
|
||||
var state = clone(this.state);
|
||||
this.messageHandlers.push(function() {
|
||||
if (data && data.length == 1) {
|
||||
self.error('close packets with data must be at least two bytes long', 1002);
|
||||
return;
|
||||
}
|
||||
var code = data && data.length > 1 ? readUInt16BE.call(data, 0) : 1000;
|
||||
if (!ErrorCodes.isValidErrorCode(code)) {
|
||||
self.error('invalid error code', 1002);
|
||||
return;
|
||||
}
|
||||
var message = '';
|
||||
if (data && data.length > 2) {
|
||||
var messageBuffer = data.slice(2);
|
||||
if (!Validation.isValidUTF8(messageBuffer)) {
|
||||
self.error('invalid utf8 sequence', 1007);
|
||||
return;
|
||||
}
|
||||
message = messageBuffer.toString('utf8');
|
||||
}
|
||||
self.onclose(code, message, {masked: state.masked});
|
||||
self.reset();
|
||||
});
|
||||
this.flush();
|
||||
},
|
||||
},
|
||||
// ping
|
||||
'9': {
|
||||
start: function(data) {
|
||||
var self = this;
|
||||
if (self.state.lastFragment == false) {
|
||||
self.error('fragmented ping is not supported', 1002);
|
||||
return;
|
||||
}
|
||||
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength < 126) {
|
||||
opcodes['9'].getData.call(self, firstLength);
|
||||
}
|
||||
else {
|
||||
self.error('control frames cannot have more than 125 bytes of data', 1002);
|
||||
}
|
||||
},
|
||||
getData: function(length) {
|
||||
var self = this;
|
||||
if (self.state.masked) {
|
||||
self.expectHeader(4, function(data) {
|
||||
var mask = data;
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['9'].finish.call(self, mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['9'].finish.call(self, null, data);
|
||||
});
|
||||
}
|
||||
},
|
||||
finish: function(mask, data) {
|
||||
var self = this;
|
||||
data = this.unmask(mask, data, true);
|
||||
var state = clone(this.state);
|
||||
this.messageHandlers.push(function(callback) {
|
||||
self.onping(data, {masked: state.masked, binary: true});
|
||||
callback();
|
||||
});
|
||||
this.flush();
|
||||
this.endPacket();
|
||||
}
|
||||
},
|
||||
// pong
|
||||
'10': {
|
||||
start: function(data) {
|
||||
var self = this;
|
||||
if (self.state.lastFragment == false) {
|
||||
self.error('fragmented pong is not supported', 1002);
|
||||
return;
|
||||
}
|
||||
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength < 126) {
|
||||
opcodes['10'].getData.call(self, firstLength);
|
||||
}
|
||||
else {
|
||||
self.error('control frames cannot have more than 125 bytes of data', 1002);
|
||||
}
|
||||
},
|
||||
getData: function(length) {
|
||||
var self = this;
|
||||
if (this.state.masked) {
|
||||
this.expectHeader(4, function(data) {
|
||||
var mask = data;
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['10'].finish.call(self, mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.expectData(length, function(data) {
|
||||
opcodes['10'].finish.call(self, null, data);
|
||||
});
|
||||
}
|
||||
},
|
||||
finish: function(mask, data) {
|
||||
var self = this;
|
||||
data = self.unmask(mask, data, true);
|
||||
var state = clone(this.state);
|
||||
this.messageHandlers.push(function(callback) {
|
||||
self.onpong(data, {masked: state.masked, binary: true});
|
||||
callback();
|
||||
});
|
||||
this.flush();
|
||||
this.endPacket();
|
||||
}
|
||||
}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var events = require('events')
|
||||
, util = require('util')
|
||||
, EventEmitter = events.EventEmitter;
|
||||
|
||||
/**
|
||||
* Hixie Sender implementation
|
||||
*/
|
||||
|
||||
function Sender(socket) {
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
this.socket = socket;
|
||||
this.continuationFrame = false;
|
||||
this.isClosed = false;
|
||||
}
|
||||
|
||||
module.exports = Sender;
|
||||
|
||||
/**
|
||||
* Inherits from EventEmitter.
|
||||
*/
|
||||
|
||||
util.inherits(Sender, events.EventEmitter);
|
||||
|
||||
/**
|
||||
* Frames and writes data.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.send = function(data, options, cb) {
|
||||
if (this.isClosed) return;
|
||||
|
||||
var isString = typeof data == 'string'
|
||||
, length = isString ? Buffer.byteLength(data) : data.length
|
||||
, lengthbytes = (length > 127) ? 2 : 1 // assume less than 2**14 bytes
|
||||
, writeStartMarker = this.continuationFrame == false
|
||||
, writeEndMarker = !options || !(typeof options.fin != 'undefined' && !options.fin)
|
||||
, buffer = new Buffer((writeStartMarker ? ((options && options.binary) ? (1 + lengthbytes) : 1) : 0) + length + ((writeEndMarker && !(options && options.binary)) ? 1 : 0))
|
||||
, offset = writeStartMarker ? 1 : 0;
|
||||
|
||||
if (writeStartMarker) {
|
||||
if (options && options.binary) {
|
||||
buffer.write('\x80', 'binary');
|
||||
// assume length less than 2**14 bytes
|
||||
if (lengthbytes > 1)
|
||||
buffer.write(String.fromCharCode(128+length/128), offset++, 'binary');
|
||||
buffer.write(String.fromCharCode(length&0x7f), offset++, 'binary');
|
||||
} else
|
||||
buffer.write('\x00', 'binary');
|
||||
}
|
||||
|
||||
if (isString) buffer.write(data, offset, 'utf8');
|
||||
else data.copy(buffer, offset, 0);
|
||||
|
||||
if (writeEndMarker) {
|
||||
if (options && options.binary) {
|
||||
// sending binary, not writing end marker
|
||||
} else
|
||||
buffer.write('\xff', offset + length, 'binary');
|
||||
this.continuationFrame = false;
|
||||
}
|
||||
else this.continuationFrame = true;
|
||||
|
||||
try {
|
||||
this.socket.write(buffer, 'binary', cb);
|
||||
} catch (e) {
|
||||
this.error(e.toString());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a close instruction to the remote party.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.close = function(code, data, mask, cb) {
|
||||
if (this.isClosed) return;
|
||||
this.isClosed = true;
|
||||
try {
|
||||
if (this.continuationFrame) this.socket.write(new Buffer([0xff], 'binary'));
|
||||
this.socket.write(new Buffer([0xff, 0x00]), 'binary', cb);
|
||||
} catch (e) {
|
||||
this.error(e.toString());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a ping message to the remote party. Not available for hixie.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.ping = function(data, options) {};
|
||||
|
||||
/**
|
||||
* Sends a pong message to the remote party. Not available for hixie.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.pong = function(data, options) {};
|
||||
|
||||
/**
|
||||
* Handles an error
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Sender.prototype.error = function (reason) {
|
||||
this.emit('error', reason);
|
||||
return this;
|
||||
};
|
||||
+309
@@ -0,0 +1,309 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var events = require('events')
|
||||
, util = require('util')
|
||||
, EventEmitter = events.EventEmitter
|
||||
, ErrorCodes = require('./ErrorCodes')
|
||||
, bufferUtil = require('./BufferUtil').BufferUtil
|
||||
, PerMessageDeflate = require('./PerMessageDeflate');
|
||||
|
||||
/**
|
||||
* HyBi Sender implementation
|
||||
*/
|
||||
|
||||
function Sender(socket, extensions) {
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
this._socket = socket;
|
||||
this.extensions = extensions || {};
|
||||
this.firstFragment = true;
|
||||
this.compress = false;
|
||||
this.messageHandlers = [];
|
||||
this.processing = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherits from EventEmitter.
|
||||
*/
|
||||
|
||||
util.inherits(Sender, events.EventEmitter);
|
||||
|
||||
/**
|
||||
* Sends a close instruction to the remote party.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.close = function(code, data, mask, cb) {
|
||||
if (typeof code !== 'undefined') {
|
||||
if (typeof code !== 'number' ||
|
||||
!ErrorCodes.isValidErrorCode(code)) throw new Error('first argument must be a valid error code number');
|
||||
}
|
||||
code = code || 1000;
|
||||
var dataBuffer = new Buffer(2 + (data ? Buffer.byteLength(data) : 0));
|
||||
writeUInt16BE.call(dataBuffer, code, 0);
|
||||
if (dataBuffer.length > 2) dataBuffer.write(data, 2);
|
||||
|
||||
var self = this;
|
||||
this.messageHandlers.push(function(callback) {
|
||||
self.frameAndSend(0x8, dataBuffer, true, mask);
|
||||
callback();
|
||||
if (typeof cb == 'function') cb();
|
||||
});
|
||||
this.flush();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a ping message to the remote party.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.ping = function(data, options) {
|
||||
var mask = options && options.mask;
|
||||
var self = this;
|
||||
this.messageHandlers.push(function(callback) {
|
||||
self.frameAndSend(0x9, data || '', true, mask);
|
||||
callback();
|
||||
});
|
||||
this.flush();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a pong message to the remote party.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.pong = function(data, options) {
|
||||
var mask = options && options.mask;
|
||||
var self = this;
|
||||
this.messageHandlers.push(function(callback) {
|
||||
self.frameAndSend(0xa, data || '', true, mask);
|
||||
callback();
|
||||
});
|
||||
this.flush();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends text or binary data to the remote party.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.send = function(data, options, cb) {
|
||||
var finalFragment = options && options.fin === false ? false : true;
|
||||
var mask = options && options.mask;
|
||||
var compress = options && options.compress;
|
||||
var opcode = options && options.binary ? 2 : 1;
|
||||
if (this.firstFragment === false) {
|
||||
opcode = 0;
|
||||
compress = false;
|
||||
} else {
|
||||
this.firstFragment = false;
|
||||
this.compress = compress;
|
||||
}
|
||||
if (finalFragment) this.firstFragment = true
|
||||
|
||||
var compressFragment = this.compress;
|
||||
|
||||
var self = this;
|
||||
this.messageHandlers.push(function(callback) {
|
||||
self.applyExtensions(data, finalFragment, compressFragment, function(err, data) {
|
||||
if (err) {
|
||||
if (typeof cb == 'function') cb(err);
|
||||
else self.emit('error', err);
|
||||
return;
|
||||
}
|
||||
self.frameAndSend(opcode, data, finalFragment, mask, compress, cb);
|
||||
callback();
|
||||
});
|
||||
});
|
||||
this.flush();
|
||||
};
|
||||
|
||||
/**
|
||||
* Frames and sends a piece of data according to the HyBi WebSocket protocol.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Sender.prototype.frameAndSend = function(opcode, data, finalFragment, maskData, compressed, cb) {
|
||||
var canModifyData = false;
|
||||
|
||||
if (!data) {
|
||||
try {
|
||||
this._socket.write(new Buffer([opcode | (finalFragment ? 0x80 : 0), 0 | (maskData ? 0x80 : 0)].concat(maskData ? [0, 0, 0, 0] : [])), 'binary', cb);
|
||||
}
|
||||
catch (e) {
|
||||
if (typeof cb == 'function') cb(e);
|
||||
else this.emit('error', e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Buffer.isBuffer(data)) {
|
||||
canModifyData = true;
|
||||
if (data && (typeof data.byteLength !== 'undefined' || typeof data.buffer !== 'undefined')) {
|
||||
data = getArrayBuffer(data);
|
||||
} else {
|
||||
data = new Buffer(data);
|
||||
}
|
||||
}
|
||||
|
||||
var dataLength = data.length
|
||||
, dataOffset = maskData ? 6 : 2
|
||||
, secondByte = dataLength;
|
||||
|
||||
if (dataLength >= 65536) {
|
||||
dataOffset += 8;
|
||||
secondByte = 127;
|
||||
}
|
||||
else if (dataLength > 125) {
|
||||
dataOffset += 2;
|
||||
secondByte = 126;
|
||||
}
|
||||
|
||||
var mergeBuffers = dataLength < 32768 || (maskData && !canModifyData);
|
||||
var totalLength = mergeBuffers ? dataLength + dataOffset : dataOffset;
|
||||
var outputBuffer = new Buffer(totalLength);
|
||||
outputBuffer[0] = finalFragment ? opcode | 0x80 : opcode;
|
||||
if (compressed) outputBuffer[0] |= 0x40;
|
||||
|
||||
switch (secondByte) {
|
||||
case 126:
|
||||
writeUInt16BE.call(outputBuffer, dataLength, 2);
|
||||
break;
|
||||
case 127:
|
||||
writeUInt32BE.call(outputBuffer, 0, 2);
|
||||
writeUInt32BE.call(outputBuffer, dataLength, 6);
|
||||
}
|
||||
|
||||
if (maskData) {
|
||||
outputBuffer[1] = secondByte | 0x80;
|
||||
var mask = this._randomMask || (this._randomMask = getRandomMask());
|
||||
outputBuffer[dataOffset - 4] = mask[0];
|
||||
outputBuffer[dataOffset - 3] = mask[1];
|
||||
outputBuffer[dataOffset - 2] = mask[2];
|
||||
outputBuffer[dataOffset - 1] = mask[3];
|
||||
if (mergeBuffers) {
|
||||
bufferUtil.mask(data, mask, outputBuffer, dataOffset, dataLength);
|
||||
try {
|
||||
this._socket.write(outputBuffer, 'binary', cb);
|
||||
}
|
||||
catch (e) {
|
||||
if (typeof cb == 'function') cb(e);
|
||||
else this.emit('error', e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bufferUtil.mask(data, mask, data, 0, dataLength);
|
||||
try {
|
||||
this._socket.write(outputBuffer, 'binary');
|
||||
this._socket.write(data, 'binary', cb);
|
||||
}
|
||||
catch (e) {
|
||||
if (typeof cb == 'function') cb(e);
|
||||
else this.emit('error', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
outputBuffer[1] = secondByte;
|
||||
if (mergeBuffers) {
|
||||
data.copy(outputBuffer, dataOffset);
|
||||
try {
|
||||
this._socket.write(outputBuffer, 'binary', cb);
|
||||
}
|
||||
catch (e) {
|
||||
if (typeof cb == 'function') cb(e);
|
||||
else this.emit('error', e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
this._socket.write(outputBuffer, 'binary');
|
||||
this._socket.write(data, 'binary', cb);
|
||||
}
|
||||
catch (e) {
|
||||
if (typeof cb == 'function') cb(e);
|
||||
else this.emit('error', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute message handler buffers
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Sender.prototype.flush = function() {
|
||||
if (this.processing) return;
|
||||
|
||||
var handler = this.messageHandlers.shift();
|
||||
if (!handler) return;
|
||||
|
||||
this.processing = true;
|
||||
|
||||
var self = this;
|
||||
|
||||
handler(function() {
|
||||
self.processing = false;
|
||||
self.flush();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply extensions to message
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Sender.prototype.applyExtensions = function(data, fin, compress, callback) {
|
||||
if (compress && data) {
|
||||
this.extensions[PerMessageDeflate.extensionName].compress(data, fin, callback);
|
||||
} else {
|
||||
callback(null, data);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Sender;
|
||||
|
||||
function writeUInt16BE(value, offset) {
|
||||
this[offset] = (value & 0xff00)>>8;
|
||||
this[offset+1] = value & 0xff;
|
||||
}
|
||||
|
||||
function writeUInt32BE(value, offset) {
|
||||
this[offset] = (value & 0xff000000)>>24;
|
||||
this[offset+1] = (value & 0xff0000)>>16;
|
||||
this[offset+2] = (value & 0xff00)>>8;
|
||||
this[offset+3] = value & 0xff;
|
||||
}
|
||||
|
||||
function getArrayBuffer(data) {
|
||||
// data is either an ArrayBuffer or ArrayBufferView.
|
||||
var array = new Uint8Array(data.buffer || data)
|
||||
, l = data.byteLength || data.length
|
||||
, o = data.byteOffset || 0
|
||||
, buffer = new Buffer(l);
|
||||
for (var i = 0; i < l; ++i) {
|
||||
buffer[i] = array[o+i];
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function getRandomMask() {
|
||||
return new Buffer([
|
||||
~~(Math.random() * 255),
|
||||
~~(Math.random() * 255),
|
||||
~~(Math.random() * 255),
|
||||
~~(Math.random() * 255)
|
||||
]);
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
module.exports.Validation = {
|
||||
isValidUTF8: function(buffer) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
try {
|
||||
module.exports = require('utf-8-validate');
|
||||
} catch (e) {
|
||||
module.exports = require('./Validation.fallback');
|
||||
}
|
||||
+937
@@ -0,0 +1,937 @@
|
||||
'use strict';
|
||||
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var url = require('url')
|
||||
, util = require('util')
|
||||
, http = require('http')
|
||||
, https = require('https')
|
||||
, crypto = require('crypto')
|
||||
, stream = require('stream')
|
||||
, Ultron = require('ultron')
|
||||
, Options = require('options')
|
||||
, Sender = require('./Sender')
|
||||
, Receiver = require('./Receiver')
|
||||
, SenderHixie = require('./Sender.hixie')
|
||||
, ReceiverHixie = require('./Receiver.hixie')
|
||||
, Extensions = require('./Extensions')
|
||||
, PerMessageDeflate = require('./PerMessageDeflate')
|
||||
, EventEmitter = require('events').EventEmitter;
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
|
||||
// Default protocol version
|
||||
|
||||
var protocolVersion = 13;
|
||||
|
||||
// Close timeout
|
||||
|
||||
var closeTimeout = 30 * 1000; // Allow 30 seconds to terminate the connection cleanly
|
||||
|
||||
/**
|
||||
* WebSocket implementation
|
||||
*
|
||||
* @constructor
|
||||
* @param {String} address Connection address.
|
||||
* @param {String|Array} protocols WebSocket protocols.
|
||||
* @param {Object} options Additional connection options.
|
||||
* @api public
|
||||
*/
|
||||
function WebSocket(address, protocols, options) {
|
||||
EventEmitter.call(this);
|
||||
|
||||
if (protocols && !Array.isArray(protocols) && 'object' === typeof protocols) {
|
||||
// accept the "options" Object as the 2nd argument
|
||||
options = protocols;
|
||||
protocols = null;
|
||||
}
|
||||
|
||||
if ('string' === typeof protocols) {
|
||||
protocols = [ protocols ];
|
||||
}
|
||||
|
||||
if (!Array.isArray(protocols)) {
|
||||
protocols = [];
|
||||
}
|
||||
|
||||
this._socket = null;
|
||||
this._ultron = null;
|
||||
this._closeReceived = false;
|
||||
this.bytesReceived = 0;
|
||||
this.readyState = null;
|
||||
this.supports = {};
|
||||
this.extensions = {};
|
||||
|
||||
if (Array.isArray(address)) {
|
||||
initAsServerClient.apply(this, address.concat(options));
|
||||
} else {
|
||||
initAsClient.apply(this, [address, protocols, options]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherits from EventEmitter.
|
||||
*/
|
||||
util.inherits(WebSocket, EventEmitter);
|
||||
|
||||
/**
|
||||
* Ready States
|
||||
*/
|
||||
["CONNECTING", "OPEN", "CLOSING", "CLOSED"].forEach(function each(state, index) {
|
||||
WebSocket.prototype[state] = WebSocket[state] = index;
|
||||
});
|
||||
|
||||
/**
|
||||
* Gracefully closes the connection, after sending a description message to the server
|
||||
*
|
||||
* @param {Object} data to be sent to the server
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.close = function close(code, data) {
|
||||
if (this.readyState === WebSocket.CLOSED) return;
|
||||
|
||||
if (this.readyState === WebSocket.CONNECTING) {
|
||||
this.readyState = WebSocket.CLOSED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.readyState === WebSocket.CLOSING) {
|
||||
if (this._closeReceived && this._isServer) {
|
||||
this.terminate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
try {
|
||||
this.readyState = WebSocket.CLOSING;
|
||||
this._closeCode = code;
|
||||
this._closeMessage = data;
|
||||
var mask = !this._isServer;
|
||||
this._sender.close(code, data, mask, function(err) {
|
||||
if (err) self.emit('error', err);
|
||||
|
||||
if (self._closeReceived && self._isServer) {
|
||||
self.terminate();
|
||||
} else {
|
||||
// ensure that the connection is cleaned up even when no response of closing handshake.
|
||||
clearTimeout(self._closeTimer);
|
||||
self._closeTimer = setTimeout(cleanupWebsocketResources.bind(self, true), closeTimeout);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
this.emit('error', e);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Pause the client stream
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.pause = function pauser() {
|
||||
if (this.readyState !== WebSocket.OPEN) throw new Error('not opened');
|
||||
|
||||
return this._socket.pause();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a ping
|
||||
*
|
||||
* @param {Object} data to be sent to the server
|
||||
* @param {Object} Members - mask: boolean, binary: boolean
|
||||
* @param {boolean} dontFailWhenClosed indicates whether or not to throw if the connection isnt open
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.ping = function ping(data, options, dontFailWhenClosed) {
|
||||
if (this.readyState !== WebSocket.OPEN) {
|
||||
if (dontFailWhenClosed === true) return;
|
||||
throw new Error('not opened');
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (typeof options.mask === 'undefined') options.mask = !this._isServer;
|
||||
|
||||
this._sender.ping(data, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a pong
|
||||
*
|
||||
* @param {Object} data to be sent to the server
|
||||
* @param {Object} Members - mask: boolean, binary: boolean
|
||||
* @param {boolean} dontFailWhenClosed indicates whether or not to throw if the connection isnt open
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.pong = function(data, options, dontFailWhenClosed) {
|
||||
if (this.readyState !== WebSocket.OPEN) {
|
||||
if (dontFailWhenClosed === true) return;
|
||||
throw new Error('not opened');
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (typeof options.mask === 'undefined') options.mask = !this._isServer;
|
||||
|
||||
this._sender.pong(data, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Resume the client stream
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.resume = function resume() {
|
||||
if (this.readyState !== WebSocket.OPEN) throw new Error('not opened');
|
||||
|
||||
return this._socket.resume();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a piece of data
|
||||
*
|
||||
* @param {Object} data to be sent to the server
|
||||
* @param {Object} Members - mask: boolean, binary: boolean, compress: boolean
|
||||
* @param {function} Optional callback which is executed after the send completes
|
||||
* @api public
|
||||
*/
|
||||
|
||||
WebSocket.prototype.send = function send(data, options, cb) {
|
||||
if (typeof options === 'function') {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
if (this.readyState !== WebSocket.OPEN) {
|
||||
if (typeof cb === 'function') cb(new Error('not opened'));
|
||||
else throw new Error('not opened');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data) data = '';
|
||||
if (this._queue) {
|
||||
var self = this;
|
||||
this._queue.push(function() { self.send(data, options, cb); });
|
||||
return;
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
options.fin = true;
|
||||
|
||||
if (typeof options.binary === 'undefined') {
|
||||
options.binary = (data instanceof ArrayBuffer || data instanceof Buffer ||
|
||||
data instanceof Uint8Array ||
|
||||
data instanceof Uint16Array ||
|
||||
data instanceof Uint32Array ||
|
||||
data instanceof Int8Array ||
|
||||
data instanceof Int16Array ||
|
||||
data instanceof Int32Array ||
|
||||
data instanceof Float32Array ||
|
||||
data instanceof Float64Array);
|
||||
}
|
||||
|
||||
if (typeof options.mask === 'undefined') options.mask = !this._isServer;
|
||||
if (typeof options.compress === 'undefined') options.compress = true;
|
||||
if (!this.extensions[PerMessageDeflate.extensionName]) {
|
||||
options.compress = false;
|
||||
}
|
||||
|
||||
var readable = typeof stream.Readable === 'function'
|
||||
? stream.Readable
|
||||
: stream.Stream;
|
||||
|
||||
if (data instanceof readable) {
|
||||
startQueue(this);
|
||||
var self = this;
|
||||
|
||||
sendStream(this, data, options, function send(error) {
|
||||
process.nextTick(function tock() {
|
||||
executeQueueSends(self);
|
||||
});
|
||||
|
||||
if (typeof cb === 'function') cb(error);
|
||||
});
|
||||
} else {
|
||||
this._sender.send(data, options, cb);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Streams data through calls to a user supplied function
|
||||
*
|
||||
* @param {Object} Members - mask: boolean, binary: boolean, compress: boolean
|
||||
* @param {function} 'function (error, send)' which is executed on successive ticks of which send is 'function (data, final)'.
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.stream = function stream(options, cb) {
|
||||
if (typeof options === 'function') {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
if (typeof cb !== 'function') throw new Error('callback must be provided');
|
||||
|
||||
if (this.readyState !== WebSocket.OPEN) {
|
||||
if (typeof cb === 'function') cb(new Error('not opened'));
|
||||
else throw new Error('not opened');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._queue) {
|
||||
this._queue.push(function () { self.stream(options, cb); });
|
||||
return;
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (typeof options.mask === 'undefined') options.mask = !this._isServer;
|
||||
if (typeof options.compress === 'undefined') options.compress = true;
|
||||
if (!this.extensions[PerMessageDeflate.extensionName]) {
|
||||
options.compress = false;
|
||||
}
|
||||
|
||||
startQueue(this);
|
||||
|
||||
function send(data, final) {
|
||||
try {
|
||||
if (self.readyState !== WebSocket.OPEN) throw new Error('not opened');
|
||||
options.fin = final === true;
|
||||
self._sender.send(data, options);
|
||||
if (!final) process.nextTick(cb.bind(null, null, send));
|
||||
else executeQueueSends(self);
|
||||
} catch (e) {
|
||||
if (typeof cb === 'function') cb(e);
|
||||
else {
|
||||
delete self._queue;
|
||||
self.emit('error', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process.nextTick(cb.bind(null, null, send));
|
||||
};
|
||||
|
||||
/**
|
||||
* Immediately shuts down the connection
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.terminate = function terminate() {
|
||||
if (this.readyState === WebSocket.CLOSED) return;
|
||||
|
||||
if (this._socket) {
|
||||
this.readyState = WebSocket.CLOSING;
|
||||
|
||||
// End the connection
|
||||
try { this._socket.end(); }
|
||||
catch (e) {
|
||||
// Socket error during end() call, so just destroy it right now
|
||||
cleanupWebsocketResources.call(this, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add a timeout to ensure that the connection is completely
|
||||
// cleaned up within 30 seconds, even if the clean close procedure
|
||||
// fails for whatever reason
|
||||
// First cleanup any pre-existing timeout from an earlier "terminate" call,
|
||||
// if one exists. Otherwise terminate calls in quick succession will leak timeouts
|
||||
// and hold the program open for `closeTimout` time.
|
||||
if (this._closeTimer) { clearTimeout(this._closeTimer); }
|
||||
this._closeTimer = setTimeout(cleanupWebsocketResources.bind(this, true), closeTimeout);
|
||||
} else if (this.readyState === WebSocket.CONNECTING) {
|
||||
cleanupWebsocketResources.call(this, true);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose bufferedAmount
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
Object.defineProperty(WebSocket.prototype, 'bufferedAmount', {
|
||||
get: function get() {
|
||||
var amount = 0;
|
||||
if (this._socket) {
|
||||
amount = this._socket.bufferSize || 0;
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Emulates the W3C Browser based WebSocket interface using function members.
|
||||
*
|
||||
* @see http://dev.w3.org/html5/websockets/#the-websocket-interface
|
||||
* @api public
|
||||
*/
|
||||
['open', 'error', 'close', 'message'].forEach(function(method) {
|
||||
Object.defineProperty(WebSocket.prototype, 'on' + method, {
|
||||
/**
|
||||
* Returns the current listener
|
||||
*
|
||||
* @returns {Mixed} the set function or undefined
|
||||
* @api public
|
||||
*/
|
||||
get: function get() {
|
||||
var listener = this.listeners(method)[0];
|
||||
return listener ? (listener._listener ? listener._listener : listener) : undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Start listening for events
|
||||
*
|
||||
* @param {Function} listener the listener
|
||||
* @returns {Mixed} the set function or undefined
|
||||
* @api public
|
||||
*/
|
||||
set: function set(listener) {
|
||||
this.removeAllListeners(method);
|
||||
this.addEventListener(method, listener);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Emulates the W3C Browser based WebSocket interface using addEventListener.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en/DOM/element.addEventListener
|
||||
* @see http://dev.w3.org/html5/websockets/#the-websocket-interface
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.addEventListener = function(method, listener) {
|
||||
var target = this;
|
||||
|
||||
function onMessage (data, flags) {
|
||||
listener.call(target, new MessageEvent(data, flags.binary ? 'Binary' : 'Text', target));
|
||||
}
|
||||
|
||||
function onClose (code, message) {
|
||||
listener.call(target, new CloseEvent(code, message, target));
|
||||
}
|
||||
|
||||
function onError (event) {
|
||||
event.target = target;
|
||||
listener.call(target, event);
|
||||
}
|
||||
|
||||
function onOpen () {
|
||||
listener.call(target, new OpenEvent(target));
|
||||
}
|
||||
|
||||
if (typeof listener === 'function') {
|
||||
if (method === 'message') {
|
||||
// store a reference so we can return the original function from the
|
||||
// addEventListener hook
|
||||
onMessage._listener = listener;
|
||||
this.on(method, onMessage);
|
||||
} else if (method === 'close') {
|
||||
// store a reference so we can return the original function from the
|
||||
// addEventListener hook
|
||||
onClose._listener = listener;
|
||||
this.on(method, onClose);
|
||||
} else if (method === 'error') {
|
||||
// store a reference so we can return the original function from the
|
||||
// addEventListener hook
|
||||
onError._listener = listener;
|
||||
this.on(method, onError);
|
||||
} else if (method === 'open') {
|
||||
// store a reference so we can return the original function from the
|
||||
// addEventListener hook
|
||||
onOpen._listener = listener;
|
||||
this.on(method, onOpen);
|
||||
} else {
|
||||
this.on(method, listener);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = WebSocket;
|
||||
|
||||
/**
|
||||
* W3C MessageEvent
|
||||
*
|
||||
* @see http://www.w3.org/TR/html5/comms.html
|
||||
* @constructor
|
||||
* @api private
|
||||
*/
|
||||
function MessageEvent(dataArg, typeArg, target) {
|
||||
this.data = dataArg;
|
||||
this.type = typeArg;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* W3C CloseEvent
|
||||
*
|
||||
* @see http://www.w3.org/TR/html5/comms.html
|
||||
* @constructor
|
||||
* @api private
|
||||
*/
|
||||
function CloseEvent(code, reason, target) {
|
||||
this.wasClean = (typeof code === 'undefined' || code === 1000);
|
||||
this.code = code;
|
||||
this.reason = reason;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* W3C OpenEvent
|
||||
*
|
||||
* @see http://www.w3.org/TR/html5/comms.html
|
||||
* @constructor
|
||||
* @api private
|
||||
*/
|
||||
function OpenEvent(target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entirely private apis,
|
||||
* which may or may not be bound to a sepcific WebSocket instance.
|
||||
*/
|
||||
function initAsServerClient(req, socket, upgradeHead, options) {
|
||||
options = new Options({
|
||||
protocolVersion: protocolVersion,
|
||||
protocol: null,
|
||||
extensions: {}
|
||||
}).merge(options);
|
||||
|
||||
// expose state properties
|
||||
this.protocol = options.value.protocol;
|
||||
this.protocolVersion = options.value.protocolVersion;
|
||||
this.extensions = options.value.extensions;
|
||||
this.supports.binary = (this.protocolVersion !== 'hixie-76');
|
||||
this.upgradeReq = req;
|
||||
this.readyState = WebSocket.CONNECTING;
|
||||
this._isServer = true;
|
||||
|
||||
// establish connection
|
||||
if (options.value.protocolVersion === 'hixie-76') {
|
||||
establishConnection.call(this, ReceiverHixie, SenderHixie, socket, upgradeHead);
|
||||
} else {
|
||||
establishConnection.call(this, Receiver, Sender, socket, upgradeHead);
|
||||
}
|
||||
}
|
||||
|
||||
function initAsClient(address, protocols, options) {
|
||||
options = new Options({
|
||||
origin: null,
|
||||
protocolVersion: protocolVersion,
|
||||
host: null,
|
||||
headers: null,
|
||||
protocol: protocols.join(','),
|
||||
agent: null,
|
||||
|
||||
// ssl-related options
|
||||
pfx: null,
|
||||
key: null,
|
||||
passphrase: null,
|
||||
cert: null,
|
||||
ca: null,
|
||||
ciphers: null,
|
||||
rejectUnauthorized: null,
|
||||
perMessageDeflate: true
|
||||
}).merge(options);
|
||||
|
||||
if (options.value.protocolVersion !== 8 && options.value.protocolVersion !== 13) {
|
||||
throw new Error('unsupported protocol version');
|
||||
}
|
||||
|
||||
// verify URL and establish http class
|
||||
var serverUrl = url.parse(address);
|
||||
var isUnixSocket = serverUrl.protocol === 'ws+unix:';
|
||||
if (!serverUrl.host && !isUnixSocket) throw new Error('invalid url');
|
||||
var isSecure = serverUrl.protocol === 'wss:' || serverUrl.protocol === 'https:';
|
||||
var httpObj = isSecure ? https : http;
|
||||
var port = serverUrl.port || (isSecure ? 443 : 80);
|
||||
var auth = serverUrl.auth;
|
||||
|
||||
// prepare extensions
|
||||
var extensionsOffer = {};
|
||||
var perMessageDeflate;
|
||||
if (options.value.perMessageDeflate) {
|
||||
perMessageDeflate = new PerMessageDeflate(typeof options.value.perMessageDeflate !== true ? options.value.perMessageDeflate : {}, false);
|
||||
extensionsOffer[PerMessageDeflate.extensionName] = perMessageDeflate.offer();
|
||||
}
|
||||
|
||||
// expose state properties
|
||||
this._isServer = false;
|
||||
this.url = address;
|
||||
this.protocolVersion = options.value.protocolVersion;
|
||||
this.supports.binary = (this.protocolVersion !== 'hixie-76');
|
||||
|
||||
// begin handshake
|
||||
var key = new Buffer(options.value.protocolVersion + '-' + Date.now()).toString('base64');
|
||||
var shasum = crypto.createHash('sha1');
|
||||
shasum.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11');
|
||||
var expectedServerKey = shasum.digest('base64');
|
||||
|
||||
var agent = options.value.agent;
|
||||
|
||||
var headerHost = serverUrl.hostname;
|
||||
// Append port number to Host and Origin header, only if specified in the url
|
||||
// and non-default
|
||||
if (serverUrl.port) {
|
||||
if ((isSecure && (port !== 443)) || (!isSecure && (port !== 80))){
|
||||
headerHost = headerHost + ':' + port;
|
||||
}
|
||||
}
|
||||
|
||||
var requestOptions = {
|
||||
port: port,
|
||||
host: serverUrl.hostname,
|
||||
headers: {
|
||||
'Connection': 'Upgrade',
|
||||
'Upgrade': 'websocket',
|
||||
'Host': headerHost,
|
||||
'Origin': headerHost,
|
||||
'Sec-WebSocket-Version': options.value.protocolVersion,
|
||||
'Sec-WebSocket-Key': key
|
||||
}
|
||||
};
|
||||
|
||||
// If we have basic auth.
|
||||
if (auth) {
|
||||
requestOptions.headers.Authorization = 'Basic ' + new Buffer(auth).toString('base64');
|
||||
}
|
||||
|
||||
if (options.value.protocol) {
|
||||
requestOptions.headers['Sec-WebSocket-Protocol'] = options.value.protocol;
|
||||
}
|
||||
|
||||
if (options.value.host) {
|
||||
requestOptions.headers.Host = options.value.host;
|
||||
}
|
||||
|
||||
if (options.value.headers) {
|
||||
for (var header in options.value.headers) {
|
||||
if (options.value.headers.hasOwnProperty(header)) {
|
||||
requestOptions.headers[header] = options.value.headers[header];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(extensionsOffer).length) {
|
||||
requestOptions.headers['Sec-WebSocket-Extensions'] = Extensions.format(extensionsOffer);
|
||||
}
|
||||
|
||||
if (options.isDefinedAndNonNull('pfx')
|
||||
|| options.isDefinedAndNonNull('key')
|
||||
|| options.isDefinedAndNonNull('passphrase')
|
||||
|| options.isDefinedAndNonNull('cert')
|
||||
|| options.isDefinedAndNonNull('ca')
|
||||
|| options.isDefinedAndNonNull('ciphers')
|
||||
|| options.isDefinedAndNonNull('rejectUnauthorized')) {
|
||||
|
||||
if (options.isDefinedAndNonNull('pfx')) requestOptions.pfx = options.value.pfx;
|
||||
if (options.isDefinedAndNonNull('key')) requestOptions.key = options.value.key;
|
||||
if (options.isDefinedAndNonNull('passphrase')) requestOptions.passphrase = options.value.passphrase;
|
||||
if (options.isDefinedAndNonNull('cert')) requestOptions.cert = options.value.cert;
|
||||
if (options.isDefinedAndNonNull('ca')) requestOptions.ca = options.value.ca;
|
||||
if (options.isDefinedAndNonNull('ciphers')) requestOptions.ciphers = options.value.ciphers;
|
||||
if (options.isDefinedAndNonNull('rejectUnauthorized')) requestOptions.rejectUnauthorized = options.value.rejectUnauthorized;
|
||||
|
||||
if (!agent) {
|
||||
// global agent ignores client side certificates
|
||||
agent = new httpObj.Agent(requestOptions);
|
||||
}
|
||||
}
|
||||
|
||||
requestOptions.path = serverUrl.path || '/';
|
||||
|
||||
if (agent) {
|
||||
requestOptions.agent = agent;
|
||||
}
|
||||
|
||||
if (isUnixSocket) {
|
||||
requestOptions.socketPath = serverUrl.pathname;
|
||||
}
|
||||
if (options.value.origin) {
|
||||
if (options.value.protocolVersion < 13) requestOptions.headers['Sec-WebSocket-Origin'] = options.value.origin;
|
||||
else requestOptions.headers.Origin = options.value.origin;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var req = httpObj.request(requestOptions);
|
||||
|
||||
req.on('error', function onerror(error) {
|
||||
self.emit('error', error);
|
||||
cleanupWebsocketResources.call(this, error);
|
||||
});
|
||||
|
||||
req.once('response', function response(res) {
|
||||
var error;
|
||||
|
||||
if (!self.emit('unexpected-response', req, res)) {
|
||||
error = new Error('unexpected server response (' + res.statusCode + ')');
|
||||
req.abort();
|
||||
self.emit('error', error);
|
||||
}
|
||||
|
||||
cleanupWebsocketResources.call(this, error);
|
||||
});
|
||||
|
||||
req.once('upgrade', function upgrade(res, socket, upgradeHead) {
|
||||
if (self.readyState === WebSocket.CLOSED) {
|
||||
// client closed before server accepted connection
|
||||
self.emit('close');
|
||||
self.removeAllListeners();
|
||||
socket.end();
|
||||
return;
|
||||
}
|
||||
|
||||
var serverKey = res.headers['sec-websocket-accept'];
|
||||
if (typeof serverKey === 'undefined' || serverKey !== expectedServerKey) {
|
||||
self.emit('error', 'invalid server key');
|
||||
self.removeAllListeners();
|
||||
socket.end();
|
||||
return;
|
||||
}
|
||||
|
||||
var serverProt = res.headers['sec-websocket-protocol'];
|
||||
var protList = (options.value.protocol || "").split(/, */);
|
||||
var protError = null;
|
||||
|
||||
if (!options.value.protocol && serverProt) {
|
||||
protError = 'server sent a subprotocol even though none requested';
|
||||
} else if (options.value.protocol && !serverProt) {
|
||||
protError = 'server sent no subprotocol even though requested';
|
||||
} else if (serverProt && protList.indexOf(serverProt) === -1) {
|
||||
protError = 'server responded with an invalid protocol';
|
||||
}
|
||||
|
||||
if (protError) {
|
||||
self.emit('error', protError);
|
||||
self.removeAllListeners();
|
||||
socket.end();
|
||||
return;
|
||||
} else if (serverProt) {
|
||||
self.protocol = serverProt;
|
||||
}
|
||||
|
||||
var serverExtensions = Extensions.parse(res.headers['sec-websocket-extensions']);
|
||||
if (perMessageDeflate && serverExtensions[PerMessageDeflate.extensionName]) {
|
||||
try {
|
||||
perMessageDeflate.accept(serverExtensions[PerMessageDeflate.extensionName]);
|
||||
} catch (err) {
|
||||
self.emit('error', 'invalid extension parameter');
|
||||
self.removeAllListeners();
|
||||
socket.end();
|
||||
return;
|
||||
}
|
||||
self.extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
|
||||
}
|
||||
|
||||
establishConnection.call(self, Receiver, Sender, socket, upgradeHead);
|
||||
|
||||
// perform cleanup on http resources
|
||||
req.removeAllListeners();
|
||||
req = null;
|
||||
agent = null;
|
||||
});
|
||||
|
||||
req.end();
|
||||
this.readyState = WebSocket.CONNECTING;
|
||||
}
|
||||
|
||||
function establishConnection(ReceiverClass, SenderClass, socket, upgradeHead) {
|
||||
var ultron = this._ultron = new Ultron(socket);
|
||||
this._socket = socket;
|
||||
|
||||
socket.setTimeout(0);
|
||||
socket.setNoDelay(true);
|
||||
var self = this;
|
||||
this._receiver = new ReceiverClass(this.extensions);
|
||||
|
||||
// socket cleanup handlers
|
||||
ultron.on('end', cleanupWebsocketResources.bind(this));
|
||||
ultron.on('close', cleanupWebsocketResources.bind(this));
|
||||
ultron.on('error', cleanupWebsocketResources.bind(this));
|
||||
|
||||
// ensure that the upgradeHead is added to the receiver
|
||||
function firstHandler(data) {
|
||||
if (self.readyState !== WebSocket.OPEN && self.readyState !== WebSocket.CLOSING) return;
|
||||
|
||||
if (upgradeHead && upgradeHead.length > 0) {
|
||||
self.bytesReceived += upgradeHead.length;
|
||||
var head = upgradeHead;
|
||||
upgradeHead = null;
|
||||
self._receiver.add(head);
|
||||
}
|
||||
|
||||
dataHandler = realHandler;
|
||||
|
||||
if (data) {
|
||||
self.bytesReceived += data.length;
|
||||
self._receiver.add(data);
|
||||
}
|
||||
}
|
||||
|
||||
// subsequent packets are pushed straight to the receiver
|
||||
function realHandler(data) {
|
||||
if (data) self.bytesReceived += data.length;
|
||||
self._receiver.add(data);
|
||||
}
|
||||
|
||||
var dataHandler = firstHandler;
|
||||
|
||||
// if data was passed along with the http upgrade,
|
||||
// this will schedule a push of that on to the receiver.
|
||||
// this has to be done on next tick, since the caller
|
||||
// hasn't had a chance to set event handlers on this client
|
||||
// object yet.
|
||||
process.nextTick(firstHandler);
|
||||
|
||||
// receiver event handlers
|
||||
self._receiver.ontext = function ontext(data, flags) {
|
||||
flags = flags || {};
|
||||
|
||||
self.emit('message', data, flags);
|
||||
};
|
||||
|
||||
self._receiver.onbinary = function onbinary(data, flags) {
|
||||
flags = flags || {};
|
||||
|
||||
flags.binary = true;
|
||||
self.emit('message', data, flags);
|
||||
};
|
||||
|
||||
self._receiver.onping = function onping(data, flags) {
|
||||
flags = flags || {};
|
||||
|
||||
self.pong(data, {
|
||||
mask: !self._isServer,
|
||||
binary: flags.binary === true
|
||||
}, true);
|
||||
|
||||
self.emit('ping', data, flags);
|
||||
};
|
||||
|
||||
self._receiver.onpong = function onpong(data, flags) {
|
||||
self.emit('pong', data, flags || {});
|
||||
};
|
||||
|
||||
self._receiver.onclose = function onclose(code, data, flags) {
|
||||
flags = flags || {};
|
||||
|
||||
self._closeReceived = true;
|
||||
self.close(code, data);
|
||||
};
|
||||
|
||||
self._receiver.onerror = function onerror(reason, errorCode) {
|
||||
// close the connection when the receiver reports a HyBi error code
|
||||
self.close(typeof errorCode !== 'undefined' ? errorCode : 1002, '');
|
||||
self.emit('error', reason, errorCode);
|
||||
};
|
||||
|
||||
// finalize the client
|
||||
this._sender = new SenderClass(socket, this.extensions);
|
||||
this._sender.on('error', function onerror(error) {
|
||||
self.close(1002, '');
|
||||
self.emit('error', error);
|
||||
});
|
||||
|
||||
this.readyState = WebSocket.OPEN;
|
||||
this.emit('open');
|
||||
|
||||
ultron.on('data', dataHandler);
|
||||
}
|
||||
|
||||
function startQueue(instance) {
|
||||
instance._queue = instance._queue || [];
|
||||
}
|
||||
|
||||
function executeQueueSends(instance) {
|
||||
var queue = instance._queue;
|
||||
if (typeof queue === 'undefined') return;
|
||||
|
||||
delete instance._queue;
|
||||
for (var i = 0, l = queue.length; i < l; ++i) {
|
||||
queue[i]();
|
||||
}
|
||||
}
|
||||
|
||||
function sendStream(instance, stream, options, cb) {
|
||||
stream.on('data', function incoming(data) {
|
||||
if (instance.readyState !== WebSocket.OPEN) {
|
||||
if (typeof cb === 'function') cb(new Error('not opened'));
|
||||
else {
|
||||
delete instance._queue;
|
||||
instance.emit('error', new Error('not opened'));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
options.fin = false;
|
||||
instance._sender.send(data, options);
|
||||
});
|
||||
|
||||
stream.on('end', function end() {
|
||||
if (instance.readyState !== WebSocket.OPEN) {
|
||||
if (typeof cb === 'function') cb(new Error('not opened'));
|
||||
else {
|
||||
delete instance._queue;
|
||||
instance.emit('error', new Error('not opened'));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
options.fin = true;
|
||||
instance._sender.send(null, options);
|
||||
|
||||
if (typeof cb === 'function') cb(null);
|
||||
});
|
||||
}
|
||||
|
||||
function cleanupWebsocketResources(error) {
|
||||
if (this.readyState === WebSocket.CLOSED) return;
|
||||
|
||||
var emitClose = this.readyState !== WebSocket.CONNECTING;
|
||||
this.readyState = WebSocket.CLOSED;
|
||||
|
||||
clearTimeout(this._closeTimer);
|
||||
this._closeTimer = null;
|
||||
|
||||
if (emitClose) {
|
||||
this.emit('close', this._closeCode || 1000, this._closeMessage || '');
|
||||
}
|
||||
|
||||
if (this._socket) {
|
||||
if (this._ultron) this._ultron.destroy();
|
||||
this._socket.on('error', function onerror() {
|
||||
try { this.destroy(); }
|
||||
catch (e) {}
|
||||
});
|
||||
|
||||
try {
|
||||
if (!error) this._socket.end();
|
||||
else this._socket.destroy();
|
||||
} catch (e) { /* Ignore termination errors */ }
|
||||
|
||||
this._socket = null;
|
||||
this._ultron = null;
|
||||
}
|
||||
|
||||
if (this._sender) {
|
||||
this._sender.removeAllListeners();
|
||||
this._sender = null;
|
||||
}
|
||||
|
||||
if (this._receiver) {
|
||||
this._receiver.cleanup();
|
||||
this._receiver = null;
|
||||
}
|
||||
|
||||
this.removeAllListeners();
|
||||
this.on('error', function onerror() {}); // catch all errors after this
|
||||
delete this._queue;
|
||||
}
|
||||
+501
@@ -0,0 +1,501 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var util = require('util')
|
||||
, events = require('events')
|
||||
, http = require('http')
|
||||
, crypto = require('crypto')
|
||||
, Options = require('options')
|
||||
, WebSocket = require('./WebSocket')
|
||||
, Extensions = require('./Extensions')
|
||||
, PerMessageDeflate = require('./PerMessageDeflate')
|
||||
, tls = require('tls')
|
||||
, url = require('url');
|
||||
|
||||
/**
|
||||
* WebSocket Server implementation
|
||||
*/
|
||||
|
||||
function WebSocketServer(options, callback) {
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
options = new Options({
|
||||
host: '0.0.0.0',
|
||||
port: null,
|
||||
server: null,
|
||||
verifyClient: null,
|
||||
handleProtocols: null,
|
||||
path: null,
|
||||
noServer: false,
|
||||
disableHixie: false,
|
||||
clientTracking: true,
|
||||
perMessageDeflate: true
|
||||
}).merge(options);
|
||||
|
||||
if (!options.isDefinedAndNonNull('port') && !options.isDefinedAndNonNull('server') && !options.value.noServer) {
|
||||
throw new TypeError('`port` or a `server` must be provided');
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
if (options.isDefinedAndNonNull('port')) {
|
||||
this._server = http.createServer(function (req, res) {
|
||||
res.writeHead(200, {'Content-Type': 'text/plain'});
|
||||
res.end('Not implemented');
|
||||
});
|
||||
this._server.listen(options.value.port, options.value.host, callback);
|
||||
this._closeServer = function() { if (self._server) self._server.close(); };
|
||||
}
|
||||
else if (options.value.server) {
|
||||
this._server = options.value.server;
|
||||
if (options.value.path) {
|
||||
// take note of the path, to avoid collisions when multiple websocket servers are
|
||||
// listening on the same http server
|
||||
if (this._server._webSocketPaths && options.value.server._webSocketPaths[options.value.path]) {
|
||||
throw new Error('two instances of WebSocketServer cannot listen on the same http server path');
|
||||
}
|
||||
if (typeof this._server._webSocketPaths !== 'object') {
|
||||
this._server._webSocketPaths = {};
|
||||
}
|
||||
this._server._webSocketPaths[options.value.path] = 1;
|
||||
}
|
||||
}
|
||||
if (this._server) this._server.once('listening', function() { self.emit('listening'); });
|
||||
|
||||
if (typeof this._server != 'undefined') {
|
||||
this._server.on('error', function(error) {
|
||||
self.emit('error', error)
|
||||
});
|
||||
this._server.on('upgrade', function(req, socket, upgradeHead) {
|
||||
//copy upgradeHead to avoid retention of large slab buffers used in node core
|
||||
var head = new Buffer(upgradeHead.length);
|
||||
upgradeHead.copy(head);
|
||||
|
||||
self.handleUpgrade(req, socket, head, function(client) {
|
||||
self.emit('connection'+req.url, client);
|
||||
self.emit('connection', client);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.options = options.value;
|
||||
this.path = options.value.path;
|
||||
this.clients = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherits from EventEmitter.
|
||||
*/
|
||||
|
||||
util.inherits(WebSocketServer, events.EventEmitter);
|
||||
|
||||
/**
|
||||
* Immediately shuts down the connection.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
WebSocketServer.prototype.close = function() {
|
||||
// terminate all associated clients
|
||||
var error = null;
|
||||
try {
|
||||
for (var i = 0, l = this.clients.length; i < l; ++i) {
|
||||
this.clients[i].terminate();
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
// remove path descriptor, if any
|
||||
if (this.path && this._server._webSocketPaths) {
|
||||
delete this._server._webSocketPaths[this.path];
|
||||
if (Object.keys(this._server._webSocketPaths).length == 0) {
|
||||
delete this._server._webSocketPaths;
|
||||
}
|
||||
}
|
||||
|
||||
// close the http server if it was internally created
|
||||
try {
|
||||
if (typeof this._closeServer !== 'undefined') {
|
||||
this._closeServer();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
delete this._server;
|
||||
}
|
||||
if (error) throw error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a HTTP Upgrade request.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
WebSocketServer.prototype.handleUpgrade = function(req, socket, upgradeHead, cb) {
|
||||
// check for wrong path
|
||||
if (this.options.path) {
|
||||
var u = url.parse(req.url);
|
||||
if (u && u.pathname !== this.options.path) return;
|
||||
}
|
||||
|
||||
if (typeof req.headers.upgrade === 'undefined' || req.headers.upgrade.toLowerCase() !== 'websocket') {
|
||||
abortConnection(socket, 400, 'Bad Request');
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.headers['sec-websocket-key1']) handleHixieUpgrade.apply(this, arguments);
|
||||
else handleHybiUpgrade.apply(this, arguments);
|
||||
}
|
||||
|
||||
module.exports = WebSocketServer;
|
||||
|
||||
/**
|
||||
* Entirely private apis,
|
||||
* which may or may not be bound to a sepcific WebSocket instance.
|
||||
*/
|
||||
|
||||
function handleHybiUpgrade(req, socket, upgradeHead, cb) {
|
||||
// handle premature socket errors
|
||||
var errorHandler = function() {
|
||||
try { socket.destroy(); } catch (e) {}
|
||||
}
|
||||
socket.on('error', errorHandler);
|
||||
|
||||
// verify key presence
|
||||
if (!req.headers['sec-websocket-key']) {
|
||||
abortConnection(socket, 400, 'Bad Request');
|
||||
return;
|
||||
}
|
||||
|
||||
// verify version
|
||||
var version = parseInt(req.headers['sec-websocket-version']);
|
||||
if ([8, 13].indexOf(version) === -1) {
|
||||
abortConnection(socket, 400, 'Bad Request');
|
||||
return;
|
||||
}
|
||||
|
||||
// verify protocol
|
||||
var protocols = req.headers['sec-websocket-protocol'];
|
||||
|
||||
// verify client
|
||||
var origin = version < 13 ?
|
||||
req.headers['sec-websocket-origin'] :
|
||||
req.headers['origin'];
|
||||
|
||||
// handle extensions offer
|
||||
var extensionsOffer = Extensions.parse(req.headers['sec-websocket-extensions']);
|
||||
|
||||
// handler to call when the connection sequence completes
|
||||
var self = this;
|
||||
var completeHybiUpgrade2 = function(protocol) {
|
||||
|
||||
// calc key
|
||||
var key = req.headers['sec-websocket-key'];
|
||||
var shasum = crypto.createHash('sha1');
|
||||
shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
key = shasum.digest('base64');
|
||||
|
||||
var headers = [
|
||||
'HTTP/1.1 101 Switching Protocols'
|
||||
, 'Upgrade: websocket'
|
||||
, 'Connection: Upgrade'
|
||||
, 'Sec-WebSocket-Accept: ' + key
|
||||
];
|
||||
|
||||
if (typeof protocol != 'undefined') {
|
||||
headers.push('Sec-WebSocket-Protocol: ' + protocol);
|
||||
}
|
||||
|
||||
var extensions = {};
|
||||
try {
|
||||
extensions = acceptExtensions.call(self, extensionsOffer);
|
||||
} catch (err) {
|
||||
abortConnection(socket, 400, 'Bad Request');
|
||||
return;
|
||||
}
|
||||
|
||||
if (Object.keys(extensions).length) {
|
||||
var serverExtensions = {};
|
||||
Object.keys(extensions).forEach(function(token) {
|
||||
serverExtensions[token] = [extensions[token].params]
|
||||
});
|
||||
headers.push('Sec-WebSocket-Extensions: ' + Extensions.format(serverExtensions));
|
||||
}
|
||||
|
||||
// allows external modification/inspection of handshake headers
|
||||
self.emit('headers', headers);
|
||||
|
||||
socket.setTimeout(0);
|
||||
socket.setNoDelay(true);
|
||||
try {
|
||||
socket.write(headers.concat('', '').join('\r\n'));
|
||||
}
|
||||
catch (e) {
|
||||
// if the upgrade write fails, shut the connection down hard
|
||||
try { socket.destroy(); } catch (e) {}
|
||||
return;
|
||||
}
|
||||
|
||||
var client = new WebSocket([req, socket, upgradeHead], {
|
||||
protocolVersion: version,
|
||||
protocol: protocol,
|
||||
extensions: extensions
|
||||
});
|
||||
|
||||
if (self.options.clientTracking) {
|
||||
self.clients.push(client);
|
||||
client.on('close', function() {
|
||||
var index = self.clients.indexOf(client);
|
||||
if (index != -1) {
|
||||
self.clients.splice(index, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// signal upgrade complete
|
||||
socket.removeListener('error', errorHandler);
|
||||
cb(client);
|
||||
}
|
||||
|
||||
// optionally call external protocol selection handler before
|
||||
// calling completeHybiUpgrade2
|
||||
var completeHybiUpgrade1 = function() {
|
||||
// choose from the sub-protocols
|
||||
if (typeof self.options.handleProtocols == 'function') {
|
||||
var protList = (protocols || "").split(/, */);
|
||||
var callbackCalled = false;
|
||||
var res = self.options.handleProtocols(protList, function(result, protocol) {
|
||||
callbackCalled = true;
|
||||
if (!result) abortConnection(socket, 401, 'Unauthorized');
|
||||
else completeHybiUpgrade2(protocol);
|
||||
});
|
||||
if (!callbackCalled) {
|
||||
// the handleProtocols handler never called our callback
|
||||
abortConnection(socket, 501, 'Could not process protocols');
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (typeof protocols !== 'undefined') {
|
||||
completeHybiUpgrade2(protocols.split(/, */)[0]);
|
||||
}
|
||||
else {
|
||||
completeHybiUpgrade2();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// optionally call external client verification handler
|
||||
if (typeof this.options.verifyClient == 'function') {
|
||||
var info = {
|
||||
origin: origin,
|
||||
secure: typeof req.connection.authorized !== 'undefined' || typeof req.connection.encrypted !== 'undefined',
|
||||
req: req
|
||||
};
|
||||
if (this.options.verifyClient.length == 2) {
|
||||
this.options.verifyClient(info, function(result, code, name) {
|
||||
if (typeof code === 'undefined') code = 401;
|
||||
if (typeof name === 'undefined') name = http.STATUS_CODES[code];
|
||||
|
||||
if (!result) abortConnection(socket, code, name);
|
||||
else completeHybiUpgrade1();
|
||||
});
|
||||
return;
|
||||
}
|
||||
else if (!this.options.verifyClient(info)) {
|
||||
abortConnection(socket, 401, 'Unauthorized');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
completeHybiUpgrade1();
|
||||
}
|
||||
|
||||
function handleHixieUpgrade(req, socket, upgradeHead, cb) {
|
||||
// handle premature socket errors
|
||||
var errorHandler = function() {
|
||||
try { socket.destroy(); } catch (e) {}
|
||||
}
|
||||
socket.on('error', errorHandler);
|
||||
|
||||
// bail if options prevent hixie
|
||||
if (this.options.disableHixie) {
|
||||
abortConnection(socket, 401, 'Hixie support disabled');
|
||||
return;
|
||||
}
|
||||
|
||||
// verify key presence
|
||||
if (!req.headers['sec-websocket-key2']) {
|
||||
abortConnection(socket, 400, 'Bad Request');
|
||||
return;
|
||||
}
|
||||
|
||||
var origin = req.headers['origin']
|
||||
, self = this;
|
||||
|
||||
// setup handshake completion to run after client has been verified
|
||||
var onClientVerified = function() {
|
||||
var wshost;
|
||||
if (!req.headers['x-forwarded-host'])
|
||||
wshost = req.headers.host;
|
||||
else
|
||||
wshost = req.headers['x-forwarded-host'];
|
||||
var location = ((req.headers['x-forwarded-proto'] === 'https' || socket.encrypted) ? 'wss' : 'ws') + '://' + wshost + req.url
|
||||
, protocol = req.headers['sec-websocket-protocol'];
|
||||
|
||||
// handshake completion code to run once nonce has been successfully retrieved
|
||||
var completeHandshake = function(nonce, rest) {
|
||||
// calculate key
|
||||
var k1 = req.headers['sec-websocket-key1']
|
||||
, k2 = req.headers['sec-websocket-key2']
|
||||
, md5 = crypto.createHash('md5');
|
||||
|
||||
[k1, k2].forEach(function (k) {
|
||||
var n = parseInt(k.replace(/[^\d]/g, ''))
|
||||
, spaces = k.replace(/[^ ]/g, '').length;
|
||||
if (spaces === 0 || n % spaces !== 0){
|
||||
abortConnection(socket, 400, 'Bad Request');
|
||||
return;
|
||||
}
|
||||
n /= spaces;
|
||||
md5.update(String.fromCharCode(
|
||||
n >> 24 & 0xFF,
|
||||
n >> 16 & 0xFF,
|
||||
n >> 8 & 0xFF,
|
||||
n & 0xFF));
|
||||
});
|
||||
md5.update(nonce.toString('binary'));
|
||||
|
||||
var headers = [
|
||||
'HTTP/1.1 101 Switching Protocols'
|
||||
, 'Upgrade: WebSocket'
|
||||
, 'Connection: Upgrade'
|
||||
, 'Sec-WebSocket-Location: ' + location
|
||||
];
|
||||
if (typeof protocol != 'undefined') headers.push('Sec-WebSocket-Protocol: ' + protocol);
|
||||
if (typeof origin != 'undefined') headers.push('Sec-WebSocket-Origin: ' + origin);
|
||||
|
||||
socket.setTimeout(0);
|
||||
socket.setNoDelay(true);
|
||||
try {
|
||||
// merge header and hash buffer
|
||||
var headerBuffer = new Buffer(headers.concat('', '').join('\r\n'));
|
||||
var hashBuffer = new Buffer(md5.digest('binary'), 'binary');
|
||||
var handshakeBuffer = new Buffer(headerBuffer.length + hashBuffer.length);
|
||||
headerBuffer.copy(handshakeBuffer, 0);
|
||||
hashBuffer.copy(handshakeBuffer, headerBuffer.length);
|
||||
|
||||
// do a single write, which - upon success - causes a new client websocket to be setup
|
||||
socket.write(handshakeBuffer, 'binary', function(err) {
|
||||
if (err) return; // do not create client if an error happens
|
||||
var client = new WebSocket([req, socket, rest], {
|
||||
protocolVersion: 'hixie-76',
|
||||
protocol: protocol
|
||||
});
|
||||
if (self.options.clientTracking) {
|
||||
self.clients.push(client);
|
||||
client.on('close', function() {
|
||||
var index = self.clients.indexOf(client);
|
||||
if (index != -1) {
|
||||
self.clients.splice(index, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// signal upgrade complete
|
||||
socket.removeListener('error', errorHandler);
|
||||
cb(client);
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
try { socket.destroy(); } catch (e) {}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// retrieve nonce
|
||||
var nonceLength = 8;
|
||||
if (upgradeHead && upgradeHead.length >= nonceLength) {
|
||||
var nonce = upgradeHead.slice(0, nonceLength);
|
||||
var rest = upgradeHead.length > nonceLength ? upgradeHead.slice(nonceLength) : null;
|
||||
completeHandshake.call(self, nonce, rest);
|
||||
}
|
||||
else {
|
||||
// nonce not present in upgradeHead, so we must wait for enough data
|
||||
// data to arrive before continuing
|
||||
var nonce = new Buffer(nonceLength);
|
||||
upgradeHead.copy(nonce, 0);
|
||||
var received = upgradeHead.length;
|
||||
var rest = null;
|
||||
var handler = function (data) {
|
||||
var toRead = Math.min(data.length, nonceLength - received);
|
||||
if (toRead === 0) return;
|
||||
data.copy(nonce, received, 0, toRead);
|
||||
received += toRead;
|
||||
if (received == nonceLength) {
|
||||
socket.removeListener('data', handler);
|
||||
if (toRead < data.length) rest = data.slice(toRead);
|
||||
completeHandshake.call(self, nonce, rest);
|
||||
}
|
||||
}
|
||||
socket.on('data', handler);
|
||||
}
|
||||
}
|
||||
|
||||
// verify client
|
||||
if (typeof this.options.verifyClient == 'function') {
|
||||
var info = {
|
||||
origin: origin,
|
||||
secure: typeof req.connection.authorized !== 'undefined' || typeof req.connection.encrypted !== 'undefined',
|
||||
req: req
|
||||
};
|
||||
if (this.options.verifyClient.length == 2) {
|
||||
var self = this;
|
||||
this.options.verifyClient(info, function(result, code, name) {
|
||||
if (typeof code === 'undefined') code = 401;
|
||||
if (typeof name === 'undefined') name = http.STATUS_CODES[code];
|
||||
|
||||
if (!result) abortConnection(socket, code, name);
|
||||
else onClientVerified.apply(self);
|
||||
});
|
||||
return;
|
||||
}
|
||||
else if (!this.options.verifyClient(info)) {
|
||||
abortConnection(socket, 401, 'Unauthorized');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// no client verification required
|
||||
onClientVerified();
|
||||
}
|
||||
|
||||
function acceptExtensions(offer) {
|
||||
var extensions = {};
|
||||
var options = this.options.perMessageDeflate;
|
||||
if (options && offer[PerMessageDeflate.extensionName]) {
|
||||
var perMessageDeflate = new PerMessageDeflate(options !== true ? options : {}, true);
|
||||
perMessageDeflate.accept(offer[PerMessageDeflate.extensionName]);
|
||||
extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
|
||||
}
|
||||
return extensions;
|
||||
}
|
||||
|
||||
function abortConnection(socket, code, name) {
|
||||
try {
|
||||
var response = [
|
||||
'HTTP/1.1 ' + code + ' ' + name,
|
||||
'Content-type: text/html'
|
||||
];
|
||||
socket.write(response.concat('', '').join('\r\n'));
|
||||
}
|
||||
catch (e) { /* ignore errors - we've aborted this connection */ }
|
||||
finally {
|
||||
// ensure that an early aborted connection is shut down completely
|
||||
try { socket.destroy(); } catch (e) {}
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var global = (function() { return this; })();
|
||||
|
||||
/**
|
||||
* WebSocket constructor.
|
||||
*/
|
||||
|
||||
var WebSocket = global.WebSocket || global.MozWebSocket;
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
*/
|
||||
|
||||
module.exports = WebSocket ? ws : null;
|
||||
|
||||
/**
|
||||
* WebSocket constructor.
|
||||
*
|
||||
* The third `opts` options object gets ignored in web browsers, since it's
|
||||
* non-standard, and throws a TypeError if passed to the constructor.
|
||||
* See: https://github.com/einaros/ws/issues/227
|
||||
*
|
||||
* @param {String} uri
|
||||
* @param {Array} protocols (optional)
|
||||
* @param {Object) opts (optional)
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function ws(uri, protocols, opts) {
|
||||
var instance;
|
||||
if (protocols) {
|
||||
instance = new WebSocket(uri, protocols);
|
||||
} else {
|
||||
instance = new WebSocket(uri);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
if (WebSocket) ws.prototype = WebSocket.prototype;
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
npm-debug.log
|
||||
node_modules
|
||||
build
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'bufferutil',
|
||||
'include_dirs': ["<!(node -e \"require('nan')\")"],
|
||||
'cflags': [ '-O3' ],
|
||||
'sources': [ 'src/bufferutil.cc' ]
|
||||
}
|
||||
]
|
||||
}
|
||||
+332
@@ -0,0 +1,332 @@
|
||||
# We borrow heavily from the kernel build setup, though we are simpler since
|
||||
# we don't have Kconfig tweaking settings on us.
|
||||
|
||||
# The implicit make rules have it looking for RCS files, among other things.
|
||||
# We instead explicitly write all the rules we care about.
|
||||
# It's even quicker (saves ~200ms) to pass -r on the command line.
|
||||
MAKEFLAGS=-r
|
||||
|
||||
# The source directory tree.
|
||||
srcdir := ..
|
||||
abs_srcdir := $(abspath $(srcdir))
|
||||
|
||||
# The name of the builddir.
|
||||
builddir_name ?= .
|
||||
|
||||
# The V=1 flag on command line makes us verbosely print command lines.
|
||||
ifdef V
|
||||
quiet=
|
||||
else
|
||||
quiet=quiet_
|
||||
endif
|
||||
|
||||
# Specify BUILDTYPE=Release on the command line for a release build.
|
||||
BUILDTYPE ?= Release
|
||||
|
||||
# Directory all our build output goes into.
|
||||
# Note that this must be two directories beneath src/ for unit tests to pass,
|
||||
# as they reach into the src/ directory for data with relative paths.
|
||||
builddir ?= $(builddir_name)/$(BUILDTYPE)
|
||||
abs_builddir := $(abspath $(builddir))
|
||||
depsdir := $(builddir)/.deps
|
||||
|
||||
# Object output directory.
|
||||
obj := $(builddir)/obj
|
||||
abs_obj := $(abspath $(obj))
|
||||
|
||||
# We build up a list of every single one of the targets so we can slurp in the
|
||||
# generated dependency rule Makefiles in one pass.
|
||||
all_deps :=
|
||||
|
||||
|
||||
|
||||
CC.target ?= $(CC)
|
||||
CFLAGS.target ?= $(CFLAGS)
|
||||
CXX.target ?= $(CXX)
|
||||
CXXFLAGS.target ?= $(CXXFLAGS) $(CPPFLAGS)
|
||||
LINK.target ?= $(LINK)
|
||||
LDFLAGS.target ?= $(LDFLAGS)
|
||||
AR.target ?= $(AR)
|
||||
|
||||
# C++ apps need to be linked with g++.
|
||||
#
|
||||
# Note: flock is used to seralize linking. Linking is a memory-intensive
|
||||
# process so running parallel links can often lead to thrashing. To disable
|
||||
# the serialization, override LINK via an envrionment variable as follows:
|
||||
#
|
||||
# export LINK=g++
|
||||
#
|
||||
# This will allow make to invoke N linker processes as specified in -jN.
|
||||
LINK ?= flock $(builddir)/linker.lock $(CXX.target)
|
||||
|
||||
# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
|
||||
# to replicate this environment fallback in make as well.
|
||||
CC.host ?= gcc
|
||||
CFLAGS.host ?=
|
||||
CXX.host ?= g++
|
||||
CXXFLAGS.host ?=
|
||||
LINK.host ?= $(CXX.host)
|
||||
LDFLAGS.host ?=
|
||||
AR.host ?= ar
|
||||
|
||||
# Define a dir function that can handle spaces.
|
||||
# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
|
||||
# "leading spaces cannot appear in the text of the first argument as written.
|
||||
# These characters can be put into the argument value by variable substitution."
|
||||
empty :=
|
||||
space := $(empty) $(empty)
|
||||
|
||||
# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
|
||||
replace_spaces = $(subst $(space),?,$1)
|
||||
unreplace_spaces = $(subst ?,$(space),$1)
|
||||
dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
|
||||
|
||||
# Flags to make gcc output dependency info. Note that you need to be
|
||||
# careful here to use the flags that ccache and distcc can understand.
|
||||
# We write to a dep file on the side first and then rename at the end
|
||||
# so we can't end up with a broken dep file.
|
||||
depfile = $(depsdir)/$(call replace_spaces,$@).d
|
||||
DEPFLAGS = -MMD -MF $(depfile).raw
|
||||
|
||||
# We have to fixup the deps output in a few ways.
|
||||
# (1) the file output should mention the proper .o file.
|
||||
# ccache or distcc lose the path to the target, so we convert a rule of
|
||||
# the form:
|
||||
# foobar.o: DEP1 DEP2
|
||||
# into
|
||||
# path/to/foobar.o: DEP1 DEP2
|
||||
# (2) we want missing files not to cause us to fail to build.
|
||||
# We want to rewrite
|
||||
# foobar.o: DEP1 DEP2 \
|
||||
# DEP3
|
||||
# to
|
||||
# DEP1:
|
||||
# DEP2:
|
||||
# DEP3:
|
||||
# so if the files are missing, they're just considered phony rules.
|
||||
# We have to do some pretty insane escaping to get those backslashes
|
||||
# and dollar signs past make, the shell, and sed at the same time.
|
||||
# Doesn't work with spaces, but that's fine: .d files have spaces in
|
||||
# their names replaced with other characters.
|
||||
define fixup_dep
|
||||
# The depfile may not exist if the input file didn't have any #includes.
|
||||
touch $(depfile).raw
|
||||
# Fixup path as in (1).
|
||||
sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
|
||||
# Add extra rules as in (2).
|
||||
# We remove slashes and replace spaces with new lines;
|
||||
# remove blank lines;
|
||||
# delete the first line and append a colon to the remaining lines.
|
||||
sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
|
||||
grep -v '^$$' |\
|
||||
sed -e 1d -e 's|$$|:|' \
|
||||
>> $(depfile)
|
||||
rm $(depfile).raw
|
||||
endef
|
||||
|
||||
# Command definitions:
|
||||
# - cmd_foo is the actual command to run;
|
||||
# - quiet_cmd_foo is the brief-output summary of the command.
|
||||
|
||||
quiet_cmd_cc = CC($(TOOLSET)) $@
|
||||
cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
|
||||
|
||||
quiet_cmd_cxx = CXX($(TOOLSET)) $@
|
||||
cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
|
||||
|
||||
quiet_cmd_touch = TOUCH $@
|
||||
cmd_touch = touch $@
|
||||
|
||||
quiet_cmd_copy = COPY $@
|
||||
# send stderr to /dev/null to ignore messages when linking directories.
|
||||
cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
|
||||
|
||||
quiet_cmd_alink = AR($(TOOLSET)) $@
|
||||
cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
|
||||
|
||||
quiet_cmd_alink_thin = AR($(TOOLSET)) $@
|
||||
cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
|
||||
|
||||
# Due to circular dependencies between libraries :(, we wrap the
|
||||
# special "figure out circular dependencies" flags around the entire
|
||||
# input list during linking.
|
||||
quiet_cmd_link = LINK($(TOOLSET)) $@
|
||||
cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
|
||||
|
||||
# We support two kinds of shared objects (.so):
|
||||
# 1) shared_library, which is just bundling together many dependent libraries
|
||||
# into a link line.
|
||||
# 2) loadable_module, which is generating a module intended for dlopen().
|
||||
#
|
||||
# They differ only slightly:
|
||||
# In the former case, we want to package all dependent code into the .so.
|
||||
# In the latter case, we want to package just the API exposed by the
|
||||
# outermost module.
|
||||
# This means shared_library uses --whole-archive, while loadable_module doesn't.
|
||||
# (Note that --whole-archive is incompatible with the --start-group used in
|
||||
# normal linking.)
|
||||
|
||||
# Other shared-object link notes:
|
||||
# - Set SONAME to the library filename so our binaries don't reference
|
||||
# the local, absolute paths used on the link command-line.
|
||||
quiet_cmd_solink = SOLINK($(TOOLSET)) $@
|
||||
cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
|
||||
|
||||
quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
|
||||
cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
|
||||
|
||||
|
||||
# Define an escape_quotes function to escape single quotes.
|
||||
# This allows us to handle quotes properly as long as we always use
|
||||
# use single quotes and escape_quotes.
|
||||
escape_quotes = $(subst ','\'',$(1))
|
||||
# This comment is here just to include a ' to unconfuse syntax highlighting.
|
||||
# Define an escape_vars function to escape '$' variable syntax.
|
||||
# This allows us to read/write command lines with shell variables (e.g.
|
||||
# $LD_LIBRARY_PATH), without triggering make substitution.
|
||||
escape_vars = $(subst $$,$$$$,$(1))
|
||||
# Helper that expands to a shell command to echo a string exactly as it is in
|
||||
# make. This uses printf instead of echo because printf's behaviour with respect
|
||||
# to escape sequences is more portable than echo's across different shells
|
||||
# (e.g., dash, bash).
|
||||
exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
|
||||
|
||||
# Helper to compare the command we're about to run against the command
|
||||
# we logged the last time we ran the command. Produces an empty
|
||||
# string (false) when the commands match.
|
||||
# Tricky point: Make has no string-equality test function.
|
||||
# The kernel uses the following, but it seems like it would have false
|
||||
# positives, where one string reordered its arguments.
|
||||
# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
|
||||
# $(filter-out $(cmd_$@), $(cmd_$(1))))
|
||||
# We instead substitute each for the empty string into the other, and
|
||||
# say they're equal if both substitutions produce the empty string.
|
||||
# .d files contain ? instead of spaces, take that into account.
|
||||
command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
|
||||
$(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
|
||||
|
||||
# Helper that is non-empty when a prerequisite changes.
|
||||
# Normally make does this implicitly, but we force rules to always run
|
||||
# so we can check their command lines.
|
||||
# $? -- new prerequisites
|
||||
# $| -- order-only dependencies
|
||||
prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
|
||||
|
||||
# Helper that executes all postbuilds until one fails.
|
||||
define do_postbuilds
|
||||
@E=0;\
|
||||
for p in $(POSTBUILDS); do\
|
||||
eval $$p;\
|
||||
E=$$?;\
|
||||
if [ $$E -ne 0 ]; then\
|
||||
break;\
|
||||
fi;\
|
||||
done;\
|
||||
if [ $$E -ne 0 ]; then\
|
||||
rm -rf "$@";\
|
||||
exit $$E;\
|
||||
fi
|
||||
endef
|
||||
|
||||
# do_cmd: run a command via the above cmd_foo names, if necessary.
|
||||
# Should always run for a given target to handle command-line changes.
|
||||
# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
|
||||
# Third argument, if non-zero, makes it do POSTBUILDS processing.
|
||||
# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
|
||||
# spaces already and dirx strips the ? characters.
|
||||
define do_cmd
|
||||
$(if $(or $(command_changed),$(prereq_changed)),
|
||||
@$(call exact_echo, $($(quiet)cmd_$(1)))
|
||||
@mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
|
||||
$(if $(findstring flock,$(word 1,$(cmd_$1))),
|
||||
@$(cmd_$(1))
|
||||
@echo " $(quiet_cmd_$(1)): Finished",
|
||||
@$(cmd_$(1))
|
||||
)
|
||||
@$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
|
||||
@$(if $(2),$(fixup_dep))
|
||||
$(if $(and $(3), $(POSTBUILDS)),
|
||||
$(call do_postbuilds)
|
||||
)
|
||||
)
|
||||
endef
|
||||
|
||||
# Declare the "all" target first so it is the default,
|
||||
# even though we don't have the deps yet.
|
||||
.PHONY: all
|
||||
all:
|
||||
|
||||
# make looks for ways to re-generate included makefiles, but in our case, we
|
||||
# don't have a direct way. Explicitly telling make that it has nothing to do
|
||||
# for them makes it go faster.
|
||||
%.d: ;
|
||||
|
||||
# Use FORCE_DO_CMD to force a target to run. Should be coupled with
|
||||
# do_cmd.
|
||||
.PHONY: FORCE_DO_CMD
|
||||
FORCE_DO_CMD:
|
||||
|
||||
TOOLSET := target
|
||||
# Suffix rules, putting all outputs into $(obj).
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
# Try building from generated source, too.
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
|
||||
ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
|
||||
$(findstring $(join ^,$(prefix)),\
|
||||
$(join ^,bufferutil.target.mk)))),)
|
||||
include bufferutil.target.mk
|
||||
endif
|
||||
|
||||
quiet_cmd_regen_makefile = ACTION Regenerating $@
|
||||
cmd_regen_makefile = cd $(srcdir); /usr/share/node-gyp/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -I/home/rsilveira/formigone/html5multiplayer/tic-tac-toe/node_modules/ws/node_modules/bufferutil/build/config.gypi -I/usr/share/node-gyp/addon.gypi -I/usr/include/nodejs/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/usr/include/nodejs" "-Dmodule_root_dir=/home/rsilveira/formigone/html5multiplayer/tic-tac-toe/node_modules/ws/node_modules/bufferutil" binding.gyp
|
||||
Makefile: $(srcdir)/../../../../../../../../../usr/include/nodejs/common.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp $(srcdir)/../../../../../../../../../usr/share/node-gyp/addon.gypi
|
||||
$(call do_cmd,regen_makefile)
|
||||
|
||||
# "all" is a concatenation of the "all" targets from all the included
|
||||
# sub-makefiles. This is just here to clarify.
|
||||
all:
|
||||
|
||||
# Add in dependency-tracking rules. $(all_deps) is the list of every single
|
||||
# target in our tree. Only consider the ones with .d (dependency) info:
|
||||
d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
|
||||
ifneq ($(d_files),)
|
||||
include $(d_files)
|
||||
endif
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
cmd_Release/bufferutil.node := ln -f "Release/obj.target/bufferutil.node" "Release/bufferutil.node" 2>/dev/null || (rm -rf "Release/bufferutil.node" && cp -af "Release/obj.target/bufferutil.node" "Release/bufferutil.node")
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
cmd_Release/obj.target/bufferutil.node := flock ./Release/linker.lock g++ -shared -pthread -rdynamic -m64 -Wl,-soname=bufferutil.node -o Release/obj.target/bufferutil.node -Wl,--start-group Release/obj.target/bufferutil/src/bufferutil.o -Wl,--end-group
|
||||
Generated
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
cmd_Release/obj.target/bufferutil/src/bufferutil.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d.raw -c -o Release/obj.target/bufferutil/src/bufferutil.o ../src/bufferutil.cc
|
||||
Release/obj.target/bufferutil/src/bufferutil.o: ../src/bufferutil.cc \
|
||||
/usr/include/nodejs/deps/v8/include/v8.h \
|
||||
/usr/include/nodejs/deps/v8/include/v8stdint.h \
|
||||
/usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \
|
||||
/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \
|
||||
/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \
|
||||
/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \
|
||||
/usr/include/nodejs/src/node_object_wrap.h \
|
||||
/usr/include/nodejs/src/node.h /usr/include/nodejs/src/node_version.h \
|
||||
/usr/include/nodejs/src/node_buffer.h \
|
||||
/usr/include/nodejs/src/node_object_wrap.h ../node_modules/nan/nan.h \
|
||||
../node_modules/nan/nan_new.h \
|
||||
../node_modules/nan/nan_implementation_pre_12_inl.h
|
||||
../src/bufferutil.cc:
|
||||
/usr/include/nodejs/deps/v8/include/v8.h:
|
||||
/usr/include/nodejs/deps/v8/include/v8stdint.h:
|
||||
/usr/include/nodejs/src/node.h:
|
||||
/usr/include/nodejs/deps/uv/include/uv.h:
|
||||
/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h:
|
||||
/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h:
|
||||
/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h:
|
||||
/usr/include/nodejs/src/node_object_wrap.h:
|
||||
/usr/include/nodejs/src/node.h:
|
||||
/usr/include/nodejs/src/node_version.h:
|
||||
/usr/include/nodejs/src/node_buffer.h:
|
||||
/usr/include/nodejs/src/node_object_wrap.h:
|
||||
../node_modules/nan/nan.h:
|
||||
../node_modules/nan/nan_new.h:
|
||||
../node_modules/nan/nan_implementation_pre_12_inl.h:
|
||||
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
+6
@@ -0,0 +1,6 @@
|
||||
# This file is generated by gyp; do not edit.
|
||||
|
||||
export builddir_name ?= build/./.
|
||||
.PHONY: all
|
||||
all:
|
||||
$(MAKE) bufferutil
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
# This file is generated by gyp; do not edit.
|
||||
|
||||
TOOLSET := target
|
||||
TARGET := bufferutil
|
||||
DEFS_Debug := \
|
||||
'-D_LARGEFILE_SOURCE' \
|
||||
'-D_FILE_OFFSET_BITS=64' \
|
||||
'-DBUILDING_NODE_EXTENSION' \
|
||||
'-DDEBUG' \
|
||||
'-D_DEBUG'
|
||||
|
||||
# Flags passed to all source files.
|
||||
CFLAGS_Debug := \
|
||||
-fPIC \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wno-unused-parameter \
|
||||
-pthread \
|
||||
-m64 \
|
||||
-O3 \
|
||||
-g \
|
||||
-O0
|
||||
|
||||
# Flags passed to only C files.
|
||||
CFLAGS_C_Debug :=
|
||||
|
||||
# Flags passed to only C++ files.
|
||||
CFLAGS_CC_Debug := \
|
||||
-fno-rtti \
|
||||
-fno-exceptions
|
||||
|
||||
INCS_Debug := \
|
||||
-I/usr/include/nodejs/src \
|
||||
-I/usr/include/nodejs/deps/uv/include \
|
||||
-I/usr/include/nodejs/deps/v8/include \
|
||||
-I$(srcdir)/node_modules/nan
|
||||
|
||||
DEFS_Release := \
|
||||
'-D_LARGEFILE_SOURCE' \
|
||||
'-D_FILE_OFFSET_BITS=64' \
|
||||
'-DBUILDING_NODE_EXTENSION'
|
||||
|
||||
# Flags passed to all source files.
|
||||
CFLAGS_Release := \
|
||||
-fPIC \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wno-unused-parameter \
|
||||
-pthread \
|
||||
-m64 \
|
||||
-O2 \
|
||||
-fno-strict-aliasing \
|
||||
-fno-tree-vrp \
|
||||
-fno-omit-frame-pointer
|
||||
|
||||
# Flags passed to only C files.
|
||||
CFLAGS_C_Release :=
|
||||
|
||||
# Flags passed to only C++ files.
|
||||
CFLAGS_CC_Release := \
|
||||
-fno-rtti \
|
||||
-fno-exceptions
|
||||
|
||||
INCS_Release := \
|
||||
-I/usr/include/nodejs/src \
|
||||
-I/usr/include/nodejs/deps/uv/include \
|
||||
-I/usr/include/nodejs/deps/v8/include \
|
||||
-I$(srcdir)/node_modules/nan
|
||||
|
||||
OBJS := \
|
||||
$(obj).target/$(TARGET)/src/bufferutil.o
|
||||
|
||||
# Add to the list of files we specially track dependencies for.
|
||||
all_deps += $(OBJS)
|
||||
|
||||
# CFLAGS et al overrides must be target-local.
|
||||
# See "Target-specific Variable Values" in the GNU Make manual.
|
||||
$(OBJS): TOOLSET := $(TOOLSET)
|
||||
$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
|
||||
$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
|
||||
|
||||
# Suffix rules, putting all outputs into $(obj).
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
|
||||
# Try building from generated source, too.
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
|
||||
# End of this set of suffix rules
|
||||
### Rules for final target.
|
||||
LDFLAGS_Debug := \
|
||||
-pthread \
|
||||
-rdynamic \
|
||||
-m64
|
||||
|
||||
LDFLAGS_Release := \
|
||||
-pthread \
|
||||
-rdynamic \
|
||||
-m64
|
||||
|
||||
LIBS :=
|
||||
|
||||
$(obj).target/bufferutil.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
|
||||
$(obj).target/bufferutil.node: LIBS := $(LIBS)
|
||||
$(obj).target/bufferutil.node: TOOLSET := $(TOOLSET)
|
||||
$(obj).target/bufferutil.node: $(OBJS) FORCE_DO_CMD
|
||||
$(call do_cmd,solink_module)
|
||||
|
||||
all_deps += $(obj).target/bufferutil.node
|
||||
# Add target alias
|
||||
.PHONY: bufferutil
|
||||
bufferutil: $(builddir)/bufferutil.node
|
||||
|
||||
# Copy this to the executable output path.
|
||||
$(builddir)/bufferutil.node: TOOLSET := $(TOOLSET)
|
||||
$(builddir)/bufferutil.node: $(obj).target/bufferutil.node FORCE_DO_CMD
|
||||
$(call do_cmd,copy)
|
||||
|
||||
all_deps += $(builddir)/bufferutil.node
|
||||
# Short alias for building this executable.
|
||||
.PHONY: bufferutil.node
|
||||
bufferutil.node: $(obj).target/bufferutil.node $(builddir)/bufferutil.node
|
||||
|
||||
# Add executable to "all" target.
|
||||
.PHONY: all
|
||||
all: $(builddir)/bufferutil.node
|
||||
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
# Do not edit. File was generated by node-gyp's "configure" step
|
||||
{
|
||||
"target_defaults": {
|
||||
"cflags": [],
|
||||
"default_configuration": "Release",
|
||||
"defines": [],
|
||||
"include_dirs": [],
|
||||
"libraries": []
|
||||
},
|
||||
"variables": {
|
||||
"clang": 0,
|
||||
"gcc_version": 48,
|
||||
"host_arch": "x64",
|
||||
"node_byteorder": "little",
|
||||
"node_install_npm": "false",
|
||||
"node_prefix": "/usr",
|
||||
"node_shared_cares": "true",
|
||||
"node_shared_http_parser": "false",
|
||||
"node_shared_libuv": "false",
|
||||
"node_shared_openssl": "true",
|
||||
"node_shared_v8": "true",
|
||||
"node_shared_zlib": "true",
|
||||
"node_tag": "",
|
||||
"node_unsafe_optimizations": 0,
|
||||
"node_use_dtrace": "false",
|
||||
"node_use_etw": "false",
|
||||
"node_use_openssl": "true",
|
||||
"node_use_perfctr": "false",
|
||||
"node_use_systemtap": "false",
|
||||
"python": "/usr/bin/python",
|
||||
"target_arch": "x64",
|
||||
"v8_enable_gdbjit": 0,
|
||||
"v8_no_strict_aliasing": 1,
|
||||
"v8_use_snapshot": "false",
|
||||
"nodedir": "/usr/include/nodejs",
|
||||
"copy_dev_lib": "true",
|
||||
"standalone_static_library": 1,
|
||||
"cache_lock_stale": "60000",
|
||||
"pre": "",
|
||||
"sign_git_tag": "",
|
||||
"always_auth": "",
|
||||
"user_agent": "node/v0.10.25 linux x64",
|
||||
"bin_links": "true",
|
||||
"description": "true",
|
||||
"fetch_retries": "2",
|
||||
"init_version": "0.0.0",
|
||||
"user": "1000",
|
||||
"force": "",
|
||||
"ignore": "",
|
||||
"cache_min": "10",
|
||||
"editor": "vi",
|
||||
"rollback": "true",
|
||||
"cache_max": "null",
|
||||
"userconfig": "/home/rsilveira/.npmrc",
|
||||
"coverage": "",
|
||||
"engine_strict": "",
|
||||
"init_author_name": "",
|
||||
"init_author_url": "",
|
||||
"tmp": "/home/rsilveira/tmp",
|
||||
"userignorefile": "/home/rsilveira/.npmignore",
|
||||
"yes": "",
|
||||
"depth": "null",
|
||||
"save_dev": "",
|
||||
"usage": "",
|
||||
"https_proxy": "",
|
||||
"onload_script": "",
|
||||
"rebuild_bundle": "true",
|
||||
"save_bundle": "",
|
||||
"shell": "/bin/bash",
|
||||
"prefix": "/usr/local",
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"__DO_NOT_MODIFY_THIS_FILE___use__etc_npmrc_instead_": "true",
|
||||
"browser": "",
|
||||
"cache_lock_wait": "10000",
|
||||
"save_optional": "",
|
||||
"searchopts": "",
|
||||
"versions": "",
|
||||
"cache": "/home/rsilveira/.npm",
|
||||
"npaturl": "http://npat.npmjs.org/",
|
||||
"searchsort": "name",
|
||||
"version": "",
|
||||
"viewer": "man",
|
||||
"color": "true",
|
||||
"fetch_retry_mintimeout": "10000",
|
||||
"umask": "18",
|
||||
"fetch_retry_maxtimeout": "60000",
|
||||
"message": "%s",
|
||||
"global": "",
|
||||
"link": "",
|
||||
"save": "",
|
||||
"unicode": "true",
|
||||
"long": "",
|
||||
"production": "",
|
||||
"unsafe_perm": "",
|
||||
"node_version": "v0.10.25",
|
||||
"tag": "latest",
|
||||
"shrinkwrap": "true",
|
||||
"fetch_retry_factor": "10",
|
||||
"npat": "",
|
||||
"proprietary_attribs": "true",
|
||||
"strict_ssl": "true",
|
||||
"username": "",
|
||||
"globalconfig": "/etc/npmrc",
|
||||
"dev": "",
|
||||
"init_module": "/home/rsilveira/.npm-init.js",
|
||||
"parseable": "",
|
||||
"globalignorefile": "/etc/npmignore",
|
||||
"cache_lock_retries": "10",
|
||||
"group": "1000",
|
||||
"init_author_email": "",
|
||||
"searchexclude": "",
|
||||
"git": "git",
|
||||
"optional": "true",
|
||||
"json": ""
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
'use strict';
|
||||
|
||||
/*!
|
||||
* bufferutil: WebSocket buffer utils
|
||||
* Copyright(c) 2015 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
module.exports.BufferUtil = {
|
||||
merge: function(mergedBuffer, buffers) {
|
||||
var offset = 0;
|
||||
|
||||
for (var i = 0, l = buffers.length; i < l; ++i) {
|
||||
var buf = buffers[i];
|
||||
buf.copy(mergedBuffer, offset);
|
||||
offset += buf.length;
|
||||
}
|
||||
},
|
||||
mask: function(source, mask, output, offset, length) {
|
||||
var maskNum = mask.readUInt32LE(0, true);
|
||||
var i = 0;
|
||||
|
||||
for (; i < length - 3; i += 4) {
|
||||
var num = maskNum ^ source.readUInt32LE(i, true);
|
||||
if (num < 0) num = 4294967296 + num;
|
||||
output.writeUInt32LE(num, offset + i, true);
|
||||
}
|
||||
|
||||
switch (length % 4) {
|
||||
case 3: output[offset + i + 2] = source[i + 2] ^ mask[2];
|
||||
case 2: output[offset + i + 1] = source[i + 1] ^ mask[1];
|
||||
case 1: output[offset + i] = source[i] ^ mask[0];
|
||||
}
|
||||
},
|
||||
unmask: function(data, mask) {
|
||||
var maskNum = mask.readUInt32LE(0, true);
|
||||
var length = data.length;
|
||||
var i = 0;
|
||||
|
||||
for (; i < length - 3; i += 4) {
|
||||
var num = maskNum ^ data.readUInt32LE(i, true);
|
||||
if (num < 0) num = 4294967296 + num;
|
||||
data.writeUInt32LE(num, i, true);
|
||||
}
|
||||
|
||||
switch (length % 4) {
|
||||
case 3: data[i + 2] = data[i + 2] ^ mask[2];
|
||||
case 2: data[i + 1] = data[i + 1] ^ mask[1];
|
||||
case 1: data[i] = data[i] ^ mask[0];
|
||||
}
|
||||
}
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
try {
|
||||
module.exports = require('bindings')('bufferutil');
|
||||
} catch (e) {
|
||||
module.exports = require('./fallback');
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
node-bindings
|
||||
=============
|
||||
### Helper module for loading your native module's .node file
|
||||
|
||||
This is a helper module for authors of Node.js native addon modules.
|
||||
It is basically the "swiss army knife" of `require()`ing your native module's
|
||||
`.node` file.
|
||||
|
||||
Throughout the course of Node's native addon history, addons have ended up being
|
||||
compiled in a variety of different places, depending on which build tool and which
|
||||
version of node was used. To make matters worse, now the _gyp_ build tool can
|
||||
produce either a _Release_ or _Debug_ build, each being built into different
|
||||
locations.
|
||||
|
||||
This module checks _all_ the possible locations that a native addon would be built
|
||||
at, and returns the first one that loads successfully.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Install with `npm`:
|
||||
|
||||
``` bash
|
||||
$ npm install bindings
|
||||
```
|
||||
|
||||
Or add it to the `"dependencies"` section of your _package.json_ file.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
`require()`ing the proper bindings file for the current node version, platform
|
||||
and architecture is as simple as:
|
||||
|
||||
``` js
|
||||
var bindings = require('bindings')('binding.node')
|
||||
|
||||
// Use your bindings defined in your C files
|
||||
bindings.your_c_function()
|
||||
```
|
||||
|
||||
|
||||
Nice Error Output
|
||||
-----------------
|
||||
|
||||
When the `.node` file could not be loaded, `node-bindings` throws an Error with
|
||||
a nice error message telling you exactly what was tried. You can also check the
|
||||
`err.tries` Array property.
|
||||
|
||||
```
|
||||
Error: Could not load the bindings file. Tried:
|
||||
→ /Users/nrajlich/ref/build/binding.node
|
||||
→ /Users/nrajlich/ref/build/Debug/binding.node
|
||||
→ /Users/nrajlich/ref/build/Release/binding.node
|
||||
→ /Users/nrajlich/ref/out/Debug/binding.node
|
||||
→ /Users/nrajlich/ref/Debug/binding.node
|
||||
→ /Users/nrajlich/ref/out/Release/binding.node
|
||||
→ /Users/nrajlich/ref/Release/binding.node
|
||||
→ /Users/nrajlich/ref/build/default/binding.node
|
||||
→ /Users/nrajlich/ref/compiled/0.8.2/darwin/x64/binding.node
|
||||
at bindings (/Users/nrajlich/ref/node_modules/bindings/bindings.js:84:13)
|
||||
at Object.<anonymous> (/Users/nrajlich/ref/lib/ref.js:5:47)
|
||||
at Module._compile (module.js:449:26)
|
||||
at Object.Module._extensions..js (module.js:467:10)
|
||||
at Module.load (module.js:356:32)
|
||||
at Function.Module._load (module.js:312:12)
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var fs = require('fs')
|
||||
, path = require('path')
|
||||
, join = path.join
|
||||
, dirname = path.dirname
|
||||
, exists = fs.existsSync || path.existsSync
|
||||
, defaults = {
|
||||
arrow: process.env.NODE_BINDINGS_ARROW || ' → '
|
||||
, compiled: process.env.NODE_BINDINGS_COMPILED_DIR || 'compiled'
|
||||
, platform: process.platform
|
||||
, arch: process.arch
|
||||
, version: process.versions.node
|
||||
, bindings: 'bindings.node'
|
||||
, try: [
|
||||
// node-gyp's linked version in the "build" dir
|
||||
[ 'module_root', 'build', 'bindings' ]
|
||||
// node-waf and gyp_addon (a.k.a node-gyp)
|
||||
, [ 'module_root', 'build', 'Debug', 'bindings' ]
|
||||
, [ 'module_root', 'build', 'Release', 'bindings' ]
|
||||
// Debug files, for development (legacy behavior, remove for node v0.9)
|
||||
, [ 'module_root', 'out', 'Debug', 'bindings' ]
|
||||
, [ 'module_root', 'Debug', 'bindings' ]
|
||||
// Release files, but manually compiled (legacy behavior, remove for node v0.9)
|
||||
, [ 'module_root', 'out', 'Release', 'bindings' ]
|
||||
, [ 'module_root', 'Release', 'bindings' ]
|
||||
// Legacy from node-waf, node <= 0.4.x
|
||||
, [ 'module_root', 'build', 'default', 'bindings' ]
|
||||
// Production "Release" buildtype binary (meh...)
|
||||
, [ 'module_root', 'compiled', 'version', 'platform', 'arch', 'bindings' ]
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* The main `bindings()` function loads the compiled bindings for a given module.
|
||||
* It uses V8's Error API to determine the parent filename that this function is
|
||||
* being invoked from, which is then used to find the root directory.
|
||||
*/
|
||||
|
||||
function bindings (opts) {
|
||||
|
||||
// Argument surgery
|
||||
if (typeof opts == 'string') {
|
||||
opts = { bindings: opts }
|
||||
} else if (!opts) {
|
||||
opts = {}
|
||||
}
|
||||
opts.__proto__ = defaults
|
||||
|
||||
// Get the module root
|
||||
if (!opts.module_root) {
|
||||
opts.module_root = exports.getRoot(exports.getFileName())
|
||||
}
|
||||
|
||||
// Ensure the given bindings name ends with .node
|
||||
if (path.extname(opts.bindings) != '.node') {
|
||||
opts.bindings += '.node'
|
||||
}
|
||||
|
||||
var tries = []
|
||||
, i = 0
|
||||
, l = opts.try.length
|
||||
, n
|
||||
, b
|
||||
, err
|
||||
|
||||
for (; i<l; i++) {
|
||||
n = join.apply(null, opts.try[i].map(function (p) {
|
||||
return opts[p] || p
|
||||
}))
|
||||
tries.push(n)
|
||||
try {
|
||||
b = opts.path ? require.resolve(n) : require(n)
|
||||
if (!opts.path) {
|
||||
b.path = n
|
||||
}
|
||||
return b
|
||||
} catch (e) {
|
||||
if (!/not find/i.test(e.message)) {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = new Error('Could not locate the bindings file. Tried:\n'
|
||||
+ tries.map(function (a) { return opts.arrow + a }).join('\n'))
|
||||
err.tries = tries
|
||||
throw err
|
||||
}
|
||||
module.exports = exports = bindings
|
||||
|
||||
|
||||
/**
|
||||
* Gets the filename of the JavaScript file that invokes this function.
|
||||
* Used to help find the root directory of a module.
|
||||
* Optionally accepts an filename argument to skip when searching for the invoking filename
|
||||
*/
|
||||
|
||||
exports.getFileName = function getFileName (calling_file) {
|
||||
var origPST = Error.prepareStackTrace
|
||||
, origSTL = Error.stackTraceLimit
|
||||
, dummy = {}
|
||||
, fileName
|
||||
|
||||
Error.stackTraceLimit = 10
|
||||
|
||||
Error.prepareStackTrace = function (e, st) {
|
||||
for (var i=0, l=st.length; i<l; i++) {
|
||||
fileName = st[i].getFileName()
|
||||
if (fileName !== __filename) {
|
||||
if (calling_file) {
|
||||
if (fileName !== calling_file) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// run the 'prepareStackTrace' function above
|
||||
Error.captureStackTrace(dummy)
|
||||
dummy.stack
|
||||
|
||||
// cleanup
|
||||
Error.prepareStackTrace = origPST
|
||||
Error.stackTraceLimit = origSTL
|
||||
|
||||
return fileName
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the root directory of a module, given an arbitrary filename
|
||||
* somewhere in the module tree. The "root directory" is the directory
|
||||
* containing the `package.json` file.
|
||||
*
|
||||
* In: /home/nate/node-native-module/lib/index.js
|
||||
* Out: /home/nate/node-native-module
|
||||
*/
|
||||
|
||||
exports.getRoot = function getRoot (file) {
|
||||
var dir = dirname(file)
|
||||
, prev
|
||||
while (true) {
|
||||
if (dir === '.') {
|
||||
// Avoids an infinite loop in rare cases, like the REPL
|
||||
dir = process.cwd()
|
||||
}
|
||||
if (exists(join(dir, 'package.json')) || exists(join(dir, 'node_modules'))) {
|
||||
// Found the 'package.json' file or 'node_modules' dir; we're done
|
||||
return dir
|
||||
}
|
||||
if (prev === dir) {
|
||||
// Got to the top
|
||||
throw new Error('Could not find module root given file: "' + file
|
||||
+ '". Do you have a `package.json` file? ')
|
||||
}
|
||||
// Try the parent dir next
|
||||
prev = dir
|
||||
dir = join(dir, '..')
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+33
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "bindings",
|
||||
"description": "Helper module for loading your native module's .node file",
|
||||
"keywords": [
|
||||
"native",
|
||||
"addon",
|
||||
"bindings",
|
||||
"gyp",
|
||||
"waf",
|
||||
"c",
|
||||
"c++"
|
||||
],
|
||||
"version": "1.2.1",
|
||||
"author": {
|
||||
"name": "Nathan Rajlich",
|
||||
"email": "nathan@tootallnate.net",
|
||||
"url": "http://tootallnate.net"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/TooTallNate/node-bindings.git"
|
||||
},
|
||||
"main": "./bindings.js",
|
||||
"bugs": {
|
||||
"url": "https://github.com/TooTallNate/node-bindings/issues"
|
||||
},
|
||||
"homepage": "https://github.com/TooTallNate/node-bindings",
|
||||
"license": "MIT",
|
||||
"readme": "node-bindings\n=============\n### Helper module for loading your native module's .node file\n\nThis is a helper module for authors of Node.js native addon modules.\nIt is basically the \"swiss army knife\" of `require()`ing your native module's\n`.node` file.\n\nThroughout the course of Node's native addon history, addons have ended up being\ncompiled in a variety of different places, depending on which build tool and which\nversion of node was used. To make matters worse, now the _gyp_ build tool can\nproduce either a _Release_ or _Debug_ build, each being built into different\nlocations.\n\nThis module checks _all_ the possible locations that a native addon would be built\nat, and returns the first one that loads successfully.\n\n\nInstallation\n------------\n\nInstall with `npm`:\n\n``` bash\n$ npm install bindings\n```\n\nOr add it to the `\"dependencies\"` section of your _package.json_ file.\n\n\nExample\n-------\n\n`require()`ing the proper bindings file for the current node version, platform\nand architecture is as simple as:\n\n``` js\nvar bindings = require('bindings')('binding.node')\n\n// Use your bindings defined in your C files\nbindings.your_c_function()\n```\n\n\nNice Error Output\n-----------------\n\nWhen the `.node` file could not be loaded, `node-bindings` throws an Error with\na nice error message telling you exactly what was tried. You can also check the\n`err.tries` Array property.\n\n```\nError: Could not load the bindings file. Tried:\n → /Users/nrajlich/ref/build/binding.node\n → /Users/nrajlich/ref/build/Debug/binding.node\n → /Users/nrajlich/ref/build/Release/binding.node\n → /Users/nrajlich/ref/out/Debug/binding.node\n → /Users/nrajlich/ref/Debug/binding.node\n → /Users/nrajlich/ref/out/Release/binding.node\n → /Users/nrajlich/ref/Release/binding.node\n → /Users/nrajlich/ref/build/default/binding.node\n → /Users/nrajlich/ref/compiled/0.8.2/darwin/x64/binding.node\n at bindings (/Users/nrajlich/ref/node_modules/bindings/bindings.js:84:13)\n at Object.<anonymous> (/Users/nrajlich/ref/lib/ref.js:5:47)\n at Module._compile (module.js:449:26)\n at Object.Module._extensions..js (module.js:467:10)\n at Module.load (module.js:356:32)\n at Function.Module._load (module.js:312:12)\n ...\n```\n\n\nLicense\n-------\n\n(The MIT License)\n\nCopyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
|
||||
"readmeFilename": "README.md",
|
||||
"_id": "bindings@1.2.1",
|
||||
"_from": "bindings@1.2.x"
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
## DNT config file
|
||||
## see https://github.com/rvagg/dnt
|
||||
|
||||
NODE_VERSIONS="\
|
||||
master \
|
||||
v0.11.13 \
|
||||
v0.10.30 \
|
||||
v0.10.29 \
|
||||
v0.10.28 \
|
||||
v0.10.26 \
|
||||
v0.10.25 \
|
||||
v0.10.24 \
|
||||
v0.10.23 \
|
||||
v0.10.22 \
|
||||
v0.10.21 \
|
||||
v0.10.20 \
|
||||
v0.10.19 \
|
||||
v0.8.28 \
|
||||
v0.8.27 \
|
||||
v0.8.26 \
|
||||
v0.8.24 \
|
||||
"
|
||||
OUTPUT_PREFIX="nan-"
|
||||
TEST_CMD=" \
|
||||
cd /dnt/ && \
|
||||
npm install && \
|
||||
node_modules/.bin/node-gyp --nodedir /usr/src/node/ rebuild --directory test && \
|
||||
node_modules/.bin/tap --gc test/js/*-test.js \
|
||||
"
|
||||
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
# NAN ChangeLog
|
||||
|
||||
**Version 1.6.0: current Node unstable: 0.11.15, Node stable: 0.10.35, io.js: 1.0.3**
|
||||
|
||||
### 1.6.0 Jan 23 2015
|
||||
- Deprecated `NanNewContextHandle` in favor of `NanNew<Context>` 49259af
|
||||
- Support utility functions moved in newer v8 versions (Node 0.11.15, io.js 1.0) a0aa179
|
||||
- Added `NanEncode`, `NanDecodeBytes` and `NanDecodeWrite` 75e6fb9
|
||||
|
||||
### 1.5.2 Jan 23 2015
|
||||
|
||||
- Bugfix: Fix non-inline definition build error with clang++ 21d96a1, 60fadd4
|
||||
- Bugfix: Readded missing String constructors 18d828f
|
||||
- Bugfix: Add overload handling NanNew<FunctionTemplate>(..) 5ef813b
|
||||
- Bugfix: Fix uv_work_cb versioning 997e4ae
|
||||
- Bugfix: Add function factory and test 4eca89c
|
||||
- Bugfix: Add object template factory and test cdcb951
|
||||
- Correctness: Lifted an io.js related typedef c9490be
|
||||
- Correctness: Make explicit downcasts of String lengths 00074e6
|
||||
- Windows: Limit the scope of disabled warning C4530 83d7deb
|
||||
|
||||
### 1.5.1 Jan 15 2015
|
||||
|
||||
- Build: version bump
|
||||
|
||||
### 1.4.3 Jan 15 2015
|
||||
|
||||
- Build: version bump
|
||||
|
||||
### 1.4.2 Jan 15 2015
|
||||
|
||||
- Feature: Support io.js 0dbc5e8
|
||||
|
||||
### 1.5.0 Jan 14 2015
|
||||
|
||||
- Feature: Support io.js b003843
|
||||
- Correctness: Improved NanNew internals 9cd4f6a
|
||||
- Feature: Implement progress to NanAsyncWorker 8d6a160
|
||||
|
||||
### 1.4.1 Nov 8 2014
|
||||
|
||||
- Bugfix: Handle DEBUG definition correctly
|
||||
- Bugfix: Accept int as Boolean
|
||||
|
||||
### 1.4.0 Nov 1 2014
|
||||
|
||||
- Feature: Added NAN_GC_CALLBACK 6a5c245
|
||||
- Performance: Removed unnecessary local handle creation 18a7243, 41fe2f8
|
||||
- Correctness: Added constness to references in NanHasInstance 02c61cd
|
||||
- Warnings: Fixed spurious warnings from -Wundef and -Wshadow, 541b122, 99d8cb6
|
||||
- Windoze: Shut Visual Studio up when compiling 8d558c1
|
||||
- License: Switch to plain MIT from custom hacked MIT license 11de983
|
||||
- Build: Added test target to Makefile e232e46
|
||||
- Performance: Removed superfluous scope in NanAsyncWorker f4b7821
|
||||
- Sugar/Feature: Added NanReturnThis() and NanReturnHolder() shorthands 237a5ff, d697208
|
||||
- Feature: Added suitable overload of NanNew for v8::Integer::NewFromUnsigned b27b450
|
||||
|
||||
### 1.3.0 Aug 2 2014
|
||||
|
||||
- Added NanNew<v8::String, std::string>(std::string)
|
||||
- Added NanNew<v8::String, std::string&>(std::string&)
|
||||
- Added NanAsciiString helper class
|
||||
- Added NanUtf8String helper class
|
||||
- Added NanUcs2String helper class
|
||||
- Deprecated NanRawString()
|
||||
- Deprecated NanCString()
|
||||
- Added NanGetIsolateData(v8::Isolate *isolate)
|
||||
- Added NanMakeCallback(v8::Handle<v8::Object> target, v8::Handle<v8::Function> func, int argc, v8::Handle<v8::Value>* argv)
|
||||
- Added NanMakeCallback(v8::Handle<v8::Object> target, v8::Handle<v8::String> symbol, int argc, v8::Handle<v8::Value>* argv)
|
||||
- Added NanMakeCallback(v8::Handle<v8::Object> target, const char* method, int argc, v8::Handle<v8::Value>* argv)
|
||||
- Added NanSetTemplate(v8::Handle<v8::Template> templ, v8::Handle<v8::String> name , v8::Handle<v8::Data> value, v8::PropertyAttribute attributes)
|
||||
- Added NanSetPrototypeTemplate(v8::Local<v8::FunctionTemplate> templ, v8::Handle<v8::String> name, v8::Handle<v8::Data> value, v8::PropertyAttribute attributes)
|
||||
- Added NanSetInstanceTemplate(v8::Local<v8::FunctionTemplate> templ, const char *name, v8::Handle<v8::Data> value)
|
||||
- Added NanSetInstanceTemplate(v8::Local<v8::FunctionTemplate> templ, v8::Handle<v8::String> name, v8::Handle<v8::Data> value, v8::PropertyAttribute attributes)
|
||||
|
||||
### 1.2.0 Jun 5 2014
|
||||
|
||||
- Add NanSetPrototypeTemplate
|
||||
- Changed NAN_WEAK_CALLBACK internals, switched _NanWeakCallbackData to class,
|
||||
introduced _NanWeakCallbackDispatcher
|
||||
- Removed -Wno-unused-local-typedefs from test builds
|
||||
- Made test builds Windows compatible ('Sleep()')
|
||||
|
||||
### 1.1.2 May 28 2014
|
||||
|
||||
- Release to fix more stuff-ups in 1.1.1
|
||||
|
||||
### 1.1.1 May 28 2014
|
||||
|
||||
- Release to fix version mismatch in nan.h and lack of changelog entry for 1.1.0
|
||||
|
||||
### 1.1.0 May 25 2014
|
||||
|
||||
- Remove nan_isolate, use v8::Isolate::GetCurrent() internally instead
|
||||
- Additional explicit overloads for NanNew(): (char*,int), (uint8_t*[,int]),
|
||||
(uint16_t*[,int), double, int, unsigned int, bool, v8::String::ExternalStringResource*,
|
||||
v8::String::ExternalAsciiStringResource*
|
||||
- Deprecate NanSymbol()
|
||||
- Added SetErrorMessage() and ErrorMessage() to NanAsyncWorker
|
||||
|
||||
### 1.0.0 May 4 2014
|
||||
|
||||
- Heavy API changes for V8 3.25 / Node 0.11.13
|
||||
- Use cpplint.py
|
||||
- Removed NanInitPersistent
|
||||
- Removed NanPersistentToLocal
|
||||
- Removed NanFromV8String
|
||||
- Removed NanMakeWeak
|
||||
- Removed NanNewLocal
|
||||
- Removed NAN_WEAK_CALLBACK_OBJECT
|
||||
- Removed NAN_WEAK_CALLBACK_DATA
|
||||
- Introduce NanNew, replaces NanNewLocal, NanPersistentToLocal, adds many overloaded typed versions
|
||||
- Introduce NanUndefined, NanNull, NanTrue and NanFalse
|
||||
- Introduce NanEscapableScope and NanEscapeScope
|
||||
- Introduce NanMakeWeakPersistent (requires a special callback to work on both old and new node)
|
||||
- Introduce NanMakeCallback for node::MakeCallback
|
||||
- Introduce NanSetTemplate
|
||||
- Introduce NanGetCurrentContext
|
||||
- Introduce NanCompileScript and NanRunScript
|
||||
- Introduce NanAdjustExternalMemory
|
||||
- Introduce NanAddGCEpilogueCallback, NanAddGCPrologueCallback, NanRemoveGCEpilogueCallback, NanRemoveGCPrologueCallback
|
||||
- Introduce NanGetHeapStatistics
|
||||
- Rename NanAsyncWorker#SavePersistent() to SaveToPersistent()
|
||||
|
||||
### 0.8.0 Jan 9 2014
|
||||
|
||||
- NanDispose -> NanDisposePersistent, deprecate NanDispose
|
||||
- Extract _NAN_*_RETURN_TYPE, pull up NAN_*()
|
||||
|
||||
### 0.7.1 Jan 9 2014
|
||||
|
||||
- Fixes to work against debug builds of Node
|
||||
- Safer NanPersistentToLocal (avoid reinterpret_cast)
|
||||
- Speed up common NanRawString case by only extracting flattened string when necessary
|
||||
|
||||
### 0.7.0 Dec 17 2013
|
||||
|
||||
- New no-arg form of NanCallback() constructor.
|
||||
- NanCallback#Call takes Handle rather than Local
|
||||
- Removed deprecated NanCallback#Run method, use NanCallback#Call instead
|
||||
- Split off _NAN_*_ARGS_TYPE from _NAN_*_ARGS
|
||||
- Restore (unofficial) Node 0.6 compatibility at NanCallback#Call()
|
||||
- Introduce NanRawString() for char* (or appropriate void*) from v8::String
|
||||
(replacement for NanFromV8String)
|
||||
- Introduce NanCString() for null-terminated char* from v8::String
|
||||
|
||||
### 0.6.0 Nov 21 2013
|
||||
|
||||
- Introduce NanNewLocal<T>(v8::Handle<T> value) for use in place of
|
||||
v8::Local<T>::New(...) since v8 started requiring isolate in Node 0.11.9
|
||||
|
||||
### 0.5.2 Nov 16 2013
|
||||
|
||||
- Convert SavePersistent and GetFromPersistent in NanAsyncWorker from protected and public
|
||||
|
||||
### 0.5.1 Nov 12 2013
|
||||
|
||||
- Use node::MakeCallback() instead of direct v8::Function::Call()
|
||||
|
||||
### 0.5.0 Nov 11 2013
|
||||
|
||||
- Added @TooTallNate as collaborator
|
||||
- New, much simpler, "include_dirs" for binding.gyp
|
||||
- Added full range of NAN_INDEX_* macros to match NAN_PROPERTY_* macros
|
||||
|
||||
### 0.4.4 Nov 2 2013
|
||||
|
||||
- Isolate argument from v8::Persistent::MakeWeak removed for 0.11.8+
|
||||
|
||||
### 0.4.3 Nov 2 2013
|
||||
|
||||
- Include node_object_wrap.h, removed from node.h for Node 0.11.8.
|
||||
|
||||
### 0.4.2 Nov 2 2013
|
||||
|
||||
- Handle deprecation of v8::Persistent::Dispose(v8::Isolate* isolate)) for
|
||||
Node 0.11.8 release.
|
||||
|
||||
### 0.4.1 Sep 16 2013
|
||||
|
||||
- Added explicit `#include <uv.h>` as it was removed from node.h for v0.11.8
|
||||
|
||||
### 0.4.0 Sep 2 2013
|
||||
|
||||
- Added NAN_INLINE and NAN_DEPRECATED and made use of them
|
||||
- Added NanError, NanTypeError and NanRangeError
|
||||
- Cleaned up code
|
||||
|
||||
### 0.3.2 Aug 30 2013
|
||||
|
||||
- Fix missing scope declaration in GetFromPersistent() and SaveToPersistent
|
||||
in NanAsyncWorker
|
||||
|
||||
### 0.3.1 Aug 20 2013
|
||||
|
||||
- fix "not all control paths return a value" compile warning on some platforms
|
||||
|
||||
### 0.3.0 Aug 19 2013
|
||||
|
||||
- Made NAN work with NPM
|
||||
- Lots of fixes to NanFromV8String, pulling in features from new Node core
|
||||
- Changed node::encoding to Nan::Encoding in NanFromV8String to unify the API
|
||||
- Added optional error number argument for NanThrowError()
|
||||
- Added NanInitPersistent()
|
||||
- Added NanReturnNull() and NanReturnEmptyString()
|
||||
- Added NanLocker and NanUnlocker
|
||||
- Added missing scopes
|
||||
- Made sure to clear disposed Persistent handles
|
||||
- Changed NanAsyncWorker to allocate error messages on the heap
|
||||
- Changed NanThrowError(Local<Value>) to NanThrowError(Handle<Value>)
|
||||
- Fixed leak in NanAsyncWorker when errmsg is used
|
||||
|
||||
### 0.2.2 Aug 5 2013
|
||||
|
||||
- Fixed usage of undefined variable with node::BASE64 in NanFromV8String()
|
||||
|
||||
### 0.2.1 Aug 5 2013
|
||||
|
||||
- Fixed 0.8 breakage, node::BUFFER encoding type not available in 0.8 for
|
||||
NanFromV8String()
|
||||
|
||||
### 0.2.0 Aug 5 2013
|
||||
|
||||
- Added NAN_PROPERTY_GETTER, NAN_PROPERTY_SETTER, NAN_PROPERTY_ENUMERATOR,
|
||||
NAN_PROPERTY_DELETER, NAN_PROPERTY_QUERY
|
||||
- Extracted _NAN_METHOD_ARGS, _NAN_GETTER_ARGS, _NAN_SETTER_ARGS,
|
||||
_NAN_PROPERTY_GETTER_ARGS, _NAN_PROPERTY_SETTER_ARGS,
|
||||
_NAN_PROPERTY_ENUMERATOR_ARGS, _NAN_PROPERTY_DELETER_ARGS,
|
||||
_NAN_PROPERTY_QUERY_ARGS
|
||||
- Added NanGetInternalFieldPointer, NanSetInternalFieldPointer
|
||||
- Added NAN_WEAK_CALLBACK, NAN_WEAK_CALLBACK_OBJECT,
|
||||
NAN_WEAK_CALLBACK_DATA, NanMakeWeak
|
||||
- Renamed THROW_ERROR to _NAN_THROW_ERROR
|
||||
- Added NanNewBufferHandle(char*, size_t, node::smalloc::FreeCallback, void*)
|
||||
- Added NanBufferUse(char*, uint32_t)
|
||||
- Added NanNewContextHandle(v8::ExtensionConfiguration*,
|
||||
v8::Handle<v8::ObjectTemplate>, v8::Handle<v8::Value>)
|
||||
- Fixed broken NanCallback#GetFunction()
|
||||
- Added optional encoding and size arguments to NanFromV8String()
|
||||
- Added NanGetPointerSafe() and NanSetPointerSafe()
|
||||
- Added initial test suite (to be expanded)
|
||||
- Allow NanUInt32OptionValue to convert any Number object
|
||||
|
||||
### 0.1.0 Jul 21 2013
|
||||
|
||||
- Added `NAN_GETTER`, `NAN_SETTER`
|
||||
- Added `NanThrowError` with single Local<Value> argument
|
||||
- Added `NanNewBufferHandle` with single uint32_t argument
|
||||
- Added `NanHasInstance(Persistent<FunctionTemplate>&, Handle<Value>)`
|
||||
- Added `Local<Function> NanCallback#GetFunction()`
|
||||
- Added `NanCallback#Call(int, Local<Value>[])`
|
||||
- Deprecated `NanCallback#Run(int, Local<Value>[])` in favour of Call
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright (c) 2015 NAN contributors
|
||||
-----------------------------------
|
||||
|
||||
*NAN contributors listed at <https://github.com/rvagg/nan#contributors>*
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+1292
File diff suppressed because it is too large
Load Diff
+35
@@ -0,0 +1,35 @@
|
||||
# http://www.appveyor.com/docs/appveyor-yml
|
||||
|
||||
# Test against these versions of Node.js.
|
||||
environment:
|
||||
matrix:
|
||||
# node.js
|
||||
- nodejs_version: "0.8"
|
||||
- nodejs_version: "0.10"
|
||||
- nodejs_version: "0.11"
|
||||
# io.js
|
||||
- nodejs_version: "1.0"
|
||||
|
||||
# Install scripts. (runs after repo cloning)
|
||||
install:
|
||||
# Get the latest stable version of Node 0.STABLE.latest
|
||||
- ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version)
|
||||
- IF NOT %nodejs_version% == 1.0 npm -g install npm
|
||||
- IF NOT %nodejs_version% == 1.0 set PATH=%APPDATA%\npm;%PATH%
|
||||
# Typical npm stuff.
|
||||
- npm install
|
||||
- npm run rebuild-tests
|
||||
|
||||
# Post-install test scripts.
|
||||
test_script:
|
||||
# Output useful info for debugging.
|
||||
- node --version
|
||||
- npm --version
|
||||
# run tests
|
||||
- npm test
|
||||
|
||||
# Don't actually build.
|
||||
build: off
|
||||
|
||||
# Set build version format here instead of in the admin panel.
|
||||
version: "{build}"
|
||||
+1
@@ -0,0 +1 @@
|
||||
console.log(require('path').relative('.', __dirname));
|
||||
+2157
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+262
@@ -0,0 +1,262 @@
|
||||
/*********************************************************************
|
||||
* NAN - Native Abstractions for Node.js
|
||||
*
|
||||
* Copyright (c) 2015 NAN contributors
|
||||
*
|
||||
* MIT License <https://github.com/rvagg/nan/blob/master/LICENSE.md>
|
||||
********************************************************************/
|
||||
|
||||
#ifndef NAN_IMPLEMENTATION_12_INL_H_
|
||||
#define NAN_IMPLEMENTATION_12_INL_H_
|
||||
//==============================================================================
|
||||
// node v0.11 implementation
|
||||
//==============================================================================
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning( disable : 4530 )
|
||||
# include <string>
|
||||
# pragma warning( default : 4530 )
|
||||
#else
|
||||
# include <string>
|
||||
#endif
|
||||
|
||||
namespace NanIntern {
|
||||
|
||||
//=== Array ====================================================================
|
||||
|
||||
Factory<v8::Array>::return_t
|
||||
Factory<v8::Array>::New() {
|
||||
return v8::Array::New(v8::Isolate::GetCurrent());
|
||||
}
|
||||
|
||||
Factory<v8::Array>::return_t
|
||||
Factory<v8::Array>::New(int length) {
|
||||
return v8::Array::New(v8::Isolate::GetCurrent(), length);
|
||||
}
|
||||
|
||||
//=== Boolean ==================================================================
|
||||
|
||||
Factory<v8::Boolean>::return_t
|
||||
Factory<v8::Boolean>::New(bool value) {
|
||||
return v8::Boolean::New(v8::Isolate::GetCurrent(), value);
|
||||
}
|
||||
|
||||
//=== Boolean Object ===========================================================
|
||||
|
||||
Factory<v8::BooleanObject>::return_t
|
||||
Factory<v8::BooleanObject>::New(bool value) {
|
||||
return v8::BooleanObject::New(value).As<v8::BooleanObject>();
|
||||
}
|
||||
|
||||
//=== Context ==================================================================
|
||||
|
||||
Factory<v8::Context>::return_t
|
||||
Factory<v8::Context>::New( v8::ExtensionConfiguration* extensions
|
||||
, v8::Handle<v8::ObjectTemplate> tmpl
|
||||
, v8::Handle<v8::Value> obj) {
|
||||
return v8::Context::New(v8::Isolate::GetCurrent(), extensions, tmpl, obj);
|
||||
}
|
||||
|
||||
//=== Date =====================================================================
|
||||
|
||||
Factory<v8::Date>::return_t
|
||||
Factory<v8::Date>::New(double value) {
|
||||
return v8::Date::New(v8::Isolate::GetCurrent(), value).As<v8::Date>();
|
||||
}
|
||||
|
||||
//=== External =================================================================
|
||||
|
||||
Factory<v8::External>::return_t
|
||||
Factory<v8::External>::New(void * value) {
|
||||
return v8::External::New(v8::Isolate::GetCurrent(), value);
|
||||
}
|
||||
|
||||
//=== Function =================================================================
|
||||
|
||||
Factory<v8::Function>::return_t
|
||||
Factory<v8::Function>::New( NanFunctionCallback callback
|
||||
, v8::Handle<v8::Value> data) {
|
||||
return v8::Function::New( v8::Isolate::GetCurrent()
|
||||
, callback
|
||||
, data);
|
||||
}
|
||||
|
||||
//=== Function Template ========================================================
|
||||
|
||||
Factory<v8::FunctionTemplate>::return_t
|
||||
Factory<v8::FunctionTemplate>::New( NanFunctionCallback callback
|
||||
, v8::Handle<v8::Value> data
|
||||
, v8::Handle<v8::Signature> signature) {
|
||||
return v8::FunctionTemplate::New( v8::Isolate::GetCurrent()
|
||||
, callback
|
||||
, data
|
||||
, signature);
|
||||
}
|
||||
|
||||
//=== Number ===================================================================
|
||||
|
||||
Factory<v8::Number>::return_t
|
||||
Factory<v8::Number>::New(double value) {
|
||||
return v8::Number::New(v8::Isolate::GetCurrent(), value);
|
||||
}
|
||||
|
||||
//=== Number Object ============================================================
|
||||
|
||||
Factory<v8::NumberObject>::return_t
|
||||
Factory<v8::NumberObject>::New(double value) {
|
||||
return v8::NumberObject::New( v8::Isolate::GetCurrent()
|
||||
, value).As<v8::NumberObject>();
|
||||
}
|
||||
|
||||
//=== Integer, Int32 and Uint32 ================================================
|
||||
|
||||
template <typename T>
|
||||
typename IntegerFactory<T>::return_t
|
||||
IntegerFactory<T>::New(int32_t value) {
|
||||
return To<T>(T::New(v8::Isolate::GetCurrent(), value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename IntegerFactory<T>::return_t
|
||||
IntegerFactory<T>::New(uint32_t value) {
|
||||
return To<T>(T::NewFromUnsigned(v8::Isolate::GetCurrent(), value));
|
||||
}
|
||||
|
||||
Factory<v8::Uint32>::return_t
|
||||
Factory<v8::Uint32>::New(int32_t value) {
|
||||
return To<v8::Uint32>(
|
||||
v8::Uint32::NewFromUnsigned(v8::Isolate::GetCurrent(), value));
|
||||
}
|
||||
|
||||
Factory<v8::Uint32>::return_t
|
||||
Factory<v8::Uint32>::New(uint32_t value) {
|
||||
return To<v8::Uint32>(
|
||||
v8::Uint32::NewFromUnsigned(v8::Isolate::GetCurrent(), value));
|
||||
}
|
||||
|
||||
//=== Object ===================================================================
|
||||
|
||||
Factory<v8::Object>::return_t
|
||||
Factory<v8::Object>::New() {
|
||||
return v8::Object::New(v8::Isolate::GetCurrent());
|
||||
}
|
||||
|
||||
//=== Object Template ==========================================================
|
||||
|
||||
Factory<v8::ObjectTemplate>::return_t
|
||||
Factory<v8::ObjectTemplate>::New() {
|
||||
return v8::ObjectTemplate::New(v8::Isolate::GetCurrent());
|
||||
}
|
||||
|
||||
//=== RegExp ===================================================================
|
||||
|
||||
Factory<v8::RegExp>::return_t
|
||||
Factory<v8::RegExp>::New(
|
||||
v8::Handle<v8::String> pattern
|
||||
, v8::RegExp::Flags flags) {
|
||||
return v8::RegExp::New(pattern, flags);
|
||||
}
|
||||
|
||||
//=== Script ===================================================================
|
||||
|
||||
Factory<v8::Script>::return_t
|
||||
Factory<v8::Script>::New( v8::Local<v8::String> source) {
|
||||
v8::ScriptCompiler::Source src(source);
|
||||
return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &src);
|
||||
}
|
||||
|
||||
Factory<v8::Script>::return_t
|
||||
Factory<v8::Script>::New( v8::Local<v8::String> source
|
||||
, v8::ScriptOrigin const& origin) {
|
||||
v8::ScriptCompiler::Source src(source, origin);
|
||||
return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &src);
|
||||
}
|
||||
|
||||
//=== Signature ================================================================
|
||||
|
||||
Factory<v8::Signature>::return_t
|
||||
Factory<v8::Signature>::New( Factory<v8::Signature>::FTH receiver
|
||||
, int argc
|
||||
, Factory<v8::Signature>::FTH argv[]) {
|
||||
return v8::Signature::New(v8::Isolate::GetCurrent(), receiver, argc, argv);
|
||||
}
|
||||
|
||||
//=== String ===================================================================
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New() {
|
||||
return v8::String::Empty(v8::Isolate::GetCurrent());
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(const char * value, int length) {
|
||||
return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), value,
|
||||
v8::String::kNormalString, length);
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(std::string const& value) {
|
||||
assert(value.size() <= INT_MAX && "string too long");
|
||||
return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(),
|
||||
value.data(), v8::String::kNormalString, static_cast<int>(value.size()));
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(const uint8_t * value, int length) {
|
||||
return v8::String::NewFromOneByte(v8::Isolate::GetCurrent(), value,
|
||||
v8::String::kNormalString, length);
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(const uint16_t * value, int length) {
|
||||
return v8::String::NewFromTwoByte(v8::Isolate::GetCurrent(), value,
|
||||
v8::String::kNormalString, length);
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(v8::String::ExternalStringResource * value) {
|
||||
return v8::String::NewExternal(v8::Isolate::GetCurrent(), value);
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(NanExternalOneByteStringResource * value) {
|
||||
return v8::String::NewExternal(v8::Isolate::GetCurrent(), value);
|
||||
}
|
||||
|
||||
//=== String Object ============================================================
|
||||
|
||||
Factory<v8::StringObject>::return_t
|
||||
Factory<v8::StringObject>::New(v8::Handle<v8::String> value) {
|
||||
return v8::StringObject::New(value).As<v8::StringObject>();
|
||||
}
|
||||
|
||||
//=== Unbound Script ===========================================================
|
||||
|
||||
Factory<v8::UnboundScript>::return_t
|
||||
Factory<v8::UnboundScript>::New(v8::Local<v8::String> source) {
|
||||
v8::ScriptCompiler::Source src(source);
|
||||
return v8::ScriptCompiler::CompileUnbound(v8::Isolate::GetCurrent(), &src);
|
||||
}
|
||||
|
||||
Factory<v8::UnboundScript>::return_t
|
||||
Factory<v8::UnboundScript>::New( v8::Local<v8::String> source
|
||||
, v8::ScriptOrigin const& origin) {
|
||||
v8::ScriptCompiler::Source src(source, origin);
|
||||
return v8::ScriptCompiler::CompileUnbound(v8::Isolate::GetCurrent(), &src);
|
||||
}
|
||||
|
||||
} // end of namespace NanIntern
|
||||
|
||||
//=== Presistents and Handles ==================================================
|
||||
|
||||
template <typename T>
|
||||
inline v8::Local<T> NanNew(v8::Handle<T> h) {
|
||||
return v8::Local<T>::New(v8::Isolate::GetCurrent(), h);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline v8::Local<T> NanNew(v8::Persistent<T> const& p) {
|
||||
return v8::Local<T>::New(v8::Isolate::GetCurrent(), p);
|
||||
}
|
||||
|
||||
#endif // NAN_IMPLEMENTATION_12_INL_H_
|
||||
Generated
Vendored
+268
@@ -0,0 +1,268 @@
|
||||
/*********************************************************************
|
||||
* NAN - Native Abstractions for Node.js
|
||||
*
|
||||
* Copyright (c) 2015 NAN contributors
|
||||
*
|
||||
* MIT License <https://github.com/rvagg/nan/blob/master/LICENSE.md>
|
||||
********************************************************************/
|
||||
|
||||
#ifndef NAN_IMPLEMENTATION_PRE_12_INL_H_
|
||||
#define NAN_IMPLEMENTATION_PRE_12_INL_H_
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning( disable : 4530 )
|
||||
# include <string>
|
||||
# include <vector>
|
||||
# pragma warning( default : 4530 )
|
||||
#else
|
||||
# include <string>
|
||||
# include <vector>
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// node v0.10 implementation
|
||||
//==============================================================================
|
||||
|
||||
namespace NanIntern {
|
||||
|
||||
//=== Array ====================================================================
|
||||
|
||||
Factory<v8::Array>::return_t
|
||||
Factory<v8::Array>::New() {
|
||||
return v8::Array::New();
|
||||
}
|
||||
|
||||
Factory<v8::Array>::return_t
|
||||
Factory<v8::Array>::New(int length) {
|
||||
return v8::Array::New(length);
|
||||
}
|
||||
|
||||
//=== Boolean ==================================================================
|
||||
|
||||
Factory<v8::Boolean>::return_t
|
||||
Factory<v8::Boolean>::New(bool value) {
|
||||
return v8::Boolean::New(value)->ToBoolean();
|
||||
}
|
||||
|
||||
//=== Boolean Object ===========================================================
|
||||
|
||||
Factory<v8::BooleanObject>::return_t
|
||||
Factory<v8::BooleanObject>::New(bool value) {
|
||||
return v8::BooleanObject::New(value).As<v8::BooleanObject>();
|
||||
}
|
||||
|
||||
//=== Context ==================================================================
|
||||
|
||||
Factory<v8::Context>::return_t
|
||||
Factory<v8::Context>::New( v8::ExtensionConfiguration* extensions
|
||||
, v8::Handle<v8::ObjectTemplate> tmpl
|
||||
, v8::Handle<v8::Value> obj) {
|
||||
v8::Persistent<v8::Context> ctx = v8::Context::New(extensions, tmpl, obj);
|
||||
v8::Local<v8::Context> lctx = v8::Local<v8::Context>::New(ctx);
|
||||
ctx.Dispose();
|
||||
return lctx;
|
||||
}
|
||||
|
||||
//=== Date =====================================================================
|
||||
|
||||
Factory<v8::Date>::return_t
|
||||
Factory<v8::Date>::New(double value) {
|
||||
return v8::Date::New(value).As<v8::Date>();
|
||||
}
|
||||
|
||||
//=== External =================================================================
|
||||
|
||||
Factory<v8::External>::return_t
|
||||
Factory<v8::External>::New(void * value) {
|
||||
return v8::External::New(value);
|
||||
}
|
||||
|
||||
//=== Function =================================================================
|
||||
|
||||
Factory<v8::Function>::return_t
|
||||
Factory<v8::Function>::New( NanFunctionCallback callback
|
||||
, v8::Handle<v8::Value> data) {
|
||||
return Factory<v8::FunctionTemplate>::New( callback
|
||||
, data
|
||||
, v8::Handle<v8::Signature>()
|
||||
)->GetFunction();
|
||||
}
|
||||
|
||||
|
||||
//=== FunctionTemplate =========================================================
|
||||
|
||||
Factory<v8::FunctionTemplate>::return_t
|
||||
Factory<v8::FunctionTemplate>::New( NanFunctionCallback callback
|
||||
, v8::Handle<v8::Value> data
|
||||
, v8::Handle<v8::Signature> signature) {
|
||||
// Note(agnat): Emulate length argument here. Unfortunately, I couldn't find
|
||||
// a way. Have at it though...
|
||||
return v8::FunctionTemplate::New( callback
|
||||
, data
|
||||
, signature);
|
||||
}
|
||||
|
||||
//=== Number ===================================================================
|
||||
|
||||
Factory<v8::Number>::return_t
|
||||
Factory<v8::Number>::New(double value) {
|
||||
return v8::Number::New(value);
|
||||
}
|
||||
|
||||
//=== Number Object ============================================================
|
||||
|
||||
Factory<v8::NumberObject>::return_t
|
||||
Factory<v8::NumberObject>::New(double value) {
|
||||
return v8::NumberObject::New(value).As<v8::NumberObject>();
|
||||
}
|
||||
|
||||
//=== Integer, Int32 and Uint32 ================================================
|
||||
|
||||
template <typename T>
|
||||
typename IntegerFactory<T>::return_t
|
||||
IntegerFactory<T>::New(int32_t value) {
|
||||
return To<T>(T::New(value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename IntegerFactory<T>::return_t
|
||||
IntegerFactory<T>::New(uint32_t value) {
|
||||
return To<T>(T::NewFromUnsigned(value));
|
||||
}
|
||||
|
||||
Factory<v8::Uint32>::return_t
|
||||
Factory<v8::Uint32>::New(int32_t value) {
|
||||
return To<v8::Uint32>(v8::Uint32::NewFromUnsigned(value));
|
||||
}
|
||||
|
||||
Factory<v8::Uint32>::return_t
|
||||
Factory<v8::Uint32>::New(uint32_t value) {
|
||||
return To<v8::Uint32>(v8::Uint32::NewFromUnsigned(value));
|
||||
}
|
||||
|
||||
|
||||
//=== Object ===================================================================
|
||||
|
||||
Factory<v8::Object>::return_t
|
||||
Factory<v8::Object>::New() {
|
||||
return v8::Object::New();
|
||||
}
|
||||
|
||||
//=== Object Template ==========================================================
|
||||
|
||||
Factory<v8::ObjectTemplate>::return_t
|
||||
Factory<v8::ObjectTemplate>::New() {
|
||||
return v8::ObjectTemplate::New();
|
||||
}
|
||||
|
||||
//=== RegExp ===================================================================
|
||||
|
||||
Factory<v8::RegExp>::return_t
|
||||
Factory<v8::RegExp>::New(
|
||||
v8::Handle<v8::String> pattern
|
||||
, v8::RegExp::Flags flags) {
|
||||
return v8::RegExp::New(pattern, flags);
|
||||
}
|
||||
|
||||
//=== Script ===================================================================
|
||||
|
||||
Factory<v8::Script>::return_t
|
||||
Factory<v8::Script>::New( v8::Local<v8::String> source) {
|
||||
return v8::Script::New(source);
|
||||
}
|
||||
Factory<v8::Script>::return_t
|
||||
Factory<v8::Script>::New( v8::Local<v8::String> source
|
||||
, v8::ScriptOrigin const& origin) {
|
||||
return v8::Script::New(source, const_cast<v8::ScriptOrigin*>(&origin));
|
||||
}
|
||||
|
||||
//=== Signature ================================================================
|
||||
|
||||
Factory<v8::Signature>::return_t
|
||||
Factory<v8::Signature>::New( Factory<v8::Signature>::FTH receiver
|
||||
, int argc
|
||||
, Factory<v8::Signature>::FTH argv[]) {
|
||||
return v8::Signature::New(receiver, argc, argv);
|
||||
}
|
||||
|
||||
//=== String ===================================================================
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New() {
|
||||
return v8::String::Empty();
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(const char * value, int length) {
|
||||
return v8::String::New(value, length);
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(std::string const& value) {
|
||||
assert(value.size() <= INT_MAX && "string too long");
|
||||
return v8::String::New( value.data(), static_cast<int>(value.size()));
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
widenString(std::vector<uint16_t> *ws, const uint8_t *s, int l = -1) {
|
||||
size_t len = static_cast<size_t>(l);
|
||||
if (l < 0) {
|
||||
len = strlen(reinterpret_cast<const char*>(s));
|
||||
}
|
||||
assert(len <= INT_MAX && "string too long");
|
||||
ws->resize(len);
|
||||
std::copy(s, s + len, ws->begin());
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(const uint16_t * value, int length) {
|
||||
return v8::String::New(value, length);
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(const uint8_t * value, int length) {
|
||||
std::vector<uint16_t> wideString;
|
||||
widenString(&wideString, value, length);
|
||||
if (wideString.size() == 0) {
|
||||
return v8::String::Empty();
|
||||
} else {
|
||||
return v8::String::New(&wideString.front()
|
||||
, static_cast<int>(wideString.size()));
|
||||
}
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(v8::String::ExternalStringResource * value) {
|
||||
return v8::String::NewExternal(value);
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(v8::String::ExternalAsciiStringResource * value) {
|
||||
return v8::String::NewExternal(value);
|
||||
}
|
||||
|
||||
//=== String Object ============================================================
|
||||
|
||||
Factory<v8::StringObject>::return_t
|
||||
Factory<v8::StringObject>::New(v8::Handle<v8::String> value) {
|
||||
return v8::StringObject::New(value).As<v8::StringObject>();
|
||||
}
|
||||
|
||||
} // end of namespace NanIntern
|
||||
|
||||
//=== Presistents and Handles ==================================================
|
||||
|
||||
template <typename T>
|
||||
inline v8::Local<T> NanNew(v8::Handle<T> h) {
|
||||
return v8::Local<T>::New(h);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline v8::Local<T> NanNew(v8::Persistent<T> const& p) {
|
||||
return v8::Local<T>::New(p);
|
||||
}
|
||||
|
||||
#endif // NAN_IMPLEMENTATION_PRE_12_INL_H_
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
/*********************************************************************
|
||||
* NAN - Native Abstractions for Node.js
|
||||
*
|
||||
* Copyright (c) 2015 NAN contributors
|
||||
*
|
||||
* MIT License <https://github.com/rvagg/nan/blob/master/LICENSE.md>
|
||||
********************************************************************/
|
||||
|
||||
#ifndef NAN_NEW_H_
|
||||
#define NAN_NEW_H_
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning( disable : 4530 )
|
||||
# include <string>
|
||||
# pragma warning( default : 4530 )
|
||||
#else
|
||||
# include <string>
|
||||
#endif
|
||||
|
||||
namespace NanIntern { // scnr
|
||||
|
||||
// TODO(agnat): Generalize
|
||||
template <typename T> v8::Local<T> To(v8::Handle<v8::Integer> i);
|
||||
|
||||
template <>
|
||||
inline
|
||||
v8::Local<v8::Integer>
|
||||
To<v8::Integer>(v8::Handle<v8::Integer> i) { return i->ToInteger(); }
|
||||
|
||||
template <>
|
||||
inline
|
||||
v8::Local<v8::Int32>
|
||||
To<v8::Int32>(v8::Handle<v8::Integer> i) { return i->ToInt32(); }
|
||||
|
||||
template <>
|
||||
inline
|
||||
v8::Local<v8::Uint32>
|
||||
To<v8::Uint32>(v8::Handle<v8::Integer> i) { return i->ToUint32(); }
|
||||
|
||||
template <typename T> struct FactoryBase { typedef v8::Local<T> return_t; };
|
||||
|
||||
template <typename T> struct Factory;
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Array> : FactoryBase<v8::Array> {
|
||||
static inline return_t New();
|
||||
static inline return_t New(int length);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Boolean> : FactoryBase<v8::Boolean> {
|
||||
static inline return_t New(bool value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::BooleanObject> : FactoryBase<v8::BooleanObject> {
|
||||
static inline return_t New(bool value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Context> : FactoryBase<v8::Context> {
|
||||
static inline
|
||||
return_t
|
||||
New( v8::ExtensionConfiguration* extensions = NULL
|
||||
, v8::Handle<v8::ObjectTemplate> tmpl = v8::Handle<v8::ObjectTemplate>()
|
||||
, v8::Handle<v8::Value> obj = v8::Handle<v8::Value>());
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Date> : FactoryBase<v8::Date> {
|
||||
static inline return_t New(double value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::External> : FactoryBase<v8::External> {
|
||||
static inline return_t New(void *value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Function> : FactoryBase<v8::Function> {
|
||||
static inline
|
||||
return_t
|
||||
New( NanFunctionCallback callback
|
||||
, v8::Handle<v8::Value> data = v8::Handle<v8::Value>());
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::FunctionTemplate> : FactoryBase<v8::FunctionTemplate> {
|
||||
static inline
|
||||
return_t
|
||||
New( NanFunctionCallback callback = NULL
|
||||
, v8::Handle<v8::Value> data = v8::Handle<v8::Value>()
|
||||
, v8::Handle<v8::Signature> signature = v8::Handle<v8::Signature>());
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Number> : FactoryBase<v8::Number> {
|
||||
static inline return_t New(double value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::NumberObject> : FactoryBase<v8::NumberObject> {
|
||||
static inline return_t New(double value);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IntegerFactory : FactoryBase<T> {
|
||||
typedef typename FactoryBase<T>::return_t return_t;
|
||||
static inline return_t New(int32_t value);
|
||||
static inline return_t New(uint32_t value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Integer> : IntegerFactory<v8::Integer> {};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Int32> : IntegerFactory<v8::Int32> {};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Uint32> : FactoryBase<v8::Uint32> {
|
||||
static inline return_t New(int32_t value);
|
||||
static inline return_t New(uint32_t value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Object> : FactoryBase<v8::Object> {
|
||||
static inline return_t New();
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::ObjectTemplate> : FactoryBase<v8::ObjectTemplate> {
|
||||
static inline return_t New();
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::RegExp> : FactoryBase<v8::RegExp> {
|
||||
static inline return_t New(
|
||||
v8::Handle<v8::String> pattern, v8::RegExp::Flags flags);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Script> : FactoryBase<v8::Script> {
|
||||
static inline return_t New( v8::Local<v8::String> source);
|
||||
static inline return_t New( v8::Local<v8::String> source
|
||||
, v8::ScriptOrigin const& origin);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Signature> : FactoryBase<v8::Signature> {
|
||||
typedef v8::Handle<v8::FunctionTemplate> FTH;
|
||||
static inline
|
||||
return_t
|
||||
New( FTH receiver = FTH(), int argc = 0, FTH argv[] = NULL );
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::String> : FactoryBase<v8::String> {
|
||||
static inline return_t New();
|
||||
static inline return_t New(const char *value, int length = -1);
|
||||
static inline return_t New(const uint16_t *value, int length = -1);
|
||||
static inline return_t New(std::string const& value);
|
||||
|
||||
static inline return_t New(v8::String::ExternalStringResource * value);
|
||||
static inline return_t New(NanExternalOneByteStringResource * value);
|
||||
|
||||
// TODO(agnat): Deprecate.
|
||||
static inline return_t New(const uint8_t * value, int length = -1);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::StringObject> : FactoryBase<v8::StringObject> {
|
||||
static inline return_t New(v8::Handle<v8::String> value);
|
||||
};
|
||||
|
||||
} // end of namespace NanIntern
|
||||
|
||||
#if (NODE_MODULE_VERSION >= 12)
|
||||
|
||||
namespace NanIntern {
|
||||
|
||||
template <>
|
||||
struct Factory<v8::UnboundScript> : FactoryBase<v8::UnboundScript> {
|
||||
static inline return_t New( v8::Local<v8::String> source);
|
||||
static inline return_t New( v8::Local<v8::String> source
|
||||
, v8::ScriptOrigin const& origin);
|
||||
};
|
||||
|
||||
} // end of namespace NanIntern
|
||||
|
||||
# include "nan_implementation_12_inl.h"
|
||||
|
||||
#else // NODE_MODULE_VERSION >= 12
|
||||
|
||||
# include "nan_implementation_pre_12_inl.h"
|
||||
|
||||
#endif
|
||||
|
||||
//=== API ======================================================================
|
||||
|
||||
template <typename T>
|
||||
typename NanIntern::Factory<T>::return_t
|
||||
NanNew() {
|
||||
return NanIntern::Factory<T>::New();
|
||||
}
|
||||
|
||||
template <typename T, typename A0>
|
||||
typename NanIntern::Factory<T>::return_t
|
||||
NanNew(A0 arg0) {
|
||||
return NanIntern::Factory<T>::New(arg0);
|
||||
}
|
||||
|
||||
template <typename T, typename A0, typename A1>
|
||||
typename NanIntern::Factory<T>::return_t
|
||||
NanNew(A0 arg0, A1 arg1) {
|
||||
return NanIntern::Factory<T>::New(arg0, arg1);
|
||||
}
|
||||
|
||||
template <typename T, typename A0, typename A1, typename A2>
|
||||
typename NanIntern::Factory<T>::return_t
|
||||
NanNew(A0 arg0, A1 arg1, A2 arg2) {
|
||||
return NanIntern::Factory<T>::New(arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
template <typename T, typename A0, typename A1, typename A2, typename A3>
|
||||
typename NanIntern::Factory<T>::return_t
|
||||
NanNew(A0 arg0, A1 arg1, A2 arg2, A3 arg3) {
|
||||
return NanIntern::Factory<T>::New(arg0, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
// Note(agnat): When passing overloaded function pointers to template functions
|
||||
// as generic arguments the compiler needs help in picking the right overload.
|
||||
// These two functions handle NanNew<Function> and NanNew<FunctionTemplate> with
|
||||
// all argument variations.
|
||||
|
||||
// v8::Function and v8::FunctionTemplate with one or two arguments
|
||||
template <typename T>
|
||||
typename NanIntern::Factory<T>::return_t
|
||||
NanNew( NanFunctionCallback callback
|
||||
, v8::Handle<v8::Value> data = v8::Handle<v8::Value>()) {
|
||||
return NanIntern::Factory<T>::New(callback, data);
|
||||
}
|
||||
|
||||
// v8::Function and v8::FunctionTemplate with three arguments
|
||||
template <typename T, typename A2>
|
||||
typename NanIntern::Factory<T>::return_t
|
||||
NanNew( NanFunctionCallback callback
|
||||
, v8::Handle<v8::Value> data = v8::Handle<v8::Value>()
|
||||
, A2 a2 = A2()) {
|
||||
return NanIntern::Factory<T>::New(callback, data, a2);
|
||||
}
|
||||
|
||||
// Convenience
|
||||
|
||||
template <typename T> inline v8::Local<T> NanNew(v8::Handle<T> h);
|
||||
template <typename T> inline v8::Local<T> NanNew(v8::Persistent<T> const& p);
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::Boolean>::return_t
|
||||
NanNew(bool value) {
|
||||
return NanNew<v8::Boolean>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::Int32>::return_t
|
||||
NanNew(int32_t value) {
|
||||
return NanNew<v8::Int32>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::Uint32>::return_t
|
||||
NanNew(uint32_t value) {
|
||||
return NanNew<v8::Uint32>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::Number>::return_t
|
||||
NanNew(double value) {
|
||||
return NanNew<v8::Number>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::String>::return_t
|
||||
NanNew(std::string const& value) {
|
||||
return NanNew<v8::String>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::String>::return_t
|
||||
NanNew(const char * value, int length) {
|
||||
return NanNew<v8::String>(value, length);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::String>::return_t
|
||||
NanNew(const char * value) {
|
||||
return NanNew<v8::String>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::String>::return_t
|
||||
NanNew(const uint8_t * value) {
|
||||
return NanNew<v8::String>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::String>::return_t
|
||||
NanNew(const uint16_t * value) {
|
||||
return NanNew<v8::String>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::String>::return_t
|
||||
NanNew(v8::String::ExternalStringResource * value) {
|
||||
return NanNew<v8::String>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::String>::return_t
|
||||
NanNew(NanExternalOneByteStringResource * value) {
|
||||
return NanNew<v8::String>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::RegExp>::return_t
|
||||
NanNew(v8::Handle<v8::String> pattern, v8::RegExp::Flags flags) {
|
||||
return NanNew<v8::RegExp>(pattern, flags);
|
||||
}
|
||||
|
||||
#endif // NAN_NEW_H_
|
||||
+69
File diff suppressed because one or more lines are too long
+39
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "bufferutil",
|
||||
"version": "1.0.1",
|
||||
"description": "WebSocket buffer utils",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"install": "node-gyp rebuild"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/websockets/bufferutil"
|
||||
},
|
||||
"keywords": [
|
||||
"bufferutil"
|
||||
],
|
||||
"author": {
|
||||
"name": "Einar Otto Stangvik",
|
||||
"email": "einaros@gmail.com",
|
||||
"url": "http://2x.io"
|
||||
},
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/websockets/bufferutil/issues"
|
||||
},
|
||||
"homepage": "https://github.com/websockets/bufferutil",
|
||||
"dependencies": {
|
||||
"bindings": "1.2.x",
|
||||
"nan": "1.6.x"
|
||||
},
|
||||
"gypfile": true,
|
||||
"readme": "ERROR: No README data found!",
|
||||
"_id": "bufferutil@1.0.1",
|
||||
"dist": {
|
||||
"shasum": "9d3f9dc10b62849bdb41d2a45871b45d27fe7742"
|
||||
},
|
||||
"_from": "bufferutil@1.0.x",
|
||||
"_resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.0.1.tgz"
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/*!
|
||||
* bufferutil: WebSocket buffer utils
|
||||
* Copyright(c) 2015 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
#include <v8.h>
|
||||
#include <node.h>
|
||||
#include <node_version.h>
|
||||
#include <node_buffer.h>
|
||||
#include <node_object_wrap.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include <stdio.h>
|
||||
#include "nan.h"
|
||||
|
||||
using namespace v8;
|
||||
using namespace node;
|
||||
|
||||
class BufferUtil : public ObjectWrap
|
||||
{
|
||||
public:
|
||||
|
||||
static void Initialize(v8::Handle<v8::Object> target)
|
||||
{
|
||||
NanScope();
|
||||
Local<FunctionTemplate> t = NanNew<FunctionTemplate>(New);
|
||||
t->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
NODE_SET_METHOD(t, "unmask", BufferUtil::Unmask);
|
||||
NODE_SET_METHOD(t, "mask", BufferUtil::Mask);
|
||||
NODE_SET_METHOD(t, "merge", BufferUtil::Merge);
|
||||
target->Set(NanNew<String>("BufferUtil"), t->GetFunction());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
static NAN_METHOD(New)
|
||||
{
|
||||
NanScope();
|
||||
BufferUtil* bufferUtil = new BufferUtil();
|
||||
bufferUtil->Wrap(args.This());
|
||||
NanReturnValue(args.This());
|
||||
}
|
||||
|
||||
static NAN_METHOD(Merge)
|
||||
{
|
||||
NanScope();
|
||||
Local<Object> bufferObj = args[0]->ToObject();
|
||||
char* buffer = Buffer::Data(bufferObj);
|
||||
Local<Array> array = Local<Array>::Cast(args[1]);
|
||||
unsigned int arrayLength = array->Length();
|
||||
size_t offset = 0;
|
||||
unsigned int i;
|
||||
for (i = 0; i < arrayLength; ++i) {
|
||||
Local<Object> src = array->Get(i)->ToObject();
|
||||
size_t length = Buffer::Length(src);
|
||||
memcpy(buffer + offset, Buffer::Data(src), length);
|
||||
offset += length;
|
||||
}
|
||||
NanReturnValue(NanTrue());
|
||||
}
|
||||
|
||||
static NAN_METHOD(Unmask)
|
||||
{
|
||||
NanScope();
|
||||
Local<Object> buffer_obj = args[0]->ToObject();
|
||||
size_t length = Buffer::Length(buffer_obj);
|
||||
Local<Object> mask_obj = args[1]->ToObject();
|
||||
unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj);
|
||||
unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj);
|
||||
size_t len32 = length / 4;
|
||||
unsigned int i;
|
||||
for (i = 0; i < len32; ++i) *(from + i) ^= *mask;
|
||||
from += i;
|
||||
switch (length % 4) {
|
||||
case 3: *((unsigned char*)from+2) = *((unsigned char*)from+2) ^ ((unsigned char*)mask)[2];
|
||||
case 2: *((unsigned char*)from+1) = *((unsigned char*)from+1) ^ ((unsigned char*)mask)[1];
|
||||
case 1: *((unsigned char*)from ) = *((unsigned char*)from ) ^ ((unsigned char*)mask)[0];
|
||||
case 0:;
|
||||
}
|
||||
NanReturnValue(NanTrue());
|
||||
}
|
||||
|
||||
static NAN_METHOD(Mask)
|
||||
{
|
||||
NanScope();
|
||||
Local<Object> buffer_obj = args[0]->ToObject();
|
||||
Local<Object> mask_obj = args[1]->ToObject();
|
||||
unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj);
|
||||
Local<Object> output_obj = args[2]->ToObject();
|
||||
unsigned int dataOffset = args[3]->Int32Value();
|
||||
unsigned int length = args[4]->Int32Value();
|
||||
unsigned int* to = (unsigned int*)(Buffer::Data(output_obj) + dataOffset);
|
||||
unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj);
|
||||
unsigned int len32 = length / 4;
|
||||
unsigned int i;
|
||||
for (i = 0; i < len32; ++i) *(to + i) = *(from + i) ^ *mask;
|
||||
to += i;
|
||||
from += i;
|
||||
switch (length % 4) {
|
||||
case 3: *((unsigned char*)to+2) = *((unsigned char*)from+2) ^ *((unsigned char*)mask+2);
|
||||
case 2: *((unsigned char*)to+1) = *((unsigned char*)from+1) ^ *((unsigned char*)mask+1);
|
||||
case 1: *((unsigned char*)to ) = *((unsigned char*)from ) ^ *((unsigned char*)mask);
|
||||
case 0:;
|
||||
}
|
||||
NanReturnValue(NanTrue());
|
||||
}
|
||||
};
|
||||
|
||||
#if !NODE_VERSION_AT_LEAST(0,10,0)
|
||||
extern "C"
|
||||
#endif
|
||||
void init (Handle<Object> target)
|
||||
{
|
||||
NanScope();
|
||||
BufferUtil::Initialize(target);
|
||||
}
|
||||
|
||||
NODE_MODULE(bufferutil, init)
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
npm-debug.log
|
||||
node_modules
|
||||
.*.swp
|
||||
.lock-*
|
||||
build/
|
||||
|
||||
test
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
ALL_TESTS = $(shell find test/ -name '*.test.js')
|
||||
|
||||
run-tests:
|
||||
@./node_modules/.bin/mocha \
|
||||
-t 2000 \
|
||||
$(TESTFLAGS) \
|
||||
$(TESTS)
|
||||
|
||||
test:
|
||||
@$(MAKE) NODE_PATH=lib TESTS="$(ALL_TESTS)" run-tests
|
||||
|
||||
.PHONY: test
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
# options.js #
|
||||
|
||||
A very light-weight in-code option parsers for node.js.
|
||||
|
||||
## Usage ##
|
||||
|
||||
``` js
|
||||
var Options = require("options");
|
||||
|
||||
// Create an Options object
|
||||
function foo(options) {
|
||||
var default_options = {
|
||||
foo : "bar"
|
||||
};
|
||||
|
||||
// Create an option object with default value
|
||||
var opts = new Options(default_options);
|
||||
|
||||
// Merge options
|
||||
opts = opts.merge(options);
|
||||
|
||||
// Reset to default value
|
||||
opts.reset();
|
||||
|
||||
// Copy selected attributes out
|
||||
var seled_att = opts.copy("foo");
|
||||
|
||||
// Read json options from a file.
|
||||
opts.read("options.file"); // Sync
|
||||
opts.read("options.file", function(err){ // Async
|
||||
if(err){ // If error occurs
|
||||
console.log("File error.");
|
||||
}else{
|
||||
// No error
|
||||
}
|
||||
});
|
||||
|
||||
// Attributes defined or not
|
||||
opts.isDefinedAndNonNull("foobar");
|
||||
opts.isDefined("foobar");
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## License ##
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2012 Einar Otto Stangvik <einaros@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*!
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
function Options(defaults) {
|
||||
var internalValues = {};
|
||||
var values = this.value = {};
|
||||
Object.keys(defaults).forEach(function(key) {
|
||||
internalValues[key] = defaults[key];
|
||||
Object.defineProperty(values, key, {
|
||||
get: function() { return internalValues[key]; },
|
||||
configurable: false,
|
||||
enumerable: true
|
||||
});
|
||||
});
|
||||
this.reset = function() {
|
||||
Object.keys(defaults).forEach(function(key) {
|
||||
internalValues[key] = defaults[key];
|
||||
});
|
||||
return this;
|
||||
};
|
||||
this.merge = function(options, required) {
|
||||
options = options || {};
|
||||
if (Object.prototype.toString.call(required) === '[object Array]') {
|
||||
var missing = [];
|
||||
for (var i = 0, l = required.length; i < l; ++i) {
|
||||
var key = required[i];
|
||||
if (!(key in options)) {
|
||||
missing.push(key);
|
||||
}
|
||||
}
|
||||
if (missing.length > 0) {
|
||||
if (missing.length > 1) {
|
||||
throw new Error('options ' +
|
||||
missing.slice(0, missing.length - 1).join(', ') + ' and ' +
|
||||
missing[missing.length - 1] + ' must be defined');
|
||||
}
|
||||
else throw new Error('option ' + missing[0] + ' must be defined');
|
||||
}
|
||||
}
|
||||
Object.keys(options).forEach(function(key) {
|
||||
if (key in internalValues) {
|
||||
internalValues[key] = options[key];
|
||||
}
|
||||
});
|
||||
return this;
|
||||
};
|
||||
this.copy = function(keys) {
|
||||
var obj = {};
|
||||
Object.keys(defaults).forEach(function(key) {
|
||||
if (keys.indexOf(key) !== -1) {
|
||||
obj[key] = values[key];
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
};
|
||||
this.read = function(filename, cb) {
|
||||
if (typeof cb == 'function') {
|
||||
var self = this;
|
||||
fs.readFile(filename, function(error, data) {
|
||||
if (error) return cb(error);
|
||||
var conf = JSON.parse(data);
|
||||
self.merge(conf);
|
||||
cb();
|
||||
});
|
||||
}
|
||||
else {
|
||||
var conf = JSON.parse(fs.readFileSync(filename));
|
||||
this.merge(conf);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
this.isDefined = function(key) {
|
||||
return typeof values[key] != 'undefined';
|
||||
};
|
||||
this.isDefinedAndNonNull = function(key) {
|
||||
return typeof values[key] != 'undefined' && values[key] !== null;
|
||||
};
|
||||
Object.freeze(values);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
module.exports = Options;
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"author": {
|
||||
"name": "Einar Otto Stangvik",
|
||||
"email": "einaros@gmail.com",
|
||||
"url": "http://2x.io"
|
||||
},
|
||||
"name": "options",
|
||||
"description": "A very light-weight in-code option parsers for node.js.",
|
||||
"version": "0.0.6",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/einaros/options.js.git"
|
||||
},
|
||||
"main": "lib/options",
|
||||
"scripts": {
|
||||
"test": "make test"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"mocha": "latest"
|
||||
},
|
||||
"readme": "# options.js #\n\nA very light-weight in-code option parsers for node.js.\n\n## Usage ##\n\n``` js\nvar Options = require(\"options\");\n\n// Create an Options object\nfunction foo(options) {\n var default_options = {\n foo : \"bar\"\n };\n \n // Create an option object with default value\n var opts = new Options(default_options);\n \n // Merge options\n opts = opts.merge(options);\n \n // Reset to default value\n opts.reset();\n \n // Copy selected attributes out\n var seled_att = opts.copy(\"foo\");\n \n // Read json options from a file. \n opts.read(\"options.file\"); // Sync\n opts.read(\"options.file\", function(err){ // Async\n if(err){ // If error occurs\n console.log(\"File error.\");\n }else{\n // No error\n }\n });\n \n // Attributes defined or not\n opts.isDefinedAndNonNull(\"foobar\");\n opts.isDefined(\"foobar\");\n}\n\n```\n\n\n## License ##\n\n(The MIT License)\n\nCopyright (c) 2012 Einar Otto Stangvik <einaros@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
|
||||
"readmeFilename": "README.md",
|
||||
"bugs": {
|
||||
"url": "https://github.com/einaros/options.js/issues"
|
||||
},
|
||||
"_id": "options@0.0.6",
|
||||
"_from": "options@>=0.0.5"
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
coverage
|
||||
.tern-port
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
- "0.11"
|
||||
before_install:
|
||||
- "npm install -g npm@1.4.x"
|
||||
script:
|
||||
- "npm run test-travis"
|
||||
after_script:
|
||||
- "npm install coveralls@2.11.x && cat coverage/lcov.info | coveralls"
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "irc.freenode.org#unshift"
|
||||
on_success: change
|
||||
on_failure: change
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
# Ultron
|
||||
|
||||
[](http://unshift.io)[](http://browsenpm.org/package/ultron)[](https://travis-ci.org/unshiftio/ultron)[](https://david-dm.org/unshiftio/ultron)[](https://coveralls.io/r/unshiftio/ultron?branch=master)[](http://webchat.freenode.net/?channels=unshift)
|
||||
|
||||
Ultron is a high-intelligence robot. It gathers intelligence so it can start
|
||||
improving upon his rudimentary design. It will learn your event emitting
|
||||
patterns and find ways to exterminate them. Allowing you to remove only the
|
||||
event emitters that **you** assigned and not the ones that your users or
|
||||
developers assigned. This can prevent race conditions, memory leaks and even file
|
||||
descriptor leaks from ever happening as you won't remove clean up processes.
|
||||
|
||||
## Installation
|
||||
|
||||
The module is designed to be used in browsers using browserify and in Node.js.
|
||||
You can install the module through the public npm registry by running the
|
||||
following command in CLI:
|
||||
|
||||
```
|
||||
npm install --save ultron
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
In all examples we assume that you've required the library as following:
|
||||
|
||||
```js
|
||||
'use strict';
|
||||
|
||||
var Ultron = require('ultron');
|
||||
```
|
||||
|
||||
Now that we've required the library we can construct our first `Ultron` instance.
|
||||
The constructor requires one argument which should be the `EventEmitter`
|
||||
instance that we need to operate upon. This can be the `EventEmitter` module
|
||||
that ships with Node.js or `EventEmitter3` or anything else as long as it
|
||||
follow the same API and internal structure as these 2. So with that in mind we
|
||||
can create the instance:
|
||||
|
||||
```js
|
||||
//
|
||||
// For the sake of this example we're going to construct an empty EventEmitter
|
||||
//
|
||||
var EventEmitter = require('events').EventEmitter; // or require('eventmitter3');
|
||||
var events = new EventEmitter();
|
||||
|
||||
var ultron = new Ultron(events);
|
||||
```
|
||||
|
||||
You can now use the following API's from the Ultron instance:
|
||||
|
||||
### Ultron.on
|
||||
|
||||
Register a new event listener for the given event. It follows the exact same API
|
||||
as `EventEmitter.on` but it will return itself instead of returning the
|
||||
EventEmitter instance. If you are using EventEmitter3 it also supports the
|
||||
context param:
|
||||
|
||||
```js
|
||||
ultron.on('event-name', handler, { custom: 'function context' });
|
||||
```
|
||||
|
||||
### Ultron.once
|
||||
|
||||
Exactly the same as the [Ultron.on](#ultronon) but it only allows the execution
|
||||
once.
|
||||
|
||||
### Ultron.remove
|
||||
|
||||
This is where all the magic happens and the safe removal starts. This function
|
||||
accepts different argument styles:
|
||||
|
||||
- No arguments, assume that all events need to be removed so it will work as
|
||||
`removeAllListeners()` API.
|
||||
- 1 argument, when it's a string it will be split on ` ` and `,` to create a
|
||||
list of events that need to be cleared.
|
||||
- Multiple arguments, we assume that they are all names of events that need to
|
||||
be cleared.
|
||||
|
||||
```js
|
||||
ultron.remove('foo, bar baz'); // Removes foo, bar and baz.
|
||||
ultron.remove('foo', 'bar', 'baz'); // Removes foo, bar and baz.
|
||||
ultron.remove(); // Removes everything.
|
||||
```
|
||||
|
||||
If you just want to remove a single event listener using a function reference
|
||||
you can still use the EventEmitter's `removeListener(event, fn)` API:
|
||||
|
||||
```js
|
||||
function foo() {}
|
||||
|
||||
ulton.on('foo', foo);
|
||||
events.removeListener('foo', foo);
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* An auto incrementing id which we can use to create "unique" Ultron instances
|
||||
* so we can track the event emitters that are added through the Ultron
|
||||
* interface.
|
||||
*
|
||||
* @type {Number}
|
||||
* @private
|
||||
*/
|
||||
var id = 0;
|
||||
|
||||
/**
|
||||
* Ultron is high-intelligence robot. It gathers intelligence so it can start improving
|
||||
* upon his rudimentary design. It will learn from your EventEmitting patterns
|
||||
* and exterminate them.
|
||||
*
|
||||
* @constructor
|
||||
* @param {EventEmitter} ee EventEmitter instance we need to wrap.
|
||||
* @api public
|
||||
*/
|
||||
function Ultron(ee) {
|
||||
if (!(this instanceof Ultron)) return new Ultron(ee);
|
||||
|
||||
this.id = id++;
|
||||
this.ee = ee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new EventListener for the given event.
|
||||
*
|
||||
* @param {String} event Name of the event.
|
||||
* @param {Functon} fn Callback function.
|
||||
* @param {Mixed} context The context of the function.
|
||||
* @returns {Ultron}
|
||||
* @api public
|
||||
*/
|
||||
Ultron.prototype.on = function on(event, fn, context) {
|
||||
fn.__ultron = this.id;
|
||||
this.ee.on(event, fn, context);
|
||||
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Add an EventListener that's only called once.
|
||||
*
|
||||
* @param {String} event Name of the event.
|
||||
* @param {Function} fn Callback function.
|
||||
* @param {Mixed} context The context of the function.
|
||||
* @returns {Ultron}
|
||||
* @api public
|
||||
*/
|
||||
Ultron.prototype.once = function once(event, fn, context) {
|
||||
fn.__ultron = this.id;
|
||||
this.ee.once(event, fn, context);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the listeners we assigned for the given event.
|
||||
*
|
||||
* @returns {Ultron}
|
||||
* @api public
|
||||
*/
|
||||
Ultron.prototype.remove = function remove() {
|
||||
var args = arguments
|
||||
, event;
|
||||
|
||||
//
|
||||
// When no event names are provided we assume that we need to clear all the
|
||||
// events that were assigned through us.
|
||||
//
|
||||
if (args.length === 1 && 'string' === typeof args[0]) {
|
||||
args = args[0].split(/[, ]+/);
|
||||
} else if (!args.length) {
|
||||
args = [];
|
||||
|
||||
for (event in this.ee._events) {
|
||||
if (this.ee._events.hasOwnProperty(event)) {
|
||||
args.push(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var listeners = this.ee.listeners(args[i]);
|
||||
|
||||
for (var j = 0; j < listeners.length; j++) {
|
||||
event = listeners[j];
|
||||
|
||||
if (event.listener) {
|
||||
if (event.listener.__ultron !== this.id) continue;
|
||||
delete event.listener.__ultron;
|
||||
} else {
|
||||
if (event.__ultron !== this.id) continue;
|
||||
delete event.__ultron;
|
||||
}
|
||||
|
||||
this.ee.removeListener(args[i], event);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroy the Ultron instance, remove all listeners and release all references.
|
||||
*
|
||||
* @returns {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
Ultron.prototype.destroy = function destroy() {
|
||||
if (!this.ee) return false;
|
||||
|
||||
this.remove();
|
||||
this.ee = null;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
//
|
||||
// Expose the module.
|
||||
//
|
||||
module.exports = Ultron;
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "ultron",
|
||||
"version": "1.0.1",
|
||||
"description": "Ultron is high-intelligence robot. It gathers intel so it can start improving upon his rudimentary design",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "mocha --reporter spec --ui bdd test.js",
|
||||
"watch": "mocha --watch --reporter spec --ui bdd test.js",
|
||||
"coverage": "istanbul cover ./node_modules/.bin/_mocha -- --reporter spec --ui bdd test.js",
|
||||
"test-travis": "istanbul cover node_modules/.bin/_mocha --report lcovonly -- --reporter spec --ui bdd test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/unshiftio/ultron"
|
||||
},
|
||||
"keywords": [
|
||||
"Ultron",
|
||||
"robot",
|
||||
"gather",
|
||||
"intelligence",
|
||||
"event",
|
||||
"events",
|
||||
"eventemitter",
|
||||
"emitter",
|
||||
"cleanup"
|
||||
],
|
||||
"author": {
|
||||
"name": "Arnout Kazemier"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"assume": "0.0.x",
|
||||
"eventemitter3": "0.1.x",
|
||||
"istanbul": "0.3.x",
|
||||
"mocha": "2.0.x",
|
||||
"pre-commit": "0.0.x"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/unshiftio/ultron/issues"
|
||||
},
|
||||
"homepage": "https://github.com/unshiftio/ultron",
|
||||
"readme": "# Ultron\n\n[](http://unshift.io)[](http://browsenpm.org/package/ultron)[](https://travis-ci.org/unshiftio/ultron)[](https://david-dm.org/unshiftio/ultron)[](https://coveralls.io/r/unshiftio/ultron?branch=master)[](http://webchat.freenode.net/?channels=unshift)\n\nUltron is a high-intelligence robot. It gathers intelligence so it can start\nimproving upon his rudimentary design. It will learn your event emitting\npatterns and find ways to exterminate them. Allowing you to remove only the\nevent emitters that **you** assigned and not the ones that your users or\ndevelopers assigned. This can prevent race conditions, memory leaks and even file\ndescriptor leaks from ever happening as you won't remove clean up processes.\n\n## Installation\n\nThe module is designed to be used in browsers using browserify and in Node.js.\nYou can install the module through the public npm registry by running the\nfollowing command in CLI:\n\n```\nnpm install --save ultron\n```\n\n## Usage\n\nIn all examples we assume that you've required the library as following:\n\n```js\n'use strict';\n\nvar Ultron = require('ultron');\n```\n\nNow that we've required the library we can construct our first `Ultron` instance.\nThe constructor requires one argument which should be the `EventEmitter`\ninstance that we need to operate upon. This can be the `EventEmitter` module\nthat ships with Node.js or `EventEmitter3` or anything else as long as it\nfollow the same API and internal structure as these 2. So with that in mind we\ncan create the instance:\n\n```js\n//\n// For the sake of this example we're going to construct an empty EventEmitter\n//\nvar EventEmitter = require('events').EventEmitter; // or require('eventmitter3');\nvar events = new EventEmitter();\n\nvar ultron = new Ultron(events);\n```\n\nYou can now use the following API's from the Ultron instance:\n\n### Ultron.on\n\nRegister a new event listener for the given event. It follows the exact same API\nas `EventEmitter.on` but it will return itself instead of returning the\nEventEmitter instance. If you are using EventEmitter3 it also supports the\ncontext param:\n\n```js\nultron.on('event-name', handler, { custom: 'function context' });\n```\n\n### Ultron.once\n\nExactly the same as the [Ultron.on](#ultronon) but it only allows the execution\nonce.\n\n### Ultron.remove\n\nThis is where all the magic happens and the safe removal starts. This function\naccepts different argument styles:\n\n- No arguments, assume that all events need to be removed so it will work as\n `removeAllListeners()` API.\n- 1 argument, when it's a string it will be split on ` ` and `,` to create a\n list of events that need to be cleared.\n- Multiple arguments, we assume that they are all names of events that need to\n be cleared.\n\n```js\nultron.remove('foo, bar baz'); // Removes foo, bar and baz.\nultron.remove('foo', 'bar', 'baz'); // Removes foo, bar and baz.\nultron.remove(); // Removes everything.\n```\n\nIf you just want to remove a single event listener using a function reference\nyou can still use the EventEmitter's `removeListener(event, fn)` API:\n\n```js\nfunction foo() {}\n\nulton.on('foo', foo);\nevents.removeListener('foo', foo);\n```\n\n## License\n\nMIT\n",
|
||||
"readmeFilename": "README.md",
|
||||
"_id": "ultron@1.0.1",
|
||||
"dist": {
|
||||
"shasum": "ed553a9be89f5176bdd5d40b3738345510b84ec6"
|
||||
},
|
||||
"_from": "ultron@1.0.x",
|
||||
"_resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.1.tgz"
|
||||
}
|
||||
+327
@@ -0,0 +1,327 @@
|
||||
/* istanbul ignore next */
|
||||
describe('Ultron', function () {
|
||||
'use strict';
|
||||
|
||||
var EventEmitter = require('eventemitter3')
|
||||
, EE = require('events').EventEmitter
|
||||
, assume = require('assume')
|
||||
, Ultron = require('./')
|
||||
, ultron
|
||||
, ee;
|
||||
|
||||
beforeEach(function () {
|
||||
ee = new EventEmitter();
|
||||
ultron = new Ultron(ee);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
ultron.destroy();
|
||||
ee.removeAllListeners();
|
||||
});
|
||||
|
||||
it('is exposed as a function', function () {
|
||||
assume(Ultron).is.a('function');
|
||||
});
|
||||
|
||||
it('can be initialized without the new keyword', function () {
|
||||
assume(Ultron(ee)).is.instanceOf(Ultron);
|
||||
});
|
||||
|
||||
it('assigns a unique id to every instance', function () {
|
||||
for (var i = 0; i < 100; i++) {
|
||||
assume(ultron.id).does.not.equal((new Ultron()).id);
|
||||
}
|
||||
});
|
||||
|
||||
it('allows removal through the event emitter', function () {
|
||||
function foo() {}
|
||||
function bar() {}
|
||||
|
||||
ultron.on('foo', foo);
|
||||
ultron.once('foo', bar);
|
||||
|
||||
assume(foo.__ultron).equals(ultron.id);
|
||||
assume(bar.__ultron).equals(ultron.id);
|
||||
assume(ee.listeners('foo').length).equals(2);
|
||||
|
||||
ee.removeListener('foo', foo);
|
||||
assume(ee.listeners('foo').length).equals(1);
|
||||
|
||||
ee.removeListener('foo', bar);
|
||||
assume(ee.listeners('foo').length).equals(0);
|
||||
});
|
||||
|
||||
describe('#on', function () {
|
||||
it('assigns a listener', function () {
|
||||
assume(ee.listeners('foo').length).equals(0);
|
||||
|
||||
function foo() {}
|
||||
|
||||
ultron.on('foo', foo);
|
||||
assume(ee.listeners('foo').length).equals(1);
|
||||
assume(ee.listeners('foo')[0]).equals(foo);
|
||||
});
|
||||
|
||||
it('tags the assigned function', function () {
|
||||
assume(ee.listeners('foo').length).equals(0);
|
||||
|
||||
ultron.on('foo', function () {});
|
||||
assume(ee.listeners('foo')[0].__ultron).equals(ultron.id);
|
||||
});
|
||||
|
||||
it('also passes in the context', function (next) {
|
||||
var context = 1313;
|
||||
|
||||
ultron.on('foo', function (a, b, c) {
|
||||
assume(a).equals('a');
|
||||
assume(b).equals('b');
|
||||
assume(c).equals('c');
|
||||
|
||||
assume(this).equals(context);
|
||||
|
||||
next();
|
||||
}, context);
|
||||
|
||||
ee.emit('foo', 'a', 'b', 'c');
|
||||
});
|
||||
|
||||
it('works with regular eventemitters as well', function (next) {
|
||||
var ee = new EE()
|
||||
, ultron = new Ultron(ee);
|
||||
|
||||
ultron.on('foo', function (a, b, c) {
|
||||
assume(a).equals('a');
|
||||
assume(b).equals('b');
|
||||
assume(c).equals('c');
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
ee.emit('foo', 'a', 'b', 'c');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#once', function () {
|
||||
it('assigns a listener', function () {
|
||||
assume(ee.listeners('foo').length).equals(0);
|
||||
|
||||
function foo() {}
|
||||
ultron.once('foo', foo);
|
||||
assume(ee.listeners('foo').length).equals(1);
|
||||
assume(ee.listeners('foo')[0]).equals(foo);
|
||||
});
|
||||
|
||||
it('tags the assigned function', function () {
|
||||
assume(ee.listeners('foo').length).equals(0);
|
||||
|
||||
ultron.once('foo', function () {});
|
||||
assume(ee.listeners('foo')[0].__ultron).equals(ultron.id);
|
||||
});
|
||||
|
||||
it('also passes in the context', function (next) {
|
||||
var context = 1313;
|
||||
|
||||
ultron.once('foo', function (a, b, c) {
|
||||
assume(a).equals('a');
|
||||
assume(b).equals('b');
|
||||
assume(c).equals('c');
|
||||
|
||||
assume(this).equals(context);
|
||||
|
||||
next();
|
||||
}, context);
|
||||
|
||||
ee.emit('foo', 'a', 'b', 'c');
|
||||
ee.emit('foo', 'a', 'b', 'c'); // Ensure that we don't double execute
|
||||
});
|
||||
|
||||
it('works with regular eventemitters as well', function (next) {
|
||||
var ee = new EE()
|
||||
, ultron = new Ultron(ee);
|
||||
|
||||
ultron.once('foo', function (a, b, c) {
|
||||
assume(a).equals('a');
|
||||
assume(b).equals('b');
|
||||
assume(c).equals('c');
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
ee.emit('foo', 'a', 'b', 'c');
|
||||
ee.emit('foo', 'a', 'b', 'c'); // Ensure that we don't double execute
|
||||
});
|
||||
});
|
||||
|
||||
describe('#remove', function () {
|
||||
it('removes only our assigned `on` listeners', function () {
|
||||
function foo() {}
|
||||
function bar() {}
|
||||
|
||||
ee.on('foo', foo);
|
||||
ultron.on('foo', bar);
|
||||
assume(ee.listeners('foo').length).equals(2);
|
||||
|
||||
ultron.remove('foo');
|
||||
assume(ee.listeners('foo').length).equals(1);
|
||||
assume(ee.listeners('foo')[0]).equals(foo);
|
||||
});
|
||||
|
||||
it('removes our private __ultron references', function () {
|
||||
function once() {}
|
||||
function on() {}
|
||||
|
||||
assume('__ultron' in once).is.false();
|
||||
assume('__ultron' in on).is.false();
|
||||
|
||||
ultron.on('foo', on);
|
||||
ultron.once('bar', once);
|
||||
|
||||
assume('__ultron' in once).is.true();
|
||||
assume('__ultron' in on).is.true();
|
||||
|
||||
ultron.remove('foo, bar');
|
||||
|
||||
assume('__ultron' in once).is.false();
|
||||
assume('__ultron' in on).is.false();
|
||||
|
||||
ultron.destroy();
|
||||
|
||||
ee = new EE();
|
||||
ultron = new Ultron(ee);
|
||||
|
||||
assume('__ultron' in once).is.false();
|
||||
assume('__ultron' in on).is.false();
|
||||
|
||||
ultron.on('foo', on);
|
||||
ultron.once('bar', once);
|
||||
|
||||
assume('__ultron' in once).is.true();
|
||||
assume('__ultron' in on).is.true();
|
||||
|
||||
ultron.remove('foo, bar');
|
||||
|
||||
assume('__ultron' in once).is.false();
|
||||
assume('__ultron' in on).is.false();
|
||||
});
|
||||
|
||||
it('removes only our assigned `once` listeners', function () {
|
||||
function foo() {}
|
||||
function bar() {}
|
||||
|
||||
ee.once('foo', foo);
|
||||
ultron.once('foo', bar);
|
||||
assume(ee.listeners('foo').length).equals(2);
|
||||
|
||||
ultron.remove('foo');
|
||||
assume(ee.listeners('foo').length).equals(1);
|
||||
assume(ee.listeners('foo')[0]).equals(foo);
|
||||
});
|
||||
|
||||
it('removes only our assigned `once` listeners from regular EE', function () {
|
||||
var ee = new EE()
|
||||
, ultron = new Ultron(ee);
|
||||
|
||||
function foo() {}
|
||||
function bar() {}
|
||||
|
||||
ee.once('foo', foo);
|
||||
ultron.once('foo', bar);
|
||||
assume(ee.listeners('foo').length).equals(2);
|
||||
|
||||
ultron.remove('foo');
|
||||
assume(ee.listeners('foo').length).equals(1);
|
||||
assume(ee.listeners('foo')[0].listener).equals(foo);
|
||||
});
|
||||
|
||||
it('removes all assigned events if called without args', function () {
|
||||
function foo() {}
|
||||
function bar() {}
|
||||
|
||||
ultron.on('foo', foo);
|
||||
ultron.on('bar', bar);
|
||||
|
||||
assume(ee.listeners('foo').length).equals(1);
|
||||
assume(ee.listeners('bar').length).equals(1);
|
||||
|
||||
ultron.remove();
|
||||
|
||||
assume(ee.listeners('foo').length).equals(0);
|
||||
assume(ee.listeners('bar').length).equals(0);
|
||||
});
|
||||
|
||||
it('removes multiple listeners based on args', function () {
|
||||
function foo() {}
|
||||
function bar() {}
|
||||
function baz() {}
|
||||
|
||||
ultron.on('foo', foo);
|
||||
ultron.on('bar', bar);
|
||||
ultron.on('baz', baz);
|
||||
|
||||
assume(ee.listeners('foo').length).equals(1);
|
||||
assume(ee.listeners('bar').length).equals(1);
|
||||
assume(ee.listeners('baz').length).equals(1);
|
||||
|
||||
ultron.remove('foo', 'bar');
|
||||
|
||||
assume(ee.listeners('foo').length).equals(0);
|
||||
assume(ee.listeners('bar').length).equals(0);
|
||||
assume(ee.listeners('baz').length).equals(1);
|
||||
});
|
||||
|
||||
it('removes multiple listeners if first arg is seperated string', function () {
|
||||
function foo() {}
|
||||
function bar() {}
|
||||
function baz() {}
|
||||
|
||||
ultron.on('foo', foo);
|
||||
ultron.on('bar', bar);
|
||||
ultron.on('baz', baz);
|
||||
|
||||
assume(ee.listeners('foo').length).equals(1);
|
||||
assume(ee.listeners('bar').length).equals(1);
|
||||
assume(ee.listeners('baz').length).equals(1);
|
||||
|
||||
ultron.remove('foo, bar');
|
||||
|
||||
assume(ee.listeners('foo').length).equals(0);
|
||||
assume(ee.listeners('bar').length).equals(0);
|
||||
assume(ee.listeners('baz').length).equals(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#destroy', function () {
|
||||
it('removes all listeners', function () {
|
||||
function foo() {}
|
||||
function bar() {}
|
||||
function baz() {}
|
||||
|
||||
ultron.on('foo', foo);
|
||||
ultron.on('bar', bar);
|
||||
ultron.on('baz', baz);
|
||||
|
||||
assume(ee.listeners('foo').length).equals(1);
|
||||
assume(ee.listeners('bar').length).equals(1);
|
||||
assume(ee.listeners('baz').length).equals(1);
|
||||
|
||||
ultron.destroy();
|
||||
|
||||
assume(ee.listeners('foo').length).equals(0);
|
||||
assume(ee.listeners('bar').length).equals(0);
|
||||
assume(ee.listeners('baz').length).equals(0);
|
||||
});
|
||||
|
||||
it('removes the .ee reference', function () {
|
||||
assume(ultron.ee).equals(ee);
|
||||
ultron.destroy();
|
||||
assume(ultron.ee).equals(null);
|
||||
});
|
||||
|
||||
it('returns booleans for state indication', function () {
|
||||
assume(ultron.destroy()).is.true();
|
||||
assume(ultron.destroy()).is.false();
|
||||
assume(ultron.destroy()).is.false();
|
||||
assume(ultron.destroy()).is.false();
|
||||
});
|
||||
});
|
||||
});
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
npm-debug.log
|
||||
node_modules
|
||||
build
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'validation',
|
||||
'include_dirs': ["<!(node -e \"require('nan')\")"],
|
||||
'cflags': [ '-O3' ],
|
||||
'sources': [ 'src/validation.cc' ]
|
||||
}
|
||||
]
|
||||
}
|
||||
+332
@@ -0,0 +1,332 @@
|
||||
# We borrow heavily from the kernel build setup, though we are simpler since
|
||||
# we don't have Kconfig tweaking settings on us.
|
||||
|
||||
# The implicit make rules have it looking for RCS files, among other things.
|
||||
# We instead explicitly write all the rules we care about.
|
||||
# It's even quicker (saves ~200ms) to pass -r on the command line.
|
||||
MAKEFLAGS=-r
|
||||
|
||||
# The source directory tree.
|
||||
srcdir := ..
|
||||
abs_srcdir := $(abspath $(srcdir))
|
||||
|
||||
# The name of the builddir.
|
||||
builddir_name ?= .
|
||||
|
||||
# The V=1 flag on command line makes us verbosely print command lines.
|
||||
ifdef V
|
||||
quiet=
|
||||
else
|
||||
quiet=quiet_
|
||||
endif
|
||||
|
||||
# Specify BUILDTYPE=Release on the command line for a release build.
|
||||
BUILDTYPE ?= Release
|
||||
|
||||
# Directory all our build output goes into.
|
||||
# Note that this must be two directories beneath src/ for unit tests to pass,
|
||||
# as they reach into the src/ directory for data with relative paths.
|
||||
builddir ?= $(builddir_name)/$(BUILDTYPE)
|
||||
abs_builddir := $(abspath $(builddir))
|
||||
depsdir := $(builddir)/.deps
|
||||
|
||||
# Object output directory.
|
||||
obj := $(builddir)/obj
|
||||
abs_obj := $(abspath $(obj))
|
||||
|
||||
# We build up a list of every single one of the targets so we can slurp in the
|
||||
# generated dependency rule Makefiles in one pass.
|
||||
all_deps :=
|
||||
|
||||
|
||||
|
||||
CC.target ?= $(CC)
|
||||
CFLAGS.target ?= $(CFLAGS)
|
||||
CXX.target ?= $(CXX)
|
||||
CXXFLAGS.target ?= $(CXXFLAGS) $(CPPFLAGS)
|
||||
LINK.target ?= $(LINK)
|
||||
LDFLAGS.target ?= $(LDFLAGS)
|
||||
AR.target ?= $(AR)
|
||||
|
||||
# C++ apps need to be linked with g++.
|
||||
#
|
||||
# Note: flock is used to seralize linking. Linking is a memory-intensive
|
||||
# process so running parallel links can often lead to thrashing. To disable
|
||||
# the serialization, override LINK via an envrionment variable as follows:
|
||||
#
|
||||
# export LINK=g++
|
||||
#
|
||||
# This will allow make to invoke N linker processes as specified in -jN.
|
||||
LINK ?= flock $(builddir)/linker.lock $(CXX.target)
|
||||
|
||||
# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
|
||||
# to replicate this environment fallback in make as well.
|
||||
CC.host ?= gcc
|
||||
CFLAGS.host ?=
|
||||
CXX.host ?= g++
|
||||
CXXFLAGS.host ?=
|
||||
LINK.host ?= $(CXX.host)
|
||||
LDFLAGS.host ?=
|
||||
AR.host ?= ar
|
||||
|
||||
# Define a dir function that can handle spaces.
|
||||
# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
|
||||
# "leading spaces cannot appear in the text of the first argument as written.
|
||||
# These characters can be put into the argument value by variable substitution."
|
||||
empty :=
|
||||
space := $(empty) $(empty)
|
||||
|
||||
# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
|
||||
replace_spaces = $(subst $(space),?,$1)
|
||||
unreplace_spaces = $(subst ?,$(space),$1)
|
||||
dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
|
||||
|
||||
# Flags to make gcc output dependency info. Note that you need to be
|
||||
# careful here to use the flags that ccache and distcc can understand.
|
||||
# We write to a dep file on the side first and then rename at the end
|
||||
# so we can't end up with a broken dep file.
|
||||
depfile = $(depsdir)/$(call replace_spaces,$@).d
|
||||
DEPFLAGS = -MMD -MF $(depfile).raw
|
||||
|
||||
# We have to fixup the deps output in a few ways.
|
||||
# (1) the file output should mention the proper .o file.
|
||||
# ccache or distcc lose the path to the target, so we convert a rule of
|
||||
# the form:
|
||||
# foobar.o: DEP1 DEP2
|
||||
# into
|
||||
# path/to/foobar.o: DEP1 DEP2
|
||||
# (2) we want missing files not to cause us to fail to build.
|
||||
# We want to rewrite
|
||||
# foobar.o: DEP1 DEP2 \
|
||||
# DEP3
|
||||
# to
|
||||
# DEP1:
|
||||
# DEP2:
|
||||
# DEP3:
|
||||
# so if the files are missing, they're just considered phony rules.
|
||||
# We have to do some pretty insane escaping to get those backslashes
|
||||
# and dollar signs past make, the shell, and sed at the same time.
|
||||
# Doesn't work with spaces, but that's fine: .d files have spaces in
|
||||
# their names replaced with other characters.
|
||||
define fixup_dep
|
||||
# The depfile may not exist if the input file didn't have any #includes.
|
||||
touch $(depfile).raw
|
||||
# Fixup path as in (1).
|
||||
sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
|
||||
# Add extra rules as in (2).
|
||||
# We remove slashes and replace spaces with new lines;
|
||||
# remove blank lines;
|
||||
# delete the first line and append a colon to the remaining lines.
|
||||
sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
|
||||
grep -v '^$$' |\
|
||||
sed -e 1d -e 's|$$|:|' \
|
||||
>> $(depfile)
|
||||
rm $(depfile).raw
|
||||
endef
|
||||
|
||||
# Command definitions:
|
||||
# - cmd_foo is the actual command to run;
|
||||
# - quiet_cmd_foo is the brief-output summary of the command.
|
||||
|
||||
quiet_cmd_cc = CC($(TOOLSET)) $@
|
||||
cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
|
||||
|
||||
quiet_cmd_cxx = CXX($(TOOLSET)) $@
|
||||
cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
|
||||
|
||||
quiet_cmd_touch = TOUCH $@
|
||||
cmd_touch = touch $@
|
||||
|
||||
quiet_cmd_copy = COPY $@
|
||||
# send stderr to /dev/null to ignore messages when linking directories.
|
||||
cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
|
||||
|
||||
quiet_cmd_alink = AR($(TOOLSET)) $@
|
||||
cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
|
||||
|
||||
quiet_cmd_alink_thin = AR($(TOOLSET)) $@
|
||||
cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
|
||||
|
||||
# Due to circular dependencies between libraries :(, we wrap the
|
||||
# special "figure out circular dependencies" flags around the entire
|
||||
# input list during linking.
|
||||
quiet_cmd_link = LINK($(TOOLSET)) $@
|
||||
cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
|
||||
|
||||
# We support two kinds of shared objects (.so):
|
||||
# 1) shared_library, which is just bundling together many dependent libraries
|
||||
# into a link line.
|
||||
# 2) loadable_module, which is generating a module intended for dlopen().
|
||||
#
|
||||
# They differ only slightly:
|
||||
# In the former case, we want to package all dependent code into the .so.
|
||||
# In the latter case, we want to package just the API exposed by the
|
||||
# outermost module.
|
||||
# This means shared_library uses --whole-archive, while loadable_module doesn't.
|
||||
# (Note that --whole-archive is incompatible with the --start-group used in
|
||||
# normal linking.)
|
||||
|
||||
# Other shared-object link notes:
|
||||
# - Set SONAME to the library filename so our binaries don't reference
|
||||
# the local, absolute paths used on the link command-line.
|
||||
quiet_cmd_solink = SOLINK($(TOOLSET)) $@
|
||||
cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
|
||||
|
||||
quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
|
||||
cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
|
||||
|
||||
|
||||
# Define an escape_quotes function to escape single quotes.
|
||||
# This allows us to handle quotes properly as long as we always use
|
||||
# use single quotes and escape_quotes.
|
||||
escape_quotes = $(subst ','\'',$(1))
|
||||
# This comment is here just to include a ' to unconfuse syntax highlighting.
|
||||
# Define an escape_vars function to escape '$' variable syntax.
|
||||
# This allows us to read/write command lines with shell variables (e.g.
|
||||
# $LD_LIBRARY_PATH), without triggering make substitution.
|
||||
escape_vars = $(subst $$,$$$$,$(1))
|
||||
# Helper that expands to a shell command to echo a string exactly as it is in
|
||||
# make. This uses printf instead of echo because printf's behaviour with respect
|
||||
# to escape sequences is more portable than echo's across different shells
|
||||
# (e.g., dash, bash).
|
||||
exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
|
||||
|
||||
# Helper to compare the command we're about to run against the command
|
||||
# we logged the last time we ran the command. Produces an empty
|
||||
# string (false) when the commands match.
|
||||
# Tricky point: Make has no string-equality test function.
|
||||
# The kernel uses the following, but it seems like it would have false
|
||||
# positives, where one string reordered its arguments.
|
||||
# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
|
||||
# $(filter-out $(cmd_$@), $(cmd_$(1))))
|
||||
# We instead substitute each for the empty string into the other, and
|
||||
# say they're equal if both substitutions produce the empty string.
|
||||
# .d files contain ? instead of spaces, take that into account.
|
||||
command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
|
||||
$(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
|
||||
|
||||
# Helper that is non-empty when a prerequisite changes.
|
||||
# Normally make does this implicitly, but we force rules to always run
|
||||
# so we can check their command lines.
|
||||
# $? -- new prerequisites
|
||||
# $| -- order-only dependencies
|
||||
prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
|
||||
|
||||
# Helper that executes all postbuilds until one fails.
|
||||
define do_postbuilds
|
||||
@E=0;\
|
||||
for p in $(POSTBUILDS); do\
|
||||
eval $$p;\
|
||||
E=$$?;\
|
||||
if [ $$E -ne 0 ]; then\
|
||||
break;\
|
||||
fi;\
|
||||
done;\
|
||||
if [ $$E -ne 0 ]; then\
|
||||
rm -rf "$@";\
|
||||
exit $$E;\
|
||||
fi
|
||||
endef
|
||||
|
||||
# do_cmd: run a command via the above cmd_foo names, if necessary.
|
||||
# Should always run for a given target to handle command-line changes.
|
||||
# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
|
||||
# Third argument, if non-zero, makes it do POSTBUILDS processing.
|
||||
# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
|
||||
# spaces already and dirx strips the ? characters.
|
||||
define do_cmd
|
||||
$(if $(or $(command_changed),$(prereq_changed)),
|
||||
@$(call exact_echo, $($(quiet)cmd_$(1)))
|
||||
@mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
|
||||
$(if $(findstring flock,$(word 1,$(cmd_$1))),
|
||||
@$(cmd_$(1))
|
||||
@echo " $(quiet_cmd_$(1)): Finished",
|
||||
@$(cmd_$(1))
|
||||
)
|
||||
@$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
|
||||
@$(if $(2),$(fixup_dep))
|
||||
$(if $(and $(3), $(POSTBUILDS)),
|
||||
$(call do_postbuilds)
|
||||
)
|
||||
)
|
||||
endef
|
||||
|
||||
# Declare the "all" target first so it is the default,
|
||||
# even though we don't have the deps yet.
|
||||
.PHONY: all
|
||||
all:
|
||||
|
||||
# make looks for ways to re-generate included makefiles, but in our case, we
|
||||
# don't have a direct way. Explicitly telling make that it has nothing to do
|
||||
# for them makes it go faster.
|
||||
%.d: ;
|
||||
|
||||
# Use FORCE_DO_CMD to force a target to run. Should be coupled with
|
||||
# do_cmd.
|
||||
.PHONY: FORCE_DO_CMD
|
||||
FORCE_DO_CMD:
|
||||
|
||||
TOOLSET := target
|
||||
# Suffix rules, putting all outputs into $(obj).
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
# Try building from generated source, too.
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
|
||||
ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
|
||||
$(findstring $(join ^,$(prefix)),\
|
||||
$(join ^,validation.target.mk)))),)
|
||||
include validation.target.mk
|
||||
endif
|
||||
|
||||
quiet_cmd_regen_makefile = ACTION Regenerating $@
|
||||
cmd_regen_makefile = cd $(srcdir); /usr/share/node-gyp/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -I/home/rsilveira/formigone/html5multiplayer/tic-tac-toe/node_modules/ws/node_modules/utf-8-validate/build/config.gypi -I/usr/share/node-gyp/addon.gypi -I/usr/include/nodejs/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/usr/include/nodejs" "-Dmodule_root_dir=/home/rsilveira/formigone/html5multiplayer/tic-tac-toe/node_modules/ws/node_modules/utf-8-validate" binding.gyp
|
||||
Makefile: $(srcdir)/../../../../../../../../../usr/include/nodejs/common.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp $(srcdir)/../../../../../../../../../usr/share/node-gyp/addon.gypi
|
||||
$(call do_cmd,regen_makefile)
|
||||
|
||||
# "all" is a concatenation of the "all" targets from all the included
|
||||
# sub-makefiles. This is just here to clarify.
|
||||
all:
|
||||
|
||||
# Add in dependency-tracking rules. $(all_deps) is the list of every single
|
||||
# target in our tree. Only consider the ones with .d (dependency) info:
|
||||
d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
|
||||
ifneq ($(d_files),)
|
||||
include $(d_files)
|
||||
endif
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
cmd_Release/obj.target/validation.node := flock ./Release/linker.lock g++ -shared -pthread -rdynamic -m64 -Wl,-soname=validation.node -o Release/obj.target/validation.node -Wl,--start-group Release/obj.target/validation/src/validation.o -Wl,--end-group
|
||||
Generated
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
cmd_Release/obj.target/validation/src/validation.o := g++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -fPIC -Wall -Wextra -Wno-unused-parameter -pthread -m64 -O2 -fno-strict-aliasing -fno-tree-vrp -fno-omit-frame-pointer -fno-rtti -fno-exceptions -MMD -MF ./Release/.deps/Release/obj.target/validation/src/validation.o.d.raw -c -o Release/obj.target/validation/src/validation.o ../src/validation.cc
|
||||
Release/obj.target/validation/src/validation.o: ../src/validation.cc \
|
||||
/usr/include/nodejs/deps/v8/include/v8.h \
|
||||
/usr/include/nodejs/deps/v8/include/v8stdint.h \
|
||||
/usr/include/nodejs/src/node.h /usr/include/nodejs/deps/uv/include/uv.h \
|
||||
/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h \
|
||||
/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h \
|
||||
/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h \
|
||||
/usr/include/nodejs/src/node_object_wrap.h \
|
||||
/usr/include/nodejs/src/node.h /usr/include/nodejs/src/node_version.h \
|
||||
/usr/include/nodejs/src/node_buffer.h \
|
||||
/usr/include/nodejs/src/node_object_wrap.h ../node_modules/nan/nan.h \
|
||||
../node_modules/nan/nan_new.h \
|
||||
../node_modules/nan/nan_implementation_pre_12_inl.h
|
||||
../src/validation.cc:
|
||||
/usr/include/nodejs/deps/v8/include/v8.h:
|
||||
/usr/include/nodejs/deps/v8/include/v8stdint.h:
|
||||
/usr/include/nodejs/src/node.h:
|
||||
/usr/include/nodejs/deps/uv/include/uv.h:
|
||||
/usr/include/nodejs/deps/uv/include/uv-private/uv-unix.h:
|
||||
/usr/include/nodejs/deps/uv/include/uv-private/ngx-queue.h:
|
||||
/usr/include/nodejs/deps/uv/include/uv-private/uv-linux.h:
|
||||
/usr/include/nodejs/src/node_object_wrap.h:
|
||||
/usr/include/nodejs/src/node.h:
|
||||
/usr/include/nodejs/src/node_version.h:
|
||||
/usr/include/nodejs/src/node_buffer.h:
|
||||
/usr/include/nodejs/src/node_object_wrap.h:
|
||||
../node_modules/nan/nan.h:
|
||||
../node_modules/nan/nan_new.h:
|
||||
../node_modules/nan/nan_implementation_pre_12_inl.h:
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
cmd_Release/validation.node := ln -f "Release/obj.target/validation.node" "Release/validation.node" 2>/dev/null || (rm -rf "Release/validation.node" && cp -af "Release/obj.target/validation.node" "Release/validation.node")
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
+6
@@ -0,0 +1,6 @@
|
||||
# This file is generated by gyp; do not edit.
|
||||
|
||||
export builddir_name ?= build/./.
|
||||
.PHONY: all
|
||||
all:
|
||||
$(MAKE) validation
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
# Do not edit. File was generated by node-gyp's "configure" step
|
||||
{
|
||||
"target_defaults": {
|
||||
"cflags": [],
|
||||
"default_configuration": "Release",
|
||||
"defines": [],
|
||||
"include_dirs": [],
|
||||
"libraries": []
|
||||
},
|
||||
"variables": {
|
||||
"clang": 0,
|
||||
"gcc_version": 48,
|
||||
"host_arch": "x64",
|
||||
"node_byteorder": "little",
|
||||
"node_install_npm": "false",
|
||||
"node_prefix": "/usr",
|
||||
"node_shared_cares": "true",
|
||||
"node_shared_http_parser": "false",
|
||||
"node_shared_libuv": "false",
|
||||
"node_shared_openssl": "true",
|
||||
"node_shared_v8": "true",
|
||||
"node_shared_zlib": "true",
|
||||
"node_tag": "",
|
||||
"node_unsafe_optimizations": 0,
|
||||
"node_use_dtrace": "false",
|
||||
"node_use_etw": "false",
|
||||
"node_use_openssl": "true",
|
||||
"node_use_perfctr": "false",
|
||||
"node_use_systemtap": "false",
|
||||
"python": "/usr/bin/python",
|
||||
"target_arch": "x64",
|
||||
"v8_enable_gdbjit": 0,
|
||||
"v8_no_strict_aliasing": 1,
|
||||
"v8_use_snapshot": "false",
|
||||
"nodedir": "/usr/include/nodejs",
|
||||
"copy_dev_lib": "true",
|
||||
"standalone_static_library": 1,
|
||||
"cache_lock_stale": "60000",
|
||||
"pre": "",
|
||||
"sign_git_tag": "",
|
||||
"always_auth": "",
|
||||
"user_agent": "node/v0.10.25 linux x64",
|
||||
"bin_links": "true",
|
||||
"description": "true",
|
||||
"fetch_retries": "2",
|
||||
"init_version": "0.0.0",
|
||||
"user": "1000",
|
||||
"force": "",
|
||||
"ignore": "",
|
||||
"cache_min": "10",
|
||||
"editor": "vi",
|
||||
"rollback": "true",
|
||||
"cache_max": "null",
|
||||
"userconfig": "/home/rsilveira/.npmrc",
|
||||
"coverage": "",
|
||||
"engine_strict": "",
|
||||
"init_author_name": "",
|
||||
"init_author_url": "",
|
||||
"tmp": "/home/rsilveira/tmp",
|
||||
"userignorefile": "/home/rsilveira/.npmignore",
|
||||
"yes": "",
|
||||
"depth": "null",
|
||||
"save_dev": "",
|
||||
"usage": "",
|
||||
"https_proxy": "",
|
||||
"onload_script": "",
|
||||
"rebuild_bundle": "true",
|
||||
"save_bundle": "",
|
||||
"shell": "/bin/bash",
|
||||
"prefix": "/usr/local",
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"__DO_NOT_MODIFY_THIS_FILE___use__etc_npmrc_instead_": "true",
|
||||
"browser": "",
|
||||
"cache_lock_wait": "10000",
|
||||
"save_optional": "",
|
||||
"searchopts": "",
|
||||
"versions": "",
|
||||
"cache": "/home/rsilveira/.npm",
|
||||
"npaturl": "http://npat.npmjs.org/",
|
||||
"searchsort": "name",
|
||||
"version": "",
|
||||
"viewer": "man",
|
||||
"color": "true",
|
||||
"fetch_retry_mintimeout": "10000",
|
||||
"umask": "18",
|
||||
"fetch_retry_maxtimeout": "60000",
|
||||
"message": "%s",
|
||||
"global": "",
|
||||
"link": "",
|
||||
"save": "",
|
||||
"unicode": "true",
|
||||
"long": "",
|
||||
"production": "",
|
||||
"unsafe_perm": "",
|
||||
"node_version": "v0.10.25",
|
||||
"tag": "latest",
|
||||
"shrinkwrap": "true",
|
||||
"fetch_retry_factor": "10",
|
||||
"npat": "",
|
||||
"proprietary_attribs": "true",
|
||||
"strict_ssl": "true",
|
||||
"username": "",
|
||||
"globalconfig": "/etc/npmrc",
|
||||
"dev": "",
|
||||
"init_module": "/home/rsilveira/.npm-init.js",
|
||||
"parseable": "",
|
||||
"globalignorefile": "/etc/npmignore",
|
||||
"cache_lock_retries": "10",
|
||||
"group": "1000",
|
||||
"init_author_email": "",
|
||||
"searchexclude": "",
|
||||
"git": "git",
|
||||
"optional": "true",
|
||||
"json": ""
|
||||
}
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
# This file is generated by gyp; do not edit.
|
||||
|
||||
TOOLSET := target
|
||||
TARGET := validation
|
||||
DEFS_Debug := \
|
||||
'-D_LARGEFILE_SOURCE' \
|
||||
'-D_FILE_OFFSET_BITS=64' \
|
||||
'-DBUILDING_NODE_EXTENSION' \
|
||||
'-DDEBUG' \
|
||||
'-D_DEBUG'
|
||||
|
||||
# Flags passed to all source files.
|
||||
CFLAGS_Debug := \
|
||||
-fPIC \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wno-unused-parameter \
|
||||
-pthread \
|
||||
-m64 \
|
||||
-O3 \
|
||||
-g \
|
||||
-O0
|
||||
|
||||
# Flags passed to only C files.
|
||||
CFLAGS_C_Debug :=
|
||||
|
||||
# Flags passed to only C++ files.
|
||||
CFLAGS_CC_Debug := \
|
||||
-fno-rtti \
|
||||
-fno-exceptions
|
||||
|
||||
INCS_Debug := \
|
||||
-I/usr/include/nodejs/src \
|
||||
-I/usr/include/nodejs/deps/uv/include \
|
||||
-I/usr/include/nodejs/deps/v8/include \
|
||||
-I$(srcdir)/node_modules/nan
|
||||
|
||||
DEFS_Release := \
|
||||
'-D_LARGEFILE_SOURCE' \
|
||||
'-D_FILE_OFFSET_BITS=64' \
|
||||
'-DBUILDING_NODE_EXTENSION'
|
||||
|
||||
# Flags passed to all source files.
|
||||
CFLAGS_Release := \
|
||||
-fPIC \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wno-unused-parameter \
|
||||
-pthread \
|
||||
-m64 \
|
||||
-O2 \
|
||||
-fno-strict-aliasing \
|
||||
-fno-tree-vrp \
|
||||
-fno-omit-frame-pointer
|
||||
|
||||
# Flags passed to only C files.
|
||||
CFLAGS_C_Release :=
|
||||
|
||||
# Flags passed to only C++ files.
|
||||
CFLAGS_CC_Release := \
|
||||
-fno-rtti \
|
||||
-fno-exceptions
|
||||
|
||||
INCS_Release := \
|
||||
-I/usr/include/nodejs/src \
|
||||
-I/usr/include/nodejs/deps/uv/include \
|
||||
-I/usr/include/nodejs/deps/v8/include \
|
||||
-I$(srcdir)/node_modules/nan
|
||||
|
||||
OBJS := \
|
||||
$(obj).target/$(TARGET)/src/validation.o
|
||||
|
||||
# Add to the list of files we specially track dependencies for.
|
||||
all_deps += $(OBJS)
|
||||
|
||||
# CFLAGS et al overrides must be target-local.
|
||||
# See "Target-specific Variable Values" in the GNU Make manual.
|
||||
$(OBJS): TOOLSET := $(TOOLSET)
|
||||
$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
|
||||
$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
|
||||
|
||||
# Suffix rules, putting all outputs into $(obj).
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
|
||||
# Try building from generated source, too.
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
|
||||
# End of this set of suffix rules
|
||||
### Rules for final target.
|
||||
LDFLAGS_Debug := \
|
||||
-pthread \
|
||||
-rdynamic \
|
||||
-m64
|
||||
|
||||
LDFLAGS_Release := \
|
||||
-pthread \
|
||||
-rdynamic \
|
||||
-m64
|
||||
|
||||
LIBS :=
|
||||
|
||||
$(obj).target/validation.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
|
||||
$(obj).target/validation.node: LIBS := $(LIBS)
|
||||
$(obj).target/validation.node: TOOLSET := $(TOOLSET)
|
||||
$(obj).target/validation.node: $(OBJS) FORCE_DO_CMD
|
||||
$(call do_cmd,solink_module)
|
||||
|
||||
all_deps += $(obj).target/validation.node
|
||||
# Add target alias
|
||||
.PHONY: validation
|
||||
validation: $(builddir)/validation.node
|
||||
|
||||
# Copy this to the executable output path.
|
||||
$(builddir)/validation.node: TOOLSET := $(TOOLSET)
|
||||
$(builddir)/validation.node: $(obj).target/validation.node FORCE_DO_CMD
|
||||
$(call do_cmd,copy)
|
||||
|
||||
all_deps += $(builddir)/validation.node
|
||||
# Short alias for building this executable.
|
||||
.PHONY: validation.node
|
||||
validation.node: $(obj).target/validation.node $(builddir)/validation.node
|
||||
|
||||
# Add executable to "all" target.
|
||||
.PHONY: all
|
||||
all: $(builddir)/validation.node
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
/*!
|
||||
* UTF-8 validate: UTF-8 validation for WebSockets.
|
||||
* Copyright(c) 2015 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
module.exports.Validation = {
|
||||
isValidUTF8: function(buffer) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
try {
|
||||
module.exports = require('bindings')('validation');
|
||||
} catch (e) {
|
||||
module.exports = require('./fallback');
|
||||
}
|
||||
Generated
Vendored
+97
@@ -0,0 +1,97 @@
|
||||
node-bindings
|
||||
=============
|
||||
### Helper module for loading your native module's .node file
|
||||
|
||||
This is a helper module for authors of Node.js native addon modules.
|
||||
It is basically the "swiss army knife" of `require()`ing your native module's
|
||||
`.node` file.
|
||||
|
||||
Throughout the course of Node's native addon history, addons have ended up being
|
||||
compiled in a variety of different places, depending on which build tool and which
|
||||
version of node was used. To make matters worse, now the _gyp_ build tool can
|
||||
produce either a _Release_ or _Debug_ build, each being built into different
|
||||
locations.
|
||||
|
||||
This module checks _all_ the possible locations that a native addon would be built
|
||||
at, and returns the first one that loads successfully.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Install with `npm`:
|
||||
|
||||
``` bash
|
||||
$ npm install bindings
|
||||
```
|
||||
|
||||
Or add it to the `"dependencies"` section of your _package.json_ file.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
`require()`ing the proper bindings file for the current node version, platform
|
||||
and architecture is as simple as:
|
||||
|
||||
``` js
|
||||
var bindings = require('bindings')('binding.node')
|
||||
|
||||
// Use your bindings defined in your C files
|
||||
bindings.your_c_function()
|
||||
```
|
||||
|
||||
|
||||
Nice Error Output
|
||||
-----------------
|
||||
|
||||
When the `.node` file could not be loaded, `node-bindings` throws an Error with
|
||||
a nice error message telling you exactly what was tried. You can also check the
|
||||
`err.tries` Array property.
|
||||
|
||||
```
|
||||
Error: Could not load the bindings file. Tried:
|
||||
→ /Users/nrajlich/ref/build/binding.node
|
||||
→ /Users/nrajlich/ref/build/Debug/binding.node
|
||||
→ /Users/nrajlich/ref/build/Release/binding.node
|
||||
→ /Users/nrajlich/ref/out/Debug/binding.node
|
||||
→ /Users/nrajlich/ref/Debug/binding.node
|
||||
→ /Users/nrajlich/ref/out/Release/binding.node
|
||||
→ /Users/nrajlich/ref/Release/binding.node
|
||||
→ /Users/nrajlich/ref/build/default/binding.node
|
||||
→ /Users/nrajlich/ref/compiled/0.8.2/darwin/x64/binding.node
|
||||
at bindings (/Users/nrajlich/ref/node_modules/bindings/bindings.js:84:13)
|
||||
at Object.<anonymous> (/Users/nrajlich/ref/lib/ref.js:5:47)
|
||||
at Module._compile (module.js:449:26)
|
||||
at Object.Module._extensions..js (module.js:467:10)
|
||||
at Module.load (module.js:356:32)
|
||||
at Function.Module._load (module.js:312:12)
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Generated
Vendored
+166
@@ -0,0 +1,166 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var fs = require('fs')
|
||||
, path = require('path')
|
||||
, join = path.join
|
||||
, dirname = path.dirname
|
||||
, exists = fs.existsSync || path.existsSync
|
||||
, defaults = {
|
||||
arrow: process.env.NODE_BINDINGS_ARROW || ' → '
|
||||
, compiled: process.env.NODE_BINDINGS_COMPILED_DIR || 'compiled'
|
||||
, platform: process.platform
|
||||
, arch: process.arch
|
||||
, version: process.versions.node
|
||||
, bindings: 'bindings.node'
|
||||
, try: [
|
||||
// node-gyp's linked version in the "build" dir
|
||||
[ 'module_root', 'build', 'bindings' ]
|
||||
// node-waf and gyp_addon (a.k.a node-gyp)
|
||||
, [ 'module_root', 'build', 'Debug', 'bindings' ]
|
||||
, [ 'module_root', 'build', 'Release', 'bindings' ]
|
||||
// Debug files, for development (legacy behavior, remove for node v0.9)
|
||||
, [ 'module_root', 'out', 'Debug', 'bindings' ]
|
||||
, [ 'module_root', 'Debug', 'bindings' ]
|
||||
// Release files, but manually compiled (legacy behavior, remove for node v0.9)
|
||||
, [ 'module_root', 'out', 'Release', 'bindings' ]
|
||||
, [ 'module_root', 'Release', 'bindings' ]
|
||||
// Legacy from node-waf, node <= 0.4.x
|
||||
, [ 'module_root', 'build', 'default', 'bindings' ]
|
||||
// Production "Release" buildtype binary (meh...)
|
||||
, [ 'module_root', 'compiled', 'version', 'platform', 'arch', 'bindings' ]
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* The main `bindings()` function loads the compiled bindings for a given module.
|
||||
* It uses V8's Error API to determine the parent filename that this function is
|
||||
* being invoked from, which is then used to find the root directory.
|
||||
*/
|
||||
|
||||
function bindings (opts) {
|
||||
|
||||
// Argument surgery
|
||||
if (typeof opts == 'string') {
|
||||
opts = { bindings: opts }
|
||||
} else if (!opts) {
|
||||
opts = {}
|
||||
}
|
||||
opts.__proto__ = defaults
|
||||
|
||||
// Get the module root
|
||||
if (!opts.module_root) {
|
||||
opts.module_root = exports.getRoot(exports.getFileName())
|
||||
}
|
||||
|
||||
// Ensure the given bindings name ends with .node
|
||||
if (path.extname(opts.bindings) != '.node') {
|
||||
opts.bindings += '.node'
|
||||
}
|
||||
|
||||
var tries = []
|
||||
, i = 0
|
||||
, l = opts.try.length
|
||||
, n
|
||||
, b
|
||||
, err
|
||||
|
||||
for (; i<l; i++) {
|
||||
n = join.apply(null, opts.try[i].map(function (p) {
|
||||
return opts[p] || p
|
||||
}))
|
||||
tries.push(n)
|
||||
try {
|
||||
b = opts.path ? require.resolve(n) : require(n)
|
||||
if (!opts.path) {
|
||||
b.path = n
|
||||
}
|
||||
return b
|
||||
} catch (e) {
|
||||
if (!/not find/i.test(e.message)) {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = new Error('Could not locate the bindings file. Tried:\n'
|
||||
+ tries.map(function (a) { return opts.arrow + a }).join('\n'))
|
||||
err.tries = tries
|
||||
throw err
|
||||
}
|
||||
module.exports = exports = bindings
|
||||
|
||||
|
||||
/**
|
||||
* Gets the filename of the JavaScript file that invokes this function.
|
||||
* Used to help find the root directory of a module.
|
||||
* Optionally accepts an filename argument to skip when searching for the invoking filename
|
||||
*/
|
||||
|
||||
exports.getFileName = function getFileName (calling_file) {
|
||||
var origPST = Error.prepareStackTrace
|
||||
, origSTL = Error.stackTraceLimit
|
||||
, dummy = {}
|
||||
, fileName
|
||||
|
||||
Error.stackTraceLimit = 10
|
||||
|
||||
Error.prepareStackTrace = function (e, st) {
|
||||
for (var i=0, l=st.length; i<l; i++) {
|
||||
fileName = st[i].getFileName()
|
||||
if (fileName !== __filename) {
|
||||
if (calling_file) {
|
||||
if (fileName !== calling_file) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// run the 'prepareStackTrace' function above
|
||||
Error.captureStackTrace(dummy)
|
||||
dummy.stack
|
||||
|
||||
// cleanup
|
||||
Error.prepareStackTrace = origPST
|
||||
Error.stackTraceLimit = origSTL
|
||||
|
||||
return fileName
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the root directory of a module, given an arbitrary filename
|
||||
* somewhere in the module tree. The "root directory" is the directory
|
||||
* containing the `package.json` file.
|
||||
*
|
||||
* In: /home/nate/node-native-module/lib/index.js
|
||||
* Out: /home/nate/node-native-module
|
||||
*/
|
||||
|
||||
exports.getRoot = function getRoot (file) {
|
||||
var dir = dirname(file)
|
||||
, prev
|
||||
while (true) {
|
||||
if (dir === '.') {
|
||||
// Avoids an infinite loop in rare cases, like the REPL
|
||||
dir = process.cwd()
|
||||
}
|
||||
if (exists(join(dir, 'package.json')) || exists(join(dir, 'node_modules'))) {
|
||||
// Found the 'package.json' file or 'node_modules' dir; we're done
|
||||
return dir
|
||||
}
|
||||
if (prev === dir) {
|
||||
// Got to the top
|
||||
throw new Error('Could not find module root given file: "' + file
|
||||
+ '". Do you have a `package.json` file? ')
|
||||
}
|
||||
// Try the parent dir next
|
||||
prev = dir
|
||||
dir = join(dir, '..')
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+33
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "bindings",
|
||||
"description": "Helper module for loading your native module's .node file",
|
||||
"keywords": [
|
||||
"native",
|
||||
"addon",
|
||||
"bindings",
|
||||
"gyp",
|
||||
"waf",
|
||||
"c",
|
||||
"c++"
|
||||
],
|
||||
"version": "1.2.1",
|
||||
"author": {
|
||||
"name": "Nathan Rajlich",
|
||||
"email": "nathan@tootallnate.net",
|
||||
"url": "http://tootallnate.net"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/TooTallNate/node-bindings.git"
|
||||
},
|
||||
"main": "./bindings.js",
|
||||
"bugs": {
|
||||
"url": "https://github.com/TooTallNate/node-bindings/issues"
|
||||
},
|
||||
"homepage": "https://github.com/TooTallNate/node-bindings",
|
||||
"license": "MIT",
|
||||
"readme": "node-bindings\n=============\n### Helper module for loading your native module's .node file\n\nThis is a helper module for authors of Node.js native addon modules.\nIt is basically the \"swiss army knife\" of `require()`ing your native module's\n`.node` file.\n\nThroughout the course of Node's native addon history, addons have ended up being\ncompiled in a variety of different places, depending on which build tool and which\nversion of node was used. To make matters worse, now the _gyp_ build tool can\nproduce either a _Release_ or _Debug_ build, each being built into different\nlocations.\n\nThis module checks _all_ the possible locations that a native addon would be built\nat, and returns the first one that loads successfully.\n\n\nInstallation\n------------\n\nInstall with `npm`:\n\n``` bash\n$ npm install bindings\n```\n\nOr add it to the `\"dependencies\"` section of your _package.json_ file.\n\n\nExample\n-------\n\n`require()`ing the proper bindings file for the current node version, platform\nand architecture is as simple as:\n\n``` js\nvar bindings = require('bindings')('binding.node')\n\n// Use your bindings defined in your C files\nbindings.your_c_function()\n```\n\n\nNice Error Output\n-----------------\n\nWhen the `.node` file could not be loaded, `node-bindings` throws an Error with\na nice error message telling you exactly what was tried. You can also check the\n`err.tries` Array property.\n\n```\nError: Could not load the bindings file. Tried:\n → /Users/nrajlich/ref/build/binding.node\n → /Users/nrajlich/ref/build/Debug/binding.node\n → /Users/nrajlich/ref/build/Release/binding.node\n → /Users/nrajlich/ref/out/Debug/binding.node\n → /Users/nrajlich/ref/Debug/binding.node\n → /Users/nrajlich/ref/out/Release/binding.node\n → /Users/nrajlich/ref/Release/binding.node\n → /Users/nrajlich/ref/build/default/binding.node\n → /Users/nrajlich/ref/compiled/0.8.2/darwin/x64/binding.node\n at bindings (/Users/nrajlich/ref/node_modules/bindings/bindings.js:84:13)\n at Object.<anonymous> (/Users/nrajlich/ref/lib/ref.js:5:47)\n at Module._compile (module.js:449:26)\n at Object.Module._extensions..js (module.js:467:10)\n at Module.load (module.js:356:32)\n at Function.Module._load (module.js:312:12)\n ...\n```\n\n\nLicense\n-------\n\n(The MIT License)\n\nCopyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
|
||||
"readmeFilename": "README.md",
|
||||
"_id": "bindings@1.2.1",
|
||||
"_from": "bindings@1.2.x"
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
## DNT config file
|
||||
## see https://github.com/rvagg/dnt
|
||||
|
||||
NODE_VERSIONS="\
|
||||
master \
|
||||
v0.11.13 \
|
||||
v0.10.30 \
|
||||
v0.10.29 \
|
||||
v0.10.28 \
|
||||
v0.10.26 \
|
||||
v0.10.25 \
|
||||
v0.10.24 \
|
||||
v0.10.23 \
|
||||
v0.10.22 \
|
||||
v0.10.21 \
|
||||
v0.10.20 \
|
||||
v0.10.19 \
|
||||
v0.8.28 \
|
||||
v0.8.27 \
|
||||
v0.8.26 \
|
||||
v0.8.24 \
|
||||
"
|
||||
OUTPUT_PREFIX="nan-"
|
||||
TEST_CMD=" \
|
||||
cd /dnt/ && \
|
||||
npm install && \
|
||||
node_modules/.bin/node-gyp --nodedir /usr/src/node/ rebuild --directory test && \
|
||||
node_modules/.bin/tap --gc test/js/*-test.js \
|
||||
"
|
||||
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
# NAN ChangeLog
|
||||
|
||||
**Version 1.6.0: current Node unstable: 0.11.15, Node stable: 0.10.35, io.js: 1.0.3**
|
||||
|
||||
### 1.6.0 Jan 23 2015
|
||||
- Deprecated `NanNewContextHandle` in favor of `NanNew<Context>` 49259af
|
||||
- Support utility functions moved in newer v8 versions (Node 0.11.15, io.js 1.0) a0aa179
|
||||
- Added `NanEncode`, `NanDecodeBytes` and `NanDecodeWrite` 75e6fb9
|
||||
|
||||
### 1.5.2 Jan 23 2015
|
||||
|
||||
- Bugfix: Fix non-inline definition build error with clang++ 21d96a1, 60fadd4
|
||||
- Bugfix: Readded missing String constructors 18d828f
|
||||
- Bugfix: Add overload handling NanNew<FunctionTemplate>(..) 5ef813b
|
||||
- Bugfix: Fix uv_work_cb versioning 997e4ae
|
||||
- Bugfix: Add function factory and test 4eca89c
|
||||
- Bugfix: Add object template factory and test cdcb951
|
||||
- Correctness: Lifted an io.js related typedef c9490be
|
||||
- Correctness: Make explicit downcasts of String lengths 00074e6
|
||||
- Windows: Limit the scope of disabled warning C4530 83d7deb
|
||||
|
||||
### 1.5.1 Jan 15 2015
|
||||
|
||||
- Build: version bump
|
||||
|
||||
### 1.4.3 Jan 15 2015
|
||||
|
||||
- Build: version bump
|
||||
|
||||
### 1.4.2 Jan 15 2015
|
||||
|
||||
- Feature: Support io.js 0dbc5e8
|
||||
|
||||
### 1.5.0 Jan 14 2015
|
||||
|
||||
- Feature: Support io.js b003843
|
||||
- Correctness: Improved NanNew internals 9cd4f6a
|
||||
- Feature: Implement progress to NanAsyncWorker 8d6a160
|
||||
|
||||
### 1.4.1 Nov 8 2014
|
||||
|
||||
- Bugfix: Handle DEBUG definition correctly
|
||||
- Bugfix: Accept int as Boolean
|
||||
|
||||
### 1.4.0 Nov 1 2014
|
||||
|
||||
- Feature: Added NAN_GC_CALLBACK 6a5c245
|
||||
- Performance: Removed unnecessary local handle creation 18a7243, 41fe2f8
|
||||
- Correctness: Added constness to references in NanHasInstance 02c61cd
|
||||
- Warnings: Fixed spurious warnings from -Wundef and -Wshadow, 541b122, 99d8cb6
|
||||
- Windoze: Shut Visual Studio up when compiling 8d558c1
|
||||
- License: Switch to plain MIT from custom hacked MIT license 11de983
|
||||
- Build: Added test target to Makefile e232e46
|
||||
- Performance: Removed superfluous scope in NanAsyncWorker f4b7821
|
||||
- Sugar/Feature: Added NanReturnThis() and NanReturnHolder() shorthands 237a5ff, d697208
|
||||
- Feature: Added suitable overload of NanNew for v8::Integer::NewFromUnsigned b27b450
|
||||
|
||||
### 1.3.0 Aug 2 2014
|
||||
|
||||
- Added NanNew<v8::String, std::string>(std::string)
|
||||
- Added NanNew<v8::String, std::string&>(std::string&)
|
||||
- Added NanAsciiString helper class
|
||||
- Added NanUtf8String helper class
|
||||
- Added NanUcs2String helper class
|
||||
- Deprecated NanRawString()
|
||||
- Deprecated NanCString()
|
||||
- Added NanGetIsolateData(v8::Isolate *isolate)
|
||||
- Added NanMakeCallback(v8::Handle<v8::Object> target, v8::Handle<v8::Function> func, int argc, v8::Handle<v8::Value>* argv)
|
||||
- Added NanMakeCallback(v8::Handle<v8::Object> target, v8::Handle<v8::String> symbol, int argc, v8::Handle<v8::Value>* argv)
|
||||
- Added NanMakeCallback(v8::Handle<v8::Object> target, const char* method, int argc, v8::Handle<v8::Value>* argv)
|
||||
- Added NanSetTemplate(v8::Handle<v8::Template> templ, v8::Handle<v8::String> name , v8::Handle<v8::Data> value, v8::PropertyAttribute attributes)
|
||||
- Added NanSetPrototypeTemplate(v8::Local<v8::FunctionTemplate> templ, v8::Handle<v8::String> name, v8::Handle<v8::Data> value, v8::PropertyAttribute attributes)
|
||||
- Added NanSetInstanceTemplate(v8::Local<v8::FunctionTemplate> templ, const char *name, v8::Handle<v8::Data> value)
|
||||
- Added NanSetInstanceTemplate(v8::Local<v8::FunctionTemplate> templ, v8::Handle<v8::String> name, v8::Handle<v8::Data> value, v8::PropertyAttribute attributes)
|
||||
|
||||
### 1.2.0 Jun 5 2014
|
||||
|
||||
- Add NanSetPrototypeTemplate
|
||||
- Changed NAN_WEAK_CALLBACK internals, switched _NanWeakCallbackData to class,
|
||||
introduced _NanWeakCallbackDispatcher
|
||||
- Removed -Wno-unused-local-typedefs from test builds
|
||||
- Made test builds Windows compatible ('Sleep()')
|
||||
|
||||
### 1.1.2 May 28 2014
|
||||
|
||||
- Release to fix more stuff-ups in 1.1.1
|
||||
|
||||
### 1.1.1 May 28 2014
|
||||
|
||||
- Release to fix version mismatch in nan.h and lack of changelog entry for 1.1.0
|
||||
|
||||
### 1.1.0 May 25 2014
|
||||
|
||||
- Remove nan_isolate, use v8::Isolate::GetCurrent() internally instead
|
||||
- Additional explicit overloads for NanNew(): (char*,int), (uint8_t*[,int]),
|
||||
(uint16_t*[,int), double, int, unsigned int, bool, v8::String::ExternalStringResource*,
|
||||
v8::String::ExternalAsciiStringResource*
|
||||
- Deprecate NanSymbol()
|
||||
- Added SetErrorMessage() and ErrorMessage() to NanAsyncWorker
|
||||
|
||||
### 1.0.0 May 4 2014
|
||||
|
||||
- Heavy API changes for V8 3.25 / Node 0.11.13
|
||||
- Use cpplint.py
|
||||
- Removed NanInitPersistent
|
||||
- Removed NanPersistentToLocal
|
||||
- Removed NanFromV8String
|
||||
- Removed NanMakeWeak
|
||||
- Removed NanNewLocal
|
||||
- Removed NAN_WEAK_CALLBACK_OBJECT
|
||||
- Removed NAN_WEAK_CALLBACK_DATA
|
||||
- Introduce NanNew, replaces NanNewLocal, NanPersistentToLocal, adds many overloaded typed versions
|
||||
- Introduce NanUndefined, NanNull, NanTrue and NanFalse
|
||||
- Introduce NanEscapableScope and NanEscapeScope
|
||||
- Introduce NanMakeWeakPersistent (requires a special callback to work on both old and new node)
|
||||
- Introduce NanMakeCallback for node::MakeCallback
|
||||
- Introduce NanSetTemplate
|
||||
- Introduce NanGetCurrentContext
|
||||
- Introduce NanCompileScript and NanRunScript
|
||||
- Introduce NanAdjustExternalMemory
|
||||
- Introduce NanAddGCEpilogueCallback, NanAddGCPrologueCallback, NanRemoveGCEpilogueCallback, NanRemoveGCPrologueCallback
|
||||
- Introduce NanGetHeapStatistics
|
||||
- Rename NanAsyncWorker#SavePersistent() to SaveToPersistent()
|
||||
|
||||
### 0.8.0 Jan 9 2014
|
||||
|
||||
- NanDispose -> NanDisposePersistent, deprecate NanDispose
|
||||
- Extract _NAN_*_RETURN_TYPE, pull up NAN_*()
|
||||
|
||||
### 0.7.1 Jan 9 2014
|
||||
|
||||
- Fixes to work against debug builds of Node
|
||||
- Safer NanPersistentToLocal (avoid reinterpret_cast)
|
||||
- Speed up common NanRawString case by only extracting flattened string when necessary
|
||||
|
||||
### 0.7.0 Dec 17 2013
|
||||
|
||||
- New no-arg form of NanCallback() constructor.
|
||||
- NanCallback#Call takes Handle rather than Local
|
||||
- Removed deprecated NanCallback#Run method, use NanCallback#Call instead
|
||||
- Split off _NAN_*_ARGS_TYPE from _NAN_*_ARGS
|
||||
- Restore (unofficial) Node 0.6 compatibility at NanCallback#Call()
|
||||
- Introduce NanRawString() for char* (or appropriate void*) from v8::String
|
||||
(replacement for NanFromV8String)
|
||||
- Introduce NanCString() for null-terminated char* from v8::String
|
||||
|
||||
### 0.6.0 Nov 21 2013
|
||||
|
||||
- Introduce NanNewLocal<T>(v8::Handle<T> value) for use in place of
|
||||
v8::Local<T>::New(...) since v8 started requiring isolate in Node 0.11.9
|
||||
|
||||
### 0.5.2 Nov 16 2013
|
||||
|
||||
- Convert SavePersistent and GetFromPersistent in NanAsyncWorker from protected and public
|
||||
|
||||
### 0.5.1 Nov 12 2013
|
||||
|
||||
- Use node::MakeCallback() instead of direct v8::Function::Call()
|
||||
|
||||
### 0.5.0 Nov 11 2013
|
||||
|
||||
- Added @TooTallNate as collaborator
|
||||
- New, much simpler, "include_dirs" for binding.gyp
|
||||
- Added full range of NAN_INDEX_* macros to match NAN_PROPERTY_* macros
|
||||
|
||||
### 0.4.4 Nov 2 2013
|
||||
|
||||
- Isolate argument from v8::Persistent::MakeWeak removed for 0.11.8+
|
||||
|
||||
### 0.4.3 Nov 2 2013
|
||||
|
||||
- Include node_object_wrap.h, removed from node.h for Node 0.11.8.
|
||||
|
||||
### 0.4.2 Nov 2 2013
|
||||
|
||||
- Handle deprecation of v8::Persistent::Dispose(v8::Isolate* isolate)) for
|
||||
Node 0.11.8 release.
|
||||
|
||||
### 0.4.1 Sep 16 2013
|
||||
|
||||
- Added explicit `#include <uv.h>` as it was removed from node.h for v0.11.8
|
||||
|
||||
### 0.4.0 Sep 2 2013
|
||||
|
||||
- Added NAN_INLINE and NAN_DEPRECATED and made use of them
|
||||
- Added NanError, NanTypeError and NanRangeError
|
||||
- Cleaned up code
|
||||
|
||||
### 0.3.2 Aug 30 2013
|
||||
|
||||
- Fix missing scope declaration in GetFromPersistent() and SaveToPersistent
|
||||
in NanAsyncWorker
|
||||
|
||||
### 0.3.1 Aug 20 2013
|
||||
|
||||
- fix "not all control paths return a value" compile warning on some platforms
|
||||
|
||||
### 0.3.0 Aug 19 2013
|
||||
|
||||
- Made NAN work with NPM
|
||||
- Lots of fixes to NanFromV8String, pulling in features from new Node core
|
||||
- Changed node::encoding to Nan::Encoding in NanFromV8String to unify the API
|
||||
- Added optional error number argument for NanThrowError()
|
||||
- Added NanInitPersistent()
|
||||
- Added NanReturnNull() and NanReturnEmptyString()
|
||||
- Added NanLocker and NanUnlocker
|
||||
- Added missing scopes
|
||||
- Made sure to clear disposed Persistent handles
|
||||
- Changed NanAsyncWorker to allocate error messages on the heap
|
||||
- Changed NanThrowError(Local<Value>) to NanThrowError(Handle<Value>)
|
||||
- Fixed leak in NanAsyncWorker when errmsg is used
|
||||
|
||||
### 0.2.2 Aug 5 2013
|
||||
|
||||
- Fixed usage of undefined variable with node::BASE64 in NanFromV8String()
|
||||
|
||||
### 0.2.1 Aug 5 2013
|
||||
|
||||
- Fixed 0.8 breakage, node::BUFFER encoding type not available in 0.8 for
|
||||
NanFromV8String()
|
||||
|
||||
### 0.2.0 Aug 5 2013
|
||||
|
||||
- Added NAN_PROPERTY_GETTER, NAN_PROPERTY_SETTER, NAN_PROPERTY_ENUMERATOR,
|
||||
NAN_PROPERTY_DELETER, NAN_PROPERTY_QUERY
|
||||
- Extracted _NAN_METHOD_ARGS, _NAN_GETTER_ARGS, _NAN_SETTER_ARGS,
|
||||
_NAN_PROPERTY_GETTER_ARGS, _NAN_PROPERTY_SETTER_ARGS,
|
||||
_NAN_PROPERTY_ENUMERATOR_ARGS, _NAN_PROPERTY_DELETER_ARGS,
|
||||
_NAN_PROPERTY_QUERY_ARGS
|
||||
- Added NanGetInternalFieldPointer, NanSetInternalFieldPointer
|
||||
- Added NAN_WEAK_CALLBACK, NAN_WEAK_CALLBACK_OBJECT,
|
||||
NAN_WEAK_CALLBACK_DATA, NanMakeWeak
|
||||
- Renamed THROW_ERROR to _NAN_THROW_ERROR
|
||||
- Added NanNewBufferHandle(char*, size_t, node::smalloc::FreeCallback, void*)
|
||||
- Added NanBufferUse(char*, uint32_t)
|
||||
- Added NanNewContextHandle(v8::ExtensionConfiguration*,
|
||||
v8::Handle<v8::ObjectTemplate>, v8::Handle<v8::Value>)
|
||||
- Fixed broken NanCallback#GetFunction()
|
||||
- Added optional encoding and size arguments to NanFromV8String()
|
||||
- Added NanGetPointerSafe() and NanSetPointerSafe()
|
||||
- Added initial test suite (to be expanded)
|
||||
- Allow NanUInt32OptionValue to convert any Number object
|
||||
|
||||
### 0.1.0 Jul 21 2013
|
||||
|
||||
- Added `NAN_GETTER`, `NAN_SETTER`
|
||||
- Added `NanThrowError` with single Local<Value> argument
|
||||
- Added `NanNewBufferHandle` with single uint32_t argument
|
||||
- Added `NanHasInstance(Persistent<FunctionTemplate>&, Handle<Value>)`
|
||||
- Added `Local<Function> NanCallback#GetFunction()`
|
||||
- Added `NanCallback#Call(int, Local<Value>[])`
|
||||
- Deprecated `NanCallback#Run(int, Local<Value>[])` in favour of Call
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright (c) 2015 NAN contributors
|
||||
-----------------------------------
|
||||
|
||||
*NAN contributors listed at <https://github.com/rvagg/nan#contributors>*
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+1292
File diff suppressed because it is too large
Load Diff
+35
@@ -0,0 +1,35 @@
|
||||
# http://www.appveyor.com/docs/appveyor-yml
|
||||
|
||||
# Test against these versions of Node.js.
|
||||
environment:
|
||||
matrix:
|
||||
# node.js
|
||||
- nodejs_version: "0.8"
|
||||
- nodejs_version: "0.10"
|
||||
- nodejs_version: "0.11"
|
||||
# io.js
|
||||
- nodejs_version: "1.0"
|
||||
|
||||
# Install scripts. (runs after repo cloning)
|
||||
install:
|
||||
# Get the latest stable version of Node 0.STABLE.latest
|
||||
- ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version)
|
||||
- IF NOT %nodejs_version% == 1.0 npm -g install npm
|
||||
- IF NOT %nodejs_version% == 1.0 set PATH=%APPDATA%\npm;%PATH%
|
||||
# Typical npm stuff.
|
||||
- npm install
|
||||
- npm run rebuild-tests
|
||||
|
||||
# Post-install test scripts.
|
||||
test_script:
|
||||
# Output useful info for debugging.
|
||||
- node --version
|
||||
- npm --version
|
||||
# run tests
|
||||
- npm test
|
||||
|
||||
# Don't actually build.
|
||||
build: off
|
||||
|
||||
# Set build version format here instead of in the admin panel.
|
||||
version: "{build}"
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
console.log(require('path').relative('.', __dirname));
|
||||
+2157
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+262
@@ -0,0 +1,262 @@
|
||||
/*********************************************************************
|
||||
* NAN - Native Abstractions for Node.js
|
||||
*
|
||||
* Copyright (c) 2015 NAN contributors
|
||||
*
|
||||
* MIT License <https://github.com/rvagg/nan/blob/master/LICENSE.md>
|
||||
********************************************************************/
|
||||
|
||||
#ifndef NAN_IMPLEMENTATION_12_INL_H_
|
||||
#define NAN_IMPLEMENTATION_12_INL_H_
|
||||
//==============================================================================
|
||||
// node v0.11 implementation
|
||||
//==============================================================================
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning( disable : 4530 )
|
||||
# include <string>
|
||||
# pragma warning( default : 4530 )
|
||||
#else
|
||||
# include <string>
|
||||
#endif
|
||||
|
||||
namespace NanIntern {
|
||||
|
||||
//=== Array ====================================================================
|
||||
|
||||
Factory<v8::Array>::return_t
|
||||
Factory<v8::Array>::New() {
|
||||
return v8::Array::New(v8::Isolate::GetCurrent());
|
||||
}
|
||||
|
||||
Factory<v8::Array>::return_t
|
||||
Factory<v8::Array>::New(int length) {
|
||||
return v8::Array::New(v8::Isolate::GetCurrent(), length);
|
||||
}
|
||||
|
||||
//=== Boolean ==================================================================
|
||||
|
||||
Factory<v8::Boolean>::return_t
|
||||
Factory<v8::Boolean>::New(bool value) {
|
||||
return v8::Boolean::New(v8::Isolate::GetCurrent(), value);
|
||||
}
|
||||
|
||||
//=== Boolean Object ===========================================================
|
||||
|
||||
Factory<v8::BooleanObject>::return_t
|
||||
Factory<v8::BooleanObject>::New(bool value) {
|
||||
return v8::BooleanObject::New(value).As<v8::BooleanObject>();
|
||||
}
|
||||
|
||||
//=== Context ==================================================================
|
||||
|
||||
Factory<v8::Context>::return_t
|
||||
Factory<v8::Context>::New( v8::ExtensionConfiguration* extensions
|
||||
, v8::Handle<v8::ObjectTemplate> tmpl
|
||||
, v8::Handle<v8::Value> obj) {
|
||||
return v8::Context::New(v8::Isolate::GetCurrent(), extensions, tmpl, obj);
|
||||
}
|
||||
|
||||
//=== Date =====================================================================
|
||||
|
||||
Factory<v8::Date>::return_t
|
||||
Factory<v8::Date>::New(double value) {
|
||||
return v8::Date::New(v8::Isolate::GetCurrent(), value).As<v8::Date>();
|
||||
}
|
||||
|
||||
//=== External =================================================================
|
||||
|
||||
Factory<v8::External>::return_t
|
||||
Factory<v8::External>::New(void * value) {
|
||||
return v8::External::New(v8::Isolate::GetCurrent(), value);
|
||||
}
|
||||
|
||||
//=== Function =================================================================
|
||||
|
||||
Factory<v8::Function>::return_t
|
||||
Factory<v8::Function>::New( NanFunctionCallback callback
|
||||
, v8::Handle<v8::Value> data) {
|
||||
return v8::Function::New( v8::Isolate::GetCurrent()
|
||||
, callback
|
||||
, data);
|
||||
}
|
||||
|
||||
//=== Function Template ========================================================
|
||||
|
||||
Factory<v8::FunctionTemplate>::return_t
|
||||
Factory<v8::FunctionTemplate>::New( NanFunctionCallback callback
|
||||
, v8::Handle<v8::Value> data
|
||||
, v8::Handle<v8::Signature> signature) {
|
||||
return v8::FunctionTemplate::New( v8::Isolate::GetCurrent()
|
||||
, callback
|
||||
, data
|
||||
, signature);
|
||||
}
|
||||
|
||||
//=== Number ===================================================================
|
||||
|
||||
Factory<v8::Number>::return_t
|
||||
Factory<v8::Number>::New(double value) {
|
||||
return v8::Number::New(v8::Isolate::GetCurrent(), value);
|
||||
}
|
||||
|
||||
//=== Number Object ============================================================
|
||||
|
||||
Factory<v8::NumberObject>::return_t
|
||||
Factory<v8::NumberObject>::New(double value) {
|
||||
return v8::NumberObject::New( v8::Isolate::GetCurrent()
|
||||
, value).As<v8::NumberObject>();
|
||||
}
|
||||
|
||||
//=== Integer, Int32 and Uint32 ================================================
|
||||
|
||||
template <typename T>
|
||||
typename IntegerFactory<T>::return_t
|
||||
IntegerFactory<T>::New(int32_t value) {
|
||||
return To<T>(T::New(v8::Isolate::GetCurrent(), value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename IntegerFactory<T>::return_t
|
||||
IntegerFactory<T>::New(uint32_t value) {
|
||||
return To<T>(T::NewFromUnsigned(v8::Isolate::GetCurrent(), value));
|
||||
}
|
||||
|
||||
Factory<v8::Uint32>::return_t
|
||||
Factory<v8::Uint32>::New(int32_t value) {
|
||||
return To<v8::Uint32>(
|
||||
v8::Uint32::NewFromUnsigned(v8::Isolate::GetCurrent(), value));
|
||||
}
|
||||
|
||||
Factory<v8::Uint32>::return_t
|
||||
Factory<v8::Uint32>::New(uint32_t value) {
|
||||
return To<v8::Uint32>(
|
||||
v8::Uint32::NewFromUnsigned(v8::Isolate::GetCurrent(), value));
|
||||
}
|
||||
|
||||
//=== Object ===================================================================
|
||||
|
||||
Factory<v8::Object>::return_t
|
||||
Factory<v8::Object>::New() {
|
||||
return v8::Object::New(v8::Isolate::GetCurrent());
|
||||
}
|
||||
|
||||
//=== Object Template ==========================================================
|
||||
|
||||
Factory<v8::ObjectTemplate>::return_t
|
||||
Factory<v8::ObjectTemplate>::New() {
|
||||
return v8::ObjectTemplate::New(v8::Isolate::GetCurrent());
|
||||
}
|
||||
|
||||
//=== RegExp ===================================================================
|
||||
|
||||
Factory<v8::RegExp>::return_t
|
||||
Factory<v8::RegExp>::New(
|
||||
v8::Handle<v8::String> pattern
|
||||
, v8::RegExp::Flags flags) {
|
||||
return v8::RegExp::New(pattern, flags);
|
||||
}
|
||||
|
||||
//=== Script ===================================================================
|
||||
|
||||
Factory<v8::Script>::return_t
|
||||
Factory<v8::Script>::New( v8::Local<v8::String> source) {
|
||||
v8::ScriptCompiler::Source src(source);
|
||||
return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &src);
|
||||
}
|
||||
|
||||
Factory<v8::Script>::return_t
|
||||
Factory<v8::Script>::New( v8::Local<v8::String> source
|
||||
, v8::ScriptOrigin const& origin) {
|
||||
v8::ScriptCompiler::Source src(source, origin);
|
||||
return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &src);
|
||||
}
|
||||
|
||||
//=== Signature ================================================================
|
||||
|
||||
Factory<v8::Signature>::return_t
|
||||
Factory<v8::Signature>::New( Factory<v8::Signature>::FTH receiver
|
||||
, int argc
|
||||
, Factory<v8::Signature>::FTH argv[]) {
|
||||
return v8::Signature::New(v8::Isolate::GetCurrent(), receiver, argc, argv);
|
||||
}
|
||||
|
||||
//=== String ===================================================================
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New() {
|
||||
return v8::String::Empty(v8::Isolate::GetCurrent());
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(const char * value, int length) {
|
||||
return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), value,
|
||||
v8::String::kNormalString, length);
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(std::string const& value) {
|
||||
assert(value.size() <= INT_MAX && "string too long");
|
||||
return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(),
|
||||
value.data(), v8::String::kNormalString, static_cast<int>(value.size()));
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(const uint8_t * value, int length) {
|
||||
return v8::String::NewFromOneByte(v8::Isolate::GetCurrent(), value,
|
||||
v8::String::kNormalString, length);
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(const uint16_t * value, int length) {
|
||||
return v8::String::NewFromTwoByte(v8::Isolate::GetCurrent(), value,
|
||||
v8::String::kNormalString, length);
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(v8::String::ExternalStringResource * value) {
|
||||
return v8::String::NewExternal(v8::Isolate::GetCurrent(), value);
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(NanExternalOneByteStringResource * value) {
|
||||
return v8::String::NewExternal(v8::Isolate::GetCurrent(), value);
|
||||
}
|
||||
|
||||
//=== String Object ============================================================
|
||||
|
||||
Factory<v8::StringObject>::return_t
|
||||
Factory<v8::StringObject>::New(v8::Handle<v8::String> value) {
|
||||
return v8::StringObject::New(value).As<v8::StringObject>();
|
||||
}
|
||||
|
||||
//=== Unbound Script ===========================================================
|
||||
|
||||
Factory<v8::UnboundScript>::return_t
|
||||
Factory<v8::UnboundScript>::New(v8::Local<v8::String> source) {
|
||||
v8::ScriptCompiler::Source src(source);
|
||||
return v8::ScriptCompiler::CompileUnbound(v8::Isolate::GetCurrent(), &src);
|
||||
}
|
||||
|
||||
Factory<v8::UnboundScript>::return_t
|
||||
Factory<v8::UnboundScript>::New( v8::Local<v8::String> source
|
||||
, v8::ScriptOrigin const& origin) {
|
||||
v8::ScriptCompiler::Source src(source, origin);
|
||||
return v8::ScriptCompiler::CompileUnbound(v8::Isolate::GetCurrent(), &src);
|
||||
}
|
||||
|
||||
} // end of namespace NanIntern
|
||||
|
||||
//=== Presistents and Handles ==================================================
|
||||
|
||||
template <typename T>
|
||||
inline v8::Local<T> NanNew(v8::Handle<T> h) {
|
||||
return v8::Local<T>::New(v8::Isolate::GetCurrent(), h);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline v8::Local<T> NanNew(v8::Persistent<T> const& p) {
|
||||
return v8::Local<T>::New(v8::Isolate::GetCurrent(), p);
|
||||
}
|
||||
|
||||
#endif // NAN_IMPLEMENTATION_12_INL_H_
|
||||
Generated
Vendored
+268
@@ -0,0 +1,268 @@
|
||||
/*********************************************************************
|
||||
* NAN - Native Abstractions for Node.js
|
||||
*
|
||||
* Copyright (c) 2015 NAN contributors
|
||||
*
|
||||
* MIT License <https://github.com/rvagg/nan/blob/master/LICENSE.md>
|
||||
********************************************************************/
|
||||
|
||||
#ifndef NAN_IMPLEMENTATION_PRE_12_INL_H_
|
||||
#define NAN_IMPLEMENTATION_PRE_12_INL_H_
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning( disable : 4530 )
|
||||
# include <string>
|
||||
# include <vector>
|
||||
# pragma warning( default : 4530 )
|
||||
#else
|
||||
# include <string>
|
||||
# include <vector>
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// node v0.10 implementation
|
||||
//==============================================================================
|
||||
|
||||
namespace NanIntern {
|
||||
|
||||
//=== Array ====================================================================
|
||||
|
||||
Factory<v8::Array>::return_t
|
||||
Factory<v8::Array>::New() {
|
||||
return v8::Array::New();
|
||||
}
|
||||
|
||||
Factory<v8::Array>::return_t
|
||||
Factory<v8::Array>::New(int length) {
|
||||
return v8::Array::New(length);
|
||||
}
|
||||
|
||||
//=== Boolean ==================================================================
|
||||
|
||||
Factory<v8::Boolean>::return_t
|
||||
Factory<v8::Boolean>::New(bool value) {
|
||||
return v8::Boolean::New(value)->ToBoolean();
|
||||
}
|
||||
|
||||
//=== Boolean Object ===========================================================
|
||||
|
||||
Factory<v8::BooleanObject>::return_t
|
||||
Factory<v8::BooleanObject>::New(bool value) {
|
||||
return v8::BooleanObject::New(value).As<v8::BooleanObject>();
|
||||
}
|
||||
|
||||
//=== Context ==================================================================
|
||||
|
||||
Factory<v8::Context>::return_t
|
||||
Factory<v8::Context>::New( v8::ExtensionConfiguration* extensions
|
||||
, v8::Handle<v8::ObjectTemplate> tmpl
|
||||
, v8::Handle<v8::Value> obj) {
|
||||
v8::Persistent<v8::Context> ctx = v8::Context::New(extensions, tmpl, obj);
|
||||
v8::Local<v8::Context> lctx = v8::Local<v8::Context>::New(ctx);
|
||||
ctx.Dispose();
|
||||
return lctx;
|
||||
}
|
||||
|
||||
//=== Date =====================================================================
|
||||
|
||||
Factory<v8::Date>::return_t
|
||||
Factory<v8::Date>::New(double value) {
|
||||
return v8::Date::New(value).As<v8::Date>();
|
||||
}
|
||||
|
||||
//=== External =================================================================
|
||||
|
||||
Factory<v8::External>::return_t
|
||||
Factory<v8::External>::New(void * value) {
|
||||
return v8::External::New(value);
|
||||
}
|
||||
|
||||
//=== Function =================================================================
|
||||
|
||||
Factory<v8::Function>::return_t
|
||||
Factory<v8::Function>::New( NanFunctionCallback callback
|
||||
, v8::Handle<v8::Value> data) {
|
||||
return Factory<v8::FunctionTemplate>::New( callback
|
||||
, data
|
||||
, v8::Handle<v8::Signature>()
|
||||
)->GetFunction();
|
||||
}
|
||||
|
||||
|
||||
//=== FunctionTemplate =========================================================
|
||||
|
||||
Factory<v8::FunctionTemplate>::return_t
|
||||
Factory<v8::FunctionTemplate>::New( NanFunctionCallback callback
|
||||
, v8::Handle<v8::Value> data
|
||||
, v8::Handle<v8::Signature> signature) {
|
||||
// Note(agnat): Emulate length argument here. Unfortunately, I couldn't find
|
||||
// a way. Have at it though...
|
||||
return v8::FunctionTemplate::New( callback
|
||||
, data
|
||||
, signature);
|
||||
}
|
||||
|
||||
//=== Number ===================================================================
|
||||
|
||||
Factory<v8::Number>::return_t
|
||||
Factory<v8::Number>::New(double value) {
|
||||
return v8::Number::New(value);
|
||||
}
|
||||
|
||||
//=== Number Object ============================================================
|
||||
|
||||
Factory<v8::NumberObject>::return_t
|
||||
Factory<v8::NumberObject>::New(double value) {
|
||||
return v8::NumberObject::New(value).As<v8::NumberObject>();
|
||||
}
|
||||
|
||||
//=== Integer, Int32 and Uint32 ================================================
|
||||
|
||||
template <typename T>
|
||||
typename IntegerFactory<T>::return_t
|
||||
IntegerFactory<T>::New(int32_t value) {
|
||||
return To<T>(T::New(value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename IntegerFactory<T>::return_t
|
||||
IntegerFactory<T>::New(uint32_t value) {
|
||||
return To<T>(T::NewFromUnsigned(value));
|
||||
}
|
||||
|
||||
Factory<v8::Uint32>::return_t
|
||||
Factory<v8::Uint32>::New(int32_t value) {
|
||||
return To<v8::Uint32>(v8::Uint32::NewFromUnsigned(value));
|
||||
}
|
||||
|
||||
Factory<v8::Uint32>::return_t
|
||||
Factory<v8::Uint32>::New(uint32_t value) {
|
||||
return To<v8::Uint32>(v8::Uint32::NewFromUnsigned(value));
|
||||
}
|
||||
|
||||
|
||||
//=== Object ===================================================================
|
||||
|
||||
Factory<v8::Object>::return_t
|
||||
Factory<v8::Object>::New() {
|
||||
return v8::Object::New();
|
||||
}
|
||||
|
||||
//=== Object Template ==========================================================
|
||||
|
||||
Factory<v8::ObjectTemplate>::return_t
|
||||
Factory<v8::ObjectTemplate>::New() {
|
||||
return v8::ObjectTemplate::New();
|
||||
}
|
||||
|
||||
//=== RegExp ===================================================================
|
||||
|
||||
Factory<v8::RegExp>::return_t
|
||||
Factory<v8::RegExp>::New(
|
||||
v8::Handle<v8::String> pattern
|
||||
, v8::RegExp::Flags flags) {
|
||||
return v8::RegExp::New(pattern, flags);
|
||||
}
|
||||
|
||||
//=== Script ===================================================================
|
||||
|
||||
Factory<v8::Script>::return_t
|
||||
Factory<v8::Script>::New( v8::Local<v8::String> source) {
|
||||
return v8::Script::New(source);
|
||||
}
|
||||
Factory<v8::Script>::return_t
|
||||
Factory<v8::Script>::New( v8::Local<v8::String> source
|
||||
, v8::ScriptOrigin const& origin) {
|
||||
return v8::Script::New(source, const_cast<v8::ScriptOrigin*>(&origin));
|
||||
}
|
||||
|
||||
//=== Signature ================================================================
|
||||
|
||||
Factory<v8::Signature>::return_t
|
||||
Factory<v8::Signature>::New( Factory<v8::Signature>::FTH receiver
|
||||
, int argc
|
||||
, Factory<v8::Signature>::FTH argv[]) {
|
||||
return v8::Signature::New(receiver, argc, argv);
|
||||
}
|
||||
|
||||
//=== String ===================================================================
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New() {
|
||||
return v8::String::Empty();
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(const char * value, int length) {
|
||||
return v8::String::New(value, length);
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(std::string const& value) {
|
||||
assert(value.size() <= INT_MAX && "string too long");
|
||||
return v8::String::New( value.data(), static_cast<int>(value.size()));
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
widenString(std::vector<uint16_t> *ws, const uint8_t *s, int l = -1) {
|
||||
size_t len = static_cast<size_t>(l);
|
||||
if (l < 0) {
|
||||
len = strlen(reinterpret_cast<const char*>(s));
|
||||
}
|
||||
assert(len <= INT_MAX && "string too long");
|
||||
ws->resize(len);
|
||||
std::copy(s, s + len, ws->begin());
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(const uint16_t * value, int length) {
|
||||
return v8::String::New(value, length);
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(const uint8_t * value, int length) {
|
||||
std::vector<uint16_t> wideString;
|
||||
widenString(&wideString, value, length);
|
||||
if (wideString.size() == 0) {
|
||||
return v8::String::Empty();
|
||||
} else {
|
||||
return v8::String::New(&wideString.front()
|
||||
, static_cast<int>(wideString.size()));
|
||||
}
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(v8::String::ExternalStringResource * value) {
|
||||
return v8::String::NewExternal(value);
|
||||
}
|
||||
|
||||
Factory<v8::String>::return_t
|
||||
Factory<v8::String>::New(v8::String::ExternalAsciiStringResource * value) {
|
||||
return v8::String::NewExternal(value);
|
||||
}
|
||||
|
||||
//=== String Object ============================================================
|
||||
|
||||
Factory<v8::StringObject>::return_t
|
||||
Factory<v8::StringObject>::New(v8::Handle<v8::String> value) {
|
||||
return v8::StringObject::New(value).As<v8::StringObject>();
|
||||
}
|
||||
|
||||
} // end of namespace NanIntern
|
||||
|
||||
//=== Presistents and Handles ==================================================
|
||||
|
||||
template <typename T>
|
||||
inline v8::Local<T> NanNew(v8::Handle<T> h) {
|
||||
return v8::Local<T>::New(h);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline v8::Local<T> NanNew(v8::Persistent<T> const& p) {
|
||||
return v8::Local<T>::New(p);
|
||||
}
|
||||
|
||||
#endif // NAN_IMPLEMENTATION_PRE_12_INL_H_
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
/*********************************************************************
|
||||
* NAN - Native Abstractions for Node.js
|
||||
*
|
||||
* Copyright (c) 2015 NAN contributors
|
||||
*
|
||||
* MIT License <https://github.com/rvagg/nan/blob/master/LICENSE.md>
|
||||
********************************************************************/
|
||||
|
||||
#ifndef NAN_NEW_H_
|
||||
#define NAN_NEW_H_
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning( disable : 4530 )
|
||||
# include <string>
|
||||
# pragma warning( default : 4530 )
|
||||
#else
|
||||
# include <string>
|
||||
#endif
|
||||
|
||||
namespace NanIntern { // scnr
|
||||
|
||||
// TODO(agnat): Generalize
|
||||
template <typename T> v8::Local<T> To(v8::Handle<v8::Integer> i);
|
||||
|
||||
template <>
|
||||
inline
|
||||
v8::Local<v8::Integer>
|
||||
To<v8::Integer>(v8::Handle<v8::Integer> i) { return i->ToInteger(); }
|
||||
|
||||
template <>
|
||||
inline
|
||||
v8::Local<v8::Int32>
|
||||
To<v8::Int32>(v8::Handle<v8::Integer> i) { return i->ToInt32(); }
|
||||
|
||||
template <>
|
||||
inline
|
||||
v8::Local<v8::Uint32>
|
||||
To<v8::Uint32>(v8::Handle<v8::Integer> i) { return i->ToUint32(); }
|
||||
|
||||
template <typename T> struct FactoryBase { typedef v8::Local<T> return_t; };
|
||||
|
||||
template <typename T> struct Factory;
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Array> : FactoryBase<v8::Array> {
|
||||
static inline return_t New();
|
||||
static inline return_t New(int length);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Boolean> : FactoryBase<v8::Boolean> {
|
||||
static inline return_t New(bool value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::BooleanObject> : FactoryBase<v8::BooleanObject> {
|
||||
static inline return_t New(bool value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Context> : FactoryBase<v8::Context> {
|
||||
static inline
|
||||
return_t
|
||||
New( v8::ExtensionConfiguration* extensions = NULL
|
||||
, v8::Handle<v8::ObjectTemplate> tmpl = v8::Handle<v8::ObjectTemplate>()
|
||||
, v8::Handle<v8::Value> obj = v8::Handle<v8::Value>());
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Date> : FactoryBase<v8::Date> {
|
||||
static inline return_t New(double value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::External> : FactoryBase<v8::External> {
|
||||
static inline return_t New(void *value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Function> : FactoryBase<v8::Function> {
|
||||
static inline
|
||||
return_t
|
||||
New( NanFunctionCallback callback
|
||||
, v8::Handle<v8::Value> data = v8::Handle<v8::Value>());
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::FunctionTemplate> : FactoryBase<v8::FunctionTemplate> {
|
||||
static inline
|
||||
return_t
|
||||
New( NanFunctionCallback callback = NULL
|
||||
, v8::Handle<v8::Value> data = v8::Handle<v8::Value>()
|
||||
, v8::Handle<v8::Signature> signature = v8::Handle<v8::Signature>());
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Number> : FactoryBase<v8::Number> {
|
||||
static inline return_t New(double value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::NumberObject> : FactoryBase<v8::NumberObject> {
|
||||
static inline return_t New(double value);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IntegerFactory : FactoryBase<T> {
|
||||
typedef typename FactoryBase<T>::return_t return_t;
|
||||
static inline return_t New(int32_t value);
|
||||
static inline return_t New(uint32_t value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Integer> : IntegerFactory<v8::Integer> {};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Int32> : IntegerFactory<v8::Int32> {};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Uint32> : FactoryBase<v8::Uint32> {
|
||||
static inline return_t New(int32_t value);
|
||||
static inline return_t New(uint32_t value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Object> : FactoryBase<v8::Object> {
|
||||
static inline return_t New();
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::ObjectTemplate> : FactoryBase<v8::ObjectTemplate> {
|
||||
static inline return_t New();
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::RegExp> : FactoryBase<v8::RegExp> {
|
||||
static inline return_t New(
|
||||
v8::Handle<v8::String> pattern, v8::RegExp::Flags flags);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Script> : FactoryBase<v8::Script> {
|
||||
static inline return_t New( v8::Local<v8::String> source);
|
||||
static inline return_t New( v8::Local<v8::String> source
|
||||
, v8::ScriptOrigin const& origin);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::Signature> : FactoryBase<v8::Signature> {
|
||||
typedef v8::Handle<v8::FunctionTemplate> FTH;
|
||||
static inline
|
||||
return_t
|
||||
New( FTH receiver = FTH(), int argc = 0, FTH argv[] = NULL );
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::String> : FactoryBase<v8::String> {
|
||||
static inline return_t New();
|
||||
static inline return_t New(const char *value, int length = -1);
|
||||
static inline return_t New(const uint16_t *value, int length = -1);
|
||||
static inline return_t New(std::string const& value);
|
||||
|
||||
static inline return_t New(v8::String::ExternalStringResource * value);
|
||||
static inline return_t New(NanExternalOneByteStringResource * value);
|
||||
|
||||
// TODO(agnat): Deprecate.
|
||||
static inline return_t New(const uint8_t * value, int length = -1);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Factory<v8::StringObject> : FactoryBase<v8::StringObject> {
|
||||
static inline return_t New(v8::Handle<v8::String> value);
|
||||
};
|
||||
|
||||
} // end of namespace NanIntern
|
||||
|
||||
#if (NODE_MODULE_VERSION >= 12)
|
||||
|
||||
namespace NanIntern {
|
||||
|
||||
template <>
|
||||
struct Factory<v8::UnboundScript> : FactoryBase<v8::UnboundScript> {
|
||||
static inline return_t New( v8::Local<v8::String> source);
|
||||
static inline return_t New( v8::Local<v8::String> source
|
||||
, v8::ScriptOrigin const& origin);
|
||||
};
|
||||
|
||||
} // end of namespace NanIntern
|
||||
|
||||
# include "nan_implementation_12_inl.h"
|
||||
|
||||
#else // NODE_MODULE_VERSION >= 12
|
||||
|
||||
# include "nan_implementation_pre_12_inl.h"
|
||||
|
||||
#endif
|
||||
|
||||
//=== API ======================================================================
|
||||
|
||||
template <typename T>
|
||||
typename NanIntern::Factory<T>::return_t
|
||||
NanNew() {
|
||||
return NanIntern::Factory<T>::New();
|
||||
}
|
||||
|
||||
template <typename T, typename A0>
|
||||
typename NanIntern::Factory<T>::return_t
|
||||
NanNew(A0 arg0) {
|
||||
return NanIntern::Factory<T>::New(arg0);
|
||||
}
|
||||
|
||||
template <typename T, typename A0, typename A1>
|
||||
typename NanIntern::Factory<T>::return_t
|
||||
NanNew(A0 arg0, A1 arg1) {
|
||||
return NanIntern::Factory<T>::New(arg0, arg1);
|
||||
}
|
||||
|
||||
template <typename T, typename A0, typename A1, typename A2>
|
||||
typename NanIntern::Factory<T>::return_t
|
||||
NanNew(A0 arg0, A1 arg1, A2 arg2) {
|
||||
return NanIntern::Factory<T>::New(arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
template <typename T, typename A0, typename A1, typename A2, typename A3>
|
||||
typename NanIntern::Factory<T>::return_t
|
||||
NanNew(A0 arg0, A1 arg1, A2 arg2, A3 arg3) {
|
||||
return NanIntern::Factory<T>::New(arg0, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
// Note(agnat): When passing overloaded function pointers to template functions
|
||||
// as generic arguments the compiler needs help in picking the right overload.
|
||||
// These two functions handle NanNew<Function> and NanNew<FunctionTemplate> with
|
||||
// all argument variations.
|
||||
|
||||
// v8::Function and v8::FunctionTemplate with one or two arguments
|
||||
template <typename T>
|
||||
typename NanIntern::Factory<T>::return_t
|
||||
NanNew( NanFunctionCallback callback
|
||||
, v8::Handle<v8::Value> data = v8::Handle<v8::Value>()) {
|
||||
return NanIntern::Factory<T>::New(callback, data);
|
||||
}
|
||||
|
||||
// v8::Function and v8::FunctionTemplate with three arguments
|
||||
template <typename T, typename A2>
|
||||
typename NanIntern::Factory<T>::return_t
|
||||
NanNew( NanFunctionCallback callback
|
||||
, v8::Handle<v8::Value> data = v8::Handle<v8::Value>()
|
||||
, A2 a2 = A2()) {
|
||||
return NanIntern::Factory<T>::New(callback, data, a2);
|
||||
}
|
||||
|
||||
// Convenience
|
||||
|
||||
template <typename T> inline v8::Local<T> NanNew(v8::Handle<T> h);
|
||||
template <typename T> inline v8::Local<T> NanNew(v8::Persistent<T> const& p);
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::Boolean>::return_t
|
||||
NanNew(bool value) {
|
||||
return NanNew<v8::Boolean>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::Int32>::return_t
|
||||
NanNew(int32_t value) {
|
||||
return NanNew<v8::Int32>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::Uint32>::return_t
|
||||
NanNew(uint32_t value) {
|
||||
return NanNew<v8::Uint32>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::Number>::return_t
|
||||
NanNew(double value) {
|
||||
return NanNew<v8::Number>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::String>::return_t
|
||||
NanNew(std::string const& value) {
|
||||
return NanNew<v8::String>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::String>::return_t
|
||||
NanNew(const char * value, int length) {
|
||||
return NanNew<v8::String>(value, length);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::String>::return_t
|
||||
NanNew(const char * value) {
|
||||
return NanNew<v8::String>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::String>::return_t
|
||||
NanNew(const uint8_t * value) {
|
||||
return NanNew<v8::String>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::String>::return_t
|
||||
NanNew(const uint16_t * value) {
|
||||
return NanNew<v8::String>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::String>::return_t
|
||||
NanNew(v8::String::ExternalStringResource * value) {
|
||||
return NanNew<v8::String>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::String>::return_t
|
||||
NanNew(NanExternalOneByteStringResource * value) {
|
||||
return NanNew<v8::String>(value);
|
||||
}
|
||||
|
||||
inline
|
||||
NanIntern::Factory<v8::RegExp>::return_t
|
||||
NanNew(v8::Handle<v8::String> pattern, v8::RegExp::Flags flags) {
|
||||
return NanNew<v8::RegExp>(pattern, flags);
|
||||
}
|
||||
|
||||
#endif // NAN_NEW_H_
|
||||
+69
File diff suppressed because one or more lines are too long
+39
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "utf-8-validate",
|
||||
"version": "1.0.1",
|
||||
"description": "Validate UTF-8 for Web",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"install": "node-gyp rebuild"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/websockets/utf-8-validate"
|
||||
},
|
||||
"keywords": [
|
||||
"utf-8-validate"
|
||||
],
|
||||
"author": {
|
||||
"name": "Einar Otto Stangvik",
|
||||
"email": "einaros@gmail.com",
|
||||
"url": "http://2x.io"
|
||||
},
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/websockets/utf-8-validate/issues"
|
||||
},
|
||||
"homepage": "https://github.com/websockets/utf-8-validate",
|
||||
"dependencies": {
|
||||
"bindings": "1.2.x",
|
||||
"nan": "1.6.x"
|
||||
},
|
||||
"gypfile": true,
|
||||
"readme": "ERROR: No README data found!",
|
||||
"_id": "utf-8-validate@1.0.1",
|
||||
"dist": {
|
||||
"shasum": "cceba50dbe5a715ab79c69a60e6cbc04f73e61dd"
|
||||
},
|
||||
"_from": "utf-8-validate@1.0.x",
|
||||
"_resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-1.0.1.tgz"
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
/*!
|
||||
* UTF-8 validate: UTF-8 validation for WebSockets.
|
||||
* Copyright(c) 2015 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
#include <v8.h>
|
||||
#include <node.h>
|
||||
#include <node_version.h>
|
||||
#include <node_buffer.h>
|
||||
#include <node_object_wrap.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <stdio.h>
|
||||
#include "nan.h"
|
||||
|
||||
using namespace v8;
|
||||
using namespace node;
|
||||
|
||||
#define UNI_SUR_HIGH_START (uint32_t) 0xD800
|
||||
#define UNI_SUR_LOW_END (uint32_t) 0xDFFF
|
||||
#define UNI_REPLACEMENT_CHAR (uint32_t) 0x0000FFFD
|
||||
#define UNI_MAX_LEGAL_UTF32 (uint32_t) 0x0010FFFF
|
||||
|
||||
static const uint8_t trailingBytesForUTF8[256] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
||||
};
|
||||
|
||||
static const uint32_t offsetsFromUTF8[6] = {
|
||||
0x00000000, 0x00003080, 0x000E2080,
|
||||
0x03C82080, 0xFA082080, 0x82082080
|
||||
};
|
||||
|
||||
static int isLegalUTF8(const uint8_t *source, const int length)
|
||||
{
|
||||
uint8_t a;
|
||||
const uint8_t *srcptr = source+length;
|
||||
switch (length) {
|
||||
default: return 0;
|
||||
/* Everything else falls through when "true"... */
|
||||
/* RFC3629 makes 5 & 6 bytes UTF-8 illegal
|
||||
case 6: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
|
||||
case 5: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; */
|
||||
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
|
||||
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
|
||||
case 2: if ((a = (*--srcptr)) > 0xBF) return 0;
|
||||
switch (*source) {
|
||||
/* no fall-through in this inner switch */
|
||||
case 0xE0: if (a < 0xA0) return 0; break;
|
||||
case 0xED: if (a > 0x9F) return 0; break;
|
||||
case 0xF0: if (a < 0x90) return 0; break;
|
||||
case 0xF4: if (a > 0x8F) return 0; break;
|
||||
default: if (a < 0x80) return 0;
|
||||
}
|
||||
|
||||
case 1: if (*source >= 0x80 && *source < 0xC2) return 0;
|
||||
}
|
||||
if (*source > 0xF4) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int is_valid_utf8 (size_t len, char *value)
|
||||
{
|
||||
/* is the string valid UTF-8? */
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
uint32_t ch = 0;
|
||||
uint8_t extrabytes = trailingBytesForUTF8[(uint8_t) value[i]];
|
||||
|
||||
if (extrabytes + i >= len)
|
||||
return 0;
|
||||
|
||||
if (isLegalUTF8 ((uint8_t *) (value + i), extrabytes + 1) == 0) return 0;
|
||||
|
||||
switch (extrabytes) {
|
||||
case 5 : ch += (uint8_t) value[i++]; ch <<= 6;
|
||||
case 4 : ch += (uint8_t) value[i++]; ch <<= 6;
|
||||
case 3 : ch += (uint8_t) value[i++]; ch <<= 6;
|
||||
case 2 : ch += (uint8_t) value[i++]; ch <<= 6;
|
||||
case 1 : ch += (uint8_t) value[i++]; ch <<= 6;
|
||||
case 0 : ch += (uint8_t) value[i];
|
||||
}
|
||||
|
||||
ch -= offsetsFromUTF8[extrabytes];
|
||||
|
||||
if (ch <= UNI_MAX_LEGAL_UTF32) {
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
class Validation : public ObjectWrap
|
||||
{
|
||||
public:
|
||||
|
||||
static void Initialize(v8::Handle<v8::Object> target)
|
||||
{
|
||||
NanScope();
|
||||
Local<FunctionTemplate> t = NanNew<FunctionTemplate>(New);
|
||||
t->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
NODE_SET_METHOD(t, "isValidUTF8", Validation::IsValidUTF8);
|
||||
target->Set(NanNew<String>("Validation"), t->GetFunction());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
static NAN_METHOD(New)
|
||||
{
|
||||
NanScope();
|
||||
Validation* validation = new Validation();
|
||||
validation->Wrap(args.This());
|
||||
NanReturnValue(args.This());
|
||||
}
|
||||
|
||||
static NAN_METHOD(IsValidUTF8)
|
||||
{
|
||||
NanScope();
|
||||
if (!Buffer::HasInstance(args[0])) {
|
||||
return NanThrowTypeError("First argument needs to be a buffer");
|
||||
}
|
||||
Local<Object> buffer_obj = args[0]->ToObject();
|
||||
char *buffer_data = Buffer::Data(buffer_obj);
|
||||
size_t buffer_length = Buffer::Length(buffer_obj);
|
||||
NanReturnValue(is_valid_utf8(buffer_length, buffer_data) == 1 ? NanTrue() : NanFalse());
|
||||
}
|
||||
};
|
||||
#if !NODE_VERSION_AT_LEAST(0,10,0)
|
||||
extern "C"
|
||||
#endif
|
||||
void init (Handle<Object> target)
|
||||
{
|
||||
NanScope();
|
||||
Validation::Initialize(target);
|
||||
}
|
||||
|
||||
NODE_MODULE(validation, init)
|
||||
|
||||
+63
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user