Repository navigation
Support asynchronous read-file function (aka read-from-stream) - #321
Conversation
Since implementing a good concurrency-handler may be painful we provide a promise-based read-locking one so that asyncReadFileFn is safe to use out-of-the-box. Given that streams-read are often unable to correctly/exactly compute their final amount of bytes to upload, the number of chunks may also be off. We handle this in a safe way via FlowChunk.readBytes: - if read using an async function - and the last chunk read less bytes than usual (including 0) - and the current chunk read no byte - assume that this chunk is in fact superfluous and simulate its completion. Previous discussion on: * flowjs#42 * flowjs#318 (In the long-term Flow.js may have to support the concept of "approximate chunk number")
203555f to
e1d527f
Compare
| } | ||
|
|
||
| if (asyncRead) { | ||
| this.readState = 1; |
There was a problem hiding this comment.
are we still using states? I suggest to remove this old code and rely only on promises. Some breaking changes are welcome.
There was a problem hiding this comment.
Yes.
- The the regular, non-async, readFileFn is untouched and still depends on state
isCompletedepends onchunk.readState === 1so we must still keep updating this value.
There was a problem hiding this comment.
We can remove regular readFileFn anyway, it's too complicated and same thing can be achieved via promises. Isn't it?
|
Hi, 👋 Thanks for your great work, What's the current state of this v3 branch, is it currently "unfinished/break" or "working/need more tests" ? |
|
It's definitely usable (and developing a E2EE project already relying on it, also not -production ready). ES6 + class-split gave us the base. But subsequent code cleaning and improvements are needed:
|
|
Awesome, I will experiment with it and will tell you if I have some feedbacks 👍 |
|
Just to let you know, I've coded an e2ee POC with v3 and it works well 👍 Here is how i did with latest v3 commit: function readFileChunk(file, startByte, endByte) {
return new Promise(resolve => {
const reader = new FileReader();
reader.onload = () => {
const bytes = new Uint8Array(reader.result);
resolve(bytes);
};
const blob = file.slice(startByte, endByte);
reader.readAsArrayBuffer(blob);
});
}
async function encryptFileChunk(plaintextbytes, iv, key) {
let cypherchunkbytes = await window.crypto.subtle.encrypt({name: 'AES-GCM', iv}, key, plaintextbytes);
if(cypherchunkbytes) {
cypherchunkbytes = new Uint8Array(cypherchunkbytes);
return cypherchunkbytes;
}
}
function init() {
const flow = new Flow({
testChunks: false,
target: '/upload',
chunkSize: window.chunkSize,
allowDuplicateUploads: true,
forceChunkSize: false,
simultaneousUploads: 4,
uploadMethod: 'POST',
fileParameterName: 'file',
asyncReadFileFn: async function(flowObj, startByte, endByte, fileType, chunk) {
const plaintextbytes = await readFileChunk(flowObj.file, startByte, endByte);
const cypherbytes = await encryptFileChunk(plaintextbytes, window.ivbytes, window.key);
// Add 16 bytes from initialization vector
chunk.chunkSize = chunk.chunkSize + 16;
const blob = new Blob([cypherbytes], {type: 'application/octet-stream'});
return blob;
}
});
flow.on('fileAdded', function(file) {
// Add 16 bytes from each chunk initialization vector to total encrypted file size
file.size += file.chunks.length * 16;
});
} |
|
Very good. In my case I had the need for an async |
|
@bertrandg Can you add this to our samples folder? It would be great to have it for others to see. It's enough just to make one |
|
@drzraf I don't think I got the whole regular file in memory there.. @AidasK Yes sure, happy to help! :) |
Reroll of #304 (see initial discussion there) based on v3 branch.
See #295, #296 and #300