в обещании - PullRequest
       47

в обещании

0 голосов
/ 30 сентября 2019

Я делаю скрипт для автоматической загрузки файла резервной копии (на Backblaze) ...

Создаю скрипт, который загружает полный файл в const, разбивает строку и загружает каждую часть, когда размер файлаувеличивается (с 1 до более 3 ГБ) мой скрипт вылетает.

Я пытался переписать скрипт полностью асинхронно.

Я пишу это:

async getFileInfoAndUploadPart(path, sizeChunk = 1024) {
    const info = {
      sha1: null,
      size: 0,
      partNumber: 0,
      partSha1: {},
    };
    return new Promise(resolve => {
      const shasumGlobal = crypto.createHash('sha1');
      console.log(path, sizeChunk);
      const input = fs.createReadStream(path);
      input.on('readable', () => {
        console.log('1');
        let chunk;
        while ((chunk = input.read(sizeChunk)) !== null) {
          console.log('2');
          const tempShasum = crypto.createHash('sha1');
          shasumGlobal.update(chunk);
          tempShasum.update(chunk);
          info.partNumber += 1;
          info.partSha1[info.partNumber] = tempShasum.digest('hex');
        }
        console.log('3');
        info.sha1 = shasumGlobal.digest('hex');
        resolve(info);
      });
    });
  }

Но обещание разрешается до while: / Какие правильные методычтобы сделать это, пока закончите, прежде чем вернуть мое обещание?

(я собираюсь вызвать асинхронную функцию для загрузки каждой части)

Редактировать

Наконец, я использую эти методы:

    async getFileInfoAndUploadPart(path, sizeChunk = 1024, fileId = 'xxx') {
    return new Promise(resolve => {
      const info = {
        fileId: fileId,
        sha1: null,
        size: 0,
        partNumber: 0,
        partSha1: {},
      };
      const input = fs.createReadStream(path, { highWaterMark: sizeChunk });
      const shasumGlobal = crypto.createHash('sha1');

      input.on('data', async dataChunk => {
        const shasumPart = await crypto.createHash('sha1');
        await shasumPart.update(dataChunk);
        await shasumGlobal.update(dataChunk);

        info.partNumber += 1;
        info.partSha1[info.partNumber] = shasumPart.digest('hex');
      });

      input.on('end', () => {
        info.sha1 = shasumGlobal.digest('hex');
        resolve(info);
      });
    });
  }

РЕДАКТИРОВАТЬ 2:

Код выше не работает хорошо ...

Во-первых, вам нужно сделатьпауза потока при воспроизведении данных и возобновление потока при обработке следующей части ...

Вторая ошибка: если вы попробуете этот код с 10-октетным файлом и используете 5-октановый блок...

Вы запускаете событие 'data' в первый раз => ok

Вы запускаете событие 'data' во второй раз => ok

Вы запускаетесобытие 'end' => ok ...

Но если вы хотите разделить поток на 3 части (Math.ceil (fileSize / chunkSize) => 4 + 4 + 2, толькопоследний номиналкороче)

Вы запускаете событие 'data' в первый раз => ok

Вы запускаете событие 'data' во второй раз => ok

Вы запускаете событие 'data' в третий раз, но вы достигаете конца потока, поэтому вы запускаете событие 'end' одновременно ...

Я не нашел ни одногорешение для запуска 'end' события только после того, как моя логика 'data' будет завершена ...

Так что я думаю, что предварительно вычисляю количество чанка и реализую свою логику 'end' в событии 'data'когда я в последний кусок ...

1 Ответ

0 голосов
/ 01 октября 2019
async getFileInfoAndUploadPart(path, sizeChunk = 1024, fileId = 'xxx') {
    return new Promise(resolve => {
      const stats = fs.statSync(path);
      const info = {
        fileId: fileId,
        sha1: null,
        size: 0,
        partNumber: 0,
        partNumberTheoretical: Math.ceil(stats.size/sizeChunk),
        partSha1: {},
      };

      const input = fs.createReadStream(path, { highWaterMark: sizeChunk });
      const shasumGlobal = crypto.createHash('sha1');

      input.on('data', async dataChunk => {
        input.pause();
        const shasumPart = crypto.createHash('sha1');
        shasumPart.update(dataChunk);
        shasumGlobal.update(dataChunk);
        info.partNumber += 1;
        info.partSha1[info.partNumber] = shasumPart.digest('hex');

        // force passe copy of info obj.
        // await this.uploadWithRetry(dataChunk, { ...info }, parameters.getConfig('maxRetry'), parameters.getConfig('waitBeforeRetry'));

        await this.debug().then(() => {
          console.log({ ... info });
        });
        input.resume();

        if (info.partNumber === info.partNumberTheoretical) {
          console.log('end');
          info.sha1 = shasumGlobal.digest('hex');
          resolve(info);
        }
      });
    });
  }

PS: отладка этой функции

async debug(time = 1000) {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve();
      }, time);
    });
  };
...