Bouw een stroom van componenten met Flow.load() en voer hem uit met exec()
Een FlowStream is een klein programma gemaakt van componenten (blokjes met ingangen en uitgangen) en verbindingen ertussen. Total.js voert het uit binnen je applicatie: een bericht komt een component binnen, de component stuurt resultaten naar zijn uitgangen en de verbindingen brengen ze naar de volgende componenten. Hetzelfde schema is wat de Flow-designer van Total.js tekent; hier is het met de hand geschreven.
Flow.load(schema, [callback]) start een FlowStream en geeft de callback (err, instance). Het schema is een object:
idenname: het id is de sleutel inFlow.instances(Flow.instances.demo); zonder id wordt een willekeurig id gemaakt.components: een object met de broncode van elke component, als tekst. De tekst is een script,<script total>...</script>(de vorm die de designer opslaat).design: de instanties van de componenten. Elke heeft eenid, decomponentdie hij gebruikt, zijnconfigenconnections, een object waarvan de sleutels uitgangs-id's zijn en de waarden lijsten van{ id, index }: de instantie en het ingangs-id die ontvangen wat naar die uitgang wordt gestuurd.variables: waarden die componenten kunnen lezen.
Een component is een module: exports.id, exports.name, exports.inputs en exports.outputs (lijsten van { id, name }), exports.config (de standaardwaarden) en exports.make = function(instance, config). In make() stelt de component instance.message = function($) {} in, die elk bericht ontvangt: $.data zijn de gegevens, $.send(outputid, data) stuurt ze naar een uitgang en $.destroy() beëindigt een bericht dat niet verder gaat.
Om de stroom vanuit je code te gebruiken, stuurt instance.exec({ id, data, callback }) data naar de instantie id en roept callback(err, message) aan wanneer het bericht eindigt; het laatste bericht van de keten is message (dus message.data is wat de laatste component ontving). instance.reconfigure(id, config) wijzigt de configuratie van een draaiende instantie en Flow.remove(id) stopt de FlowStream en vergeet hem. FlowStream is hetzelfde object als Flow: twee namen voor de beheerder.
Een component is code die met alle rechten van de applicatie draait (in dezelfde thread tenzij het schema worker zegt). Laad nooit een schema of een component die een bezoeker kan schrijven.
const upper = `<script total>
exports.id = 'upper';
exports.name = 'Upper case';
exports.inputs = [{ id: 'input', name: 'Input' }];
exports.outputs = [{ id: 'output', name: 'Output' }];
exports.config = { prefix: '' };
exports.make = function(instance, config) {
instance.message = function($) {
$.send('output', config.prefix + String($.data).toUpperCase());
};
};
</script>`;
const collect = `<script total>
exports.id = 'collect';
exports.name = 'Collect';
exports.inputs = [{ id: 'input', name: 'Input' }];
exports.make = function(instance) {
instance.message = function($) {
MAIN.collected.push($.data);
$.destroy();
};
};
</script>`;
MAIN.collected = [];
MAIN.flow = null;
Flow.load({
id: 'demo',
name: 'Demo',
components: { upper: upper, collect: collect },
design: {
a: { id: 'a', component: 'upper', config: { prefix: '> ' }, connections: { output: [{ id: 'b', index: 'input' }] } },
b: { id: 'b', component: 'collect', config: {}, connections: {} }
},
variables: {}
}, function(err, instance) {
MAIN.flow = instance;
});exports.install = function() {
ROUTE('GET /shout/', shout);
ROUTE('POST /prefix/ @json', prefix);
ROUTE('GET /collected/', collected);
ROUTE('GET /info/', info);
ROUTE('POST /stop/', stop);
};
function shout($) {
if (!MAIN.flow)
return $.invalid('The flow is not running');
MAIN.flow.exec({ id: 'a', data: $.query.text, callback: (err, message) => $.json({ result: message ? message.data : null }) });
}
function prefix($) {
MAIN.flow.reconfigure('a', { prefix: $.body.prefix });
$.json({ ok: true });
}
function collected($) {
$.json(MAIN.collected);
}
function info($) {
$.json({ flows: Object.keys(Flow.instances), instances: Object.keys(MAIN.flow.flow.meta.flow), same: Flow === FlowStream });
}
function stop($) {
Flow.remove('demo');
MAIN.flow = null;
$.json({ flows: Object.keys(Flow.instances) });
}