spincycle
Version:
A reactive message router and object manager that lets clients subscribe to object property changes on the server
440 lines (376 loc) • 14.4 kB
JavaScript
// Generated by CoffeeScript 1.12.6
(function() {
var ClientEndpoints, DB, DDAPI, EventManager, HttpMethod, MessageRouter, OStore, ObjectManager, RateLimiter, RedisMethod, ResolveModule, SpinApp, SpinFunction, SpinMeta, SpinModule, SpinTag, StatsD, SuperModel, Taginator, WsMethod, colors, defer, e, error, express, path, serveStatic,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
ObjectManager = require('./ObjectManager');
error = require('./Error').error;
HttpMethod = require('./HttpMethod');
WsMethod = require('./WsMethod');
RedisMethod = require('./RedisMethod');
DB = require('./DB');
EventManager = require('./EventManager');
SuperModel = require('./SuperModel');
SpinModule = require('./SpinModule');
SpinApp = require('./SpinApp');
SpinFunction = require('./SpinFunction');
SpinTag = require('./SpinTag');
ClientEndpoints = require('./ClientEndpoints');
OStore = require('./OStore');
ResolveModule = require('./ResolveModule');
RateLimiter = require('limiter').RateLimiter;
e = require('./EventManager');
express = require("express");
path = require('path');
defer = require('node-promise').defer;
serveStatic = require('serve-static');
colors = require('colors/safe');
DDAPI = require('./DDAPI');
StatsD = require('node-statsd').StatsD;
Taginator = require('./Taginator');
SpinMeta = require('./SpinMeta');
MessageRouter = (function() {
var debug;
MessageRouter.HttpMethod = HttpMethod;
MessageRouter.WsMethod = WsMethod;
MessageRouter.RedisMethod = RedisMethod;
MessageRouter.DB = DB;
MessageRouter.EventManager = EventManager;
MessageRouter.SuperModel = SuperModel;
MessageRouter.ObjectManager = ObjectManager;
MessageRouter.ClientEndpoints = ClientEndpoints;
MessageRouter.OStore = OStore;
MessageRouter.ResolveModule = ResolveModule;
MessageRouter.status = 'closed';
MessageRouter.dogstatsd = void 0;
debug = process.env["DEBUG"];
function MessageRouter(authMgr, dburl, msgPS, app, dbtype, datadogOptions) {
var q;
this.authMgr = authMgr;
this.app = app;
if (dbtype == null) {
dbtype = 'mongodb';
}
this.datadogOptions = datadogOptions;
this.searchForTags = bind(this.searchForTags, this);
this.getTagsFor = bind(this.getTagsFor, this);
this.setTag = bind(this.setTag, this);
this.uniqueMetric = bind(this.uniqueMetric, this);
this.gaugeMetric = bind(this.gaugeMetric, this);
this.incrementMetric = bind(this.incrementMetric, this);
this.routeMessage = bind(this.routeMessage, this);
this.removeTarget = bind(this.removeTarget, this);
this.addTarget = bind(this.addTarget, this);
this.addMethod = bind(this.addMethod, this);
this.close = bind(this.close, this);
this.open = bind(this.open, this);
this.makeRESTful = bind(this.makeRESTful, this);
this.expose = bind(this.expose, this);
this.register = bind(this.register, this);
this.addServicePage = bind(this.addServicePage, this);
this.setup = bind(this.setup, this);
q = defer();
MessageRouter.DB.dburl = dburl;
MessageRouter.DB.dbname = dbtype;
this.resolver = new ResolveModule();
ResolveModule.modulecache['SpinModule'] = SpinModule;
ResolveModule.modulecache['SpinFunction'] = SpinFunction;
ResolveModule.modulecache['SpinApp'] = SpinApp;
ResolveModule.modulecache['SpinTag'] = SpinTag;
ResolveModule.modulecache['SpinMeta'] = SpinMeta;
DB.getDataStore(dbtype).then((function(_this) {
return function() {
var pjson;
pjson = require('../package.json');
_this.messagesPerSecond = msgPS || 100;
console.log(colors.blue.inverse('-----------------------------------------------------------------------------------------------'));
console.log(colors.blue.bold.inverse(' SpinCycle messageRouter constructor. Version - ' + pjson.version + ' messages per user per second limit = ' + _this.messagesPerSecond + ' '));
console.log(colors.blue.inverse('-----------------------------------------------------------------------------------------------'));
if (_this.datadogOptions) {
console.log('datadog options are');
console.dir(_this.datadogOptions);
_this.dogstatsd = new StatsD();
DDAPI.init(_this.datadogOptions);
}
_this.authMgr.messagerouter = _this;
_this.targets = [];
_this.debugtargets = [];
_this.args = [];
_this.methods = [];
_this.objectManager = new ObjectManager(_this);
_this.objectManager.setup();
if (_this.authMgr.setup) {
_this.authMgr.setup(_this);
}
_this.setup();
return q.resolve(_this);
};
})(this));
return q;
}
MessageRouter.prototype.setup = function() {
this.addTarget('listcommands', '<noargs>', (function(_this) {
return function(msg) {
var name, ref, rv, target;
rv = {
listcommands: '<noarg>'
};
ref = _this.targets;
for (name in ref) {
target = ref[name];
rv[name] = _this.args[name];
}
return msg.replyFunc({
status: EventManager.general.SUCCESS,
info: 'list of available targets',
payload: rv
});
};
})(this));
if (this.datadogOptions) {
this.addTarget('ddapi', 'metric,value,tags', (function(_this) {
return function(msg) {
var err;
console.log('ddapi got call');
console.dir(msg);
if (msg.metric && msg.value) {
if (typeof msg.tags === 'string') {
try {
msg.tags = JSON.parse(msg.tags);
} catch (error1) {
err = error1;
msg.replyFunc({
status: 'FAILURE',
info: 'lossy JSON format of tags',
payload: msg.metric
});
return;
}
}
_this.gaugeMetric(msg.metric, msg.value, msg.tags || {});
return msg.replyFunc({
status: 'SUCCESS',
info: 'datadog metric sent',
payload: msg.metric
});
} else {
return msg.replyFunc({
status: 'FAILURE',
info: 'missing parameter(s)',
payload: msg.metric
});
}
};
})(this));
}
return setTimeout(this.addServicePage.bind(this), 1);
};
MessageRouter.prototype.addServicePage = function() {
var p;
p = __dirname + '/spin';
if (this.app) {
console.log('**************** addServicePage called -> ' + p);
this.app.use('/spin', express["static"](p));
this.app.use('/spin/bower_components', express["static"](p + '/bower_components'));
} else {
console.log('no app argument provided to MessageRouter! Unable to set up /spin route');
}
console.log('**************** exposing SpinModule and SpinFunction');
return DB.createDatabases(['SpinModule', 'SpinFunction', 'SpinApp', 'SpinTag']).then((function(_this) {
return function() {
console.log(' DB init done..');
_this.objectManager.expose('SpinModule');
_this.objectManager.expose('SpinFunction');
_this.objectManager.expose('SpinApp');
_this.objectManager.expose('SpinMeta');
_this.makeRESTful('SpinModule');
_this.makeRESTful('SpinFunction');
_this.makeRESTful('SpinApp');
return _this.makeRESTful('SpinMeta');
};
})(this));
};
MessageRouter.prototype.register = function(types) {
var q, typenames;
q = defer();
typenames = [];
types.forEach((function(_this) {
return function(type) {
typenames.push(type.name);
ResolveModule.modulecache[type.name] = type.module;
_this.objectManager.expose(type.name);
return _this.makeRESTful(type.name);
};
})(this));
DB.createDatabases(typenames).then((function(_this) {
return function() {
return q.resolve();
};
})(this));
return q;
};
MessageRouter.prototype.expose = function(type) {
var method, name, ref, results;
ref = this.methods;
results = [];
for (name in ref) {
method = ref[name];
results.push(method.expose(type));
}
return results;
};
MessageRouter.prototype.makeRESTful = function(type) {
var method, name, ref, results;
ref = this.methods;
results = [];
for (name in ref) {
method = ref[name];
if (name === 'express') {
results.push(method.makeRESTful(type));
} else {
results.push(void 0);
}
}
return results;
};
MessageRouter.prototype.open = function() {
MessageRouter.status = 'open';
return console.log(colors.inverse.green(' * opening message router * '));
};
MessageRouter.prototype.close = function() {
MessageRouter.status = 'closed';
return console.log('closing message router');
};
MessageRouter.prototype.addMethod = function(methodName, method) {
var results, targetName;
console.log('addMethod called for "' + methodName + '"');
this.methods[methodName] = method;
results = [];
for (targetName in this.targets) {
results.push(method.registrationFunc(targetName, this.routeMessage));
}
return results;
};
MessageRouter.prototype.addTarget = function(targetName, args, targetFunc, props) {
var method, name, ref, results;
this.targets[targetName] = targetFunc;
this.args[targetName] = args;
ref = this.methods;
results = [];
for (name in ref) {
method = ref[name];
if (method.registrationFunc) {
results.push(method.registrationFunc(targetName, this.routeMessage, props));
} else {
console.log('Spincycle did NOT find target for ' + targetName);
console.log('----------------methods-------------------');
results.push(console.dir(this.methods));
}
}
return results;
};
MessageRouter.prototype.removeTarget = function(targetName) {
return this.targets[targetName] = null;
};
MessageRouter.prototype.routeMessage = function(message) {
var fn;
if (MessageRouter.status !== 'open') {
return message.replyFunc({
status: e.general.NOT_ALLOWED,
info: 'Message router is not yet open',
payload: {
error: 'ERRCHILLMAN'
}
});
} else {
fn = this.targets[message.target];
if (fn) {
return this.authMgr.decorateMessageWithUser(message).then((function(_this) {
return function(m) {
if (!m.user) {
console.log('** SpinCycle did not get message decorated with user property from AuthenticationManager **');
exit(-1);
}
if (!m.user.limiter) {
m.user.limiter = new RateLimiter(parseInt(_this.messagesPerSecond), 1000);
}
if (m.user.limiter && m.user.limiter.removeTokens) {
return m.user.limiter.removeTokens(1, function(err, remainingRequests) {
if (parseInt(remainingRequests) < 1) {
return m.replyFunc({
status: e.general.NOT_ALLOWED,
info: 'packets over ' + _this.messagesPerSecond + '/s dropped. Have a nice day.',
payload: {
error: 'TOOMANYPACKETSPERSECOND'
}
});
} else {
return fn(m);
}
});
} else {
console.log('** user ' + m.user.name + ' have no ratelimiter or at least not one with a removeToken function!!!');
return console.dir(m.user);
}
};
})(this));
} else {
return console.log('--- could not find registered target for message! ---');
}
}
};
MessageRouter.prototype.incrementMetric = function(metric, tags) {
if (this.datadogOptions) {
return DDAPI.writePoint(metric, tags, 'increment');
}
};
MessageRouter.prototype.gaugeMetric = function(metric, val, tags) {
if (this.datadogOptions) {
return DDAPI.writePoint(metric, val, tags, 'gauge');
}
};
MessageRouter.prototype.uniqueMetric = function(metric, val, tags) {
if (this.datadogOptions) {
return DDAPI.writePoint(metric, val, tags, 'unique');
}
};
MessageRouter.prototype.setTag = function(type, id, tag) {
var q;
q = defer();
DB.getDataStore().then((function(_this) {
return function(store) {
return Taginator.setTag(store, type, id, tag).then(function(value) {
return q.resolve(value);
});
};
})(this));
return q;
};
MessageRouter.prototype.getTagsFor = function(type, id) {
var q;
q = defer();
DB.getDataStore().then((function(_this) {
return function(store) {
return Taginator.getTagsFor(store, type, id).then(function(value) {
return q.resolve(value);
});
};
})(this));
return q;
};
MessageRouter.prototype.searchForTags = function(type, tags) {
var q;
q = defer();
DB.getDataStore().then((function(_this) {
return function(store) {
return Taginator.searchForTags(store, type, tags).then(function(value) {
return q.resolve(value);
});
};
})(this));
return q;
};
return MessageRouter;
})();
module.exports = MessageRouter;
}).call(this);
//# sourceMappingURL=MessageRouter.js.map