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
}
Другие вопросы по тегам