You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
2.2 KiB
101 lines
2.2 KiB
'use strict'; |
|
|
|
var util = require('util'); |
|
var EventEmitter = require('events').EventEmitter; |
|
|
|
function Hose(socket, options, filter) { |
|
EventEmitter.call(this); |
|
|
|
if (typeof options === 'function') { |
|
filter = options; |
|
options = {}; |
|
} |
|
|
|
this.socket = socket; |
|
this.options = options; |
|
this.filter = filter; |
|
|
|
this.buffer = null; |
|
|
|
var self = this; |
|
this.listeners = { |
|
error: function(err) { |
|
return self.onError(err); |
|
}, |
|
data: function(chunk) { |
|
return self.onData(chunk); |
|
}, |
|
end: function() { |
|
return self.onEnd(); |
|
} |
|
}; |
|
|
|
this.socket.on('error', this.listeners.error); |
|
this.socket.on('data', this.listeners.data); |
|
this.socket.on('end', this.listeners.end); |
|
} |
|
util.inherits(Hose, EventEmitter); |
|
module.exports = Hose; |
|
|
|
Hose.create = function create(socket, options, filter) { |
|
return new Hose(socket, options, filter); |
|
}; |
|
|
|
Hose.prototype.detach = function detach() { |
|
// Stop the flow |
|
this.socket.pause(); |
|
|
|
this.socket.removeListener('error', this.listeners.error); |
|
this.socket.removeListener('data', this.listeners.data); |
|
this.socket.removeListener('end', this.listeners.end); |
|
}; |
|
|
|
Hose.prototype.reemit = function reemit() { |
|
var buffer = this.buffer; |
|
this.buffer = null; |
|
|
|
// Modern age |
|
if (this.socket.unshift) { |
|
this.socket.unshift(buffer); |
|
if (this.socket.listeners('data').length > 0) |
|
this.socket.resume(); |
|
return; |
|
} |
|
|
|
// Rusty node v0.8 |
|
if (this.socket.ondata) |
|
this.socket.ondata(buffer, 0, buffer.length); |
|
this.socket.emit('data', buffer); |
|
this.socket.resume(); |
|
}; |
|
|
|
Hose.prototype.onError = function onError(err) { |
|
this.detach(); |
|
this.emit('error', err); |
|
}; |
|
|
|
Hose.prototype.onData = function onData(chunk) { |
|
if (this.buffer) |
|
this.buffer = Buffer.concat([ this.buffer, chunk ]); |
|
else |
|
this.buffer = chunk; |
|
|
|
var self = this; |
|
this.filter(this.buffer, function(err, protocol) { |
|
if (err) |
|
return self.onError(err); |
|
|
|
// No protocol selected yet |
|
if (!protocol) |
|
return; |
|
|
|
self.detach(); |
|
self.emit('select', protocol, self.socket); |
|
self.reemit(); |
|
}); |
|
}; |
|
|
|
Hose.prototype.onEnd = function onEnd() { |
|
this.detach(); |
|
this.emit('error', new Error('Not enough data to recognize protocol')); |
|
};
|
|
|