Zostavte tok komponentov cez Flow.load() a spustite ho cez exec()
FlowStream je malý program zložený z komponentov (políčok so vstupmi a výstupmi) a spojení medzi nimi. Total.js ho spúšťa vo vašej aplikácii: správa vstúpi do jedného komponentu, komponent pošle výsledky na svoje výstupy a spojenia ich prenesú do ďalších komponentov. Rovnakú schému kreslí návrhár Flow v Total.js; tu je napísaná ručne.
Flow.load(schema, [callback]) spustí FlowStream a dá callbacku (err, instance). Schéma je objekt:
idaname: id je kľúč vFlow.instances(Flow.instances.demo); bez id sa vytvorí náhodné.components: objekt so zdrojovým kódom každého komponentu ako textom. Text je skript,<script total>...</script>(forma, ktorú ukladá návrhár).design: inštancie komponentov. Každá máid,component, ktorý používa, svojeconfigaconnections, objekt, ktorého kľúče sú id výstupov a hodnoty sú zoznamy{ id, index }: inštancia a id vstupu, ktoré dostanú to, čo sa pošle na daný výstup.variables: hodnoty, ktoré môžu komponenty čítať.
Komponent je modul: exports.id, exports.name, exports.inputs a exports.outputs (zoznamy { id, name }), exports.config (predvolené hodnoty) a exports.make = function(instance, config). V make() komponent nastaví instance.message = function($) {}, ktorá prijíma každú správu: $.data sú dáta, $.send(outputid, data) ich pošle na výstup a $.destroy() ukončí správu, ktorá nejde ďalej.
Na použitie toku z vášho kódu instance.exec({ id, data, callback }) pošle data inštancii id a zavolá callback(err, message), keď správa skončí; posledná správa reťazca je message (takže message.data je to, čo dostal posledný komponent). instance.reconfigure(id, config) zmení konfiguráciu bežiacej inštancie a Flow.remove(id) zastaví FlowStream a zabudne ho. FlowStream je ten istý objekt ako Flow: dva názvy pre správcu.
Komponent je kód, ktorý beží so všetkými právami aplikácie (v tom istom vlákne, pokiaľ schéma nehovorí worker). Nikdy nenačítavajte schému ani komponent, ktorý môže napísať návštevník.
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) });
}