1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | import { injectable } from 'inversify';
|
18 | import { CancellationToken } from '../common/cancellation';
|
19 | import { ProgressClient } from '../common/progress-service-protocol';
|
20 | import { ProgressMessage, ProgressUpdate } from '../common/message-service-protocol';
|
21 | import { Deferred } from '../common/promise-util';
|
22 | import { Event, Emitter } from '../common/event';
|
23 |
|
24 | export interface LocationProgress {
|
25 | show: boolean;
|
26 | }
|
27 |
|
28 | @injectable()
|
29 | export class ProgressLocationService implements ProgressClient {
|
30 |
|
31 | protected emitters = new Map<string, Emitter<LocationProgress>[]>();
|
32 | protected lastEvents = new Map<string, LocationProgress>();
|
33 |
|
34 | getProgress(locationId: string): LocationProgress | undefined {
|
35 | return this.lastEvents.get(locationId);
|
36 | }
|
37 | onProgress(locationId: string): Event<LocationProgress> {
|
38 | const emitter = this.addEmitter(locationId);
|
39 | return emitter.event;
|
40 | }
|
41 | protected addEmitter(locationId: string): Emitter<LocationProgress> {
|
42 | const emitter = new Emitter<LocationProgress>();
|
43 | const list = this.emitters.get(locationId) || [];
|
44 | list.push(emitter);
|
45 | this.emitters.set(locationId, list);
|
46 | return emitter;
|
47 | }
|
48 |
|
49 | protected readonly progressByLocation = new Map<string, Set<string>>();
|
50 |
|
51 | async showProgress(progressId: string, message: ProgressMessage, cancellationToken: CancellationToken): Promise<string | undefined> {
|
52 | const locationId = this.getLocationId(message);
|
53 | const result = new Deferred<string | undefined>();
|
54 | cancellationToken.onCancellationRequested(() => {
|
55 | this.processEvent(progressId, locationId, 'done');
|
56 | result.resolve(ProgressMessage.Cancel);
|
57 | });
|
58 | this.processEvent(progressId, locationId, 'start');
|
59 | return result.promise;
|
60 | }
|
61 | protected processEvent(progressId: string, locationId: string, event: 'start' | 'done'): void {
|
62 | const progressSet = this.progressByLocation.get(locationId) || new Set<string>();
|
63 | if (event === 'start') {
|
64 | progressSet.add(progressId);
|
65 | } else {
|
66 | progressSet.delete(progressId);
|
67 | }
|
68 | this.progressByLocation.set(locationId, progressSet);
|
69 | const show = !!progressSet.size;
|
70 | this.fireEvent(locationId, show);
|
71 | }
|
72 | protected fireEvent(locationId: string, show: boolean): void {
|
73 | const lastEvent = this.lastEvents.get(locationId);
|
74 | const shouldFire = !lastEvent || lastEvent.show !== show;
|
75 | if (shouldFire) {
|
76 | this.lastEvents.set(locationId, { show });
|
77 | this.getOrCreateEmitters(locationId).forEach(e => e.fire({ show }));
|
78 | }
|
79 | }
|
80 | protected getOrCreateEmitters(locationId: string): Emitter<LocationProgress>[] {
|
81 | let emitters = this.emitters.get(locationId);
|
82 | if (!emitters) {
|
83 | emitters = [this.addEmitter(locationId)];
|
84 | }
|
85 | return emitters;
|
86 | }
|
87 |
|
88 | protected getLocationId(message: ProgressMessage): string {
|
89 | return message.options && message.options.location || 'unknownLocation';
|
90 | }
|
91 |
|
92 | async reportProgress(progressId: string, update: ProgressUpdate, message: ProgressMessage, cancellationToken: CancellationToken): Promise<void> {
|
93 |
|
94 | }
|
95 |
|
96 | }
|