swh:1:snp:c53ab93da1867a0ee99951a3636bca865f9194df
Tip revision: 3ebd1565166cedc7a824759ddef0ea891796f3dc authored by einaros on 12 April 2012, 12:03:51 UTC
bump
bump
Tip revision: 3ebd156
Receiver.hixie.js
/*!
* ws: a node.js websocket client
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
* MIT Licensed
*/
var events = require('events')
, util = require('util')
, EventEmitter = events.EventEmitter;
/**
* State constants
*/
var EMPTY = 0
, BODY = 1;
/**
* Hixie Receiver implementation
*/
function Receiver () {
this.state = EMPTY;
this.buffers = [];
this.messageEnd = -1;
this.spanLength = 0;
this.dead = false;
}
module.exports = Receiver;
/**
* Inherits from EventEmitter.
*/
util.inherits(Receiver, events.EventEmitter);
/**
* Add new data to the parser.
*
* @api public
*/
Receiver.prototype.add = function(data) {
var self = this;
function doAdd() {
if (self.state === EMPTY) {
if (data.length == 2 && data[0] == 0xFF && data[1] == 0x00) {
self.reset();
self.emit('close');
return;
}
if (data[0] !== 0x00) {
self.error('payload must start with 0x00 byte', true);
return;
}
data = data.slice(1);
self.state = BODY;
}
self.buffers.push(data);
if ((self.messageEnd = bufferIndex(data, 0xFF)) != -1) {
self.spanLength += self.messageEnd;
return self.parse();
}
else self.spanLength += data.length;
}
while(data) data = doAdd();
}
/**
* Releases all resources used by the receiver.
*
* @api public
*/
Receiver.prototype.cleanup = function() {
this.dead = true;
this.state = EMPTY;
this.buffers = [];
}
/**
* Process buffered data.
*
* @api public
*/
Receiver.prototype.parse = function() {
var output = new Buffer(this.spanLength);
var outputIndex = 0;
for (var bi = 0, bl = this.buffers.length; bi < bl - 1; ++bi) {
var buffer = this.buffers[bi];
buffer.copy(output, outputIndex);
outputIndex += buffer.length;
}
var lastBuffer = this.buffers[this.buffers.length - 1];
if (this.messageEnd > 0) lastBuffer.copy(output, outputIndex, 0, this.messageEnd);
var tail = null;
if (this.messageEnd < lastBuffer.length - 1) {
tail = lastBuffer.slice(this.messageEnd + 1);
}
this.reset();
this.emit('text', output.toString('utf8'));
return tail;
}
/**
* Handles an error
*
* @api private
*/
Receiver.prototype.error = function (reason, terminate) {
this.reset();
this.emit('error', reason, terminate);
return this;
}
/**
* Reset parser state
*
* @api private
*/
Receiver.prototype.reset = function (reason) {
if (this.dead) return;
this.state = EMPTY;
this.buffers = [];
this.messageEnd = -1;
this.spanLength = 0;
}
/**
* Internal api
*/
function bufferIndex(buffer, byte) {
for (var i = 0, l = buffer.length; i < l; ++i) {
if (buffer[i] === byte) return i;
}
return -1;
}