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