Your filter idea seems to be equivalent to a createStream that I suggested some time ago (like node), what about:

var encryptionPromise = crypto.subtle.encrypt(aesAlgorithmEncrypt, aesKey, sourceStream).createStream();

So you don't need to modify the APIs where you can not specify the responseType.

I was thinking to add stop/resume and pause/unpause:

- stop: insert eof in the stream
Example : finalize the hash when eof is received

- resume: restart from where the stream stopped
Example : restart the hash from the state the operation was before receiving eof (related to Issue22 in WebCrypto that was closed without any solution, might imply to clone the state of the operation)

- pause: pause the stream, do not send eof

- unpause: restart the stream

And flow control should be back and explicit, not sure right now how to define it but I think it's impossible for a js app to do a precise flow control, and for existing APIs like WebSockets it's not easy to control the flow and avoid in some situations to overload the UA.

Regards,

Aymeric

Le 21/10/2013 13:14, Takeshi Yoshino a écrit :
Sorry for blank of ~2 weeks.

On Fri, Oct 4, 2013 at 5:57 PM, Aymeric Vitte <[email protected] <mailto:[email protected]>> 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);
    },
    ...
  );


--
Peersm : http://www.peersm.com
node-Tor : https://www.github.com/Ayms/node-Tor
GitHub : https://www.github.com/Ayms

Reply via email to