initial import for Open Source 🎉

This commit is contained in:
Jimmy Zelinskie 2019-11-12 11:09:47 -05:00
parent 1898c361f3
commit 9c0dd3b722
2048 changed files with 218743 additions and 0 deletions

View file

@ -0,0 +1,124 @@
import { DataFileServiceImpl } from './datafile.service.impl';
import { Mock } from 'ts-mocks';
import Spy = jasmine.Spy;
describe("DataFileServiceImpl", () => {
var dataFileServiceImpl: DataFileServiceImpl;
var fileReaderMock: Mock<FileReader>;
var fileReader: FileReader;
beforeEach(() => {
fileReaderMock = new Mock<FileReader>();
fileReader = fileReaderMock.Object;
dataFileServiceImpl = new DataFileServiceImpl(() => fileReader);
});
describe("blobToString", () => {
var data: any;
var blob: Blob;
beforeEach(() => {
data = {hello: "world"};
blob = new Blob([JSON.stringify(data)]);
fileReaderMock.setup(mock => mock.readAsText).is((blob: Blob) => {
fileReaderMock.Object.onload(<any>{target: {result: data}});
});
});
it("calls file reader to read given blob", (done) => {
dataFileServiceImpl.blobToString(blob, (result) => {
expect((<Spy>fileReader.readAsText).calls.argsFor(0)[0]).toEqual(blob);
done();
});
});
it("calls given callback with null if file reader errors", (done) => {
fileReaderMock.setup(mock => mock.readAsText).is((blob: Blob) => {
fileReaderMock.Object.onerror(new Mock<ProgressEvent<FileReader>>().Object);
});
dataFileServiceImpl.blobToString(blob, (result) => {
expect(result).toBe(null);
done();
});
});
it("calls given callback with null if file reader aborts", (done) => {
fileReaderMock.setup(mock => mock.readAsText).is((blob: Blob) => {
fileReaderMock.Object.onabort(new Mock<ProgressEvent<FileReader>>().Object);
});
dataFileServiceImpl.blobToString(blob, (result) => {
expect(result).toBe(null);
done();
});
});
it("calls given callback with result when file reader successfully loads", (done) => {
dataFileServiceImpl.blobToString(blob, (result) => {
expect(result).toBe(data);
done();
});
});
});
describe("arrayToString", () => {
var blob: Blob;
var data: any;
beforeEach(() => {
data = JSON.stringify({hello: "world"});
blob = new Blob([data], {type: 'application/octet-binary'});
fileReaderMock.setup(mock => mock.readAsText).is((blob: Blob) => {
fileReaderMock.Object.onload(<any>{target: {result: data}});
});
});
it("calls file reader to read blob created from given buffer", (done) => {
dataFileServiceImpl.arrayToString(data, (result) => {
expect((<Spy>fileReader.readAsText).calls.argsFor(0)[0]).toEqual(blob);
done();
});
});
it("calls given callback with null if file reader errors", (done) => {
fileReaderMock.setup(mock => mock.readAsText).is((blob: Blob) => {
fileReaderMock.Object.onerror(new Mock<ProgressEvent<FileReader>>().Object);
});
dataFileServiceImpl.arrayToString(data, (result) => {
expect(result).toEqual(null);
done();
});
});
it("calls given callback with null if file reader aborts", (done) => {
fileReaderMock.setup(mock => mock.readAsText).is((blob: Blob) => {
fileReaderMock.Object.onabort(new Mock<ProgressEvent<FileReader>>().Object);
});
dataFileServiceImpl.arrayToString(data, (result) => {
expect(result).toEqual(null);
done();
});
});
it("calls given callback with result when file reader successfully loads", (done) => {
dataFileServiceImpl.arrayToString(data, (result) => {
expect(result).toEqual(data);
done();
});
});
});
describe("readDataArrayAsPossibleArchive", () => {
// TODO
});
describe("downloadDataFileAsArrayBuffer", () => {
// TODO
});
});

View file

