hudson-taylor
Version:
Hudson Taylor is a set of libraries for making awesome microservices
242 lines (202 loc) • 5.99 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var async = require('async');
var s = require('ht-schema');
var clone = require('clone');
var utils = require('ht-utils');
var Service = function Service(Transports, config) {
var _this = this;
if (!(this instanceof Service)) {
return new Service(Transports, config);
}
if (typeof (Transports || {}).Server === 'function') {
Transports = [Transports];
} else if ((typeof Transports === 'undefined' ? 'undefined' : _typeof(Transports)) === 'object' && !Array.isArray(Transports)) {
config = Transports;
Transports = [];
} else if (!Transports) {
Transports = [];
config = {};
}
this.config = config;
this._methods = {};
this._servers = [];
this.listening = false;
this._middleware = {
before: [],
after: []
};
this.fn = function (method, data, cb) {
// clone data
data = clone(data);
var context = {
method: method
};
var _beforeMiddleware = _this._middleware.before.filter(function (m) {
if (m.method && m.method !== context.method) {
return false;
}
return true;
});
async.eachSeries(_beforeMiddleware, function (middleware, done) {
middleware.fn.call(context, data, function (err, result) {
if (err) {
return done(err);
}
data = result;
done();
});
}, function (err) {
if (err) {
return cb(err);
}
var _tmp = _this._methods[context.method];
if (!_tmp) {
return cb({
error: 'unknown-method',
method: context.method
});
}
var finish = function finish(response) {
var _afterMiddleware = _this._middleware.after.filter(function (m) {
if (m.method && m.method !== context.method) {
return false;
}
return true;
});
async.eachSeries(_afterMiddleware, function (middleware, done) {
middleware.fn.call(context, response, function (err, _response) {
if (err) {
return done(err);
}
response = _response;
done();
});
}, function (err) {
if (err) {
return cb(err);
}
cb(null, response);
});
};
if (_tmp.schema) {
_tmp.schema.validate(data, function (err, data) {
if (err) {
return cb({
$htValidationError: true,
error: err.message
});
}
return go(data);
});
} else {
go(data);
}
function go(data) {
// Handle both callbacks and promises here.
// It is expected that the CALLER only calls the callback OR
// returns a promise. If they do both, there will be two callbacks
var callbackHandler = function callbackHandler(err, response) {
if (err) return cb(err);
return finish(response);
};
var response = _tmp.fn(data, callbackHandler);
if (response && typeof response.then === 'function') {
return response.then(finish, cb);
// if an exception was thrown from finish(), let it bubble up
// as an unhandled rejection, rather than also call cb()
}
}
});
};
this.on('$htMultiCall', s.Array({ opt: false }, [s.Object({
method: s.String(),
data: s.Any({ opt: true })
})]), function (data, callback) {
utils.getLastResult.call(_this, data, callback, true);
});
Transports.forEach(function (transport) {
_this.addTransport(transport);
});
};
Service.prototype.addTransport = function (transport) {
var done = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
var server = new transport.Server(this.fn);
this._servers.push(server);
if (this.listening) {
server.listen(done);
} else {
done();
}
};
Service.prototype.on = function (method, schema, fn) {
if (!fn) {
fn = schema;
schema = null;
}
if (schema) {
if (typeof schema.validate !== 'function') {
throw new Error('Schema for ' + method + ' does not have a validate function.');
}
}
this._methods[method] = {
schema: schema,
fn: fn
};
};
Service.prototype.before = function (fn) {
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var method = opts.method;
this._middleware.before.push({
method: method,
fn: fn
});
};
Service.prototype.after = function (fn) {
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var method = opts.method;
this._middleware.after.push({
method: method,
fn: fn
});
};
Service.prototype.listen = function () {
var _this2 = this;
var done = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
if (this.listening) {
return done();
}
async.each(this._servers, function (s, cb) {
s.listen(cb);
}, function (err) {
if (err) {
return done(err);
}
_this2.listening = true;
done();
});
};
Service.prototype.stop = function () {
var _this3 = this;
var done = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
if (!this.listening) {
return done();
}
async.each(this._servers, function (s, cb) {
s.stop(cb);
}, function (err) {
if (err) {
return done(err);
}
_this3.listening = false;
done();
});
};
Service.prototype.call = function (method, data, cb) {
this.fn(method, data, cb);
};
exports.default = Service;
module.exports = exports['default'];