Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Preparing for node-websocket-protocol / v2.0.00.

DO NOT USE, WAIT FOR v2.0.00, THE SERVER WILL NOT RUN 
WITH THIS CODE AT PRESENT.

Changes:
    - added dependency on "websocket-protocol"
    - added node_modules to .gitignore
    - removed old files that weren't really needed / in use.
    - renamed internal variables in lib/ws/server.js
    - added exports for Connection and Manager to lib/ws/server.js
    - removed old protocol code in lib/ws/connection.js
    - changed internal code for Connections (refactor)
    - changed API for the Connection "message" event, see note#1

Notes:
    1. The API for the Connection "message" event is now:
            connection.on("message", function(type, data) {
              // ...
            });
       
       This change is in order to support the receiving of Binary 
       WebSocket frames. The 'type' argument indicates whether the
       message is a UTF8 string or whether the message is a binary
       message. This in turn changes the data type of the 'data'
       argument between being a String or a Buffer.
  • Loading branch information...
commit 82217958b8b46728aa1fe99ef51ada4006a1d6ad 1 parent 29ba5f0
@miksago authored
View
1  .gitignore
@@ -1 +1,2 @@
*.pyc
+node_modules
View
4 lib/_events.js
@@ -1,5 +1,5 @@
-var util = require('./_util'),
- events = require('events');
+var util = require(process.binding('natives').util ? 'util' : 'sys');
+var events = require('events');
EventEmitter = exports.EventEmitter = function() {
events.EventEmitter.call(this);
View
1  lib/_util.js
@@ -1 +0,0 @@
-module.exports = require(process.binding('natives').util ? 'util' : 'sys');
View
601 lib/ws/connection.js
@@ -1,22 +1,34 @@
/*-----------------------------------------------
Requirements:
-----------------------------------------------*/
-var debug = function() {};
-
-var util = require('../_util'),
- events = require('events'),
- Url = require('url'),
- Buffer = require('buffer').Buffer,
- Crypto = require('crypto'),
- Constants = require('constants');
+var util = require(process.binding('natives').util ? 'util' : 'sys');
+var events = require('events');
+var Constants = require('constants');
+var WebSocketProtocol = require('websocket-protocol');
var _events = require('../_events');
var Mixin = require('../lang/mixin');
-var CLOSE_FRAME = new Buffer(2);
-CLOSE_FRAME[0] = 0xFF;
-CLOSE_FRAME[1] = 0x00;
+/*-----------------------------------------------
+ Constants:
+-----------------------------------------------*/
+var TEXT_TYPE = 'text';
+var BINARY_TYPE = 'binary';
+
+
+/*-----------------------------------------------
+ Various utility style functions:
+-----------------------------------------------*/
+var debug = function() {
+ // no-op, unless server.options.debug === true;
+};
+
+var close = function(connection) {
+ connection.socket.end();
+ connection.socket.destroy();
+}
+
/*-----------------------------------------------
The Connection:
@@ -24,244 +36,84 @@ CLOSE_FRAME[1] = 0x00;
module.exports = Connection;
// Our connection instance:
-function Connection(manager, options, req, socket, upgradeHead) {
- var _firstFrame, connection = this;
-
+function Connection(server, req, upgradeHead) {
_events.EventEmitter.call(this);
- this._req = req;
- this._socket = socket;
- this._manager = manager;
- this.id = manager.createId(socket.remotePort);
+ var connection = this;
+ var manager = this._manager = server.manager;
+ var options = this._options = server.options;
- this._options = Mixin({
- version: 'auto', // String: Value must be either: draft75, draft76, auto
- origin: '*', // String,Array: Valid connection origins.
- subprotocol: '*', // String,Array: Valid connection subprotocols.
- debug: true
- }, options);
- if (connection._options.debug) {
+ if (options.debug) {
debug = function() {
util.error(
'\033[90mWS: ' +
Array.prototype.join.call(arguments, ' ') +
'\033[39m'
);
+
process.stdout.flush();
};
}
- Object.defineProperties(this, {
- version: {
- get: function() {
- if (req.headers['sec-websocket-key1'] &&
- req.headers['sec-websocket-key2']) {
- return 'draft76';
- }
- return 'draft75';
- }
+
+ this.id = manager.createId(req.socket.remotePort);
+
+ this.req = req;
+ this.socket = req.socket;
+
+ this.protocol = WebSocketProtocol.getProtocol(this._req, upgradeHead);
+
+ if (this.protocol === 'unknown') {
+ manager.emit('invalid_connection', connection);
+
+ if (options.close_invalid === true) {
+ close(connection);
}
- });
+ }
// Close timeout, for browsers that don't send the close packet.
- connection._closeTimer = undefined;
+ this._closeTimer = undefined;
+ this._closeFrameSent = false;
+
- // Set the initial connecting state.
- connection.state(1);
// Setup the connection manager's state change listeners:
connection.on('stateChange', function(state, laststate) {
- if (connection._options.debug) {
+ if (options.debug) {
debug(connection.id, 'stateChange: ', laststate, '->', state);
}
if (state === 4) {
manager.attach(connection);
- // Handle first frame breakages.
- if (_firstFrame) {
- parser.write(_firstFrame);
- delete _firstFrame;
- }
- } else if (state === 5 && laststate !== 6 && laststate !== 5) {
- close(connection);
- } else if (state === 6 && laststate === 5) {
+ connection.startProtocol();
+ } else if (state === 5) {
+ connection.close();
+ } else if (state === 6) {
manager.detach(connection);
connection.emit('close');
}
});
+ // Bubble errors up to the manager.
+ connection.bubbleEvent('error', manager);
- // Start to process the connection
- if (!checkVersion(this)) {
- this.reject('Invalid version.');
- } else {
- // Let the debug mode know that we have a connection:
- debug(this.id, this.version + ' connection');
-
- socket.setTimeout(0);
- socket.setNoDelay(true);
- socket.setKeepAlive(true, 0);
-
- // Handle incoming data:
- var parser = new Parser(this);
-
- parser.on('message', function(message) {
- debug(connection.id, 'recv: ' + message);
- connection.emit('message', message);
- });
-
- parser.on('close', function() {
- debug(connection.id, 'requested close');
-
- // Timer to catch clients that don't send close packets.
- // I'm looking at you safari and chrome.
- if (connection._closeTimer) {
- clearTimeout(connection._closeTimer);
- }
- connection.state(5);
- });
-
- socket.on('data', function(data) {
- parser.write(data);
- });
-
- // Handle the end of the stream, and set the state
- // appropriately to notify the correct events.
- socket.on('end', function() {
- debug(connection.id, 'end');
- connection.state(5);
- });
-
- socket.on('timeout', function() {
- debug(connection.id, 'timed out');
- connection.emit('timeout');
- });
-
- socket.on('error', function(e) {
- debug(connection.id, 'error', e);
- if (e.errno != Constants.EPIPE ||
- e.errno != connection.ECONNRESET) {
- connection.emit('error', e);
- }
- connection.state(5);
- });
-
- // Bubble errors up to the manager.
- connection.bubbleEvent('error', manager);
-
- // Carry out the handshaking.
- // - Draft75: There's no upgradeHead, goto Then.
- // Draft76: If there's an upgradeHead of the right length, goto Then.
- // Then: carry out the handshake.
- //
- // - Currently no browsers to my knowledge split the upgradeHead off
- // the request,
- // but in the case it does happen, then the state is set to waiting for
- // the upgradeHead.
- //
- // This switch is sorted in order of probably of occurence.
- switch (this.version) {
- case 'draft76':
- if (upgradeHead.length >= 8) {
- if (upgradeHead.length > 8) {
- _firstFrame = upgradeHead.slice(8, upgradeHead.length);
- }
-
- handshakes.draft76(connection, upgradeHead.slice(0, 8));
- } else {
- connection.reject('Missing key3');
- }
- break;
- case 'draft75':
- handshakes.draft75(connection);
- break;
- default:
- connection.reject('Unknown version: ' + this.version);
- break;
- }
- }
+ // Set the initial connecting state.
+ connection.state(1);
+ connection.handshake(upgradeHead);
}
util.inherits(Connection, _events.EventEmitter);
-/*-----------------------------------------------
- Various utility style functions:
------------------------------------------------*/
-function write(connection, data) {
- debug(connection.id, 'write: ', data.inspect());
- if (connection._socket.writable) {
- return connection._socket.write(data);
- }
- return false;
-}
-
-function close(connection) {
- connection._socket.end();
- connection._socket.destroy();
- debug(connection.id, 'socket closed');
- connection.state(6);
-}
-
-function checkVersion(connection) {
- var server_version = connection._options.version.toLowerCase();
-
- return (server_version == 'auto' || server_version == connection.version);
-}
-
-function pack(num) {
- var result = '';
- result += String.fromCharCode(num >> 24 & 0xFF);
- result += String.fromCharCode(num >> 16 & 0xFF);
- result += String.fromCharCode(num >> 8 & 0xFF);
- result += String.fromCharCode(num & 0xFF);
- return result;
-}
-
-
-/*-----------------------------------------------
- Formatters for the urls
------------------------------------------------*/
-
-// TODO: Properly handle origin headers.
-function websocket_origin(connection) {
- var origin = connection._options.origin || '*';
-
- if (origin == '*' || Array.isArray(origin)) {
- origin = connection._req.headers.origin;
- }
-
- return origin;
-}
-
-function websocket_location(connection) {
- if (connection._req.headers['host'] === undefined) {
- connection.reject('Missing host header');
- return;
- }
-
- var location = '',
- secure = connection._socket.secure,
- host = connection._req.headers.host.split(':'),
- port = host[1] !== undefined ? host[1] : (secure ? 443 : 80);
-
- location += secure ? 'wss://' : 'ws://';
- location += host[0];
-
- if (!secure && port != 80 || secure && port != 443) {
- location += ':' + port;
- }
-
- location += connection._req.url;
-
- return location;
-}
+Connection.prototype.inspect = function() {
+ return '<WS:Connection ' + this.id + '>';
+};
/*-----------------------------------------------
0. unknown
1. opening
- 2. waiting
+ 2. waiting deprecated
3. handshaking
4, connected
5. closing
@@ -281,243 +133,168 @@ Connection.prototype.state = function(state) {
}
};
-Connection.prototype.inspect = function() {
- return '<WS:Connection ' + this.id + '>';
-};
-Connection.prototype.write = function(data) {
- if (this._state === 4) {
- var byteLen = Buffer.byteLength(data, 'utf8'),
- bytes = new Buffer(byteLen + 2);
-
- bytes[0] = 0x00;
- bytes.write(data, 1, 'utf8');
- bytes[byteLen + 1] = 0xFF;
- return write(this, bytes);
- } else {
- debug(this.id, '\033[31mCould not send.');
- }
- return false;
-};
+Connection.prototype.startProtocol = function() {
+ var incoming = this.protocol.incoming;
+ var outgoing = this.protocol.outgoing;
+ var socket = this.socket;
-Connection.prototype.send = Connection.prototype.write;
+ /*-----------------------------------------------
+ Socket Setup:
+ -----------------------------------------------*/
+ socket.setTimeout(0);
+ socket.setNoDelay(true);
+ socket.setKeepAlive(true, 0);
-Connection.prototype.broadcast = function(data) {
- this._manager.forEach(function(client) {
- if (client && client._state === 4 && client.id != this.id) {
- client.write(data);
- }
- }, this);
-};
+ // Handle the end of the stream, and set the state
+ // appropriately to notify the correct events.
+ socket.on('end', function() {
+ debug(connection.id, 'end');
+ close(connection);
+ });
-Connection.prototype.close = function() {
- var connection = this;
+ socket.on('close', function() {
+ debug(connection.id, 'socket closed');
+ connection.state(6);
+ });
- if (connection._state == 4 && connection._socket.writable) {
- write(connection, CLOSE_FRAME);
- }
+ socket.on('timeout', function() {
+ debug(connection.id, 'timed out');
+ connection.emit('timeout');
+ });
- // Add a two second timeout for closing connections.
- connection._closeTimer = setTimeout(function() {
+ socket.on('error', function(e) {
+ debug(connection.id, 'error', e);
+ if (e.errno != Constants.EPIPE ||
+ e.errno != connection.ECONNRESET) {
+ connection.emit('error', e);
+ }
connection.state(5);
- }, 15 * 1000);
-};
-
-Connection.prototype.reject = function(reason) {
- debug(this.id, 'rejected. Reason: ' + reason);
- this.state(5);
-};
-
-Connection.prototype.handshake = function() {
- if (this._state < 3) {
- debug(this.id, this.version + ' handshake');
-
- this.state(3);
-
- doHandshake[this.version].call(this);
- } else {
- debug(this.id, 'Already handshaked.');
- }
-};
-
-/*-----------------------------------------------
- Do the handshake.
------------------------------------------------*/
-var handshakes = {
- // Using draft75, work out and send the handshake.
- draft75: function(connection) {
- connection.state(3);
-
- var location = websocket_location(connection), res;
-
- if (location) {
- res = 'HTTP/1.1 101 Web Socket Protocol Handshake\r\n' +
- 'Upgrade: WebSocket\r\n' +
- 'Connection: Upgrade\r\n' +
- 'WebSocket-Origin: ' + websocket_origin(connection) + '\r\n' +
- 'WebSocket-Location: ' + location;
-
- if (connection._options.subprotocol &&
- typeof connection._options.subprotocol == 'string') {
- res += '\r\nWebSocket-Protocol: ' + connection._options.subprotocol;
- }
-
- connection._socket.write(res + '\r\n\r\n', 'ascii');
+ });
- connection.state(4);
+ // pipe data from our network socket to the incoming data parser:
+ socket.pipe(incoming);
+
+ // pipe data from the encoder to the network socket:
+ outgoing.pipe(socket);
+
+
+ /*-----------------------------------------------
+ Incoming data parser events:
+ -------------------------------------------------
+ - emits:
+ - text(bool:continues, string:data)
+ - binary(bool:continues, buffer:data)
+ - control(bool:continues, opcode, frame)
+ - extension(bool:continues, opcode, frame)
+ - close
+ - ping
+ - pong
+ -----------------------------------------------*/
+ incoming.on('text', function(continues, data) {
+ debug(connection.id, 'received TEXT: ' + data, 'continues='+continues);
+ if (!continues) {
+ connection.emit('message', TEXT_TYPE, data);
}
- },
+ });
- // Using draft76 (security model), work out and send the handshake.
- draft76: function(connection, upgradeHead) {
- connection.state(3);
+ incoming.on('binary', function(continues, data) {
+ debug(connection.id, 'received BINARY: length=' + Buffer.byteLength(data), 'continues='+continues);
+ if (!continues) {
+ connection.emit('message', BINARY_TYPE, data);
+ }
+ });
- var location = websocket_location(connection), res;
+ incoming.on('ping', function() {
+ debug(connection.id, 'received PING (sent PONG)');
+ outgoing.pong();
+ });
- if (location) {
- res = 'HTTP/1.1 101 WebSocket Protocol Handshake\r\n' +
- 'Upgrade: WebSocket\r\n' +
- 'Connection: Upgrade\r\n' +
- 'Sec-WebSocket-Origin: ' + websocket_origin(connection) + '\r\n' +
- 'Sec-WebSocket-Location: ' + location;
+ incoming.on('pong', function() {
+ debug(connection.id, 'received PONG');
+ // TODO: handle a pong response when the
+ // server initiated the PING.
+ });
- if (connection._options.subprotocol &&
- typeof connection._options.subprotocol == 'string') {
- res += '\r\nSec-WebSocket-Protocol: ' + connection._options.subprotocol;
- }
+ incoming.on('close', function() {
+ debug(connection.id, 'requested close');
- var strkey1 = connection._req.headers['sec-websocket-key1'],
- strkey2 = connection._req.headers['sec-websocket-key2'],
- numkey1 = parseInt(strkey1.replace(/[^\d]/g, ''), 10),
- numkey2 = parseInt(strkey2.replace(/[^\d]/g, ''), 10),
- spaces1 = strkey1.replace(/[^\ ]/g, '').length,
- spaces2 = strkey2.replace(/[^\ ]/g, '').length;
+ // TODO: Add hard/soft close?
+ connection.close();
+ });
- if (spaces1 == 0 || spaces2 == 0 ||
- numkey1 % spaces1 != 0 || numkey2 % spaces2 != 0) {
- connection.reject('WebSocket Handshake contained an invalid key');
- } else {
- var hash = Crypto.createHash('md5'),
- key1 = pack(parseInt(numkey1 / spaces1)),
- key2 = pack(parseInt(numkey2 / spaces2));
+ /*-----------------------------------------------
+ Outgoing from the encoder to the socket:
+ -----------------------------------------------*/
+ outgoing.on('error', function(err) {
+ debug(err);
+ });
+};
- hash.update(key1);
- hash.update(key2);
- hash.update(upgradeHead.toString('binary'));
- res += '\r\n\r\n';
- res += hash.digest('binary');
+Connection.prototype.handshake = function(upgradeHead) {
+ var connection = this;
- connection._socket.write(res, 'binary');
+ if (this._state < 3) {
+ debug(this.id, 'Connection Handshake In Progress');
+ this.state(3);
+ this.protocol.handshake(this.req, upgradeHead, function(err) {
+ if (err) {
+ debug(connection.id, 'Connection Handshake Error');
+ throw err;
+ } else {
+ debug(connection.id, 'Connection Handshake Successful');
connection.state(4);
}
- }
+ });
+ } else {
+ debug(this.id, 'Already handshaked.');
}
};
-/*-----------------------------------------------
- The new onData callback for
- http.Server IncomingMessage
------------------------------------------------*/
-function Parser() {
- events.EventEmitter.call(this);
-
- this.frameData = [];
- this.order = 0;
- this.closing = false;
-}
-util.inherits(Parser, events.EventEmitter);
+Connection.prototype.write = function(data) {
+ if (this._state === 4) {
+ if (Buffer.isBuffer(data)) {
+ this.protocol.outgoing.binary(data);
+ } else {
+ this.protocol.outgoing.text(data);
+ }
+ } else {
+ debug(this.id, '\033[31mSend failed due to connection not being open.');
+ }
+ return false;
+};
-Parser.prototype.write = function(data) {
- var pkt, msg;
+// alias
+Connection.prototype.send = Connection.prototype.write;
- debug('parse.write', data.inspect());
- for (var i = 0, len = data.length; i < len; i++) {
- if (this.order == 0) {
- if (data[i] & 0x80 == 0x80) {
- this.order = 1;
- } else {
- this.order = -1;
- }
+Connection.prototype.broadcast = function(data) {
+ this._manager.forEach(function(client) {
+ if (client && client.id != this.id) {
+ client.write(data);
}
+ }, this);
+};
- if (this.order == -1) {
- if (data[i] === 0xFF) {
- pkt = new Buffer(this.frameData);
- this.order = 0;
- this.frameData = [];
- this.emit('message', pkt.toString('utf8', 0, pkt.length));
- } else if (data[i] !== 0x00) {
- this.frameData.push(data[i]);
- }
- } else if (this.order == 1) {
- if (this.closing && data[i] === 0x00) {
- this.emit('close');
- this.closing = false;
- } else if (data[i] === 0xFF && this.frameData.length == 0) {
- this.closing = true;
- } else {
- debug('High Order packet handling is not yet implemented.');
- this.order = 0;
- this.closing = false;
- }
- }
- }
-};
+Connection.prototype.close = function() {
+ var connection = this;
-/*
-function ondata(data, start, end) {
- if (this.state == 2 && this.version == 'draft76') {
- // TODO: I need to figure out an alternative here.
- // data.copy(this._req.upgradeHead, 0, start, end);
- debug.call(this, 'Using draft76 & upgrade body not sent with request.');
- this.reject('missing upgrade body');
- // Assume the data is now a message:
- } else if (this.state == 4) {
- data = data.slice(start, end);
-
- var frame_type = null, length, b;
- var parser_offset = -1;
- var raw_data = [];
-
- while(parser_offset < data.length-2) {
- frame_type = data[parser_offset ++ ];
-
- if (frame_type & 0x80 == 0x80) {
- debug.call(this, 'high');
- b = null;
- length = 1;
- while(length--) {
- b = data[parser_offset ++ ];
- length = length * 128 + (b & 0x7F);
- if (b & 0x80 == 0) {
- break;
- }
- }
- parser_offset += length;
- if (frame_type == 0xFF && length == 0) {
- this.close();
- }
- } else {
- raw_data = [];
-
- while(parser_offset <= data.length) {
- b = data[parser_offset ++ ];
- if (b == 0xFF) {
- var buf = new Buffer(raw_data);
- this.emit('message', buf.toString('utf8', 0, buf.length));
- break;
- }
- raw_data.push(b);
- }
- }
+ if (connection._state == 4 || connection._state == 5) {
+
+ if (!connection._closeFrameSent) {
+ connection.protocol.outgoing.close();
+ connection._closeFrameSent = true;
}
+
+ // Add a two second timeout for closing connections.
+ connection._closeTimer = setTimeout(function() {
+ close(connection);
+ }, 15 * 1000);
}
-};
-*/
+};
View
4 lib/ws/manager.js
@@ -1,7 +1,7 @@
var debug = function() {};
-var util = require('../_util'),
- events = require('../_events');
+var util = require(process.binding('natives').util ? 'util' : 'sys');
+var events = require('../_events');
/*-----------------------------------------------
Connection Manager
View
141 lib/ws/parser.js
@@ -1,141 +0,0 @@
-/*-----------------------------------------------
- The new onData callback for
- http.Server IncomingMessage
------------------------------------------------*/
-var sys = require('sys'),
- events = require('events');
-
-module.exports = Parser;
-
-function Parser(version) {
- events.EventEmitter.call(this);
-
- this.version = version.toLowerCase() || 'draft76';
- this.readable = true;
- this.paused = false;
-
- if (this.version == 'draft76' || this.version == 'draft75') {
- this.frameData = [];
- this.frameStage = 'begin';
- }
-}
-
-sys.inherits(Parser, events.EventEmitter);
-
-
-Parser.prototype.write = function(data) {
- var pkt, msg;
- for (var i = 0, len = data.length; i < len; i++) {
- if (this.order == 0) {
- if (data[i] & 0x80 == 0x80) {
- this.order = 1;
- } else {
- this.order = -1;
- }
- } else if (this.order == -1) {
- if (data[i] === 0xFF) {
- pkt = new Buffer(this.frameData);
- this.order = 0;
- this.frameData = [];
-
- this.emit('data', pkt.toString('utf8', 0, pkt.length));
- } else {
- this.frameData.push(data[i]);
- }
- } else if (this.order == 1) {
- this.emit('error', 'High Order packet handling is not yet implemented.');
- this.order = 0;
- }
- }
-};
-
-Parser.prototype.destroy = function() {
- delete this.order;
- delete this.frameData;
-};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-exports.createParseStream = function(version) {
- return new ParserStream(version);
-};
-
-var ParserStream = exports.ParseStream = function(version) {
- events.EventEmitter.call(this);
-
- // states
- this.readable = true;
- this.writable = true;
- this.paused = false;
-
- // stream options
- this.version = version.toLowerCase() || 'draft76';
-
- // A buffer to store #write data
- this.bufferSize = 40 * 1024;
- this.buffer = new Buffer(this.bufferSize);
-
- // we need to use a
- this.frameBuffer = [];
- this.parseState = '';
-};
-
-sys.inherits(ParserStream, events.EventEmitter);
-
-// Readable Stream
-ParserStream.prototype._read = function() {
- var self = this;
-
- // can't read a paused stream.
- if (!self.readable || self.paused) return;
-
-
- // on new frame:
- var msg = new events.EventEmitter();
-
- this.emit('message', msg);
-
- /*while len,
- if this.frameState is 'start' or 'part'
- // when we get part of a message:
- // say, we buffer 100 bytes or something, a small buffer amount.
- msg.emit('data', this.frameBuffer);
-
- else,
- // when the frame finishes:
- msg.emit('end', this.frameBuffer);
- end
- */
-};
-
-ParserStream.prototype.pause = function() {
- this.paused = true;
-};
-
-ParserStream.prototype.resume = function() {
- this.paused = false;
-
- //this.buffer.length >
-};
-
-ParserStream.prototype.destroy = function() {};
-
-
-// Writable Stream
-ParserStream.prototype.write = function() {};
-ParserStream.prototype.flush = function() {};
-ParserStream.prototype.end = function() {};
View
80 lib/ws/server.js
@@ -1,11 +1,11 @@
/*-----------------------------------------------
Requirements:
-----------------------------------------------*/
-var http = require('http'),
- path = require('path');
+var http = require('http');
+var path = require('path');
+var util = require(process.binding('natives').util ? 'util' : 'sys');
-var util = require('../_util'),
- events = require('../_events');
+var events = require('../_events');
var Manager = require('./manager'),
Connection = require('./connection'),
@@ -36,57 +36,42 @@ function clientWrite(client, data) {
}
/*-----------------------------------------------
- WebSocket Server Exports:
------------------------------------------------*/
-exports.Server = Server;
-exports.createServer = function(options) {
- return new Server(options);
-};
-
-/*-----------------------------------------------
WebSocket Server Implementation:
-----------------------------------------------*/
-function Server(o) {
+function Server(options) {
+ var server = this;
+
events.EventEmitter.call(this);
- var options = Mixin({
- debug: false,
- server: new http.Server()
- }, o);
+ var opts = this.options = Mixin({
+ debug: true,
+ close_invalid: false,
+ server: undefined
+ }, options);
- var manager = new Manager(options),
- server = options.server;
+ var http_server = this.server = opts.server || new http.Server();
+ var manager = this.manager = new Manager(opts);
- if (options.datastore) {
- throw new Error(
- 'Built-in DataStore has been removed, ' +
- 'see: http://github.com/miksago/nws-memstore'
- );
- }
- server.on('upgrade', function(req, socket, upgradeHead) {
- if (req.method == 'GET' &&
- (req.headers['upgrade'] && req.headers['connection']) &&
- req.headers.upgrade.toLowerCase() == 'websocket' &&
- req.headers.connection.toLowerCase() == 'upgrade') {
- new Connection(manager, options, req, socket, upgradeHead);
- }
+ http_server.on('upgrade', function(req, socket, upgradeHead) {
+ new Connection(server, req, upgradeHead);
});
manager.bubbleEvent('error', this);
reflectEvent(manager, 'attach', this, 'connection');
- reflectEvent(manager, 'detach', this, 'disconnect');
+ reflectEvent(manager, 'invalid_connection', this, 'invalid_connection');
+ reflectEvent(manager, 'disconnect', this, 'disconnect');
- reflectEvent(server, 'listening', this);
- reflectEvent(server, 'request', this);
- reflectEvent(server, 'stream', this);
- reflectEvent(server, 'close', this);
- reflectEvent(server, 'clientError', this);
- reflectEvent(server, 'error', this);
+ reflectEvent(http_server, 'listening', this);
+ reflectEvent(http_server, 'request', this);
+ reflectEvent(http_server, 'stream', this);
+ reflectEvent(http_server, 'close', this);
+ reflectEvent(http_server, 'clientError', this);
+ reflectEvent(http_server, 'error', this);
- reflectMethod(server, 'listen', this);
- reflectMethod(server, 'close', this);
+ reflectMethod(http_server, 'listen', this);
+ reflectMethod(http_server, 'close', this);
this.send = function(id, data) {
manager.find(id, function(client) {
@@ -100,10 +85,17 @@ function Server(o) {
});
};
- this.server = server;
- this.manager = manager;
- this.options = options;
}
util.inherits(Server, events.EventEmitter);
+/*-----------------------------------------------
+ WebSocket Server Exports:
+-----------------------------------------------*/
+exports.Server = Server;
+exports.createServer = function(options) {
+ return new Server(options);
+};
+
+exports.Connection = Connection;
+exports.Manager = Manager;
View
2  package.json
@@ -1 +1 @@
-{"version":"1.4.04","description":"A WebSocket Server for node.js, 90-100% spec compatible.","repository":{"type":"git","url":"http://github.com/miksago/node-websocket-server.git"},"directories":{"doc":"./doc","lib":"./lib/ws"},"main":"./lib/ws/server","bugs":{"web":"http://github.com/miksago/node-websocket-server/issues"},"author":"Micheil Smith <micheil@brandedcode.com>","licenses":[{"type":"MIT","url":"./LICENSE.md"}],"name":"websocket-server","engines":{"node":">=0.2.0-0"}}
+{"version":"2.0.00","description":"A WebSocket Server for node.js, 90-100% spec compatible.","repository":{"type":"git","url":"http://github.com/miksago/node-websocket-server.git"},"directories":{"doc":"./doc","lib":"./lib/ws"},"main":"./lib/ws/server","bugs":{"web":"http://github.com/miksago/node-websocket-server/issues"},"author":"Micheil Smith <micheil@brandedcode.com>","licenses":[{"type":"MIT","url":"./LICENSE.md"}],"name":"websocket-server","engines":{"node":">=0.2.0-0"},"dependencies":{"websocket-protocol":"~0.0.0"},"devDependencies":{}}
View
6 tools/release.js
@@ -28,6 +28,10 @@ cp.exec("git describe", function(err, stdout, stderr) {
name: "websocket-server",
engines: {
node: ">=0.2.0-0"
- }
+ },
+ dependencies: {
+ "websocket-protocol": "~0.0.0"
+ },
+ devDependencies: {}
}));
});
Please sign in to comment.
Something went wrong with that request. Please try again.