From bcdac0d20cf149cf2e3f7dced909bc8ea4d02c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Uhl=C3=AD=C5=99?= Date: Fri, 28 Jan 2022 12:06:56 +0100 Subject: [PATCH] feat: add download progress example --- upload-progress/public/index.html | 15 +++-- upload-progress/src/main.ts | 42 ++++++++++-- upload-progress/src/support.ts | 102 ++++++++++++++++++++++++------ 3 files changed, 131 insertions(+), 28 deletions(-) diff --git a/upload-progress/public/index.html b/upload-progress/public/index.html index 1f574ac..3e11a0c 100644 --- a/upload-progress/public/index.html +++ b/upload-progress/public/index.html @@ -24,7 +24,7 @@ -

Upload progress example

+

Tracking data progress example

Currently bee-js does not natively support upload progress as it is using fetch based HTTP client that unfortunately does not support this feature at the moment (please comment on the appropriate @@ -39,18 +39,25 @@

Upload progress example

Open the browser console to see what is exactly happening! ;-)

-
+

Upload progress

+

- +
-
+
+

Download progress

+
+ + +
+

Logging progress:
diff --git a/upload-progress/src/main.ts b/upload-progress/src/main.ts index 9b77e85..413b257 100644 --- a/upload-progress/src/main.ts +++ b/upload-progress/src/main.ts @@ -4,21 +4,51 @@ import { buildAxiosFetch } from '@lifeomic/axios-fetch' import runExample from './support' /** - * Function `runExample` is where all the supporting and UI handling code is placed. - * The main functionality that this example demonstrates is in the function - * bellow where inputs are: + * Example code for tracking upload progress. * * @param bee Bee instance * @param batchId Postage Batch in order to write data to Bee * @param input File instance that contains the data to be uploaded * @param progressCb Simple callback that anything can be passed into and will be logged into the logging window on the page */ -runExample(async (bee, batchId, input, progressCb) => { +async function uploadProgressExample (bee, batchId, input, progressCb) { const axiosInstance = axios.create({ - onUploadProgress: progressCb + onUploadProgress: progressCb, }) const fetch = buildAxiosFetch(axiosInstance) // @ts-ignore return await bee.uploadFile(batchId, input, undefined, { fetch }) -}) +} + +/** + * Example code for tracking download progress. + * FYI. if you need to track only downloading progress you don't have to use `axios-fetch` as you can do it with Fetch directly as well. + * See for example: https://javascript.info/fetch-progress + * + * @param bee Bee instance + * @param reference Reference to download + * @param progressCb Simple callback that anything can be passed into and will be logged into the logging window on the page + */ +async function downloadProgressExample (bee, reference, progressCb) { + const axiosInstance = axios.create({ + onDownloadProgress: (e) => { + // By default the browser uses gzip and hence does not expose content-length + // to the ProgressEvent which makes the `total` property zero. + // Bee sends separate header with the decompressed size so here we replace it. + // For context see: https://github.com/axios/axios/issues/1591 + e.total = e.target.getResponseHeader('decompressed-content-length') + progressCb(e) + }, + }) + const fetch = buildAxiosFetch(axiosInstance) + + // @ts-ignore + return await bee.downloadFile(reference, undefined, { fetch }) +} + +/** + * Function `runExample` is where all the supporting and UI handling code is placed. + * The main functionality that this example demonstrates are in the functions above. + */ +runExample(uploadProgressExample, downloadProgressExample) diff --git a/upload-progress/src/support.ts b/upload-progress/src/support.ts index 633824a..ca3e379 100644 --- a/upload-progress/src/support.ts +++ b/upload-progress/src/support.ts @@ -1,14 +1,32 @@ /* eslint-disable no-alert,no-console */ import { Bee, BeeDebug, UploadResult } from '@ethersphere/bee-js' -type ProgressCb = (info: any) => void -type ExecutorCb = (bee: Bee, batchId: string, input: File, progressCb: ProgressCb) => Promise +type ProgressCb = (info: any) => void; +type UploadExecutorCb = ( + bee: Bee, + batchId: string, + input: File, + progressCb: ProgressCb, +) => Promise; + +type DownloadExecutorCb = ( + bee: Bee, + reference: string, + progressCb: ProgressCb, +) => Promise; const BEE_URL = 'http://localhost:1633' const BEE_DEBUG_URL = 'http://localhost:1635' -let sendBtn: HTMLButtonElement, - resultLink: HTMLLinkElement, dataInput: HTMLInputElement, createBatchBtn: HTMLButtonElement, bee, beeDebug, logs: HTMLDivElement +let uploadBtn: HTMLButtonElement, + downloadBtn: HTMLButtonElement, + resultLink: HTMLLinkElement, + uploadInput: HTMLInputElement, + referenceInput: HTMLInputElement, + createBatchBtn: HTMLButtonElement, + bee, + beeDebug, + logs: HTMLDivElement async function createBatchGuide (): Promise { if (!confirm('This will create new postage batch that requires on-chain transaction and spending Eth and BZZ! Do you want to continue?')) { @@ -49,38 +67,74 @@ function logProgress (input: any): void { logs.appendChild(logEntry) } -async function formSubmitted (executor: ExecutorCb, e: Event): Promise { +async function uploadFormSubmitted ( + executor: UploadExecutorCb, + e: Event, +): Promise { e.preventDefault() // Lets not submit the form try { - sendBtn.disabled = true - sendBtn.value = 'Uploading...' + uploadBtn.disabled = true + uploadBtn.value = 'Uploading...' logs.innerHTML = '' // Reset logging - - const file = dataInput.files.item(0) - const batchId = (document.getElementById('batchId') as HTMLInputElement).value - const {reference: result} = await executor(bee, batchId, file, logProgress) + const file = uploadInput.files.item(0) + const batchId = (document.getElementById('batchId') as HTMLInputElement) + .value + const { reference: result } = await executor( + bee, + batchId, + file, + logProgress, + ) resultLink.href = `${BEE_URL}/files/${result}` resultLink.innerText = `Uploaded link: ${BEE_URL}/files/${result}` } catch (e) { alert(e) } finally { - sendBtn.disabled = false - sendBtn.value = 'Upload!' + uploadBtn.disabled = false + uploadBtn.value = 'Upload!' + } +} + +async function downloadFormSubmitted ( + executor: DownloadExecutorCb, + e: Event, +): Promise { + e.preventDefault() // Lets not submit the form + + try { + downloadBtn.disabled = true + downloadBtn.value = 'Downloading...' + logs.innerHTML = '' // Reset logging + + const reference = referenceInput.value + await executor(bee, reference, logProgress) + } catch (e) { + alert(e) + } finally { + downloadBtn.disabled = false + downloadBtn.value = 'Download!' } } -export default function runExample (executor: ExecutorCb): void { +export default function runExample ( + uploadExecutor: UploadExecutorCb, + downloadExecutor: DownloadExecutorCb, +): void { bee = new Bee(BEE_URL) beeDebug = new BeeDebug(BEE_DEBUG_URL) - sendBtn = document.getElementById('send') as HTMLButtonElement + uploadBtn = document.getElementById('upload') as HTMLButtonElement + downloadBtn = document.getElementById('download') as HTMLButtonElement resultLink = document.getElementById('result') as HTMLLinkElement logs = document.getElementById('logs') as HTMLDivElement - dataInput = document.getElementById('data') as HTMLInputElement - createBatchBtn = document.getElementById('createBatchBtn') as HTMLButtonElement + uploadInput = document.getElementById('data') as HTMLInputElement + referenceInput = document.getElementById('reference') as HTMLInputElement + createBatchBtn = document.getElementById( + 'createBatchBtn', + ) as HTMLButtonElement if (!createBatchBtn) { throw new Error('Create Batch Button does not exists') @@ -88,5 +142,17 @@ export default function runExample (executor: ExecutorCb): void { createBatchBtn.addEventListener('click', createBatchGuide) - document.getElementById('form')!.addEventListener('submit', formSubmitted.bind(undefined, executor)) + document + .getElementById('uploadForm')! + .addEventListener( + 'submit', + uploadFormSubmitted.bind(undefined, uploadExecutor), + ) + + document + .getElementById('downloadForm')! + .addEventListener( + 'submit', + downloadFormSubmitted.bind(undefined, downloadExecutor), + ) }