changeset 325:38f3fe548ac0

Merge pull request #1 from LucasThompson/fix/mobile-safari-high-water Fix/mobile safari high water
author Lucas Thompson <LucasThompson@users.noreply.github.com>
date Tue, 16 May 2017 16:46:32 +0100
parents 64dee0c156b1 (current diff) e433a2da0ada (diff)
children e401995304a7
files
diffstat 4 files changed, 94 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- 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 {
--- 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> = () => T;
+
+function waterfall<T>(tasks: (() => Promise<T>)[]): Promise<T[]> {
+  const reducer = (running: T[], next: Promise<T>): Promise<T[]> => {
+    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<LibraryKey, PiperStreamingService>;
+  private services: Map<LibraryKey, Factory<PiperStreamingService>>;
 
   constructor() {
-    this.services = new Map<LibraryKey, PiperStreamingService>();
+    this.services = new Map<LibraryKey, Factory<PiperStreamingService>>();
     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<PiperStreamingService>): void {
     this.services.set(key, service);
   }
 
+  hasRemoteService(key: LibraryKey): boolean {
+    return this.services.has(key);
+  }
+
   list(request: ListRequest): Promise<ListResponse> {
-    return Promise.all(
-      [...this.services.values()].map(client => client.list({}))
-    ).then(allAvailable => ({
-        available: allAvailable.reduce(
-          (all, current) => all.concat(current.available),
-          []
-        )
-      })
-    );
+    const listThunks: (() => Promise<ListResponse>)[] = [
+      ...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<StreamingResponse> {
@@ -66,8 +89,8 @@
   protected dispatch(method: 'process',
                      request: SimpleRequest): Observable<StreamingResponse> {
     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<LibraryKey> { // 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');
+      }
+    });
+  }
 }
--- 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<ListResponse> {
-    return this.client.list({});
+    return this.client.list({}).then(response => {
+      this.librariesUpdated.next(response);
+      return response;
+    });
   }
 
   extract(analysisItemId: string, request: SimpleRequest): Promise<void> {
@@ -87,20 +90,16 @@
     });
   }
 
-  updateAvailableLibraries(): Observable<AvailableLibraries> {
-    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 {
--- 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"