ForgeTotal.js 5
de

Total.js 5

Einen Fluss aus Komponenten mit Flow.load() bauen und mit exec() ausführen

Total.js 5 · total5@0.0.19 flowflowstreamcomponentsautomation Mit Total.js 5 ausgeführt

Ein FlowStream ist ein kleines Programm aus Komponenten (Kästchen mit Ein- und Ausgängen) und Verbindungen zwischen ihnen. Total.js führt es in deiner Anwendung aus: Eine Nachricht tritt in eine Komponente ein, die Komponente sendet Ergebnisse an ihre Ausgänge, und die Verbindungen tragen sie zu den nächsten Komponenten. Dasselbe Schema zeichnet der Flow-Designer von Total.js; hier ist es von Hand geschrieben.

Flow.load(schema, [callback]) startet einen FlowStream und gibt dem Callback (err, instance). Das Schema ist ein Objekt:

  • id und name: Die ID ist der Schlüssel in Flow.instances (Flow.instances.demo); ohne ID wird eine zufällige erzeugt.
  • components: ein Objekt mit dem Quellcode jeder Komponente als Text. Der Text ist ein Skript, <script total>...</script> (die Form, die der Designer speichert).
  • design: die Instanzen der Komponenten. Jede hat eine id, die component, die sie verwendet, ihre config und connections, ein Objekt, dessen Schlüssel Ausgangs-IDs und dessen Werte Listen von { id, index } sind: die Instanz und die Eingangs-ID, die erhalten, was an diesen Ausgang gesendet wird.
  • variables: Werte, die Komponenten lesen können.

Eine Komponente ist ein Modul: exports.id, exports.name, exports.inputs und exports.outputs (Listen von { id, name }), exports.config (die Standardwerte) und exports.make = function(instance, config). In make() setzt die Komponente instance.message = function($) {}, die jede Nachricht erhält: $.data sind die Daten, $.send(outputid, data) sendet sie an einen Ausgang und $.destroy() beendet eine Nachricht, die nicht weitergeht.

Um den Fluss aus deinem Code zu benutzen, sendet instance.exec({ id, data, callback }) data an die Instanz id und ruft callback(err, message) auf, wenn die Nachricht endet; die letzte Nachricht der Kette ist message (message.data ist also das, was die letzte Komponente erhalten hat). instance.reconfigure(id, config) ändert die Konfiguration einer laufenden Instanz, und Flow.remove(id) stoppt den FlowStream und vergisst ihn. FlowStream ist dasselbe Objekt wie Flow: zwei Namen für den Manager.

Eine Komponente ist Code, der mit allen Rechten der Anwendung läuft (im selben Thread, sofern das Schema nicht worker sagt). Lade niemals ein Schema oder eine Komponente, die ein Besucher schreiben kann.

definitions/flow.js
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;
});
controllers/flow.js
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) });
}