ForgeTotal.js 5
es

Total.js 5

Construye un flujo de componentes con Flow.load() y ejecútalo con exec()

Total.js 5 · total5@0.0.19 flowflowstreamcomponentsautomation Ejecutada con Total.js 5

Un FlowStream es un programa pequeño hecho de componentes (cajas con entradas y salidas) y conexiones entre ellos. Total.js lo ejecuta dentro de tu aplicación: un mensaje entra en un componente, el componente envía resultados a sus salidas y las conexiones los llevan a los siguientes componentes. El mismo esquema es lo que dibuja el diseñador de Flow de Total.js; aquí está escrito a mano.

Flow.load(schema, [callback]) inicia un FlowStream y da al callback (err, instance). El esquema es un objeto:

  • id y name: el id es la clave en Flow.instances (Flow.instances.demo); sin id se crea uno aleatorio.
  • components: un objeto con el código fuente de cada componente, como texto. El texto es un script, <script total>...</script> (la forma que guarda el diseñador).
  • design: las instancias de los componentes. Cada una tiene un id, el component que usa, su config y connections, un objeto cuyas claves son ids de salida y cuyos valores son listas de { id, index }: la instancia y el id de entrada que reciben lo que se envía a esa salida.
  • variables: valores que los componentes pueden leer.

Un componente es un módulo: exports.id, exports.name, exports.inputs y exports.outputs (listas de { id, name }), exports.config (los valores por defecto) y exports.make = function(instance, config). En make() el componente define instance.message = function($) {}, que recibe cada mensaje: $.data son los datos, $.send(outputid, data) los envía a una salida y $.destroy() termina un mensaje que no va más lejos.

Para usar el flujo desde tu código, instance.exec({ id, data, callback }) envía data a la instancia id y llama a callback(err, message) cuando el mensaje termina; el último mensaje de la cadena es message (así que message.data es lo que recibió el último componente). instance.reconfigure(id, config) cambia la configuración de una instancia en marcha y Flow.remove(id) detiene el FlowStream y lo olvida. FlowStream es el mismo objeto que Flow: dos nombres para el gestor.

Un componente es código que se ejecuta con todos los derechos de la aplicación (en el mismo hilo, salvo que el esquema diga worker). No cargues nunca un esquema o un componente que pueda escribir un visitante.

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) });
}