yichael há 4 anos atrás
commit
9e430d87ff

+ 22 - 0
node_modules/nodejs-websocket/.jshintrc

@@ -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
+}

+ 7 - 0
node_modules/nodejs-websocket/.travis.yml

@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+  - "4"
+  - "6"
+  - "8"
+  - "10"
+  - "node"

+ 679 - 0
node_modules/nodejs-websocket/Connection.js

@@ -0,0 +1,679 @@
+/**
+ * @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')
+
+/**
+ * @typedef {Object} Connection~Options
+ * @param {string} path
+ * @param {string} host
+ * @param {?Object<string>} extraHeaders
+ * @param {?Array<string>} protocols
+ */
+
+/**
+ * @class
+ * @param {(net.Socket|tls.CleartextStream)} socket a net or tls socket
+ * @param {(Server|Connection~Options)} parentOrOptions parent in case of server-side connection,  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, parentOrOptions, callback) {
+	var that = this,
+		connectEvent
+
+	if (parentOrOptions instanceof Server) {
+		// Server-side connection
+		this.server = parentOrOptions
+		this.path = null
+		this.host = null
+		this.extraHeaders = null
+		this.protocols = []
+	} else {
+		// Client-side
+		this.server = null
+		this.path = parentOrOptions.path
+		this.host = parentOrOptions.host
+		this.extraHeaders = parentOrOptions.extraHeaders
+		this.protocols = parentOrOptions.protocols || []
+	}
+
+	this.protocol = undefined
+	this.socket = socket
+	this.readyState = this.CONNECTING
+	this.buffer = Buffer.alloc(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'))
+	} else {
+		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'))
+	} else {
+		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'))
+	} else {
+		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) {
+		this.socket.write(frame.createPingFrame(data || '', !this.server))
+	} else {
+		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 = Buffer.alloc(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'
+	}
+
+	if (this.protocols && this.protocols.length) {
+		headers['Sec-WebSocket-Protocol'] = this.protocols.join(', ')
+	}
+
+	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
+		if (this.server) {
+			this.socket.end('HTTP/1.1 400 Bad Request\r\n\r\n')
+		} else {
+			this.socket.end()
+			this.emit('error', new Error('Handshake is too big'))
+		}
+		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, protocol
+
+	// First line
+	if (lines.length < 4) {
+		this.emit('error', new Error('Invalid handshake: too short'))
+		return false
+	}
+	if (!lines[0].match(/^HTTP\/\d\.\d 101( .*)?$/i)) {
+		this.emit('error', new Error('Invalid handshake: invalid first line format'))
+		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)) {
+		this.emit('error', new Error('Invalid handshake: missing required headers'))
+		return false
+	}
+	if (this.headers.upgrade.toLowerCase() !== 'websocket' ||
+		this.headers.connection.toLowerCase().split(/\s*,\s*/).indexOf('upgrade') === -1) {
+		this.emit('error', new Error('Invalid handshake: invalid Upgrade or Connection header'))
+		return false
+	}
+	key = this.headers['sec-websocket-accept']
+
+	// Check protocol negotiation
+	protocol = this.headers['sec-websocket-protocol']
+	if (this.protocols && this.protocols.length) {
+		// The server must choose one from our list
+		if (!protocol || this.protocols.indexOf(protocol) === -1) {
+			this.emit('error', new Error('Invalid handshake: no protocol was negotiated'))
+			return false
+		}
+	} else {
+		// The server must not choose a protocol
+		if (protocol) {
+			this.emit('error', new Error('Invalid handshake: no protocol negotiation was expected'))
+			return false
+		}
+	}
+	this.protocol = protocol
+
+	// Check the key
+	sha1 = crypto.createHash('sha1')
+	sha1.end(this.key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
+	if (key !== sha1.read().toString('base64')) {
+		this.emit('error', new Error('Invalid handshake: hash mismatch'))
+		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, headers
+
+	// 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(/\s*,\s*/).indexOf('upgrade') === -1) {
+		return false
+	}
+	if (this.headers['sec-websocket-version'] !== '13') {
+		return false
+	}
+
+	this.key = this.headers['sec-websocket-key']
+
+	// Agree on a protocol
+	if ('sec-websocket-protocol' in this.headers) {
+		// Parse
+		this.protocols = this.headers['sec-websocket-protocol'].split(',').map(function (each) {
+			return each.trim()
+		})
+
+		// Select protocol
+		if (this.server._selectProtocol) {
+			this.protocol = this.server._selectProtocol(this, this.protocols)
+		}
+	}
+
+	// Build and send the response
+	sha1 = crypto.createHash('sha1')
+	sha1.end(this.key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
+	key = sha1.read().toString('base64')
+	headers = {
+		Upgrade: 'websocket',
+		Connection: 'Upgrade',
+		'Sec-WebSocket-Accept': key
+	}
+	if (this.protocol) {
+		headers['Sec-WebSocket-Protocol'] = this.protocol
+	}
+	this.socket.write(this.buildRequest('HTTP/1.1 101 Switching Protocols', headers))
+	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'
+}

+ 31 - 0
node_modules/nodejs-websocket/HISTORY.md

@@ -0,0 +1,31 @@
+# 1.7.2
+* Fixed: parsing error when `Connection` header uses ',' instead of ', ' (with space) [#46](https://github.com/sitegui/nodejs-websocket/pull/46)
+* Fixed: uses Buffer.alloc and Buffer.from instead of new Buffer
+* Changed: Drop support for Node v0.12
+
+# 1.7.1
+* Fixed: two errors were emitted when trying to sendText to a closed connection while there was another pending binary write operation.
+
+# 1.7.0
+* Added: emit `Connection#error` event on invalid handshake response with the reason why it was rejected
+* Added: support for protocol negotiation
+* Added: `validProtocols` and `selectProtocol` options to `ws.createServer()`
+* Added: `protocols` option to `ws.connect`
+* Added: `Connection#protocols` and `Connection#protocol`
+
+# 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 - 0
node_modules/nodejs-websocket/InStream.js

@@ -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 - 0
node_modules/nodejs-websocket/LICENSE

@@ -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 - 0
node_modules/nodejs-websocket/OutStream.js

@@ -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 = Buffer.alloc(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 = Buffer.alloc(0)
+		this.hasSent = true
+		if (this.connection.readyState !== this.connection.OPEN) {
+			callback()
+		}
+	} else {
+		callback()
+	}
+}

+ 208 - 0
node_modules/nodejs-websocket/README.md

@@ -0,0 +1,208 @@
+# 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.
+
+To support protocols, the `options` object may have either of these properties:
+* `validProtocols`: an array of protocol names the server accepts. The server will pick the most preferred protocol in the client's list.
+* `selectProtocol`: a callback to resolve the protocol negotiation. This callback will be passed two parameters: the connection handling the handshake and the array of protocol names informed by the client, ordered by preference. It should return the resolved protocol, or empty if there is no agreement.
+
+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 optional property `extraHeaders` will be used to add more headers to the HTTP handshake request. If present, it must be an object, like `{'X-My-Header': 'value'}`.
+The optional property `protocols` will be used in the handshake (as "Sec-WebSocket-Protocol" header) to allow the server to choose one of those values. If present, it must be an array of strings.
+
+`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
+
+## connection.protocols
+Array of protocols requested by the client. If no protocols were requested, it will be an empty array.
+
+Additional resources on websocket subprotocols:
+* [WebSocket Subprotocol Name Registry](http://www.iana.org/assignments/websocket/websocket.xml#subprotocol-name)
+* [The WebSocket Protocol](https://tools.ietf.org/html/rfc6455#section-11.3.4)
+
+## connection.protocol
+The protocol agreed for this connection, if any. It will be an element of `connection.protocols`.
+
+## 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).
+In case of an invalid handshake response will also be emited.
+
+## 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 = Buffer.alloc(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

+ 158 - 0
node_modules/nodejs-websocket/Server.js

@@ -0,0 +1,158 @@
+/**
+ * @file Represents a websocket server
+ */
+'use strict'
+
+function nop() {}
+
+var util = require('util'),
+	net = require('net'),
+	tls = require('tls'),
+	events = require('events'),
+	Connection
+
+/**
+ * @callback SelectProtocolCallback
+ * @param {Connection} connection
+ * @param {Array<string>} protocols
+ * @returns {?string}
+ */
+
+/**
+ * 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 {Array<string>} [options.validProtocols]
+ * @param {SelectProtocolCallback} [options.selectProtocol]
+ * @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)
+	}
+
+	// Add protocol agreement handling
+	/**
+	 * @member {?SelectProtocolCallback}
+	 * @private
+	 */
+	this._selectProtocol = null
+
+	if (options && options.selectProtocol) {
+		// User-provided logic
+		this._selectProtocol = options.selectProtocol
+	} else if (options && options.validProtocols) {
+		// Default logic
+		this._selectProtocol = this._buildSelectProtocol(options.validProtocols)
+	}
+}
+
+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()
+}
+
+/**
+ * Create a resolver to pick the client's most preferred protocol the server recognises
+ * @param {Array<string>} validProtocols
+ * @returns {SelectProtocolCallback}
+ * @private
+ */
+Server.prototype._buildSelectProtocol = function (validProtocols) {
+	return function (conn, protocols) {
+		var i
+
+		for (i = 0; i < protocols.length; i++) {
+			if (validProtocols.indexOf(protocols[i]) !== -1) {
+				// A valid protocol was found
+				return protocols[i]
+			}
+		}
+
+		// No agreement
+	}
+}

+ 152 - 0
node_modules/nodejs-websocket/frame.js

@@ -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 = Buffer.from(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 = Buffer.alloc(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 = Buffer.from(reason === undefined ? '--' : '--' + reason)
+		payload.writeUInt16BE(code, 0)
+	} else {
+		payload = Buffer.alloc(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 = Buffer.from(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 = Buffer.from(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 = Buffer.alloc(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 = Buffer.alloc(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
+}

+ 99 - 0
node_modules/nodejs-websocket/index.js

@@ -0,0 +1,99 @@
+'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 || {}
+
+	var connectionOptions = parseWSURL(URL)
+	options.port = connectionOptions.port
+	options.host = connectionOptions.host
+
+	connectionOptions.extraHeaders = options.extraHeaders
+	connectionOptions.protocols = options.protocols
+
+	if (connectionOptions.secure) {
+		socket = tls.connect(options)
+	} else {
+		socket = net.connect(options)
+	}
+
+	return new Connection(socket, connectionOptions, 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
+	}
+}

+ 61 - 0
node_modules/nodejs-websocket/package.json

@@ -0,0 +1,61 @@
+{
+  "_from": "nodejs-websocket",
+  "_id": "nodejs-websocket@1.7.2",
+  "_inBundle": false,
+  "_integrity": "sha512-PFX6ypJcCNDs7obRellR0DGTebfUhw1SXGKe2zpB+Ng1DQJhdzbzx1ob+AvJCLzy2TJF4r8cCDqMQqei1CZdPQ==",
+  "_location": "/nodejs-websocket",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "tag",
+    "registry": true,
+    "raw": "nodejs-websocket",
+    "name": "nodejs-websocket",
+    "escapedName": "nodejs-websocket",
+    "rawSpec": "",
+    "saveSpec": null,
+    "fetchSpec": "latest"
+  },
+  "_requiredBy": [
+    "#USER",
+    "/"
+  ],
+  "_resolved": "https://registry.npmjs.org/nodejs-websocket/-/nodejs-websocket-1.7.2.tgz",
+  "_shasum": "94abd1e248f57d4d1c663dec3831015c6dad98a6",
+  "_spec": "nodejs-websocket",
+  "_where": "C:\\Projects\\NodeJs\\Socket",
+  "author": {
+    "name": "Sitegui",
+    "email": "sitegui@sitegui.com.br"
+  },
+  "bugs": {
+    "url": "https://github.com/sitegui/nodejs-websocket/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Basic server&client approach to websocket (text and binary frames)",
+  "devDependencies": {
+    "mocha": "^5.2.0",
+    "should": "^13.2.3"
+  },
+  "engines": {
+    "node": ">=4"
+  },
+  "homepage": "https://github.com/sitegui/nodejs-websocket#readme",
+  "keywords": [
+    "websocket",
+    "websocket-server",
+    "websocket-client"
+  ],
+  "license": "MIT",
+  "main": "./index.js",
+  "name": "nodejs-websocket",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sitegui/nodejs-websocket.git"
+  },
+  "scripts": {
+    "start": "node server.js",
+    "test": "mocha -R spec -b"
+  },
+  "version": "1.7.2"
+}

+ 11 - 0
package-lock.json

@@ -0,0 +1,11 @@
+{
+  "requires": true,
+  "lockfileVersion": 1,
+  "dependencies": {
+    "nodejs-websocket": {
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/nodejs-websocket/-/nodejs-websocket-1.7.2.tgz",
+      "integrity": "sha512-PFX6ypJcCNDs7obRellR0DGTebfUhw1SXGKe2zpB+Ng1DQJhdzbzx1ob+AvJCLzy2TJF4r8cCDqMQqei1CZdPQ=="
+    }
+  }
+}

+ 84 - 0
server-socket.js

@@ -0,0 +1,84 @@
+//用户信息
+let guest_info = function () {
+    this.connect = null;
+    this.name = '';
+}
+//所有用户,必须用全局global安装,这样保证每一个线程都能访问到相同的全局数组
+global.guest_arr = [];
+
+
+var ws = require("nodejs-websocket");
+// 创建服务器
+var server = ws.createServer(function (connect) 
+{
+    // 监听客户端回调信息
+    connect.on("text", function (data) {
+
+        let data_json = JSON.parse(data);
+
+        //用户登录
+        if (data_json.type === 'login') {
+            let bUserExist = false;
+
+            for (let i = 0; i < global.guest_arr.length; i++) {
+                let guest = global.guest_arr[i];
+                if (guest.name === data_json.name) {
+                    bUserExist = true;
+                    global.guest_arr[i].connect = connect;
+                }
+            }
+            //如果新用户就注册
+            if (!bUserExist) {
+                let guest = new guest_info();
+                guest.connect = connect;
+                guest.name = data_json.name;
+                global.guest_arr.push(guest);
+            }
+            console.log(data_json.name+'进入聊天室')
+        }
+        //只需要服务器接收消息不需要发送给其他用户
+        else if (data_json.type === 'server') {
+
+        }
+        //发送消息给指定名字的用户
+        else if (data_json.type === 'user') {
+            console.log('收到'+data_json.name+'的消息')
+
+            let guest = null;
+            // 判断用户是否存在
+            for (let i = 0; i < global.guest_arr.length; i++) {
+                let name = global.guest_arr[i].name;
+                if (name === data_json.user_name) {
+                    guest = global.guest_arr[i];
+                    console.log('存在用户')
+                }
+            }
+            // 用户存在发送消息
+            if (guest) {
+                guest.connect.sendText('{"name":"'+ data_json.name +'","message":"'+data_json.message+'"}');
+                console.log(data_json.name+'发送信息给'+guest.name)
+                console.log(data_json.message)
+            }
+
+        }
+        //发送消息给所有用户
+        else if (data_json.type === 'all') {
+
+            for (let i = 0; i < global.guest_arr.length; i++) {
+                let guest = global.guest_arr[i];
+                guest.connect.sendText('{"name":"'+ data_json.name +'","message":"'+data_json.message+'"}');
+            }
+
+        }
+    })
+    connect.on("close", function (code, reason) {
+        // console.log(code.name+'退出聊天室')
+        console.log("关闭连接")
+    });
+    connect.on("error", function (code, reason) {
+        // console.log(code.name+'异常退出聊天室')
+        console.log("异常关闭")
+    });
+}).listen(3000)
+console.log("WebSocket建立完毕")
+