comparison src/app/services/feature-extraction/FeatureExtractionWorker.ts @ 449:dc7237d84f8d

When a remote extractor fails, still populate menu with ones that were valid.
author Lucas Thompson <dev@lucas.im>
date Wed, 28 Jun 2017 10:40:36 +0100
parents 676c4d6d35f7
children c39df81c4dae
comparison
equal deleted inserted replaced
448:d2cf357c946b 449:dc7237d84f8d
43 }); 43 });
44 }; 44 };
45 45
46 return tasks.reduce((runningResponses, nextResponse) => { 46 return tasks.reduce((runningResponses, nextResponse) => {
47 return runningResponses.then(response => { 47 return runningResponses.then(response => {
48 return reducer(response, nextResponse()); 48 try {
49 return reducer(response, nextResponse());
50 } catch (e) {
51 throw new QueuedTaskFailure(runningResponses);
52 }
49 }); 53 });
50 }, Promise.resolve([])); 54 }, Promise.resolve([]));
55 }
56
57 class QueuedTaskFailure<T> extends Error {
58 public previousResponses: Promise<T[]>;
59
60 constructor(previousResponses: Promise<T[]>, message?: string) {
61 super(message || 'Queued task failed.');
62 this.previousResponses = previousResponses;
63 }
64 }
65
66 function flattenListResponses(responses: ListResponse[]): ListResponse {
67 return {
68 available: responses.reduce(
69 (flat, res) => flat.concat(res.available),
70 []
71 )
72 };
51 } 73 }
52 74
53 class AggregateStreamingService implements StreamingService { 75 class AggregateStreamingService implements StreamingService {
54 private services: Map<LibraryKey, Factory<PiperStreamingService>>; 76 private services: Map<LibraryKey, Factory<PiperStreamingService>>;
55 77
69 91
70 list(request: ListRequest): Promise<ListResponse> { 92 list(request: ListRequest): Promise<ListResponse> {
71 const listThunks: (() => Promise<ListResponse>)[] = [ 93 const listThunks: (() => Promise<ListResponse>)[] = [
72 ...this.services.values() 94 ...this.services.values()
73 ].map(createClient => () => createClient().list({})); 95 ].map(createClient => () => createClient().list({}));
74 96 return waterfall(listThunks)
75 return waterfall(listThunks).then(responses => ({ 97 .then(flattenListResponses);
76 available: responses.reduce((flat, res) => flat.concat(res.available), [])
77 }));
78 } 98 }
79 99
80 process(request: SimpleRequest): Observable<StreamingResponse> { 100 process(request: SimpleRequest): Observable<StreamingResponse> {
81 return this.dispatch('process', request); 101 return this.dispatch('process', request);
82 } 102 }
160 .then(response => { 180 .then(response => {
161 this.workerScope.postMessage({ 181 this.workerScope.postMessage({
162 method: 'import', 182 method: 'import',
163 result: response 183 result: response
164 }); 184 });
185 })
186 .catch((e) => {
187 console.warn(`${e.message}. Try using results so far`);
188 e.previousResponses.then(responses => {
189 this.workerScope.postMessage({
190 method: 'import',
191 result: flattenListResponses(responses)
192 });
193 });
165 }); 194 });
166 } 195 }
167 }; 196 };
168 } 197 }
169 198
170 private downloadRemoteLibrary(key: LibraryKey, 199 private downloadRemoteLibrary(key: LibraryKey,
171 uri: LibraryUri): Promise<Factory<Service>> { 200 uri: LibraryUri): Promise<Factory<Service>> {
172 return new Promise((res, rej) => { 201 return new Promise((res, rej) => {
173 this.requireJs([uri], (plugin) => { 202 this.requireJs([uri], (createModule) => {
174 res(() => { 203 res(() => {
175 // TODO a factory with more logic probably belongs in piper-js 204 // TODO a factory with more logic probably belongs in piper-js
176 const lib: any | EmscriptenModule = plugin.createLibrary(); 205 const lib: any | EmscriptenModule = createModule();
177 const isEmscriptenModule = typeof lib.cwrap === 'function'; 206 const isEmscriptenModule = typeof lib.cwrap === 'function';
178 return isEmscriptenModule ? new PiperVampService(lib) : lib; // TODO 207 return isEmscriptenModule ? new PiperVampService(lib) : lib; // TODO
179 }); 208 });
180 }, (err) => { 209 }, (err) => {
181 rej(`Failed to load ${key} remote module.`); 210 rej(`Failed to load ${key} remote module.`);