wires-domain
Version:
Restfull service with dependency injection
198 lines (183 loc) • 6.37 kB
JavaScript
var logger = require("log4js").getLogger("domain");
var _ = require("lodash");
var Promise = require('promise');
var Class = require('wires-class');
var Promise = require("promise");
var domainEach = require("./_each.js");
var isPromise = function(v) {
return _.isFunction(v.then) && _.isFunction(v.catch);
};
global.__wires_services_cached__ = global.__wires_services_cached__ || {};
//Extract parameter names from a function
var getParamNames = function(func) {
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var ARGUMENT_NAMES = /([^\s,]+)/g;
var fnStr = func.toString().replace(STRIP_COMMENTS, '');
var result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
if (result === null)
result = [];
return result;
};
// Extracts arguments and defined target for the require function
var getInputArguments = function(args) {
var out = {};
out.localServices = {};
if (args.length > 0) {
out.source = args[0];
out.target = args[0];
if (_.isPlainObject(args[0])) {
var opts = args[0];
out.target = opts.target;
out.source = opts.source;
out.instance = opts.instance;
}
// call(func, callback)
if (args.length > 1) {
var argsDefined = _.isString(args[0]) || _.isArray(args[0]);
if (argsDefined) {
if (_.isArray(args[0])) {
out.source = args[0];
} else {
out.source = _.isString(args[0]) ? [args[0]] : args[0];
}
if (_.isFunction(args[1])) {
out.target = args[1];
}
if (_.isFunction(args[2])) {
out.target = args[2];
}
} else {
if (_.isFunction(args[1])) {
out.callReady = args[1];
}
if (_.isPlainObject(args[1])) {
out.localServices = args[1];
}
}
}
if (args.length === 3) {
if (_.isPlainObject(args[1])) {
out.localServices = args[1];
}
if (_.isFunction(args[2])) {
out.callReady = args[2];
}
}
}
out.target = out.target || function() {};
out.source = out.source ? out.source : out.target;
out.callReady = out.callReady || function() {};
return out;
};
// Register local services
// Will be available only on rest service construct
var Require = {
// Factory constructor
// Class is used for creating an instance with following resolution
service: function() {
this.register.apply(this, arguments);
},
module: function(name, func, opts) {
opts = opts || {};
opts.cache = true;
this.register.apply(this, [name, func, opts]);
},
register: function(name, arg1, arg2) {
var localArgs = null;
var target = arg1;
if (_.isArray(arg1)) {
localArgs = arg1;
target = arg2;
}
var cache = false;
if (_.isPlainObject(arg2)) {
cache = arg2.cache === true;
}
global.__wires_services__ = global.__wires_services__ || {};
global.__wires_services__[name] = {
name: name,
target: target,
args: localArgs,
cache: cache
};
},
isServiceRegistered: function(name) {
return global.__wires_services__ && global.__wires_services__[name] !== undefined;
},
requirePackage: function(name) {
var _packageServices = {}
var self = this;
return domainEach(global.__wires_services__, function(service, serviceName) {
var _package = serviceName.split(".")[0];
if (_package === name) {
return self.require([serviceName], function(serviceInstance) {
_packageServices[serviceName] = serviceInstance
})
}
}).then(function() {
return _packageServices;
});
},
promise: function(cb) {
return new Promise(cb);
},
storeModule: function(name, inst) {
global.__wires_services_cached__[name] = inst;
},
require: function() {
var data = getInputArguments(arguments);
var self = this;
var localServices = data.localServices;
var variables = _.isArray(data.source) ? data.source : getParamNames(data.source);
var target = data.target;
var callReady = data.callReady;
var instance = data.instance;
var globalServices = global.__wires_services__;
var resultPromise = new Promise(function(resolve, reject) {
var args = [];
var avialableServices = _.merge(localServices, globalServices);
for (var i in variables) {
var v = variables[i];
var variableName = variables[i];
if (!avialableServices[variableName]) {
logger.fatal("Error while injecting variable '" + variableName + "' into function \n" +
data.source.toString());
return reject({
status: 500,
message: "Service with name '" + variableName + "' was not found "
});
}
args.push(avialableServices[variableName]);
}
var results = [];
return domainEach(args, function(item) {
if (item.cache && global.__wires_services_cached__[item.name]) {
return global.__wires_services_cached__[item.name];
}
var argService = item.target;
var requiredArgs = item.args;
if (_.isFunction(argService)) {
var promised;
var currentArgs = [];
if (requiredArgs) {
currentArgs = [requiredArgs, localServices, argService];
} else {
currentArgs = [argService, localServices];
}
return self.require.apply(self, currentArgs).then(function(dest) {
if (item.cache) {
self.storeModule(item.name, dest);
}
return dest;
});
} else {
return argService || item;
}
}).then(function(results) {
return target.apply(instance || results, results);
}).then(resolve).catch(reject);
});
return resultPromise;
}
};
module.exports = Require;