From 9fbe63fc0ef7efc12aecf91a23c431ae424096d1 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 22 May 2018 18:50:49 +0100 Subject: [PATCH] feat: upload screen improvements - display visual feedback for ongoing upload (realtime if possible) - use streaming to solve a set of errors caused by big files and js-ipfs --- add-on/_locales/en/messages.json | 8 ++++++ add-on/src/popup/quick-upload.js | 45 +++++++++++++++++++++++++++----- package.json | 2 ++ yarn.lock | 18 ++++++++++++- 4 files changed, 65 insertions(+), 8 deletions(-) diff --git a/add-on/_locales/en/messages.json b/add-on/_locales/en/messages.json index f433e9940..e95abe836 100644 --- a/add-on/_locales/en/messages.json +++ b/add-on/_locales/en/messages.json @@ -366,6 +366,14 @@ "message": "drop it here to share", "description": "Partial info stats beneath the header on the share files page (quickUpload_drop_it_here)" }, + "quickUpload_state_uploading": { + "message": "Upload in progress..", + "description": "Status label on the share files page (quickUpload_state_uploading)" + }, + "quickUpload_state_buffering": { + "message": "(buffering, please wait)", + "description": "Status label on the share files page (quickUpload_state_buffering)" + }, "quickUpload_options_show": { "message": "upload options", "description": "Button on the share files page (quickUpload_options_show)" diff --git a/add-on/src/popup/quick-upload.js b/add-on/src/popup/quick-upload.js index d8c353435..ff1e66fd7 100644 --- a/add-on/src/popup/quick-upload.js +++ b/add-on/src/popup/quick-upload.js @@ -5,6 +5,8 @@ const browser = require('webextension-polyfill') const choo = require('choo') const html = require('choo/html') const logo = require('./logo') +const fileReaderPullStream = require('filereader-pull-stream') +const byteSize = require('byte-size') document.title = browser.i18n.getMessage('panel_quickUpload') @@ -14,6 +16,7 @@ app.use(quickUploadStore) app.route('*', quickUploadPage) app.mount('#root') +/* disabled in favor of fileReaderPullStream function file2buffer (file) { return new Promise((resolve, reject) => { const reader = new FileReader() @@ -21,6 +24,22 @@ function file2buffer (file) { reader.onerror = reject reader.readAsArrayBuffer(file) }) +} */ + +function progressHandler (doneBytes, totalBytes, state, emitter) { + state.message = browser.i18n.getMessage('quickUpload_state_uploading') + // console.log('Upload progress:', doneBytes) + if (doneBytes && doneBytes > 0) { + const done = byteSize(doneBytes, { units: 'iec', precision: 2 }) + const total = byteSize(totalBytes, { units: 'iec', precision: 2 }) + const percent = ((doneBytes / totalBytes) * 100).toFixed(0) + state.progress = `${done.value} ${done.unit} / ${total.value} ${total.unit} (${percent}%)` + } else { + // This is a gracefull fallback for environments in which progress reporting is delayed + // until entire file/chunk is bufferend into memory (eg. js-ipfs-api) + state.progress = browser.i18n.getMessage('quickUpload_state_buffering') + } + emitter.emit('render') } function quickUploadStore (state, emitter) { @@ -55,25 +74,37 @@ function quickUploadStore (state, emitter) { const { ipfsCompanion } = await browser.runtime.getBackgroundPage() const uploadTab = await browser.tabs.getCurrent() const files = [] + let totalSize = 0 for (let file of event.target.files) { - const buffer = await file2buffer(file) + // const uploadContent = await file2buffer(file) + const uploadContent = fileReaderPullStream(file, {chunkSize: 32 * 1024 * 1024}) files.push({ path: file.name, - content: buffer + content: uploadContent }) + totalSize += file.size } + progressHandler(0, totalSize, state, emitter) + emitter.emit('render') + // TODO: update flag below after wrapping support is released with new js-ipfs + // TODO: also enable multiple file selection in (blocked for js-ipfs for now) + const wrapFlag = (state.wrapWithDirectory || files.length > 1) && state.ipfsNodeType !== 'embedded' const uploadOptions = { - wrapWithDirectory: state.wrapWithDirectory || files.length > 1, + progress: (len) => progressHandler(len, totalSize, state, emitter), + wrapWithDirectory: wrapFlag, pin: state.pinUpload } + console.log('Calling background.ipfsAddAndShow', files) const result = await ipfsCompanion.ipfsAddAndShow(files, uploadOptions) + emitter.emit('render') console.log('Upload result', result) // close upload tab as it will be replaced with a new tab with uploaded content - browser.tabs.remove(uploadTab.id) + await browser.tabs.remove(uploadTab.id) } catch (err) { console.error('Unable to perform quick upload', err) // keep upload tab and display error message in it - state.message = `Unable to upload to IPFS API: ${err}` + state.message = `Unable to upload to IPFS API: ${err.name ? err.name : err}` + state.progress = '' emitter.emit('render') } }) @@ -129,7 +160,7 @@ function quickUploadPage (state, emit) { diff --git a/package.json b/package.json index 2bbafa425..bb914a177 100644 --- a/package.json +++ b/package.json @@ -90,9 +90,11 @@ "web-ext": "2.6.0" }, "dependencies": { + "byte-size": "4.0.3", "choo": "6.8.0", "doc-sniff": "1.0.1", "file-type": "7.6.0", + "filereader-pull-stream": "1.0.0", "ipfs": "0.28.2", "ipfs-api": "21.0.0", "ipfs-css": "0.3.0", diff --git a/yarn.lock b/yarn.lock index 1280ac6f6..1f982df97 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1252,6 +1252,10 @@ bunyan@1.8.12: mv "~2" safe-json-stringify "~1" +byte-size@4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-4.0.3.tgz#b7c095efc68eadf82985fccd9a2df43a74fa2ccd" + byteman@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/byteman/-/byteman-1.3.5.tgz#d6061f7536c7e7c4bcb756037ef9c4c266ec51fd" @@ -3188,6 +3192,12 @@ filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" +filereader-pull-stream@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/filereader-pull-stream/-/filereader-pull-stream-1.0.0.tgz#9cd17b66a5085a8770ab58c2882396b3d4f2e030" + dependencies: + typedarray-to-buffer "^3.1.2" + filesize@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.0.tgz#22d079615624bb6fd3c04026120628a41b3f4efa" @@ -4999,7 +5009,7 @@ is-symbol@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" -is-typedarray@~1.0.0: +is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -9881,6 +9891,12 @@ type-detect@^4.0.0, type-detect@^4.0.5: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" +typedarray-to-buffer@^3.1.2: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + dependencies: + is-typedarray "^1.0.0" + typedarray-to-buffer@~1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-1.0.4.tgz#9bb8ba0e841fb3f4cf1fe7c245e9f3fa8a5fe99c"