monkey-bus
Version:
A micro-service bus framework for RabbitMQ
177 lines (149 loc) • 5.01 kB
JavaScript
"use strict";
var filter = require('../filter');
var logger = require("../logging")("bus-process");
var uuid = require("node-uuid");
const processNS = "process";
var snapshot = function(data) {
var cache = [];
var str = JSON.stringify(data, function(key, value) {
if (typeof value === 'object' && value !== null) {
if (key === "timer") {
return;
}
if (cache.indexOf(value) !== -1) {
return JSON.parse(JSON.stringify(value));
}
cache.push(value);
}
return value;
});
return JSON.parse(str);
};
function ProcessClass(bus, fsmName) {
this.id = uuid.v4();
this.bus = bus;
this.payload = null;
this.fsmName = fsmName;
this.promiseResolve = null;
this.promiseReject = null;
}
var processListeners = {
};
var mainListener = function (eventName, eventPayload) {
if (
processListeners[eventPayload.client.id] &&
processListeners[eventPayload.client.id][eventName]
) {
var eventListeners = processListeners[eventPayload.client.id][eventName];
var size = processListeners[eventPayload.client.id][eventName].length;
var i = 0;
for (; i < size; i += 1) {
var properties = eventListeners[i].props;
var eventPayloadHasNeededProperties = true;
for (var prop in properties) {
if (!eventPayload[prop] || eventPayload[prop] !== properties[prop]) {
eventPayloadHasNeededProperties = false;
break;
}
}
if (eventPayloadHasNeededProperties) {
eventListeners[i].callback(eventPayload.client);
}
}
}
if (eventName === 'transition') {
var fsm = registeredFSMs[eventPayload.client.fsmName];
if (fsm.finalState && fsm.finalState === eventPayload.toState) {
delete processListeners[eventPayload.client.id];
}
}
if (eventName === 'exception') {
delete processListeners[eventPayload.client.id];
}
};
var fsmListeners = {};
ProcessClass.prototype = (function () {
return {
start: function(payload) {
this.payload = payload;
return new Promise((resolve, reject) => {
this.promiseResolve = resolve;
this.promiseReject = reject;
Promise.all([
this.on(
'transition',
(data) => {
this.promiseResolve(data);
},
{
toState: 'success'
}
),
this.on(
'transition',
(data) => {
this.promiseReject(data);
},
{
toState: 'exception'
}
)
]).then(() => {
registeredFSMs[this.fsmName].start(this);
});
});
},
on: function(eventName, cb, properties){
properties = properties || {};
if (!processListeners[this.id]) {
processListeners[this.id] = {};
}
if (!processListeners[this.id][eventName]) {
processListeners[this.id][eventName] = [];
}
processListeners[this.id][eventName].push({
props: properties,
callback: cb
});
if (!fsmListeners[this.fsmName][eventName]) {
fsmListeners[this.fsmName][eventName] =
this.bus.event([processNS, this.fsmName, eventName].join('.'))
.subscribe(mainListener.bind(null, eventName));
}
return fsmListeners[this.fsmName][eventName];
}
}
}());
var registeredFSMs = {};
function fsmFactory(fsmName, bus) {
var fsm;
try {
fsm = require('./fsm/' + fsmName);
} catch (exception) {
if (global.__baseAppDir) {
fsm = require(global.__baseAppDir + 'fsm/' + fsmName);
} else {
throw exception;
}
}
fsm.namespace = fsmName;
fsm.on("*", function (event, data){
bus.event([processNS, fsmName, event].join('.')).publish(data, {
correlationId: data.client.id
});
});
fsmListeners[fsmName] = {};
return fsm;
}
function registerFsm(fsmName, bus) {
if (!registeredFSMs[fsmName]) {
registeredFSMs[fsmName] = fsmFactory(fsmName, bus);
logger.debug('fsm "' + fsmName + '" created');
}
return registeredFSMs[fsmName];
}
module.exports = function(_fsmName, bus) {
var fsmName = filter.string(_fsmName)
registerFsm(fsmName, bus);
return new ProcessClass(bus, fsmName);
};