Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add download progress example #25

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions upload-progress/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
</style>
</head>
<body>
<h1>Upload progress example</h1>
<h1>Tracking data progress example</h1>

Currently bee-js does not natively support upload progress as it is using <code>fetch</code> based HTTP client
that unfortunately does not support this feature at the moment (please comment on the appropriate
Expand All @@ -39,18 +39,25 @@ <h1>Upload progress example</h1>
<strong>Open the browser console to see what is exactly happening! ;-)</strong>

<br><br>
<form id="form">
<h3>Upload progress</h3>
<form id="uploadForm">
<input id="batchId" type="text" placeholder="Postage Batch ID" required size="64">
<button id="createBatchBtn" type="button">Create Postage Batch</button>
<br>
<input id="data" type="file"><br>
<input id="send" type="submit" value="Upload!">
<input id="upload" type="submit" value="Upload!">
</form>

<div>
<a href="#" id="result" target="_blank"></a>
</div>

<br>
<h3>Download progress</h3>
<form id="downloadForm">
<input id="reference" type="text" placeholder="Reference" required size="64">
<input id="download" type="submit" value="Download!">
</form>

<br><br>
Logging progress:
<div id="content">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<div id="content">
<div id="logs">

Expand Down
42 changes: 36 additions & 6 deletions upload-progress/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Comment on lines +40 to +41
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an assignment to private variable.

Suggested change
e.total = e.target.getResponseHeader('decompressed-content-length')
progressCb(e)
progressCb({...e, total: e.target.getResponseHeader('decompressed-content-length')})

},
})
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)
104 changes: 85 additions & 19 deletions upload-progress/src/support.ts
Original file line number Diff line number Diff line change
@@ -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<UploadResult>
type ProgressCb = (info: any) => void;
type UploadExecutorCb = (
bee: Bee,
batchId: string,
input: File,
progressCb: ProgressCb,
) => Promise<UploadResult>;

type DownloadExecutorCb = (
bee: Bee,
reference: string,
progressCb: ProgressCb,
) => Promise<UploadResult>;

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<void> {
if (!confirm('This will create new postage batch that requires on-chain transaction and spending Eth and BZZ! Do you want to continue?')) {
Expand Down Expand Up @@ -49,44 +67,92 @@ function logProgress (input: any): void {
logs.appendChild(logEntry)
}

async function formSubmitted (executor: ExecutorCb, e: Event): Promise<void> {
async function uploadFormSubmitted (
executor: UploadExecutorCb,
e: Event,
): Promise<void> {
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<void> {
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('content') as HTMLDivElement
dataInput = document.getElementById('data') as HTMLInputElement
createBatchBtn = document.getElementById('createBatchBtn') as HTMLButtonElement
logs = document.getElementById('logs') as HTMLDivElement
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')
}

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),
)
}