- From: Takeshi Yoshino <tyoshino@google.com>
- Date: Wed, 30 Oct 2013 20:14:13 +0900
- To: Aymeric Vitte <vitteaymeric@gmail.com>
- Cc: Kenneth Russell <kbr@google.com>, Isaac Schlueter <i@izs.me>, Jonas Sicking <jonas@sicking.cc>, Austin William Wright <aaa@bzfx.net>, Domenic Denicola <domenic@domenicdenicola.com>, "public-webapps@w3.org" <public-webapps@w3.org>
- Message-ID: <CAH9hSJYL_e+qpQvo=EMxkOL_t0sEZfqSVrWAkKKvwhJryK1oZA@mail.gmail.com>
On Wed, Oct 23, 2013 at 11:42 PM, Aymeric Vitte <vitteaymeric@gmail.com>wrote: > 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 > close() does this. > 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) > > Should it really be a part of Streams API? How about just making the filter (not Stream itself) returned by WebCrypto reusable and add some method to recycle it? > - pause: pause the stream, do not send eof > > Sorry, what will be paused? Output? > - 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 <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); > }, > ... > ); > > > > -- > Peersm : http://www.peersm.com > node-Tor : https://www.github.com/Ayms/node-Tor > GitHub : https://www.github.com/Ayms > >
Received on Wednesday, 30 October 2013 11:15:06 UTC