Sestavte tok komponent pomocí Flow.load() a spusťte jej pomocí exec()
FlowStream je malý program složený z komponent (políček se vstupy a výstupy) a spojení mezi nimi. Total.js jej spouští ve vaší aplikaci: zpráva vstoupí do jedné komponenty, komponenta pošle výsledky na své výstupy a spojení je přenesou do dalších komponent. Stejné schéma kreslí návrhář Flow v Total.js; zde je napsáno ručně.
Flow.load(schema, [callback]) spustí FlowStream a dá callbacku (err, instance). Schéma je objekt:
idaname: id je klíč vFlow.instances(Flow.instances.demo); bez id se vytvoří náhodné.components: objekt se zdrojovým kódem každé komponenty jako textem. Text je skript,<script total>...</script>(forma, kterou ukládá návrhář).design: instance komponent. Každá máid,component, který používá, svéconfigaconnections, objekt, jehož klíče jsou id výstupů a hodnoty jsou seznamy{ id, index }: instance a id vstupu, které dostanou to, co se pošle na daný výstup.variables: hodnoty, které komponenty mohou číst.
Komponenta je modul: exports.id, exports.name, exports.inputs a exports.outputs (seznamy { id, name }), exports.config (výchozí hodnoty) a exports.make = function(instance, config). V make() komponenta nastaví instance.message = function($) {}, která přijímá každou zprávu: $.data jsou data, $.send(outputid, data) je pošle na výstup a $.destroy() ukončí zprávu, která nejde dál.
K použití toku z vašeho kódu instance.exec({ id, data, callback }) pošle data instanci id a zavolá callback(err, message), když zpráva skončí; poslední zpráva řetězce je message (takže message.data je to, co dostala poslední komponenta). instance.reconfigure(id, config) změní konfiguraci běžící instance a Flow.remove(id) zastaví FlowStream a zapomene jej. FlowStream je tentýž objekt jako Flow: dva názvy pro správce.
Komponenta je kód, který běží se všemi právy aplikace (ve stejném vlákně, pokud schéma neříká worker). Nikdy nenačítejte schéma ani komponentu, kterou může napsat návštěvní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) });
}