Node.js - смотреть вывод порожденного ребенка для конкретного текста
Итак, я использую Node's child_process
модуль для создания экземпляра упругого поиска. Мне нужно проверить, когда сервис работает и resolve()
обещание, когда оно есть. Вот как я делаю это прямо сейчас:
const { join } = require('path');
const { spawn } = require('child_process');
const { createWriteStream } = require('fs');
const { Transform } = require('stream');
function start() {
return new Promise(resolve => {
const outStream = new Transform({
transform(chunk, encoding, callback) {
if (chunk.toString().includes('started')) resolve();
this.push(chunk);
callback();
}
});
const logFile = createWriteStream(join(LOG_DIR, 'es.log'), 'w');
const errorFile = createWriteStream(join(LOG_DIR, 'es.error.log'), 'w');
outStream.pipe(logFile);
child = spawn(
ES_BAT_PATH,
[],
{ cwd: process.cwd(), stdio: ['ignore', outStream, errorFile] }
);
});
}
Это лучший способ? (вероятно, нет), если нет, как я должен идти об этом?
1 ответ
В целом, я бы сказал, что это разумный способ сделать это, но я вижу здесь некоторые проблемы:
- Куски могут не содержать целого слова, которое вы ищете, но они могут находиться между двумя (один кусок заканчивается на
'sta'
и следующий начинается с'rted'
, - После первоначального поиска у вас все еще есть поток преобразования, который вам больше не нужен
- Существует также проблема символов Unicode, но так как вы ищете
' started '
Вы можете опустить это.
Первая проблема будет легко смягчена, если оставить последнюю часть после пробела. Во-вторых, вам нужно отключить преобразование, чтобы вы получили что-то вроде этого:
const { join } = require('path');
const { spawn } = require('child_process');
const { createWriteStream } = require('fs');
const { Readable, PassThrough } = require('stream');
function start() {
return new Promise(resolve => {
const outStream = new PassThrough();
let last;
const lookupStream = new Readable({
read(chunk, encoding, callback) {
const ref = chunk.toString();
if ((last + ref).includes('started')) {
outStream.unpipe(lookupStream);
resolve();
}
last = ref.replace(/^.* /, '');
callback();
}
});
const logFile = createWriteStream(join(LOG_DIR, 'es.log'), 'w');
const errorFile = createWriteStream(join(LOG_DIR, 'es.error.log'), 'w');
outStream.pipe(logFile);
outStream.pipe(lookupStream);
child = spawn(
ES_BAT_PATH,
[],
{ cwd: process.cwd(), stdio: ['ignore', outStream, errorFile] }
);
});
}
Другой вариант заключается в использовании on('data'
слушатель и удалите его после того, как правый кусок найден.
Наконец, мои рамки, scramjet
сделало бы это немного легче
const { join } = require('path');
const { spawn } = require('child_process');
const { createWriteStream } = require('fs');
const { StringStream } = require('scramjet');
function start() {
const outStream = new PassThrough();
const lookupStream = new StringStream();
const logFile = createWriteStream(join(LOG_DIR, 'es.log'), 'w');
const errorFile = createWriteStream(join(LOG_DIR, 'es.error.log'), 'w');
outStream.pipe(logFile);
outStream.pipe(lookupStream);
child = spawn(
ES_BAT_PATH,
[],
{ cwd: process.cwd(), stdio: ['ignore', outStream, errorFile] }
);
return lookupStream
.split('\n') // split line by line
.filter(x => x.includes('started')) // check if line contains "started"
.until(x => outStream.unpipe(lookupStream)) // end stream on first occurence
.run(); // run and resolve on stream end
}