node.js gerando um processo filho interativamente com streams stdout e stderr separados
Considere o seguinte programa C (test.c):
#include <stdio.h>
int main() {
printf("string out 1\n");
fprintf(stderr, "string err 1\n");
getchar();
printf("string out 2\n");
fprintf(stderr, "string err 2\n");
fclose(stdout);
}
Qual deve imprimir uma linha para stdout, uma linha para stderr, então espere pela entrada do usuário, então outra linha para stdout e outra linha para stderr. Muito básico! Quando compilado e executado na linha de comando, a saída do programa é concluída (a entrada do usuário é recebida para getchar ()):
$ ./test
string out 1
string err 1
string out 2
string err 2
Ao tentar gerar este programa como um processo filho usando o nodejs com o seguinte código:
var TEST_EXEC = './test';
var spawn = require('child_process').spawn;
var test = spawn(TEST_EXEC);
test.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
test.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
// Simulate entering data for getchar() after 1 second
setTimeout(function() {
test.stdin.write('\n');
}, 1000);
A saída aparece assim:
$ nodejs test.js
stderr: string err 1
stdout: string out 1
string out 2
stderr: string err 2
Muito diferente da saída como visto ao executar ./test no terminal. Isso ocorre porque o programa ./test não está sendo executado em um shell interativo quando gerado por nodejs. O fluxo stdout test.c é armazenado em buffer e quando executado em um terminal assim que um \ n é atingido, o buffer é liberado, mas quando gerado dessa maneira com o nó, o buffer não é liberado. Isso pode ser resolvido pela descarga da stdout após cada impressão ou pela alteração do fluxo de stdout para que ele fique sem buffer, liberando tudo imediatamente. Assumindo que a fonte test.c não está disponível ou modificável, nenhuma das duas opções mencionadas pode ser implementada.
Comecei então a analisar a emulação de um shell interativo, há o pty.js (pseudo terminal) que faz um bom trabalho, por exemplo:
var spawn = require('pty.js').spawn;
var test = spawn(TEST_EXEC);
test.on('data', function (data) {
console.log('data: ' + data);
});
// Simulate entering data for getchar() after 1 second
setTimeout(function() {
test.write('\n');
}, 1000);
Quais saídas:
$ nodejs test.js
data: string out 1
string err 1
data:
data: string out 2
string err 2
No entanto, ambos stdout e stderr são mesclados juntos (como você veria ao executar o programa em um terminal) e não consigo pensar em uma maneira de separar os dados dos fluxos.
Então a questão ..
Existe alguma maneira de usar o nodejs para obter a saída como visto ao executar o ./test sem modificar o código do test.c? Por emulação de terminal ou desova de processo ou qualquer outro método?
Felicidades!