changeset 72:cb91d7e40068

Add a couple of methods to the worker for adding remote library repos (well, key value pairs of library keys and URIs to fetch the library from) - and one for actually importing the libraries (currently using RequireJS (<script> / importScripts(...) method tying into global AMD module registration) ). Also updated list method to concatenate the available outputs from all loaded libraries.
author Lucas Thompson <dev@lucas.im>
date Wed, 18 Jan 2017 10:18:10 +0000
parents 0980eb001bde
children d3abd81e8ab6
files src/app/services/feature-extraction/FeatureExtractionWorker.ts
diffstat 1 files changed, 82 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/src/app/services/feature-extraction/FeatureExtractionWorker.ts	Wed Jan 18 10:14:05 2017 +0000
+++ b/src/app/services/feature-extraction/FeatureExtractionWorker.ts	Wed Jan 18 10:18:10 2017 +0000
@@ -2,27 +2,49 @@
  * Created by lucas on 01/12/2016.
  */
 
-import { EmscriptenProxy } from 'piper';
-import { PiperSimpleClient } from 'piper/HigherLevelUtilities';
+import {EmscriptenProxy, ListRequest, ListResponse} from 'piper';
+import {
+  PiperSimpleClient, SimpleRequest,
+  SimpleResponse
+} from 'piper/HigherLevelUtilities';
 import { VampExamplePlugins } from 'piper/ext/VampExamplePluginsModule';
+import {AvailableLibraries} from "./feature-extraction.service";
 
 // TODO TypeScript has a .d.ts file for webworkers, but for some reason it clashes with the typings for dom and causes compiler errors
 interface WorkerGlobalScope {
   onmessage: (this: this, ev: MessageEvent) => any;
   postMessage(data: any): void;
+  importScripts(uri: string): void;
 }
 
 interface MessageEvent {
   readonly data: any;
 }
 
+type LibraryUri = string;
+type LibraryKey = string;
+
+interface Message {
+  method: string;
+  params: any;
+}
+
+type RequireJs = (libs: string[], callback: (...libs: any[]) => void) => void;
+
 export default class FeatureExtractionWorker {
   private workerScope: WorkerGlobalScope;
-  private piperClient: PiperSimpleClient;
+  private clients: Map<string, PiperSimpleClient>;
+  private remoteLibraries: Map<LibraryKey, LibraryUri>;
 
-  constructor(workerScope: WorkerGlobalScope) {
+  constructor(workerScope: WorkerGlobalScope, private requireJs: RequireJs) {
     this.workerScope = workerScope;
-    this.piperClient = new PiperSimpleClient(new EmscriptenProxy(VampExamplePlugins()));
+    this.clients = new Map<LibraryKey, PiperSimpleClient>();
+    this.remoteLibraries = new Map<LibraryKey, LibraryUri>();
+    this.clients.set(
+      'vamp-example-plugins',
+      new PiperSimpleClient(new EmscriptenProxy(VampExamplePlugins()))
+    );
+
     this.workerScope.onmessage = (ev: MessageEvent) => {
       const sendResponse = (result) => {
         this.workerScope.postMessage({
@@ -32,15 +54,67 @@
       };
       switch (ev.data.method) {
         case 'list':
-          this.piperClient.list({}).then(sendResponse);
+          this.list(ev.data.params)
+            .then(sendResponse)
+            .catch(err => console.error(err)); // TODO handle error
           break;
         case 'process':
-          this.piperClient.process(ev.data.params).then(sendResponse);
+          this.process(ev.data.params)
+            .then(sendResponse)
+            .catch(err => console.error(err)); // TODO handle error
           break;
         case 'collect':
-          this.piperClient.collect(ev.data.params).then(sendResponse).catch(err => console.error(err));
+          this.collect(ev.data.params)
+            .then(sendResponse)
+            .catch(err => console.error(err)); // TODO handle error
+          break;
+        case 'import':
+          // this.workerScope.importScripts(ev.data.params);
+          const key: LibraryKey = ev.data.params;
+          if (this.remoteLibraries.has(key)) {
+            this.requireJs([this.remoteLibraries.get(key)], (plugin) => {
+              this.clients.set(
+                key,
+                new PiperSimpleClient(new EmscriptenProxy(plugin.createLibrary()))
+              ); // TODO won't always be an emscripten module
+              this.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(key => {
+            this.remoteLibraries.set(key, available[key]);
+          });
       }
     };
   }
 
+  private list(request: ListRequest): Promise<ListResponse> {
+    // TODO actually pay attention to ListRequest
+    return Promise.all([...this.clients.values()].map(client => client.list({})))
+      .then(allAvailable => {
+        return {
+          available: allAvailable.reduce(
+            (all, current) => all.concat(current.available),
+            []
+          )
+        };
+      });
+  }
+
+  // TODO reduce dupe
+  private process(request: SimpleRequest): Promise<SimpleResponse> {
+    const key: LibraryKey = request.key.split(':')[0];
+    const client: PiperSimpleClient = this.clients.get(key);
+    return client ? client.process(request) : Promise.reject("Invalid plugin library key.");
+  }
+
+  private collect(request: SimpleRequest): Promise<SimpleResponse> {
+    const key: LibraryKey = request.key.split(':')[0];
+    const client: PiperSimpleClient = this.clients.get(key);
+    return client ? client.collect(request) : Promise.reject("Invalid plugin library key.");
+  }
 }