Created
July 14, 2020 12:13
-
-
Save rndazurescript/fda86d7ad140a7c1de5e3274c80a1397 to your computer and use it in GitHub Desktop.
Old blob uploader in typescript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module UpZure.Blob { | |
// An uploader client | |
// based on https://msdn.microsoft.com/en-us/library/azure/mt427365.aspx | |
// Limitations taken from https://msdn.microsoft.com/en-us/library/azure/dd135726.aspx | |
export class BlobUploader { | |
private MAX_BLOB_SIZE = 4 * 1024 * 1024;//Each file will be split in 4Mb (used to be 256 KB). | |
private BLOCK_NAME_PREFIX = "blk-"; | |
private MAX_BLOCKS = 50000;//a maximum of 50,000 blocks | |
private fileReader: FileReader; | |
private handleError(desc: string, err: string) { | |
console.error(desc, err); | |
} | |
private handlePercentCompleted(value: string) { | |
console.info("Completed " + value + "%"); | |
} | |
private handleFinish() { | |
console.info("Finished uploading"); | |
} | |
constructor(private url: string, private file: File) { | |
// Check if all the File APIs are supported. | |
if (!(File && FileReader && FileList && Blob)) { | |
throw new Error('The File APIs are not fully supported in this browser.'); | |
} | |
this.totalSize = file.size; | |
this.fileReader = new FileReader(); | |
this.fileReader.onloadend = (evt: IFileReaderProgressEvent) => { | |
if (evt.target.readyState == FileReaderReadyState.DONE) { | |
var uri = url + '&comp=block&blockid=' + this.blockIds[this.blockIds.length - 1]; | |
var requestData = new Uint8Array(evt.target.result); | |
$.ajax({ | |
url: uri, | |
type: "PUT", | |
data: requestData, | |
processData: false, | |
beforeSend: function (xhr) { | |
xhr.setRequestHeader('x-ms-blob-type', 'BlockBlob'); | |
}, | |
success: (data, status) => { | |
// update current indexes | |
this.currentFilePointer += requestData.length; | |
this.remainingBytes -= requestData.length; | |
// Calculate percent | |
var percentComplete = ((this.currentFilePointer / this.totalSize) * 100).toFixed(2); | |
this.handlePercentCompleted(percentComplete); | |
// And move along | |
this.processRemainingFile(); | |
}, | |
error: (xhr, desc, err) => { | |
this.handleError(desc, err); | |
} | |
}); | |
} | |
}; | |
} | |
// The size of the file to upload | |
private totalSize: number = 0; | |
// The bytes left to upload | |
private remainingBytes: number = 0; | |
// Current point in the file | |
private currentFilePointer: number = 0; | |
// The ids of the uploaded blocks | |
private blockIds: string[] = []; | |
// Flag to stop processing | |
private stopProcessing: boolean = false; | |
private getNextBlockId(): string { | |
// We need a string | |
var currentId = this.blockIds.length + ''; | |
// We pad it with 0's (50k is the max number so) | |
currentId = "00000".substring(currentId.length) + currentId; | |
return this.BLOCK_NAME_PREFIX + currentId; | |
} | |
private processRemainingFile() { | |
if (this.stopProcessing) return; | |
if (this.remainingBytes > 0) { | |
var bytesToRead = this.MAX_BLOB_SIZE; | |
// If close the end | |
if (this.remainingBytes < bytesToRead) { | |
bytesToRead = this.remainingBytes; | |
} | |
// Get a slice of the file | |
var fileContent = this.file.slice(this.currentFilePointer, this.currentFilePointer + bytesToRead); | |
var blockName = this.getNextBlockId(); | |
this.blockIds.push(btoa(blockName)); | |
// and read it | |
this.fileReader.readAsArrayBuffer(fileContent); | |
} else { | |
this.commitBlockList(); | |
} | |
} | |
private commitBlockList() { | |
var uri = this.url + '&comp=blocklist'; | |
var requestBody = '<?xml version="1.0" encoding="utf-8"?><BlockList>'; | |
for (var i = 0; i < this.blockIds.length; i++) { | |
requestBody += '<Latest>' + this.blockIds[i] + '</Latest>'; | |
} | |
requestBody += '</BlockList>'; | |
$.ajax({ | |
url: uri, | |
type: "PUT", | |
data: requestBody, | |
beforeSend: (xhr) => { | |
xhr.setRequestHeader('x-ms-blob-content-type', this.file.type); | |
xhr.setRequestHeader('Content-Length', ''+ requestBody.length); | |
}, | |
success: (data, status) => { | |
this.handleFinish(); | |
}, | |
error: (xhr, desc, err) => { | |
this.handleError(desc, err); | |
} | |
}); | |
} | |
public Upload(finishCb: ISuccessCallback = null, errorCb: IErrorCallback = null, notifyPercent: INotifyPercent = null) { | |
if (finishCb != null) { | |
this.handleFinish = finishCb; | |
} | |
if (errorCb != null) { | |
this.handleError = errorCb; | |
} | |
if (notifyPercent != null) { | |
this.handlePercentCompleted = notifyPercent; | |
} | |
this.remainingBytes = this.totalSize; | |
this.currentFilePointer = 0; | |
this.blockIds = []; | |
this.stopProcessing = false; | |
this.processRemainingFile(); | |
} | |
public CancelUpload() { | |
this.stopProcessing = true; | |
} | |
} | |
interface IFileReaderProgressEvent extends ProgressEvent { | |
target: FileReaderEventTarget | |
} | |
/* File API Extensions*/ | |
interface FileReaderEventTarget extends EventTarget { | |
//https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readyState | |
// EMPTY : 0 : No data has been loaded yet. | |
// LOADING: 1 : Data is currently being loaded. | |
// DONE : 2 : The entire read request has been completed. | |
readyState: number; | |
result: ArrayBuffer; | |
} | |
enum FileReaderReadyState { | |
EMPTY = 0, | |
LOADING = 1, | |
DONE = 2 | |
} | |
export interface INotifyPercent { | |
(value: string): void; | |
} | |
export interface ISuccessCallback { | |
(): void; | |
} | |
export interface IErrorCallback { | |
(desc: string, err: string): void; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment