annotate src/app/services/feature-extraction/FeatureExtractionWorker.ts @ 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 270f59ef3b83
children 8aa6830ea41d
rev   line source
dev@40 1 /**
dev@40 2 * Created by lucas on 01/12/2016.
dev@40 3 */
dev@40 4
dev@72 5 import {EmscriptenProxy, ListRequest, ListResponse} from 'piper';
dev@72 6 import {
dev@72 7 PiperSimpleClient, SimpleRequest,
dev@72 8 SimpleResponse
dev@72 9 } from 'piper/HigherLevelUtilities';
dev@44 10 import { VampExamplePlugins } from 'piper/ext/VampExamplePluginsModule';
dev@72 11 import {AvailableLibraries} from "./feature-extraction.service";
dev@44 12
dev@40 13 // TODO TypeScript has a .d.ts file for webworkers, but for some reason it clashes with the typings for dom and causes compiler errors
dev@40 14 interface WorkerGlobalScope {
dev@40 15 onmessage: (this: this, ev: MessageEvent) => any;
dev@40 16 postMessage(data: any): void;
dev@72 17 importScripts(uri: string): void;
dev@40 18 }
dev@40 19
dev@40 20 interface MessageEvent {
dev@40 21 readonly data: any;
dev@40 22 }
dev@40 23
dev@72 24 type LibraryUri = string;
dev@72 25 type LibraryKey = string;
dev@72 26
dev@72 27 interface Message {
dev@72 28 method: string;
dev@72 29 params: any;
dev@72 30 }
dev@72 31
dev@72 32 type RequireJs = (libs: string[], callback: (...libs: any[]) => void) => void;
dev@72 33
dev@40 34 export default class FeatureExtractionWorker {
dev@40 35 private workerScope: WorkerGlobalScope;
dev@72 36 private clients: Map<string, PiperSimpleClient>;
dev@72 37 private remoteLibraries: Map<LibraryKey, LibraryUri>;
dev@40 38
dev@72 39 constructor(workerScope: WorkerGlobalScope, private requireJs: RequireJs) {
dev@40 40 this.workerScope = workerScope;
dev@72 41 this.clients = new Map<LibraryKey, PiperSimpleClient>();
dev@72 42 this.remoteLibraries = new Map<LibraryKey, LibraryUri>();
dev@72 43 this.clients.set(
dev@72 44 'vamp-example-plugins',
dev@72 45 new PiperSimpleClient(new EmscriptenProxy(VampExamplePlugins()))
dev@72 46 );
dev@72 47
dev@44 48 this.workerScope.onmessage = (ev: MessageEvent) => {
dev@64 49 const sendResponse = (result) => {
dev@64 50 this.workerScope.postMessage({
dev@64 51 method: ev.data.method,
dev@64 52 result: result
dev@64 53 });
dev@64 54 };
dev@44 55 switch (ev.data.method) {
dev@44 56 case 'list':
dev@72 57 this.list(ev.data.params)
dev@72 58 .then(sendResponse)
dev@72 59 .catch(err => console.error(err)); // TODO handle error
dev@47 60 break;
dev@47 61 case 'process':
dev@72 62 this.process(ev.data.params)
dev@72 63 .then(sendResponse)
dev@72 64 .catch(err => console.error(err)); // TODO handle error
dev@62 65 break;
dev@62 66 case 'collect':
dev@72 67 this.collect(ev.data.params)
dev@72 68 .then(sendResponse)
dev@72 69 .catch(err => console.error(err)); // TODO handle error
dev@72 70 break;
dev@72 71 case 'import':
dev@72 72 // this.workerScope.importScripts(ev.data.params);
dev@72 73 const key: LibraryKey = ev.data.params;
dev@72 74 if (this.remoteLibraries.has(key)) {
dev@72 75 this.requireJs([this.remoteLibraries.get(key)], (plugin) => {
dev@72 76 this.clients.set(
dev@72 77 key,
dev@72 78 new PiperSimpleClient(new EmscriptenProxy(plugin.createLibrary()))
dev@72 79 ); // TODO won't always be an emscripten module
dev@72 80 this.list({}).then(sendResponse);
dev@72 81 });
dev@72 82 } else {
dev@72 83 console.error('Non registered library key.'); // TODO handle error
dev@72 84 }
dev@72 85 break;
dev@72 86 case 'addRemoteLibraries': // TODO rename
dev@72 87 const available: AvailableLibraries = ev.data.params;
dev@72 88 Object.keys(available).forEach(key => {
dev@72 89 this.remoteLibraries.set(key, available[key]);
dev@72 90 });
dev@44 91 }
dev@44 92 };
dev@40 93 }
dev@44 94
dev@72 95 private list(request: ListRequest): Promise<ListResponse> {
dev@72 96 // TODO actually pay attention to ListRequest
dev@72 97 return Promise.all([...this.clients.values()].map(client => client.list({})))
dev@72 98 .then(allAvailable => {
dev@72 99 return {
dev@72 100 available: allAvailable.reduce(
dev@72 101 (all, current) => all.concat(current.available),
dev@72 102 []
dev@72 103 )
dev@72 104 };
dev@72 105 });
dev@72 106 }
dev@72 107
dev@72 108 // TODO reduce dupe
dev@72 109 private process(request: SimpleRequest): Promise<SimpleResponse> {
dev@72 110 const key: LibraryKey = request.key.split(':')[0];
dev@72 111 const client: PiperSimpleClient = this.clients.get(key);
dev@72 112 return client ? client.process(request) : Promise.reject("Invalid plugin library key.");
dev@72 113 }
dev@72 114
dev@72 115 private collect(request: SimpleRequest): Promise<SimpleResponse> {
dev@72 116 const key: LibraryKey = request.key.split(':')[0];
dev@72 117 const client: PiperSimpleClient = this.clients.get(key);
dev@72 118 return client ? client.collect(request) : Promise.reject("Invalid plugin library key.");
dev@72 119 }
dev@40 120 }