node-etcd
Version:
etcd library for node.js (etcd v2 api)
243 lines (209 loc) • 7.39 kB
JavaScript
// Generated by CoffeeScript 1.12.7
var CancellationToken, Client, _, deasync, defaultClientOptions, defaultRequestOptions, exports, request,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
request = require('request');
deasync = require('deasync');
_ = require('lodash');
defaultRequestOptions = {
pool: {
maxSockets: 100
},
followAllRedirects: true
};
defaultClientOptions = {
maxRetries: 3
};
CancellationToken = (function() {
function CancellationToken(servers1, maxRetries, retries1, errors1) {
this.servers = servers1;
this.maxRetries = maxRetries;
this.retries = retries1 != null ? retries1 : 0;
this.errors = errors1 != null ? errors1 : [];
this.abort = bind(this.abort, this);
this.isAborted = bind(this.isAborted, this);
this.setRequest = bind(this.setRequest, this);
this.aborted = false;
}
CancellationToken.prototype.setRequest = function(req) {
return this.req = req;
};
CancellationToken.prototype.isAborted = function() {
return this.aborted;
};
CancellationToken.prototype.abort = function() {
this.aborted = true;
if (this.req != null) {
return this.req.abort();
}
};
CancellationToken.prototype.cancel = CancellationToken.prototype.abort;
CancellationToken.prototype.wasAborted = CancellationToken.prototype.isAborted;
return CancellationToken;
})();
Client = (function() {
function Client(hosts, options1, sslopts) {
this.hosts = hosts;
this.options = options1;
this.sslopts = sslopts;
this._shouldRetry = bind(this._shouldRetry, this);
this._retry = bind(this._retry, this);
this._multiserverHelper = bind(this._multiserverHelper, this);
this["delete"] = bind(this["delete"], this);
this.patch = bind(this.patch, this);
this.post = bind(this.post, this);
this.get = bind(this.get, this);
this.put = bind(this.put, this);
this.execute = bind(this.execute, this);
this.syncmsg = {};
}
Client.prototype.execute = function(method, options, callback) {
var opt, servers, syncResp, token;
opt = _.defaults(_.clone(options), this.options, defaultRequestOptions, {
method: method
});
opt.clientOptions = _.defaults(opt.clientOptions, defaultClientOptions);
servers = _.shuffle(this.hosts);
token = new CancellationToken(servers, opt.clientOptions.maxRetries);
syncResp = this._multiserverHelper(servers, opt, token, callback);
if (options.synchronous === true) {
return syncResp;
} else {
return token;
}
};
Client.prototype.put = function(options, callback) {
return this.execute("PUT", options, callback);
};
Client.prototype.get = function(options, callback) {
return this.execute("GET", options, callback);
};
Client.prototype.post = function(options, callback) {
return this.execute("POST", options, callback);
};
Client.prototype.patch = function(options, callback) {
return this.execute("PATCH", options, callback);
};
Client.prototype["delete"] = function(options, callback) {
return this.execute("DELETE", options, callback);
};
Client.prototype._multiserverHelper = function(servers, options, token, callback) {
var host, req, reqRespHandler, syncRespHandler;
host = _.first(servers);
options.url = "" + host + options.path;
if (token.isAborted()) {
return;
}
if (host == null) {
if (this._shouldRetry(token)) {
return this._retry(token, options, callback);
}
return this._error(token, callback);
}
reqRespHandler = (function(_this) {
return function(err, resp, body) {
if (token.isAborted()) {
return;
}
if (_this._isHttpError(err, resp)) {
token.errors.push({
server: host,
httperror: err,
httpstatus: resp != null ? resp.statusCode : void 0,
httpbody: resp != null ? resp.body : void 0,
response: resp,
timestamp: new Date()
});
return _this._multiserverHelper(_.drop(servers), options, token, callback);
}
return _this._handleResponse(err, resp, body, callback);
};
})(this);
syncRespHandler = (function(_this) {
return function(err, body, headers) {
options.syncdone = true;
return _this.syncmsg = {
err: err,
body: body,
headers: headers
};
};
})(this);
if (options.synchronous === true) {
callback = syncRespHandler;
}
req = this._doRequest(options, reqRespHandler);
token.setRequest(req);
if (options.synchronous === true && options.syncdone === void 0) {
options.syncdone = false;
deasync.loopWhile((function(_this) {
return function() {
return !options.syncdone;
};
})(this));
delete options.syncdone;
return this.syncmsg;
} else {
return req;
}
};
Client.prototype._doRequest = function(options, reqRespHandler) {
return request(options, reqRespHandler);
};
Client.prototype._retry = function(token, options, callback) {
var doRetry, waitTime;
doRetry = (function(_this) {
return function() {
return _this._multiserverHelper(token.servers, options, token, callback);
};
})(this);
waitTime = this._waitTime(token.retries);
token.retries += 1;
return setTimeout(doRetry, waitTime);
};
Client.prototype._waitTime = function(retries) {
if (process.env.RUNNING_UNIT_TESTS === 'true') {
return 1;
}
/* !pragma no-coverage-next */
return 100 * Math.pow(16, retries);
};
Client.prototype._shouldRetry = function(token) {
return token.retries < token.maxRetries && this._isPossibleLeaderElection(token.errors);
};
Client.prototype._error = function(token, callback) {
var error;
error = new Error('All servers returned error');
error.errors = token.errors;
error.retries = token.retries;
if (callback) {
return callback(error);
}
};
Client.prototype._isPossibleLeaderElection = function(errors) {
var checkError;
checkError = function(e) {
var ref, ref1, ref2, ref3;
return ((ref = e != null ? (ref1 = e.httperror) != null ? ref1.code : void 0 : void 0) === 'ECONNREFUSED' || ref === 'ECONNRESET') || ((ref2 = e != null ? (ref3 = e.httpbody) != null ? ref3.errorCode : void 0 : void 0) === 300 || ref2 === 301) || /Not current leader/.test(e != null ? e.httpbody : void 0);
};
return (errors != null) && _.every(errors, checkError);
};
Client.prototype._isHttpError = function(err, resp) {
return err || (((resp != null ? resp.statusCode : void 0) != null) && resp.statusCode >= 500);
};
Client.prototype._handleResponse = function(err, resp, body, callback) {
var error;
if (callback == null) {
return;
}
if ((body != null ? body.errorCode : void 0) != null) {
error = new Error((body != null ? body.message : void 0) || 'Etcd error');
error.errorCode = body.errorCode;
error.error = body;
return callback(error, "", (resp != null ? resp.headers : void 0) || {});
} else {
return callback(null, body, (resp != null ? resp.headers : void 0) || {});
}
};
return Client;
})();
exports = module.exports = Client;