noflo
Version:
Flow-Based Programming environment for JavaScript
270 lines (255 loc) • 7.71 kB
JavaScript
(function() {
var ComponentLoader, Graph, IP, Network, getType, internalSocket, normalizeOptions, normalizeOutput, prepareInputMap, prepareNetwork, runNetwork, sendOutputMap;
ComponentLoader = require('./ComponentLoader').ComponentLoader;
Network = require('./Network').Network;
IP = require('./IP');
internalSocket = require('./InternalSocket');
Graph = require('fbp-graph').Graph;
normalizeOptions = function(options, component) {
if (!options) {
options = {};
}
if (!options.name) {
options.name = component;
}
if (options.loader) {
options.baseDir = options.loader.baseDir;
}
if (!options.baseDir && process && process.cwd) {
options.baseDir = process.cwd();
}
if (!options.loader) {
options.loader = new ComponentLoader(options.baseDir);
}
if (!options.raw) {
options.raw = false;
}
return options;
};
prepareNetwork = function(component, options, callback) {
return options.loader.load(component, function(err, instance) {
var def, graph, inPorts, network, nodeName, outPorts, port;
if (err) {
return callback(err);
}
graph = new Graph(options.name);
nodeName = options.name;
graph.addNode(nodeName, component);
inPorts = instance.inPorts.ports || instance.inPorts;
outPorts = instance.outPorts.ports || instance.outPorts;
for (port in inPorts) {
def = inPorts[port];
graph.addInport(port, nodeName, port);
}
for (port in outPorts) {
def = outPorts[port];
graph.addOutport(port, nodeName, port);
}
graph.componentLoader = options.loader;
network = new Network(graph, options);
return network.connect(function(err) {
if (err) {
return callback(err);
}
return callback(null, network);
});
});
};
runNetwork = function(network, inputs, options, callback) {
var inPorts, inSockets, outPorts, outSockets, process, received;
process = network.getNode(options.name);
inPorts = Object.keys(network.graph.inports);
inSockets = {};
inPorts.forEach(function(inport) {
inSockets[inport] = internalSocket.createSocket();
return process.component.inPorts[inport].attach(inSockets[inport]);
});
received = [];
outPorts = Object.keys(network.graph.outports);
outSockets = {};
outPorts.forEach(function(outport) {
outSockets[outport] = internalSocket.createSocket();
process.component.outPorts[outport].attach(outSockets[outport]);
return outSockets[outport].on('ip', function(ip) {
var res;
res = {};
res[outport] = ip;
return received.push(res);
});
});
network.once('end', function() {
var port, socket;
for (port in outSockets) {
socket = outSockets[port];
process.component.outPorts[port].detach(socket);
}
outSockets = {};
inSockets = {};
return callback(null, received);
});
return network.start(function(err) {
var i, inputMap, len, port, results, value;
if (err) {
return callback(err);
}
results = [];
for (i = 0, len = inputs.length; i < len; i++) {
inputMap = inputs[i];
results.push((function() {
var results1;
results1 = [];
for (port in inputMap) {
value = inputMap[port];
if (IP.isIP(value)) {
inSockets[port].post(value);
continue;
}
results1.push(inSockets[port].post(new IP('data', value)));
}
return results1;
})());
}
return results;
});
};
getType = function(inputs, network) {
var key, maps, value;
if (typeof inputs !== 'object') {
return 'simple';
}
if (Array.isArray(inputs)) {
maps = inputs.filter(function(entry) {
return getType(entry, network) === 'map';
});
if (maps.length === inputs.length) {
return 'sequence';
}
return 'simple';
}
if (!Object.keys(inputs).length) {
return 'simple';
}
for (key in inputs) {
value = inputs[key];
if (!network.graph.inports[key]) {
return 'simple';
}
}
return 'map';
};
prepareInputMap = function(inputs, inputType, network) {
var inPort, map;
if (inputType === 'sequence') {
return inputs;
}
if (inputType === 'map') {
return [inputs];
}
inPort = Object.keys(network.graph.inports)[0];
if (network.graph.inports["in"]) {
inPort = 'in';
}
map = {};
map[inPort] = inputs;
return [map];
};
normalizeOutput = function(values, options) {
var current, i, len, packet, previous, result;
if (options.raw) {
return values;
}
result = [];
previous = null;
current = result;
for (i = 0, len = values.length; i < len; i++) {
packet = values[i];
if (packet.type === 'openBracket') {
previous = current;
current = [];
previous.push(current);
}
if (packet.type === 'data') {
current.push(packet.data);
}
if (packet.type === 'closeBracket') {
current = previous;
}
}
if (result.length === 1) {
return result[0];
}
return result;
};
sendOutputMap = function(outputs, resultType, options, callback) {
var errors, i, key, len, map, mappedOutputs, outputKeys, packets, port, result, val, withValue;
errors = outputs.filter(function(map) {
return map.error != null;
}).map(function(map) {
return map.error;
});
if (errors.length) {
return callback(normalizeOutput(errors, options));
}
if (resultType === 'sequence') {
return callback(null, outputs.map(function(map) {
var key, res, val;
res = {};
for (key in map) {
val = map[key];
if (options.raw) {
res[key] = val;
continue;
}
res[key] = normalizeOutput([val], options);
}
return res;
}));
}
mappedOutputs = {};
for (i = 0, len = outputs.length; i < len; i++) {
map = outputs[i];
for (key in map) {
val = map[key];
if (!mappedOutputs[key]) {
mappedOutputs[key] = [];
}
mappedOutputs[key].push(val);
}
}
outputKeys = Object.keys(mappedOutputs);
withValue = outputKeys.filter(function(outport) {
return mappedOutputs[outport].length > 0;
});
if (withValue.length === 0) {
return callback(null);
}
if (withValue.length === 1 && resultType === 'simple') {
return callback(null, normalizeOutput(mappedOutputs[withValue[0]], options));
}
result = {};
for (port in mappedOutputs) {
packets = mappedOutputs[port];
result[port] = normalizeOutput(packets, options);
}
return callback(null, result);
};
exports.asCallback = function(component, options) {
options = normalizeOptions(options, component);
return function(inputs, callback) {
return prepareNetwork(component, options, function(err, network) {
var inputMap, resultType;
if (err) {
return callback(err);
}
resultType = getType(inputs, network);
inputMap = prepareInputMap(inputs, resultType, network);
return runNetwork(network, inputMap, options, function(err, outputMap) {
if (err) {
return callback(err);
}
return sendOutputMap(outputMap, resultType, options, callback);
});
});
};
};
}).call(this);