# HG changeset patch # User Lucas Thompson # Date 1494949592 -3600 # Node ID 38f3fe548ac05e27d9e76fe9eebde4c9f21b5776 # Parent 64dee0c156b107d4f816a786e95b225022acb196# Parent e433a2da0adaca5e0aee14534314531e8752074f Merge pull request #1 from LucasThompson/fix/mobile-safari-high-water Fix/mobile safari high water diff -r 64dee0c156b1 -r 38f3fe548ac0 src/app/feature-extraction-menu/feature-extraction-menu.component.ts --- a/src/app/feature-extraction-menu/feature-extraction-menu.component.ts Mon May 15 17:57:42 2017 +0100 +++ b/src/app/feature-extraction-menu/feature-extraction-menu.component.ts Tue May 16 16:46:32 2017 +0100 @@ -80,9 +80,9 @@ } ngOnInit() { - this.piperService.list().then(this.populateExtractors); this.librariesUpdatedSubscription = this.piperService.librariesUpdated$.subscribe(this.populateExtractors); + this.piperService.list().then(this.populateExtractors); } extract(combinedKey: string): void { @@ -94,9 +94,7 @@ } load(): void { - this.piperService.updateAvailableLibraries().subscribe(res => { - Object.keys(res).forEach(key => this.piperService.load(key)); - }); + this.piperService.updateAvailableLibraries(); } ngOnDestroy(): void { diff -r 64dee0c156b1 -r 38f3fe548ac0 src/app/services/feature-extraction/FeatureExtractionWorker.ts --- a/src/app/services/feature-extraction/FeatureExtractionWorker.ts Mon May 15 17:57:42 2017 +0100 +++ b/src/app/services/feature-extraction/FeatureExtractionWorker.ts Tue May 16 16:46:32 2017 +0100 @@ -31,32 +31,55 @@ type LibraryKey = string; type RequireJs = (libs: string[], callback: (...libs: any[]) => void) => void; +type Factory = () => T; + +function waterfall(tasks: (() => Promise)[]): Promise { + const reducer = (running: T[], next: Promise): Promise => { + return next.then(response => { + running = running.concat(response); + return running; + }); + }; + + return tasks.reduce((runningResponses, nextResponse) => { + return runningResponses.then(response => { + return reducer(response, nextResponse()); + }) + }, Promise.resolve([])); +} class AggregateStreamingService implements StreamingService { - private services: Map; + private services: Map>; constructor() { - this.services = new Map(); + this.services = new Map>(); this.services.set( 'vamp-example-plugins', - new PiperStreamingService(new PiperVampService(VampExamplePlugins())) + () => new PiperStreamingService( + new PiperVampService(VampExamplePlugins()) + ) ); } - addService(key: LibraryKey, service: PiperStreamingService): void { + addService(key: LibraryKey, service: Factory): void { this.services.set(key, service); } + hasRemoteService(key: LibraryKey): boolean { + return this.services.has(key); + } + list(request: ListRequest): Promise { - return Promise.all( - [...this.services.values()].map(client => client.list({})) - ).then(allAvailable => ({ - available: allAvailable.reduce( - (all, current) => all.concat(current.available), - [] - ) - }) - ); + const listThunks: (() => Promise)[] = [ + ...this.services.values() + ].map(client => () => client().list({})); + + return waterfall(listThunks).then(responses => { + return responses.reduce((allAvailable, res) => { + allAvailable.available = allAvailable.available.concat(res.available); + return allAvailable; + }, {available: []}); + }) } process(request: SimpleRequest): Observable { @@ -66,8 +89,8 @@ protected dispatch(method: 'process', request: SimpleRequest): Observable { const key = request.key.split(':')[0]; - return this.services.has(key) ? - this.services.get(key)[method](request) : Observable.throw('Invalid key'); + return this.services.has(key) ? this.services.get(key)()[method](request) : + Observable.throw('Invalid key'); } } @@ -123,36 +146,49 @@ private setupImportLibraryListener(): void { this.workerScope.onmessage = (ev: MessageEvent) => { - const sendResponse = (result) => { - this.workerScope.postMessage({ - method: ev.data.method, - result: result - }); - }; switch (ev.data.method) { - case 'import': - const key: LibraryKey = ev.data.params; - if (this.remoteLibraries.has(key)) { - this.requireJs([this.remoteLibraries.get(key)], (plugin) => { - // TODO a factory with more logic probably belongs in piper-js - const lib: any | EmscriptenModule = plugin.createLibrary(); - const isEmscriptenModule = typeof lib.cwrap === 'function'; - const service = new PiperStreamingService( - isEmscriptenModule ? new PiperVampService(lib) : lib // TODO - ); - this.service.addService(key, service); - this.service.list({}).then(sendResponse); - }); - } else { - console.error('Non registered library key.'); // TODO handle error - } - break; case 'addRemoteLibraries': // TODO rename const available: AvailableLibraries = ev.data.params; - Object.keys(available).forEach(libraryKey => { - this.remoteLibraries.set(libraryKey, available[libraryKey]); + const importThunks = Object.keys(available).map(libraryKey => { + return () => { + this.remoteLibraries.set(libraryKey, available[libraryKey]); + return this.import(libraryKey).then(key => { + return key; + }); + }; }); + waterfall(importThunks).then(() => { + this.service.list({}).then(response => { + this.workerScope.postMessage({ + method: 'import', + result: response + }); + }); + }) } }; } + + private import(key: LibraryKey): Promise { // TODO return type? + return new Promise((res, rej) => { + if (this.remoteLibraries.has(key)) { + // TODO RequireJs can fail... need to reject the promise then + this.requireJs([this.remoteLibraries.get(key)], (plugin) => { + + const service = () => { + // TODO a factory with more logic probably belongs in piper-js + const lib: any | EmscriptenModule = plugin.createLibrary(); + const isEmscriptenModule = typeof lib.cwrap === 'function'; + return new PiperStreamingService( + isEmscriptenModule ? new PiperVampService(lib) : lib // TODO + ); + }; + this.service.addService(key, service); + res(key); + }); + } else { + rej('Invalid remote library key'); + } + }); + } } diff -r 64dee0c156b1 -r 38f3fe548ac0 src/app/services/feature-extraction/feature-extraction.service.ts --- a/src/app/services/feature-extraction/feature-extraction.service.ts Mon May 15 17:57:42 2017 +0100 +++ b/src/app/services/feature-extraction/feature-extraction.service.ts Tue May 16 16:46:32 2017 +0100 @@ -8,7 +8,7 @@ } from 'piper/HigherLevelUtilities'; import {Subject} from 'rxjs/Subject'; import {Observable} from 'rxjs/Observable'; -import {Http, Response} from '@angular/http'; +import {Http} from '@angular/http'; import { countingIdProvider, WebWorkerStreamingClient @@ -63,7 +63,10 @@ } list(): Promise { - return this.client.list({}); + return this.client.list({}).then(response => { + this.librariesUpdated.next(response); + return response; + }); } extract(analysisItemId: string, request: SimpleRequest): Promise { @@ -87,20 +90,16 @@ }); } - updateAvailableLibraries(): Observable { - return this.http.get(this.repositoryUri) - .map(res => { - const map = res.json(); + updateAvailableLibraries(): void { + this.http.get(this.repositoryUri) + .toPromise() // just turn into a promise for now to subscribe / execute + .then(res => { this.worker.postMessage({ method: 'addRemoteLibraries', - params: map - }); - return map; + params: res.json() + }) }) - .catch((error: Response | any) => { - console.error(error); - return Observable.throw(error); - }); + .catch(console.error); // TODO Report error to user } load(libraryKey: string): void { diff -r 64dee0c156b1 -r 38f3fe548ac0 yarn.lock --- a/yarn.lock Mon May 15 17:57:42 2017 +0100 +++ b/yarn.lock Tue May 16 16:46:32 2017 +0100 @@ -391,10 +391,6 @@ version "0.8.12" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" -ast-types@0.8.15: - version "0.8.15" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" - ast-types@0.9.6: version "0.9.6" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" @@ -4080,9 +4076,9 @@ version "0.16.0" resolved "https://codeload.github.com/piper-audio/piper-js/tar.gz/e42d0165d93794eeade2b09a345b6123d298f13c" dependencies: - "@types/base64-js" "^1.2.5" + "@types/base64-js" "^1.1.4" base64-js "^1.2.0" - rxjs "^5.4.0" + rxjs "^5.2.0" portfinder@^1.0.9, portfinder@~1.0.12: version "1.0.13" @@ -4602,7 +4598,7 @@ readable-stream "^2.0.2" set-immediate-shim "^1.0.1" -recast@0.10.33: +recast@0.10.33, recast@^0.10.10: version "0.10.33" resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" dependencies: @@ -4611,15 +4607,6 @@ private "~0.1.5" source-map "~0.5.0" -recast@^0.10.10: - version "0.10.43" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" - dependencies: - ast-types "0.8.15" - esprima-fb "~15001.1001.0-dev-harmony-fb" - private "~0.1.5" - source-map "~0.5.0" - recast@^0.11.17: version "0.11.23" resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" @@ -6046,20 +6033,13 @@ imurmurhash "^0.1.4" slide "^1.1.5" -ws@1.1.1: +ws@1.1.1, ws@^1.0.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" dependencies: options ">=0.0.5" ultron "1.0.x" -ws@^1.0.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" - dependencies: - options ">=0.0.5" - ultron "1.0.x" - wtf-8@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a"