HCBASE-93

Error code overview:

IPConnection.ERROR_ALREADY_CONNECTED = 11
IPConnection.ERROR_NOT_CONNECTED = 12
IPConnection.ERROR_CONNECT_FAILED = 13
IPConnection.ERROR_INVALID_FUNCTION_ID = 21
IPConnection.ERROR_TIMEOUT = 31
IPConnection.ERROR_INVALID_PARAMETER = 41
IPConnection.ERROR_FUNCTION_NOT_SUPPORTED = 42
IPConnection.ERROR_UNKNOWN_ERROR = 43

http://www.tinkerforge.com/de/doc/Software/Bricklets/MotionDetector_Bricklet_JavaScript.html
https://www.npmjs.com/package/nodejs-websocket
https://devcenter.heroku.com/articles/node-websockets
This commit is contained in:
Gerrit Linnemann 2016-06-08 18:08:00 +02:00
parent badf407e27
commit 971495b393
17 changed files with 1435 additions and 10 deletions

View File

@ -2,7 +2,8 @@ var Tinkerforge = require('../Tinkerforge')
, Conf = require('./config.json') , Conf = require('./config.json')
, Helper = require('../Adawim/helper') , Helper = require('../Adawim/helper')
, Log = require('../Adawim/logging') , Log = require('../Adawim/logging')
, http = require('http'); , http = require('http')
, ws = require("nodejs-websocket");
Helper.each(Conf.items, function(item) { Helper.each(Conf.items, function(item) {
@ -42,14 +43,15 @@ Helper.each(Conf.items, function(item) {
// Register motion detected callback // Register motion detected callback
md.on(Tinkerforge.BrickletMotionDetector.CALLBACK_MOTION_DETECTED, md.on(Tinkerforge.BrickletMotionDetector.CALLBACK_MOTION_DETECTED,
// Callback function for motion detected callback // Callback function for motion detected callback
function () { function () {
Log.log('Motion detected'); Log.log('Motion detected');
} sendToHoBu("ping");
}
); );
process.on( 'SIGINT', function() { process.on( 'SIGINT', function() {
console.log( "\nGracefully disconnect " + HOST ); Log.log( "Gracefully disconnect " + HOST );
ipcon.disconnect(); ipcon.disconnect();
process.exit( ); process.exit( );
}); });
@ -74,3 +76,22 @@ function doHoBuDoorBellCall(options) {
http.request(options, callback).end(); http.request(options, callback).end();
} }
/* private */
function sendToHoBu(data) {
Log.debug('Send data to ' + Conf.hobu.webservice);
try {
ws.connect(Conf.hobu.webservice, null, function(conn) {
if(Helper.isDefinedAndNotNull(conn)) {
conn.send(data, null);
} else {
Log.error('Connection is NULL.');
}
//TODO: disconnect!!
});
} catch(err) {
Log.error(err.message);
}
}

View File

@ -53,7 +53,7 @@ Helper.each(Conf.items, function(item) {
); );
process.on( 'SIGINT', function() { process.on( 'SIGINT', function() {
console.log( "\nGracefully disconnect " + HOST ); Log.log( "Gracefully disconnect " + HOST );
ipcon.disconnect(); ipcon.disconnect();
process.exit( ); process.exit( );
}); });

View File

@ -57,7 +57,7 @@ ai.on(Tinkerforge.BrickletAnalogInV2.CALLBACK_VOLTAGE,
); );
process.on( 'SIGINT', function() { process.on( 'SIGINT', function() {
console.log( "\nGracefully disconnect " + HOST ); Log.log( "Gracefully disconnect " + HOST );
ipcon.disconnect(); ipcon.disconnect();
process.exit( ); process.exit( );
}); });

22
node_modules/nodejs-websocket/.jshintrc generated vendored Normal file
View File

@ -0,0 +1,22 @@
{
"curly": true,
"eqeqeq": true,
"nonew": true,
"latedef": "nofunc",
"unused": true,
"noarg": true,
"asi": true,
"trailing": true,
"quotmark": true,
"strict": true,
"undef": true,
"expr": true,
"newcap": true,
"immed": true,
"node": true,
"camelcase": true,
"devel": true,
"freeze": true,
"-W033": true,
"-W058": true
}

3
node_modules/nodejs-websocket/.npmignore generated vendored Normal file
View File

@ -0,0 +1,3 @@
node_modules
test
samples

5
node_modules/nodejs-websocket/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,5 @@
language: node_js
node_js:
- "0.12"
- "4.2.1"
- "node"

616
node_modules/nodejs-websocket/Connection.js generated vendored Normal file
View File

@ -0,0 +1,616 @@
/**
* @file Represents a connection (both client and server sides)
*/
'use strict'
var util = require('util'),
events = require('events'),
crypto = require('crypto'),
InStream = require('./InStream'),
OutStream = require('./OutStream'),
frame = require('./frame'),
Server = require('./Server')
/**
* @class
* @param {(net.Socket|tls.CleartextStream)} socket a net or tls socket
* @param {(Server|{path:string,host:string})} parentOrUrl parent in case of server-side connection, url object in case of client-side
* @param {Function} [callback] will be added as a listener to 'connect'
* @inherits EventEmitter
* @event close the numeric code and string reason will be passed
* @event error an error object is passed
* @event text a string is passed
* @event binary a inStream object is passed
* @event pong a string is passed
* @event connect
*/
function Connection(socket, parentOrUrl, callback) {
var that = this,
connectEvent
if (parentOrUrl instanceof Server) {
// Server-side connection
this.server = parentOrUrl
this.path = null
this.host = null
this.extraHeaders = null
} else {
// Client-side
this.server = null
this.path = parentOrUrl.path
this.host = parentOrUrl.host
this.extraHeaders = parentOrUrl.extraHeaders
}
this.socket = socket
this.readyState = this.CONNECTING
this.buffer = new Buffer(0)
this.frameBuffer = null // string for text frames and InStream for binary frames
this.outStream = null // current allocated OutStream object for sending binary frames
this.key = null // the Sec-WebSocket-Key header
this.headers = {} // read only map of header names and values. Header names are lower-cased
// Set listeners
socket.on('readable', function () {
that.doRead()
})
socket.on('error', function (err) {
that.emit('error', err)
})
if (!this.server) {
connectEvent = socket.constructor.name === 'CleartextStream' ? 'secureConnect' : 'connect'
socket.on(connectEvent, function () {
that.startHandshake()
})
}
// Close listeners
var onclose = function () {
if (that.readyState === that.CONNECTING || that.readyState === that.OPEN) {
that.emit('close', 1006, '')
}
that.readyState = this.CLOSED
if (that.frameBuffer instanceof InStream) {
that.frameBuffer.end()
that.frameBuffer = null
}
if (that.outStream instanceof OutStream) {
that.outStream.end()
that.outStream = null
}
}
socket.once('close', onclose)
socket.once('finish', onclose)
// super constructor
events.EventEmitter.call(this)
if (callback) {
this.once('connect', callback)
}
}
util.inherits(Connection, events.EventEmitter)
module.exports = Connection
/**
* Minimum size of a pack of binary data to send in a single frame
* @property {number} binaryFragmentation
*/
Connection.binaryFragmentation = 512 * 1024 // .5 MiB
/**
* The maximum size the internal Buffer can grow
* If at any time it stays bigger than this, the connection will be closed with code 1009
* This is a security measure, to avoid memory attacks
* @property {number} maxBufferLength
*/
Connection.maxBufferLength = 2 * 1024 * 1024 // 2 MiB
/**
* Possible ready states for the connection
* @constant {number} CONNECTING
* @constant {number} OPEN
* @constant {number} CLOSING
* @constant {number} CLOSED
*/
Connection.prototype.CONNECTING = 0
Connection.prototype.OPEN = 1
Connection.prototype.CLOSING = 2
Connection.prototype.CLOSED = 3
/**
* Send a given string to the other side
* @param {string} str
* @param {Function} [callback] will be executed when the data is finally written out
*/
Connection.prototype.sendText = function (str, callback) {
if (this.readyState === this.OPEN) {
if (!this.outStream) {
return this.socket.write(frame.createTextFrame(str, !this.server), callback)
}
this.emit('error', new Error('You can\'t send a text frame until you finish sending binary frames'))
}
this.emit('error', new Error('You can\'t write to a non-open connection'))
}
/**
* Request for a OutStream to send binary data
* @returns {OutStream}
*/
Connection.prototype.beginBinary = function () {
if (this.readyState === this.OPEN) {
if (!this.outStream) {
return (this.outStream = new OutStream(this, Connection.binaryFragmentation))
}
this.emit('error', new Error('You can\'t send more binary frames until you finish sending the previous binary frames'))
}
this.emit('error', new Error('You can\'t write to a non-open connection'))
}
/**
* Sends a binary buffer at once
* @param {Buffer} data
* @param {Function} [callback] will be executed when the data is finally written out
*/
Connection.prototype.sendBinary = function (data, callback) {
if (this.readyState === this.OPEN) {
if (!this.outStream) {
return this.socket.write(frame.createBinaryFrame(data, !this.server, true, true), callback)
}
this.emit('error', new Error('You can\'t send more binary frames until you finish sending the previous binary frames'))
}
this.emit('error', new Error('You can\'t write to a non-open connection'))
}
/**
* Sends a text or binary frame
* @param {string|Buffer} data
* @param {Function} [callback] will be executed when the data is finally written out
*/
Connection.prototype.send = function (data, callback) {
if (typeof data === 'string') {
this.sendText(data, callback)
} else if (Buffer.isBuffer(data)) {
this.sendBinary(data, callback)
} else {
throw new TypeError('data should be either a string or a Buffer instance')
}
}
/**
* Sends a ping to the remote
* @param {string} [data=''] - optional ping data
* @fires pong when pong reply is received
*/
Connection.prototype.sendPing = function (data) {
if (this.readyState === this.OPEN) {
return this.socket.write(frame.createPingFrame(data || '', !this.server))
}
this.emit('error', new Error('You can\'t write to a non-open connection'))
}
/**
* Close the connection, sending a close frame and waiting for response
* If the connection isn't OPEN, closes it without sending a close frame
* @param {number} [code]
* @param {string} [reason]
* @fires close
*/
Connection.prototype.close = function (code, reason) {
if (this.readyState === this.OPEN) {
this.socket.write(frame.createCloseFrame(code, reason, !this.server))
this.readyState = this.CLOSING
} else if (this.readyState !== this.CLOSED) {
this.socket.end()
this.readyState = this.CLOSED
}
this.emit('close', code, reason)
}
/**
* Reads contents from the socket and process it
* @fires connect
* @private
*/
Connection.prototype.doRead = function () {
var buffer, temp
// Fetches the data
buffer = this.socket.read()
if (!buffer) {
// Waits for more data
return
}
// Save to the internal buffer
this.buffer = Buffer.concat([this.buffer, buffer], this.buffer.length + buffer.length)
if (this.readyState === this.CONNECTING) {
if (!this.readHandshake()) {
// May have failed or we're waiting for more data
return
}
}
if (this.readyState !== this.CLOSED) {
// Try to read as many frames as possible
while ((temp = this.extractFrame()) === true) {}
if (temp === false) {
// Protocol error
this.close(1002)
} else if (this.buffer.length > Connection.maxBufferLength) {
// Frame too big
this.close(1009)
}
}
}
/**
* Create and send a handshake as a client
* @private
*/
Connection.prototype.startHandshake = function () {
var str, i, key, headers, header
key = new Buffer(16)
for (i = 0; i < 16; i++) {
key[i] = Math.floor(Math.random() * 256)
}
this.key = key.toString('base64')
headers = {
Host: this.host,
Upgrade: 'websocket',
Connection: 'Upgrade',
'Sec-WebSocket-Key': this.key,
'Sec-WebSocket-Version': '13'
}
for (header in this.extraHeaders) {
headers[header] = this.extraHeaders[header]
}
str = this.buildRequest('GET ' + this.path + ' HTTP/1.1', headers)
this.socket.write(str)
}
/**
* Try to read the handshake from the internal buffer
* If it succeeds, the handshake data is consumed from the internal buffer
* @returns {boolean} - whether the handshake was done
* @private
*/
Connection.prototype.readHandshake = function () {
var found = false,
i, data
// Do the handshake and try to connect
if (this.buffer.length > Connection.maxBufferLength) {
// Too big for a handshake
this.socket.end(this.server ? 'HTTP/1.1 400 Bad Request\r\n\r\n' : undefined)
return false
}
// Search for '\r\n\r\n'
for (i = 0; i < this.buffer.length - 3; i++) {
if (this.buffer[i] === 13 && this.buffer[i + 2] === 13 &&
this.buffer[i + 1] === 10 && this.buffer[i + 3] === 10) {
found = true
break
}
}
if (!found) {
// Wait for more data
return false
}
data = this.buffer.slice(0, i + 4).toString().split('\r\n')
if (this.server ? this.answerHandshake(data) : this.checkHandshake(data)) {
this.buffer = this.buffer.slice(i + 4)
this.readyState = this.OPEN
this.emit('connect')
return true
} else {
this.socket.end(this.server ? 'HTTP/1.1 400 Bad Request\r\n\r\n' : undefined)
return false
}
}
/**
* Read headers from HTTP protocol
* Update the Connection#headers property
* @param {string[]} lines one for each '\r\n'-separated HTTP request line
* @private
*/
Connection.prototype.readHeaders = function (lines) {
var i, match
// Extract all headers
// Ignore bad-formed lines and ignore the first line (HTTP header)
for (i = 1; i < lines.length; i++) {
if ((match = lines[i].match(/^([a-z-]+): (.+)$/i))) {
this.headers[match[1].toLowerCase()] = match[2]
}
}
}
/**
* Process and check a handshake answered by a server
* @param {string[]} lines one for each '\r\n'-separated HTTP request line
* @returns {boolean} if the handshake was sucessful. If not, the connection must be closed
* @private
*/
Connection.prototype.checkHandshake = function (lines) {
var key, sha1
// First line
if (lines.length < 4) {
return false
}
if (!lines[0].match(/^HTTP\/\d\.\d 101( .*)?$/i)) {
return false
}
// Extract all headers
this.readHeaders(lines)
// Validate necessary headers
if (!('upgrade' in this.headers) ||
!('sec-websocket-accept' in this.headers) ||
!('connection' in this.headers)) {
return false
}
if (this.headers.upgrade.toLowerCase() !== 'websocket' ||
this.headers.connection.toLowerCase().split(', ').indexOf('upgrade') === -1) {
return false
}
key = this.headers['sec-websocket-accept']
// Check the key
sha1 = crypto.createHash('sha1')
sha1.end(this.key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
if (key !== sha1.read().toString('base64')) {
return false
}
return true
}
/**
* Process and answer a handshake started by a client
* @param {string[]} lines one for each '\r\n'-separated HTTP request line
* @returns {boolean} if the handshake was sucessful. If not, the connection must be closed with error 400-Bad Request
* @private
*/
Connection.prototype.answerHandshake = function (lines) {
var path, key, sha1
// First line
if (lines.length < 6) {
return false
}
path = lines[0].match(/^GET (.+) HTTP\/\d\.\d$/i)
if (!path) {
return false
}
this.path = path[1]
// Extract all headers
this.readHeaders(lines)
// Validate necessary headers
if (!('host' in this.headers) ||
!('sec-websocket-key' in this.headers) ||
!('upgrade' in this.headers) ||
!('connection' in this.headers)) {
return false
}
if (this.headers.upgrade.toLowerCase() !== 'websocket' ||
this.headers.connection.toLowerCase().split(', ').indexOf('upgrade') === -1) {
return false
}
if (this.headers['sec-websocket-version'] !== '13') {
return false
}
this.key = this.headers['sec-websocket-key']
// Build and send the response
sha1 = crypto.createHash('sha1')
sha1.end(this.key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
key = sha1.read().toString('base64')
this.socket.write(this.buildRequest('HTTP/1.1 101 Switching Protocols', {
Upgrade: 'websocket',
Connection: 'Upgrade',
'Sec-WebSocket-Accept': key
}))
return true
}
/**
* Try to extract frame contents from the buffer (and execute it)
* @returns {(boolean|undefined)} false=something went wrong (the connection must be closed); undefined=there isn't enough data to catch a frame; true=the frame was successfully fetched and executed
* @private
*/
Connection.prototype.extractFrame = function () {
var fin, opcode, B, HB, mask, len, payload, start, i, hasMask
if (this.buffer.length < 2) {
return
}
// Is this the last frame in a sequence?
B = this.buffer[0]
HB = B >> 4
if (HB % 8) {
// RSV1, RSV2 and RSV3 must be clear
return false
}
fin = HB === 8
opcode = B % 16
if (opcode !== 0 && opcode !== 1 && opcode !== 2 &&
opcode !== 8 && opcode !== 9 && opcode !== 10) {
// Invalid opcode
return false
}
if (opcode >= 8 && !fin) {
// Control frames must not be fragmented
return false
}
B = this.buffer[1]
hasMask = B >> 7
if ((this.server && !hasMask) || (!this.server && hasMask)) {
// Frames sent by clients must be masked
return false
}
len = B % 128
start = hasMask ? 6 : 2
if (this.buffer.length < start + len) {
// Not enough data in the buffer
return
}
// Get the actual payload length
if (len === 126) {
len = this.buffer.readUInt16BE(2)
start += 2
} else if (len === 127) {
// Warning: JS can only store up to 2^53 in its number format
len = this.buffer.readUInt32BE(2) * Math.pow(2, 32) + this.buffer.readUInt32BE(6)
start += 8
}
if (this.buffer.length < start + len) {
return
}
// Extract the payload
payload = this.buffer.slice(start, start + len)
if (hasMask) {
// Decode with the given mask
mask = this.buffer.slice(start - 4, start)
for (i = 0; i < payload.length; i++) {
payload[i] ^= mask[i % 4]
}
}
this.buffer = this.buffer.slice(start + len)
// Proceeds to frame processing
return this.processFrame(fin, opcode, payload)
}
/**
* Process a given frame received
* @param {boolean} fin
* @param {number} opcode
* @param {Buffer} payload
* @returns {boolean} false if any error occurs, true otherwise
* @fires text
* @fires binary
* @private
*/
Connection.prototype.processFrame = function (fin, opcode, payload) {
if (opcode === 8) {
// Close frame
if (this.readyState === this.CLOSING) {
this.socket.end()
} else if (this.readyState === this.OPEN) {
this.processCloseFrame(payload)
}
return true
} else if (opcode === 9) {
// Ping frame
if (this.readyState === this.OPEN) {
this.socket.write(frame.createPongFrame(payload.toString(), !this.server))
}
return true
} else if (opcode === 10) {
// Pong frame
this.emit('pong', payload.toString())
return true
}
if (this.readyState !== this.OPEN) {
// Ignores if the connection isn't opened anymore
return true
}
if (opcode === 0 && this.frameBuffer === null) {
// Unexpected continuation frame
return false
} else if (opcode !== 0 && this.frameBuffer !== null) {
// Last sequence didn't finished correctly
return false
}
if (!opcode) {
// Get the current opcode for fragmented frames
opcode = typeof this.frameBuffer === 'string' ? 1 : 2
}
if (opcode === 1) {
// Save text frame
payload = payload.toString()
this.frameBuffer = this.frameBuffer ? this.frameBuffer + payload : payload
if (fin) {
// Emits 'text' event
this.emit('text', this.frameBuffer)
this.frameBuffer = null
}
} else {
// Sends the buffer for InStream object
if (!this.frameBuffer) {
// Emits the 'binary' event
this.frameBuffer = new InStream
this.emit('binary', this.frameBuffer)
}
this.frameBuffer.addData(payload)
if (fin) {
// Emits 'end' event
this.frameBuffer.end()
this.frameBuffer = null
}
}
return true
}
/**
* Process a close frame, emitting the close event and sending back the frame
* @param {Buffer} payload
* @fires close
* @private
*/
Connection.prototype.processCloseFrame = function (payload) {
var code, reason
if (payload.length >= 2) {
code = payload.readUInt16BE(0)
reason = payload.slice(2).toString()
} else {
code = 1005
reason = ''
}
this.socket.write(frame.createCloseFrame(code, reason, !this.server))
this.readyState = this.CLOSED
this.emit('close', code, reason)
}
/**
* Build the header string
* @param {string} requestLine
* @param {Object<string>} headers
* @returns {string}
* @private
*/
Connection.prototype.buildRequest = function (requestLine, headers) {
var headerString = requestLine + '\r\n',
headerName
for (headerName in headers) {
headerString += headerName + ': ' + headers[headerName] + '\r\n'
}
return headerString + '\r\n'
}

16
node_modules/nodejs-websocket/HISTORY.md generated vendored Normal file
View File

@ -0,0 +1,16 @@
# 1.6.0
* Added: `Server#close` as a short hand for `Server#socket.close`
# 1.5.0
* Added: `Connection#send` as a short hand for `Connection#sendText` or `Connection#sendBinary`, depending on the data type (string or Buffer)
# 1.4.1
* Added: example to README
# 1.4.0
* Added: `extraHeaders` option in `ws.connect(URL, [options], [callback])` to let one add custom headers to the HTTP handshake request
# 1.3.0
* Added: `Connection#sendPing([data=''])`
* Added: `pong(data)` event

44
node_modules/nodejs-websocket/InStream.js generated vendored Normal file
View File

@ -0,0 +1,44 @@
/**
* @file Simple wrapper for stream.Readable, used for receiving binary data
*/
'use strict'
var util = require('util'),
stream = require('stream')
/**
* Represents the readable stream for binary frames
* @class
* @event readable
* @event end
*/
function InStream() {
stream.Readable.call(this)
}
module.exports = InStream
util.inherits(InStream, stream.Readable)
/**
* No logic here, the pushs are made outside _read
* @private
*/
InStream.prototype._read = function () {}
/**
* Add more data to the stream and fires "readable" event
* @param {Buffer} data
* @private
*/
InStream.prototype.addData = function (data) {
this.push(data)
}
/**
* Indicates there is no more data to add to the stream
* @private
*/
InStream.prototype.end = function () {
this.push(null)
}

21
node_modules/nodejs-websocket/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Guilherme Souza
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.

59
node_modules/nodejs-websocket/OutStream.js generated vendored Normal file
View File

@ -0,0 +1,59 @@
/**
* @file Simple wrapper for stream.Writable, used for sending binary data
*/
'use strict'
var util = require('util'),
stream = require('stream'),
frame = require('./frame')
/**
* @class Represents the writable stream for binary frames
* @param {Connection} connection
* @param {number} minSize
*/
function OutStream(connection, minSize) {
var that = this
this.connection = connection
this.minSize = minSize
this.buffer = new Buffer(0)
this.hasSent = false // Indicates if any frame has been sent yet
stream.Writable.call(this)
this.on('finish', function () {
if (that.connection.readyState === that.connection.OPEN) {
// Ignore if not connected anymore
that.connection.socket.write(frame.createBinaryFrame(that.buffer, !that.connection.server, !that.hasSent, true))
}
that.connection.outStream = null
})
}
module.exports = OutStream
util.inherits(OutStream, stream.Writable)
/**
* @param {Buffer} chunk
* @param {string} encoding
* @param {Function} callback
* @private
*/
OutStream.prototype._write = function (chunk, encoding, callback) {
var frameBuffer
this.buffer = Buffer.concat([this.buffer, chunk], this.buffer.length + chunk.length)
if (this.buffer.length >= this.minSize) {
if (this.connection.readyState === this.connection.OPEN) {
// Ignore if not connected anymore
frameBuffer = frame.createBinaryFrame(this.buffer, !this.connection.server, !this.hasSent, false)
this.connection.socket.write(frameBuffer, encoding, callback)
}
this.buffer = new Buffer(0)
this.hasSent = true
if (this.connection.readyState !== this.connection.OPEN) {
callback()
}
} else {
callback()
}
}

192
node_modules/nodejs-websocket/README.md generated vendored Normal file
View File

@ -0,0 +1,192 @@
# Nodejs Websocket
[![Build Status](https://travis-ci.org/sitegui/nodejs-websocket.svg?branch=master)](https://travis-ci.org/sitegui/nodejs-websocket)
[![Inline docs](https://inch-ci.org/github/sitegui/nodejs-websocket.svg?branch=master)](https://inch-ci.org/github/sitegui/nodejs-websocket)
[![Dependency Status](https://david-dm.org/sitegui/nodejs-websocket.svg)](https://david-dm.org/sitegui/nodejs-websocket)
A nodejs module for websocket server and client
# How to use it
Install with `npm install nodejs-websocket` or put all files in a folder called "nodejs-websocket", and:
```javascript
var ws = require("nodejs-websocket")
// Scream server example: "hi" -> "HI!!!"
var server = ws.createServer(function (conn) {
console.log("New connection")
conn.on("text", function (str) {
console.log("Received "+str)
conn.sendText(str.toUpperCase()+"!!!")
})
conn.on("close", function (code, reason) {
console.log("Connection closed")
})
}).listen(8001)
```
Se other examples inside the folder samples
# ws
The main object, returned by `require("nodejs-websocket")`.
## ws.createServer([options], [callback])
Returns a new `Server` object.
The `options` is an optional object that will be handed to net.createServer() to create an ordinary socket.
If it has a property called "secure" with value `true`, tls.createServer() will be used instead.
The `callback` is a function which is automatically added to the `"connection"` event.
## ws.connect(URL, [options], [callback])
Returns a new `Connection` object, representing a websocket client connection
`URL` is a string with the format "ws://localhost:8000/chat" (the port can be omitted)
`options` is an object that will be passed to net.connect() (or tls.connect() if the protocol is "wss:").
The properties "host" and "port" will be read from the `URL`.
The property `extraHeaders` will be used to add more headers to the HTTP handshake request.
`callback` will be added as "connect" listener
## ws.setBinaryFragmentation(bytes)
Sets the minimum size of a pack of binary data to send in a single frame (default: 512kiB)
## ws.setMaxBufferLength(bytes)
Set the maximum size the internal Buffer can grow (default: 2MiB)
If at any time it stays bigger than this, the connection will be closed with code 1009
This is a security measure, to avoid memory attacks
# Server
The class that represents a websocket server, much like a HTTP server
## server.listen(port, [host], [callback])
Starts accepting connections on a given `port` and `host`.
If the `host` is omitted, the server will accept connections directed to any IPv4 address (INADDR_ANY).
A `port` value of zero will assign a random port.
`callback` will be added as an listener for the `'listening'` event.
## server.close([callback])
Stops the server from accepting new connections and keeps existing connections. This function is asynchronous, the server is finally closed when all connections are ended and the server emits a 'close' event. The optional callback will be called once the 'close' event occurs.
## server.socket
The underlying socket, returned by net.createServer or tls.createServer
## server.connections
An Array with all connected clients. It's useful for broadcasting a message:
```javascript
function broadcast(server, msg) {
server.connections.forEach(function (conn) {
conn.sendText(msg)
})
}
```
## Event: 'listening()'
Emitted when the server has been bound after calling server.listen
## Event: 'close()'
Emitted when the server closes. Note that if connections exist, this event is not emitted until all connections are completely ended.
## Event: 'error(errObj)'
Emitted when an error occurs. The 'close' event will be called directly following this event.
## Event: 'connection(conn)'
Emitted when a new connection is made successfully (after the handshake have been completed). conn is an instance of Connection
# Connection
The class that represents a connection, either a client-created (accepted by a nodejs ws server) or client connection.
The websocket protocol has two types of data frames: text and binary.
Text frames are implemented as simple send function and receive event.
Binary frames are implemented as streams: when you receive binary data, you get a ReadableStream; to send binary data, you must ask for a WritableStream and write into it.
The binary data will be divided into frames and be sent over the socket.
You cannot send text data while sending binary data. If you try to do so, the connection will emit an "error" event
## connection.sendText(str, [callback])
Sends a given string to the other side. You can't send text data in the middle of a binary transmission.
`callback` will be added as a listener to write operation over the socket
## connection.beginBinary()
Asks the connection to begin transmitting binary data. Returns a WritableStream.
The binary transmission will end when the WritableStream finishes (like when you call .end on it)
## connection.sendBinary(data, [callback])
Sends a single chunk of binary data (like calling connection.beginBinary().end(data))
`callback` will be added as a listener to write operation over the socket
## connection.send(data, [callback])
Sends a given string or Buffer to the other side. This is simply an alias for `sendText()` if data is a string or `sendBinary()` if the data is a Buffer.
`callback` will be added as a listener to write operation over the socket
## connection.sendPing([data=''])
Sends a [ping](http://tools.ietf.org/html/rfc6455#section-5.5.2) with optional payload
## connection.close([code, [reason]])
Starts the closing handshake (sends a close frame)
## connection.socket
The underlying net or tls socket
## connection.server
If the connection was accepted by a nodejs server, a reference to it will be saved here. null otherwise
## connection.readyState
One of these constants, representing the current state of the connection. Only an open connection can be used to send/receive data.
* connection.CONNECTING (waiting for handshake completion)
* connection.OPEN
* connection.CLOSING (waiting for the answer to a close frame)
* connection.CLOSED
## connection.outStream
Stores the OutStream object returned by connection.beginBinary(). null if there is no current binary data beeing sent.
## connection.path
For a connection accepted by a server, it is a string representing the path to which the connection was made (example: "/chat"). null otherwise
## connection.headers
Read only map of header names and values. Header names are lower-cased
## Event: 'close(code, reason)'
Emitted when the connection is closed by any side
## Event: 'error(err)'
Emitted in case of error (like trying to send text data while still sending binary data)
## Event: 'text(str)'
Emitted when a text is received. `str` is a string
## Event: 'binary(inStream)'
Emitted when the beginning of binary data is received. `inStream` is a [ReadableStream](https://nodejs.org/api/stream.html#stream_class_stream_readable):
```javascript
var server = ws.createServer(function (conn) {
console.log("New connection")
conn.on("binary", function (inStream) {
// Empty buffer for collecting binary data
var data = new Buffer(0)
// Read chunks of binary data and add to the buffer
inStream.on("readable", function () {
var newData = inStream.read()
if (newData)
data = Buffer.concat([data, newData], data.length+newData.length)
})
inStream.on("end", function () {
console.log("Received " + data.length + " bytes of binary data")
process_my_data(data)
})
})
conn.on("close", function (code, reason) {
console.log("Connection closed")
})
}).listen(8001)
```
## Event: 'connect()'
Emitted when the connection is fully established (after the handshake)
## Event: 'pong(data)'
Emitted when a [pong](http://tools.ietf.org/html/rfc6455#section-5.5.3) is received, usually after a ping was sent. `data` is the pong payload, as a string

113
node_modules/nodejs-websocket/Server.js generated vendored Normal file
View File

@ -0,0 +1,113 @@
/**
* @file Represents a websocket server
*/
'use strict'
function nop() {}
var util = require('util'),
net = require('net'),
tls = require('tls'),
events = require('events'),
Connection
/**
* Creates a new ws server and starts listening for new connections
* @class
* @param {boolean} secure indicates if it should use tls
* @param {Object} [options] will be passed to net.createServer() or tls.createServer()
* @param {Function} [callback] will be added as "connection" listener
* @inherits EventEmitter
* @event listening
* @event close
* @event error an error object is passed
* @event connection a Connection object is passed
*/
function Server(secure, options, callback) {
var that = this
if (typeof options === 'function') {
callback = options
options = undefined
}
var onConnection = function (socket) {
var conn = new Connection(socket, that, function () {
that.connections.push(conn)
conn.removeListener('error', nop)
that.emit('connection', conn)
})
conn.on('close', function () {
var pos = that.connections.indexOf(conn)
if (pos !== -1) {
that.connections.splice(pos, 1)
}
})
// Ignore errors before the connection is established
conn.on('error', nop)
}
if (secure) {
this.socket = tls.createServer(options, onConnection)
} else {
this.socket = net.createServer(options, onConnection)
}
this.socket.on('close', function () {
that.emit('close')
})
this.socket.on('error', function (err) {
that.emit('error', err)
})
this.connections = []
// super constructor
events.EventEmitter.call(this)
if (callback) {
this.on('connection', callback)
}
}
util.inherits(Server, events.EventEmitter)
module.exports = Server
Connection = require('./Connection')
/**
* Start listening for connections
* @param {number} port
* @param {string} [host]
* @param {Function} [callback] will be added as "connection" listener
*/
Server.prototype.listen = function (port, host, callback) {
var that = this
if (typeof host === 'function') {
callback = host
host = undefined
}
if (callback) {
this.on('listening', callback)
}
this.socket.listen(port, host, function () {
that.emit('listening')
})
return this
}
/**
* Stops the server from accepting new connections and keeps existing connections.
* This function is asynchronous, the server is finally closed when all connections are ended and the server emits a 'close' event.
* The optional callback will be called once the 'close' event occurs.
* @param {function()} [callback]
*/
Server.prototype.close = function (callback) {
if (callback) {
this.once('close', callback)
}
this.socket.close()
}

152
node_modules/nodejs-websocket/frame.js generated vendored Normal file
View File

@ -0,0 +1,152 @@
/**
* @file Utility functions for creating frames
*/
'use strict'
/**
* Creates a text frame
* @param {string} data
* @param {boolean} [masked=false] if the frame should be masked
* @returns {Buffer}
* @private
*/
exports.createTextFrame = function (data, masked) {
var payload, meta
payload = new Buffer(data)
meta = generateMetaData(true, 1, masked === undefined ? false : masked, payload)
return Buffer.concat([meta, payload], meta.length + payload.length)
}
/**
* Create a binary frame
* @param {Buffer} data
* @param {boolean} [masked=false] if the frame should be masked
* @param {boolean} [first=true] if this is the first frame in a sequence
* @param {boolean} [fin=true] if this is the final frame in a sequence
* @returns {Buffer}
* @private
*/
exports.createBinaryFrame = function (data, masked, first, fin) {
var payload, meta
first = first === undefined ? true : first
masked = masked === undefined ? false : masked
if (masked) {
payload = new Buffer(data.length)
data.copy(payload)
} else {
payload = data
}
meta = generateMetaData(fin === undefined ? true : fin, first ? 2 : 0, masked, payload)
return Buffer.concat([meta, payload], meta.length + payload.length)
}
/**
* Create a close frame
* @param {number} code
* @param {string} [reason='']
* @param {boolean} [masked=false] if the frame should be masked
* @returns {Buffer}
* @private
*/
exports.createCloseFrame = function (code, reason, masked) {
var payload, meta
if (code !== undefined && code !== 1005) {
payload = new Buffer(reason === undefined ? '--' : '--' + reason)
payload.writeUInt16BE(code, 0)
} else {
payload = new Buffer(0)
}
meta = generateMetaData(true, 8, masked === undefined ? false : masked, payload)
return Buffer.concat([meta, payload], meta.length + payload.length)
}
/**
* Create a ping frame
* @param {string} data
* @param {boolean} [masked=false] if the frame should be masked
* @returns {Buffer}
* @private
*/
exports.createPingFrame = function (data, masked) {
var payload, meta
payload = new Buffer(data)
meta = generateMetaData(true, 9, masked === undefined ? false : masked, payload)
return Buffer.concat([meta, payload], meta.length + payload.length)
}
/**
* Create a pong frame
* @param {string} data
* @param {boolean} [masked=false] if the frame should be masked
* @returns {Buffer}
* @private
*/
exports.createPongFrame = function (data, masked) {
var payload, meta
payload = new Buffer(data)
meta = generateMetaData(true, 10, masked === undefined ? false : masked, payload)
return Buffer.concat([meta, payload], meta.length + payload.length)
}
/**
* Creates the meta-data portion of the frame
* If the frame is masked, the payload is altered accordingly
* @param {boolean} fin
* @param {number} opcode
* @param {boolean} masked
* @param {Buffer} payload
* @returns {Buffer}
* @private
*/
function generateMetaData(fin, opcode, masked, payload) {
var len, meta, start, mask, i
len = payload.length
// Creates the buffer for meta-data
meta = new Buffer(2 + (len < 126 ? 0 : (len < 65536 ? 2 : 8)) + (masked ? 4 : 0))
// Sets fin and opcode
meta[0] = (fin ? 128 : 0) + opcode
// Sets the mask and length
meta[1] = masked ? 128 : 0
start = 2
if (len < 126) {
meta[1] += len
} else if (len < 65536) {
meta[1] += 126
meta.writeUInt16BE(len, 2)
start += 2
} else {
// Warning: JS doesn't support integers greater than 2^53
meta[1] += 127
meta.writeUInt32BE(Math.floor(len / Math.pow(2, 32)), 2)
meta.writeUInt32BE(len % Math.pow(2, 32), 6)
start += 8
}
// Set the mask-key
if (masked) {
mask = new Buffer(4)
for (i = 0; i < 4; i++) {
meta[start + i] = mask[i] = Math.floor(Math.random() * 256)
}
for (i = 0; i < payload.length; i++) {
payload[i] ^= mask[i % 4]
}
start += 4
}
return meta
}

100
node_modules/nodejs-websocket/index.js generated vendored Normal file
View File

@ -0,0 +1,100 @@
'use strict'
var Server = require('./Server'),
Connection = require('./Connection'),
net = require('net'),
tls = require('tls'),
url = require('url')
/**
* Create a WebSocket server
* @param {Object} [options] will be passed to net.createServer() or tls.createServer(), with the additional property 'secure' (a boolean)
* @param {Function} callback will be added as 'connection' listener
* @returns {Server}
*/
exports.createServer = function (options, callback) {
if (typeof options === 'function' || !arguments.length) {
return new Server(false, options)
}
return new Server(Boolean(options.secure), options, callback)
}
/**
* Create a WebSocket client
* @param {string} URL with the format 'ws://localhost:8000/chat' (the port can be ommited)
* @param {Object} [options] will be passed to net.connect() or tls.connect()
* @param {Function} callback will be added as 'connect' listener
* @returns {Connection}
*/
exports.connect = function (URL, options, callback) {
var socket
if (typeof options === 'function') {
callback = options
options = undefined
}
options = options || {}
URL = parseWSURL(URL)
options.port = URL.port
options.host = URL.host
if (options.hasOwnProperty('extraHeaders')) {
URL.extraHeaders = options.extraHeaders
}
if (URL.secure) {
socket = tls.connect(options)
} else {
socket = net.connect(options)
}
return new Connection(socket, URL, callback)
}
/**
* Set the minimum size of a pack of binary data to send in a single frame
* @param {number} bytes
*/
exports.setBinaryFragmentation = function (bytes) {
Connection.binaryFragmentation = bytes
}
/**
* Set the maximum size the internal Buffer can grow, to avoid memory attacks
* @param {number} bytes
*/
exports.setMaxBufferLength = function (bytes) {
Connection.maxBufferLength = bytes
}
/**
* Parse the WebSocket URL
* @param {string} URL
* @returns {Object}
* @private
*/
function parseWSURL(URL) {
var parts, secure
parts = url.parse(URL)
parts.protocol = parts.protocol || 'ws:'
if (parts.protocol === 'ws:') {
secure = false
} else if (parts.protocol === 'wss:') {
secure = true
} else {
throw new Error('Invalid protocol ' + parts.protocol + '. It must be ws or wss')
}
parts.port = parts.port || (secure ? 443 : 80)
parts.path = parts.path || '/'
return {
path: parts.path,
port: parts.port,
secure: secure,
host: parts.hostname
}
}

60
node_modules/nodejs-websocket/package.json generated vendored Normal file
View File

@ -0,0 +1,60 @@
{
"name": "nodejs-websocket",
"version": "1.6.0",
"author": {
"name": "Sitegui",
"email": "sitegui@sitegui.com.br"
},
"description": "Basic server&client approach to websocket (text and binary frames)",
"main": "./index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/sitegui/nodejs-websocket.git"
},
"keywords": [
"websocket",
"websocket-server",
"websocket-client"
],
"license": "MIT",
"engines": {
"node": ">=0.10"
},
"scripts": {
"test": "mocha -R spec -b"
},
"devDependencies": {
"mocha": "^2.4.5",
"should": "^8.3.1"
},
"gitHead": "7398f57a6054724418ccaa0829daddc5ff62c908",
"bugs": {
"url": "https://github.com/sitegui/nodejs-websocket/issues"
},
"homepage": "https://github.com/sitegui/nodejs-websocket#readme",
"_id": "nodejs-websocket@1.6.0",
"_shasum": "e6db8d2e5af9e730bf70818bfd189783fe02797a",
"_from": "nodejs-websocket@*",
"_npmVersion": "2.14.20",
"_nodeVersion": "4.4.0",
"_npmUser": {
"name": "sitegui",
"email": "sitegui@sitegui.com.br"
},
"dist": {
"shasum": "e6db8d2e5af9e730bf70818bfd189783fe02797a",
"tarball": "https://registry.npmjs.org/nodejs-websocket/-/nodejs-websocket-1.6.0.tgz"
},
"maintainers": [
{
"name": "sitegui",
"email": "sitegui@sitegui.com.br"
}
],
"_npmOperationalInternal": {
"host": "packages-16-east.internal.npmjs.com",
"tmp": "tmp/nodejs-websocket-1.6.0.tgz_1462798103164_0.4242532418575138"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/nodejs-websocket/-/nodejs-websocket-1.6.0.tgz"
}

View File

@ -1,6 +1,6 @@
{ {
"name": "TF-HoBu", "name": "TF-HoBu",
"version": "0.0.1", "version": "0.0.2",
"description": "", "description": "",
"private": true, "private": true,
"repository": "ssh://git@stash.adawim.com:7999/tf/nodejs.git", "repository": "ssh://git@stash.adawim.com:7999/tf/nodejs.git",
@ -9,6 +9,7 @@
"errorhandler": "*", "errorhandler": "*",
"urlencode": "*", "urlencode": "*",
"dateformat": "*", "dateformat": "*",
"byline": "*" "byline": "*",
"nodejs-websocket": "*"
} }
} }