Construiește un flux de componente cu Flow.load() și rulează-l cu exec()
Un FlowStream este un program mic făcut din componente (casete cu intrări și ieșiri) și conexiuni între ele. Total.js îl rulează în aplicația ta: un mesaj intră într-o componentă, componenta trimite rezultate la ieșirile ei, iar conexiunile le duc la următoarele componente. Aceeași schemă este ceea ce desenează designerul Flow din Total.js; aici este scrisă de mână.
Flow.load(schema, [callback]) pornește un FlowStream și dă callbackului (err, instance). Schema este un obiect:
idșiname: id-ul este cheia dinFlow.instances(Flow.instances.demo); fără id se creează unul aleatoriu.components: un obiect cu codul sursă al fiecărei componente, ca text. Textul este un script,<script total>...</script>(forma pe care o salvează designerul).design: instanțele componentelor. Fiecare are unid,componentpe care îl folosește,configșiconnections, un obiect ale cărui chei sunt id-uri de ieșire și ale cărui valori sunt liste de{ id, index }: instanța și id-ul de intrare care primesc ce se trimite la acea ieșire.variables: valori pe care componentele le pot citi.
O componentă este un modul: exports.id, exports.name, exports.inputs și exports.outputs (liste de { id, name }), exports.config (valorile implicite) și exports.make = function(instance, config). În make() componenta setează instance.message = function($) {}, care primește fiecare mesaj: $.data sunt datele, $.send(outputid, data) le trimite la o ieșire, iar $.destroy() încheie un mesaj care nu merge mai departe.
Pentru a folosi fluxul din codul tău, instance.exec({ id, data, callback }) trimite data instanței id și apelează callback(err, message) când mesajul se termină; ultimul mesaj al lanțului este message (deci message.data este ce a primit ultima componentă). instance.reconfigure(id, config) schimbă configurația unei instanțe care rulează, iar Flow.remove(id) oprește FlowStream-ul și îl uită. FlowStream este același obiect ca Flow: două nume pentru manager.
O componentă este cod care rulează cu toate drepturile aplicației (în același fir, dacă schema nu spune worker). Nu încărca niciodată o schemă sau o componentă pe care o poate scrie un vizitator.
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) });
}