@ -0,0 +1,182 @@
import { DataFileService } from './datafile.service';
import { Injectable, Inject } from 'ng-metadata/core';
declare const JSZip: (buf: any) => void;
declare const Zlib: any;
declare const Untar: (uint8Array: Uint8Array) => void;
@Injectable(DataFileService.name)
export class DataFileServiceImpl implements DataFileService {
constructor(@Inject('fileReaderFactory') private fileReaderFactory: () => FileReader) {
}
public blobToString(blob: Blob, callback: (result: string) => void): void {
var reader: FileReader = this.fileReaderFactory();
reader.onload = (event: Event) => callback(event.target['result']);
reader.onerror = (event: Event) => callback(null);
reader.onabort = (event: Event) => callback(null);
reader.readAsText(blob);
}
public arrayToString(buf: any, callback: (result: string) => void): void {
const blob: Blob = new Blob([buf], {type: 'application/octet-binary'});
var reader: FileReader = this.fileReaderFactory();
reader.onload = (event: Event) => callback(event.target['result']);
reader.onerror = (event: Event) => callback(null);
reader.onabort = (event: Event) => callback(null);
reader.readAsText(blob);
}
public readDataArrayAsPossibleArchive(buf: any,
success: (result: any) => void,
failure: (error: any) => void): void {
this.tryAsZip(buf, success, () => {
this.tryAsTarGz(buf, success, () => {
this.tryAsTar(buf, success, failure);
});
});
}
public downloadDataFileAsArrayBuffer($scope: ng.IScope,
url: string,
progress: (percent: number) => void,
error: () => void,
loaded: (uint8array: Uint8Array) => void): void {
var request: XMLHttpRequest = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onprogress = (e) => {
$scope.$apply(() => {
var percentLoaded;
if (e.lengthComputable) {
progress(e.loaded / e.total);
}
});
};
request.onerror = () => {
$scope.$apply(() => {
error();
});
};
request.onload = function() {
if (request.status == 200) {
$scope.$apply(() => {
var uint8array = new Uint8Array(request.response);
loaded(uint8array);
});
return;
}
};
request.send();
}
private getName(filePath: string): string {
var parts: string[] = filePath.split('/');
return parts[parts.length - 1];
}
private tryAsZip(buf: any, success: (result: any) => void, failure: (error?: any) => void): void {
var zip = null;
var zipFiles = null;
try {
zip = new JSZip(buf);
zipFiles = zip.files;
} catch (e) {
failure();
return;
}
var files = [];
for (var filePath in zipFiles) {
if (zipFiles.hasOwnProperty(filePath)) {
files.push({
'name': this.getName(filePath),
'path': filePath,
'canRead': true,
'toBlob': (function(fp) {
return function() {
return new Blob([zip.file(fp).asArrayBuffer()]);
};
}(filePath))
});
}
}
success(files);
}
private tryAsTarGz(buf: any, success: (result: any) => void, failure: (error?: any) => void): void {
var gunzip = new Zlib.Gunzip(new Uint8Array(buf));
var plain = null;
try {
plain = gunzip.decompress();
} catch (e) {
failure();
return;
}
if (plain.byteLength == 0) {
plain = buf;
}
this.tryAsTar(plain, success, failure);
}
private tryAsTar(buf: any, success: (result: any) => void, failure: (error?: any) => void): void {
var collapsePath = function(originalPath) {
// Tar files can contain entries of the form './', so we need to collapse
// those paths down.
var parts = originalPath.split('/');
for (var i = parts.length - 1; i >= 0; i--) {
var part = parts[i];
if (part == '.') {
parts.splice(i, 1);
}
}
return parts.join('/');
};
try {
var handler = new Untar(new Uint8Array(buf));
handler.process((status, read, files, err) => {
switch (status) {
case 'error':
failure(err);
break;
case 'done':
var processed = [];
for (var i = 0; i < files.length; ++i) {
var currentFile = files[i];
var path = collapsePath(currentFile.meta.filename);
if (path == '' || path == 'pax_global_header') { continue; }
processed.push({
'name': this.getName(path),
'path': path,
'canRead': true,
'toBlob': (function(file) {
return function() {
return new Blob([file.buffer], {type: 'application/octet-binary'});
};
}(currentFile))
});
}
success(processed);
break;
}
});
} catch (e) {
failure();
}
}
}

View file

@ -0,0 +1,48 @@
/**
* Service which provides helper methods for downloading a data file from a URL, and extracting
* its contents as .tar, .tar.gz, or .zip file. Note that this service depends on external
* library code in the lib/ directory:
* - jszip.min.js
* - Blob.js
* - zlib.js
*/
export abstract class DataFileService {
/**
* Convert a blob to a string.
* @param blob The blob to convert.
* @param callback The success callback given converted blob.
*/
public abstract blobToString(blob: Blob, callback: (result: string) => void): void;
/**
* Convert array to string.
* @param buf The array buffer to convert.
* @param callback The success callback given converted array buffer.
*/
public abstract arrayToString(buf: any, callback: (result: string) => void): void;
/**
* Determine if a given data array is an archive file.
* @param buf The data array to check.
* @param success The success callback if the given array is an archive file, given the file contents.
* @param failure The failure callback if the given array is not an archive file, given the error message.
*/
public abstract readDataArrayAsPossibleArchive(buf: any,
success: (result: any) => void,
failure: (error: any) => void): void;
/**
* Download a file into an array buffer while tracking progress.
* @param $scope An AngularJS $scope instance.
* @param url The URL of the file to be downloaded.
* @param progress The callback for download progress.
* @param error The error callback.
* @param loaded The success callback given the downloaded array buffer.
*/
public abstract downloadDataFileAsArrayBuffer($scope: ng.IScope,
url: string,
progress: (percent: number) => void,
error: () => void,
loaded: (uint8array: Uint8Array) => void): void;
}