Skip to content

Commit

Permalink
Merge pull request #29 from cloudnc/demo/switch-to-md5
Browse files Browse the repository at this point in the history
demo: Use md5 implementation as crypto.subtle is uncertain about it's use of threads.
  • Loading branch information
zakhenry authored Aug 17, 2019
2 parents 2f4c850 + 4fbf655 commit a2ddadb
Show file tree
Hide file tree
Showing 13 changed files with 48 additions and 91 deletions.
18 changes: 5 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ import { Observable } from 'rxjs';
import { fromWorkerPool } from 'observable-webworker';

export function computeHashes(files: File[]): Observable<string> {
return fromWorkerPool<File, string>(() => new Worker('./transferable.worker', { type: 'module' }), files);
return fromWorkerPool<File, string>(() => new Worker('./worker-pool-hash.worker', { type: 'module' }), files);
}

```
Expand All @@ -200,23 +200,15 @@ export function computeHashes(files: File[]): Observable<string> {
```ts
// src/readme/worker-pool-hash.worker.ts

import * as md5 from 'js-md5';
import { DoWorkUnit, ObservableWorker } from 'observable-webworker';
import { Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { DoWorkUnit, ObservableWorker } from '../../projects/observable-webworker/src/public-api';
import { map } from 'rxjs/operators';

@ObservableWorker()
export class WorkerPoolHashWorker implements DoWorkUnit<File, string> {
public workUnit(input: File): Observable<string> {
return this.readFileAsArrayBuffer(input).pipe(
switchMap(arrayBuffer => crypto.subtle.digest('SHA-256', arrayBuffer)),
map((digest: ArrayBuffer) => this.arrayBufferToHex(digest)),
);
}

private arrayBufferToHex(buffer: ArrayBuffer): string {
return Array.from(new Uint8Array(buffer))
.map(value => value.toString(16).padStart(2, '0'))
.join('');
return this.readFileAsArrayBuffer(input).pipe(map(arrayBuffer => md5(arrayBuffer)));
}

private readFileAsArrayBuffer(blob: Blob): Observable<ArrayBuffer> {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@angular/platform-browser-dynamic": "~8.0.0",
"@angular/router": "~8.0.0",
"google-charts": "2.0.0",
"js-md5": "0.7.3",
"rxjs": "~6.4.0",
"tslib": "^1.9.0",
"zone.js": "~0.9.1"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import * as md5 from 'js-md5';
import { ObservableWorker } from 'observable-webworker';
import { Observable, ReplaySubject, Subject } from 'rxjs';
import { map, switchMap, take, tap } from 'rxjs/operators';
import { map, take, tap } from 'rxjs/operators';
import { DoWorkUnit } from '../../projects/observable-webworker/src/lib/observable-worker.types';
import { FileHashEvent, ShaWorkerMessage, Thread } from './sha-worker.types';
import { FileHashEvent, HashWorkerMessage, Thread } from './hash-worker.types';

@ObservableWorker()
export class SecureHashAlgorithmWorker implements DoWorkUnit<File, ShaWorkerMessage> {
public workUnit(input: File): Observable<ShaWorkerMessage> {
const output$: Subject<ShaWorkerMessage> = new ReplaySubject(Infinity);
export class FileHashWorker implements DoWorkUnit<File, HashWorkerMessage> {
public workUnit(input: File): Observable<HashWorkerMessage> {
const output$: Subject<HashWorkerMessage> = new ReplaySubject(Infinity);

const log = (fileEventType: FileHashEvent, message: string): ShaWorkerMessage => ({
const log = (fileEventType: FileHashEvent, message: string): HashWorkerMessage => ({
file: input.name,
timestamp: new Date(),
message,
Expand All @@ -21,9 +22,9 @@ export class SecureHashAlgorithmWorker implements DoWorkUnit<File, ShaWorkerMess
this.readFileAsArrayBuffer(input)
.pipe(
tap(() => output$.next(log(FileHashEvent.FILE_READ, `read file`))),
switchMap(arrayBuffer => crypto.subtle.digest('SHA-256', arrayBuffer)),
map(arrayBuffer => md5(arrayBuffer)),
tap(() => output$.next(log(FileHashEvent.HASH_COMPUTED, `hashed file`))),
map((digest: ArrayBuffer): ShaWorkerMessage => log(null, `hash result: ${this.arrayBufferToHex(digest)}`)),
map((digest: string): HashWorkerMessage => log(null, `hash result: ${digest}`)),
tap(out => {
output$.next(out);
output$.complete();
Expand All @@ -35,16 +36,6 @@ export class SecureHashAlgorithmWorker implements DoWorkUnit<File, ShaWorkerMess
return output$;
}

private arrayBufferToHex(buffer: ArrayBuffer): string {
return Array.from(new Uint8Array(buffer))
.map(value => {
const hexCode = value.toString(16);
const paddedHexCode = hexCode.padStart(2, '0');
return paddedHexCode;
})
.join('');
}

private readFileAsArrayBuffer(blob: Blob): Observable<ArrayBuffer> {
return new Observable(observer => {
if (!(blob instanceof Blob)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export interface ShaWorkerMessage {
export interface HashWorkerMessage {
file?: string;
timestamp: Date;
message: string;
Expand Down
6 changes: 3 additions & 3 deletions src/app/multiple-worker-pool/log-line/log-line.component.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
import { ShaWorkerMessage } from '../../sha-worker.types';
import { HashWorkerMessage } from '../../hash-worker.types';

@Component({
selector: 'app-log-line',
templateUrl: './log-line.component.html',
styleUrls: ['./log-line.component.scss'],
// changeDetection: ChangeDetectionStrategy.OnPush,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LogLineComponent implements OnInit {
@Input() message: ShaWorkerMessage;
@Input() message: HashWorkerMessage;
@Input() files: string[];

public color: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<h2>Multiple Worker Pool</h2>
<h3 *ngIf="status$ | async as status">({{ status }})</h3>

<p>Select multiple files of varying sizes to compute SHA-256 sum of, in pool of webworkers:</p>
<p>Select multiple files of varying sizes to compute MD5 sum of, in pool of webworkers:</p>

<section>
<small>(No files are uploaded; they're kept entirely within your browser)</small>
</section>
<input type="file" multiple (change)="calculateSha256Multiple($event)" />
<input type="file" multiple (change)="calculateMD5Multiple($event)" />

<h3 [attr.data]="chartObserver$ | async">Timeline</h3>
<div #timeline></div>
Expand Down
20 changes: 10 additions & 10 deletions src/app/multiple-worker-pool/multiple-worker-pool.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
} from 'rxjs/operators';
import { fromWorkerPool } from '../../../projects/observable-webworker/src/lib/from-worker-pool';
import { GoogleChartsService } from '../google-charts.service';
import { FileHashEvent, ShaWorkerMessage, Thread } from '../sha-worker.types';
import { FileHashEvent, HashWorkerMessage, Thread } from '../hash-worker.types';
import TimelineOptions = google.visualization.TimelineOptions;

@Component({
Expand All @@ -50,7 +50,7 @@ export class MultipleWorkerPoolComponent {
shareReplay(1),
);

public eventsPool$: Subject<ShaWorkerMessage> = new Subject();
public eventsPool$: Subject<HashWorkerMessage> = new Subject();

public completedFiles$: Observable<string[]> = this.filenames$.pipe(
switchMap(() =>
Expand Down Expand Up @@ -87,7 +87,7 @@ export class MultipleWorkerPoolComponent {
}),
);

public eventsTimedPool$: Observable<ShaWorkerMessage> = this.eventsPool$.pipe(
public eventsTimedPool$: Observable<HashWorkerMessage> = this.eventsPool$.pipe(
groupBy(m => m.file),
mergeMap(fileMessage$ => {
return fileMessage$.pipe(
Expand All @@ -103,8 +103,8 @@ export class MultipleWorkerPoolComponent {
}),
);

public eventListPool$: Observable<ShaWorkerMessage[]> = this.eventsTimedPool$.pipe(
scan<ShaWorkerMessage>((list, event) => {
public eventListPool$: Observable<HashWorkerMessage[]> = this.eventsTimedPool$.pipe(
scan<HashWorkerMessage>((list, event) => {
list.push(event);
return list;
}, []),
Expand Down Expand Up @@ -217,11 +217,11 @@ export class MultipleWorkerPoolComponent {
}
}

public hashMultipleFiles(files: File[]): Observable<ShaWorkerMessage> {
public hashMultipleFiles(files: File[]): Observable<HashWorkerMessage> {
const queue: IterableIterator<File> = this.workPool(files);

return fromWorkerPool<Blob, ShaWorkerMessage>(index => {
const worker = new Worker('../secure-hash-algorithm.worker', { name: `sha-worker-${index}`, type: 'module' });
return fromWorkerPool<Blob, HashWorkerMessage>(index => {
const worker = new Worker('../file-hash.worker', { name: `hash-worker-${index}`, type: 'module' });
this.eventsPool$.next(this.logMessage(null, `worker ${index} created`));
return worker;
}, queue).pipe(
Expand All @@ -240,15 +240,15 @@ export class MultipleWorkerPoolComponent {
);
}

public calculateSha256Multiple($event): void {
public calculateMD5Multiple($event): void {
const files: File[] = Array.from($event.target.files);
this.multiFilesToHash.next(files);
for (const file of files) {
this.eventsPool$.next(this.logMessage(FileHashEvent.SELECTED, 'file selected', file.name));
}
}

private logMessage(eventType: FileHashEvent | null, message: string, file?: string): ShaWorkerMessage {
private logMessage(eventType: FileHashEvent | null, message: string, file?: string): HashWorkerMessage {
return { message, file, timestamp: new Date(), thread: Thread.MAIN, fileEventType: eventType };
}
}
4 changes: 2 additions & 2 deletions src/app/single-worker/single-worker.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<h2>Single Worker</h2>

Select file to compute SHA-256 sum of, in webworker:
<input type="file" (change)="calculateSha256($event)" />
Select file to compute MD5 sum of, in webworker:
<input type="file" (change)="calculateMD5($event)" />

<h3>Events:</h3>
<ol [attr.data]="hashResult$ | async">
Expand Down
10 changes: 5 additions & 5 deletions src/app/single-worker/single-worker.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
import { Observable, of, Subject } from 'rxjs';
import { scan, switchMap, tap } from 'rxjs/operators';
import { fromWorker } from '../../../projects/observable-webworker/src/lib/from-worker';
import { ShaWorkerMessage } from '../sha-worker.types';
import { HashWorkerMessage } from '../hash-worker.types';

@Component({
selector: 'app-single-worker',
Expand All @@ -23,18 +23,18 @@ export class SingleWorkerComponent {

public hashResult$ = this.filesToHash.pipe(switchMap(file => this.hashFile(file)));

public calculateSha256($event): void {
public calculateMD5($event): void {
this.events$.next('Main: file selected');
const file: File = $event.target.files[0];

this.filesToHash.next(file);
}

public hashFile(file: Blob): Observable<ShaWorkerMessage> {
public hashFile(file: Blob): Observable<HashWorkerMessage> {
const input$: Observable<Blob> = of(file);

return fromWorker<Blob, ShaWorkerMessage>(() => {
const worker = new Worker('../secure-hash-algorithm.worker', { name: 'sha-worker', type: 'module' });
return fromWorker<Blob, HashWorkerMessage>(() => {
const worker = new Worker('../file-hash.worker', { name: 'md5-worker', type: 'module' });
this.events$.next('Main: worker created');
return worker;
}, input$).pipe(
Expand Down
24 changes: 0 additions & 24 deletions src/readme/hash.worker.ts

This file was deleted.

16 changes: 4 additions & 12 deletions src/readme/worker-pool-hash.worker.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
import * as md5 from 'js-md5';
import { DoWorkUnit, ObservableWorker } from 'observable-webworker';
import { Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { DoWorkUnit, ObservableWorker } from '../../projects/observable-webworker/src/public-api';
import { map } from 'rxjs/operators';

@ObservableWorker()
export class WorkerPoolHashWorker implements DoWorkUnit<File, string> {
public workUnit(input: File): Observable<string> {
return this.readFileAsArrayBuffer(input).pipe(
switchMap(arrayBuffer => crypto.subtle.digest('SHA-256', arrayBuffer)),
map((digest: ArrayBuffer) => this.arrayBufferToHex(digest)),
);
}

private arrayBufferToHex(buffer: ArrayBuffer): string {
return Array.from(new Uint8Array(buffer))
.map(value => value.toString(16).padStart(2, '0'))
.join('');
return this.readFileAsArrayBuffer(input).pipe(map(arrayBuffer => md5(arrayBuffer)));
}

private readFileAsArrayBuffer(blob: Blob): Observable<ArrayBuffer> {
Expand Down
2 changes: 1 addition & 1 deletion src/readme/worker-pool.main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { Observable } from 'rxjs';
import { fromWorkerPool } from 'observable-webworker';

export function computeHashes(files: File[]): Observable<string> {
return fromWorkerPool<File, string>(() => new Worker('./transferable.worker', { type: 'module' }), files);
return fromWorkerPool<File, string>(() => new Worker('./worker-pool-hash.worker', { type: 'module' }), files);
}
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5303,6 +5303,11 @@ java-properties@^1.0.0:
resolved "https://registry.yarnpkg.com/java-properties/-/java-properties-1.0.2.tgz#ccd1fa73907438a5b5c38982269d0e771fe78211"
integrity sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==

js-md5@0.7.3:
version "0.7.3"
resolved "https://registry.yarnpkg.com/js-md5/-/js-md5-0.7.3.tgz#b4f2fbb0b327455f598d6727e38ec272cd09c3f2"
integrity sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ==

"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
Expand Down

0 comments on commit a2ddadb

Please sign in to comment.