Re: Overlap between StreamReader and FileReader

Sorry for blank of ~2 weeks.

On Fri, Oct 4, 2013 at 5:57 PM, Aymeric Vitte <vitteaymeric@gmail.com>wrote:

>  I am still not very familiar with promises, but if I take your preceeding
> example:
>
>
> var sourceStream = xhr.response;
> var resultStream = new Stream();
> var fileWritingPromise = fileWriter.write(resultStream);
> var encryptionPromise = crypto.subtle.encrypt(aesAlgorithmEncrypt, aesKey,
> sourceStream, resultStream);
>  Promise.all(fileWritingPromise, encryptionPromise).then(
>   ...
> );
>

I made a mistake. The argument of Promise.all should be an Array. So,
[fileWritingPromise, encryptionPromise].


>
>
> shoud'nt it be more something like:
>
> var sourceStream = xhr.response;
> var encryptionPromise = crypto.subtle.encrypt(aesAlgorithmEncrypt, aesKey);
> var resultStream=sourceStream.pipe(encryptionPromise);
> var fileWritingPromise = fileWriter.write(resultStream);
>  Promise.all(fileWritingPromise, encryptionPromise).then(
>   ...
> );
>

Promises just tell the user completion of each operation with some value
indicating the result of the operation. It's not destination of data.

Do you think it's good to create objects representing each encrypt
operation? So, some objects called "filter" is introduced and the code
would be like:

var pipeToFilterPromise;

var encryptionFilter;
var fileWriter;

xhr.onreadystatechange = function() {
  ...
  } else if (this.readyState == this.LOADING) {
     if (this.status != 200) {
      ...
    }

    var sourceStream = xhr.response;

    encryptionFilter =
crypto.subtle.createEncryptionFilter(aesAlgorithmEncrypt, aesKey);
    // Starts the filter.
    var encryptionPromise = encryptionFilter.encrypt();
    // Also starts pouring data but separately from promise creation.
    pipeToFilterPromise = sourceStream.pipe(encryptionFilter);

    fileWriter = ...;
    // encryptionFilter works as data producer for FileWriter.
    var fileWritingPromise = fileWriter.write(encryptionFilter);

    // Set only handler for rejection now.
    pipeToFilterPromise.catch(
      function(result) {
        xhr.abort();
        encryptionFilter.abort();
        fileWriter.abort();
      }
    );

    encryptionPromise.catch(
      function(result) {
        xhr.abort();
        fileWriter.abort();
      }
    );

    fileWritingPromise.catch(
      function(result) {
        xhr.abort();
        encryptionFilter.abort();
      }
    );

    // As encryptionFilter will be (successfully) closed only
    // when XMLHttpRequest and pipe() are both successful.
    // So, it's ok to set handler for fulfillment now.
    Promise.all([encryptionPromise, fileWritingPromise]).then(
      function(result) {
        // Done everything successfully!
        // We come here only when encryptionFilter is close()-ed.
        fileWriter.close();
        processFile();
      }
    );
  } else if (this.readyState == this.DONE) {
     if (this.status != 200) {
      encryptionFilter.abort();
      fileWriter.abort();
    } else {
      // Now we know that XHR was successful.
      // Let's close() the filter to finish encryption
      // successfully.
      pipeToFilterPromise.then(
        function(result) {
          // XMLHttpRequest closes sourceStream but pipe()
          // resolves pipeToFilterPromise without closing
          // encryptionFilter.
          encryptionFilter.close();
        }
      );
    }
  }
};
xhr.send();

encryptionFilter has the same interface as normal stream but encrypts piped
data. Encrypted data is readable from it. It has special methods, encrypt()
and abort().

processFile() is hypothetical function must be called only when all of
loading, encryption and saving to file were successful.


>
> or
>
> var sourceStream = xhr.response;
> var encryptionPromise = crypto.subtle.encrypt(aesAlgorithmEncrypt, aesKey);
> var hashPromise = crypto.subtle.digest(hash);
> var resultStream = sourceStream.pipe([encryptionPromise,hashPromise]);
> var fileWritingPromise = fileWriter.write(resultStream);
> Promise.all([fileWritingPromise, resultStream]).then(
>   ...
> );
>
>
and this should be:

var sourceStream = xhr.response;

encryptionFilter =
crypto.subtle.createEncryptionFilter(aesAlgorithmEncrypt, aesKey);
var encryptionPromise = encryptionFilter.crypt();

hashFilter = crypto.subtle.createDigestFilter(hash);
var hashPromise = hashFilter.digest();

pipeToFiltersPromise = sourceStream.pipe([encryptionFilter, hashFilter]);

var encryptedDataWritingPromise = fileWriter.write(encryptionFilter);

var hashWritingPromise =
  Promise.all([encryptionPromise, encryptedDataWritingPromise]).then(
    function(result) {
      return fileWriter.write(hashFilter)
    },
    ...
  );

Promise.all([hashPromise, hashWritingPromise]).then(
  function(result) {
    fileWriter.close();
    processFile();
  },
  ...
);

Or, we can also choose to let the writer API to create a special object
that has the Stream interface for receiving input and then let
encryptionFilter and hashFilter to pipe() to it.

...
pipeToFiltersPromise = sourceStream.pipe([encryptionFilter, hashFilter]);
var streamForFileWrite = fileWriter.createStreamForWrite(encryptionFilter);
var encryptedDataWritingPromise = encryptionFilter.pipe(streamForFileWrite);
 var hashWritingPromise =
  Promise.all([encryptionPromise, encryptedDataWritingPromise]).then(
    function(result) {
      return hashFilter.pipe(streamForWrite);
    },
    ...
  );

Received on Monday, 21 October 2013 11:15:41 UTC