lumberjack-protocol
Version:
Node.js implementation of the lumberjack protocol.
136 lines (109 loc) • 4.42 kB
JavaScript
// Generated by CoffeeScript 1.12.1
(function() {
var ClientSocket, DEFAULT_WINDOW_SIZE, DroppedError, EventEmitter, MAX_UINT_32, SEND_WINDOW_SIZE_FACTOR, assert, id, lumberjack, tls,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
assert = require('assert');
EventEmitter = require('events').EventEmitter;
tls = require('tls');
lumberjack = require('./lumberjack');
MAX_UINT_32 = require('./constants').MAX_UINT_32;
DEFAULT_WINDOW_SIZE = 1000;
SEND_WINDOW_SIZE_FACTOR = 10;
DroppedError = function(message) {
Error.captureStackTrace(this, lumberjack.TooShortError);
this.name = 'DroppedError';
return this.message = message;
};
DroppedError.prototype = Object.create(Error.prototype);
id = 0;
ClientSocket = (function(superClass) {
extend(ClientSocket, superClass);
ClientSocket.prototype.DroppedError = DroppedError;
function ClientSocket(options) {
var ref;
this.options = options != null ? options : {};
this._onData = bind(this._onData, this);
this._disconnect = bind(this._disconnect, this);
this.connected = false;
this._closed = false;
this.id = id++;
this._windowSize = (ref = this.options.windowSize) != null ? ref : DEFAULT_WINDOW_SIZE;
this._nextSequenceNumber = 1;
this.lastAck = 0;
this._parser = new lumberjack.Parser();
this._parser.on('data', this._onData);
this._parser.on('error', this._disconnect);
}
ClientSocket.prototype.connect = function(tlsConnectOptions) {
this._socket = tls.connect(tlsConnectOptions);
this._socket.on('secureConnect', (function(_this) {
return function() {
return _this._socket.write(lumberjack.makeWindowSizeFrame(_this._windowSize), null, function() {
_this.connected = true;
return _this.emit('connect');
});
};
})(this));
this._socket.on('error', this._disconnect);
this._socket.on('end', this._disconnect);
return this._socket.pipe(this._parser);
};
ClientSocket.prototype._disconnect = function(err) {
if (this._closed) {
return;
}
if (err) {
this.emit('error', err);
} else {
this.emit('end');
}
this.connected = false;
if (this._socket) {
this._socket.removeAllListeners();
this._socket.on('error', function() {});
}
this._socket = null;
return this.removeAllListeners();
};
ClientSocket.prototype._onData = function(data) {
assert(data.type === 'ack', "Receiver should only ever send 'ack' messages: " + data.type);
this.lastAck = data.seq;
return this.emit('ack', data.seq);
};
ClientSocket.prototype._getSequenceNumber = function() {
this.lastSequenceNumber = this._nextSequenceNumber++;
if (this._nextSequenceNumber > MAX_UINT_32) {
this._nextSequenceNumber = 0;
}
return this.lastSequenceNumber;
};
ClientSocket.prototype.writeDataFrame = function(data, done) {
var drop;
if (!this.connected) {
done(new Error("Can't write data when not connected."));
}
drop = ((this._nextSequenceNumber - this.lastAck) > (this._windowSize * SEND_WINDOW_SIZE_FACTOR)) && ((this.options.allowDrop == null) || !!this.options.allowDrop(data));
if (drop) {
this.emit('dropped', 1);
return done(new DroppedError("Dropped message"));
} else {
return this._socket.write(lumberjack.makeDataFrame(this._getSequenceNumber(), data), null, done);
}
};
ClientSocket.prototype.getLastSequenceNumber = function() {
return this._nextSequenceNumber - 1;
};
ClientSocket.prototype.close = function() {
this._closed = true;
return this._disconnect();
};
ClientSocket.prototype.unref = function() {
return this._socket.unref();
};
return ClientSocket;
})(EventEmitter);
module.exports = ClientSocket;
module.exports.DroppedError = DroppedError;
}).call(this);