diff options
Diffstat (limited to 'language-web/src/main')
-rw-r--r-- | language-web/src/main/js/editor/EditorStore.ts | 11 | ||||
-rw-r--r-- | language-web/src/main/js/xtext/ContentAssistService.ts | 4 | ||||
-rw-r--r-- | language-web/src/main/js/xtext/HighlightingService.ts | 4 | ||||
-rw-r--r-- | language-web/src/main/js/xtext/OccurrencesService.ts | 10 | ||||
-rw-r--r-- | language-web/src/main/js/xtext/UpdateService.ts | 116 | ||||
-rw-r--r-- | language-web/src/main/js/xtext/ValidationService.ts | 4 | ||||
-rw-r--r-- | language-web/src/main/js/xtext/XtextClient.ts | 22 | ||||
-rw-r--r-- | language-web/src/main/js/xtext/XtextWebSocketClient.ts | 34 |
8 files changed, 130 insertions, 75 deletions
diff --git a/language-web/src/main/js/editor/EditorStore.ts b/language-web/src/main/js/editor/EditorStore.ts index 8788e00f..ba31efcb 100644 --- a/language-web/src/main/js/editor/EditorStore.ts +++ b/language-web/src/main/js/editor/EditorStore.ts | |||
@@ -56,11 +56,11 @@ import { XtextClient } from '../xtext/XtextClient'; | |||
56 | const log = getLogger('editor.EditorStore'); | 56 | const log = getLogger('editor.EditorStore'); |
57 | 57 | ||
58 | export class EditorStore { | 58 | export class EditorStore { |
59 | themeStore; | 59 | private readonly themeStore; |
60 | 60 | ||
61 | state: EditorState; | 61 | state: EditorState; |
62 | 62 | ||
63 | client: XtextClient; | 63 | private readonly client: XtextClient; |
64 | 64 | ||
65 | showLineNumbers = false; | 65 | showLineNumbers = false; |
66 | 66 | ||
@@ -74,11 +74,11 @@ export class EditorStore { | |||
74 | 74 | ||
75 | infoCount = 0; | 75 | infoCount = 0; |
76 | 76 | ||
77 | readonly defaultDispatcher = (tr: Transaction): void => { | 77 | private readonly defaultDispatcher = (tr: Transaction): void => { |
78 | this.onTransaction(tr); | 78 | this.onTransaction(tr); |
79 | }; | 79 | }; |
80 | 80 | ||
81 | dispatcher = this.defaultDispatcher; | 81 | private dispatcher = this.defaultDispatcher; |
82 | 82 | ||
83 | constructor(initialValue: string, themeStore: ThemeStore) { | 83 | constructor(initialValue: string, themeStore: ThemeStore) { |
84 | this.themeStore = themeStore; | 84 | this.themeStore = themeStore; |
@@ -148,10 +148,7 @@ export class EditorStore { | |||
148 | }, | 148 | }, |
149 | ); | 149 | ); |
150 | makeAutoObservable(this, { | 150 | makeAutoObservable(this, { |
151 | themeStore: false, | ||
152 | state: observable.ref, | 151 | state: observable.ref, |
153 | defaultDispatcher: false, | ||
154 | dispatcher: false, | ||
155 | }); | 152 | }); |
156 | } | 153 | } |
157 | 154 | ||
diff --git a/language-web/src/main/js/xtext/ContentAssistService.ts b/language-web/src/main/js/xtext/ContentAssistService.ts index 8461ec7f..f085c5b1 100644 --- a/language-web/src/main/js/xtext/ContentAssistService.ts +++ b/language-web/src/main/js/xtext/ContentAssistService.ts | |||
@@ -61,9 +61,9 @@ function computeSpan(prefix: string, entryCount: number) { | |||
61 | } | 61 | } |
62 | 62 | ||
63 | export class ContentAssistService { | 63 | export class ContentAssistService { |
64 | updateService: UpdateService; | 64 | private readonly updateService: UpdateService; |
65 | 65 | ||
66 | lastCompletion: CompletionResult | null = null; | 66 | private lastCompletion: CompletionResult | null = null; |
67 | 67 | ||
68 | constructor(updateService: UpdateService) { | 68 | constructor(updateService: UpdateService) { |
69 | this.updateService = updateService; | 69 | this.updateService = updateService; |
diff --git a/language-web/src/main/js/xtext/HighlightingService.ts b/language-web/src/main/js/xtext/HighlightingService.ts index 451a3a52..fc3e9e53 100644 --- a/language-web/src/main/js/xtext/HighlightingService.ts +++ b/language-web/src/main/js/xtext/HighlightingService.ts | |||
@@ -7,9 +7,9 @@ import { isHighlightingResult } from './xtextServiceResults'; | |||
7 | const log = getLogger('xtext.ValidationService'); | 7 | const log = getLogger('xtext.ValidationService'); |
8 | 8 | ||
9 | export class HighlightingService { | 9 | export class HighlightingService { |
10 | private store: EditorStore; | 10 | private readonly store: EditorStore; |
11 | 11 | ||
12 | private updateService: UpdateService; | 12 | private readonly updateService: UpdateService; |
13 | 13 | ||
14 | constructor(store: EditorStore, updateService: UpdateService) { | 14 | constructor(store: EditorStore, updateService: UpdateService) { |
15 | this.store = store; | 15 | this.store = store; |
diff --git a/language-web/src/main/js/xtext/OccurrencesService.ts b/language-web/src/main/js/xtext/OccurrencesService.ts index 804f5ba2..d1dec9e9 100644 --- a/language-web/src/main/js/xtext/OccurrencesService.ts +++ b/language-web/src/main/js/xtext/OccurrencesService.ts | |||
@@ -34,19 +34,19 @@ function transformOccurrences(regions: ITextRegion[]): IOccurrence[] { | |||
34 | } | 34 | } |
35 | 35 | ||
36 | export class OccurrencesService { | 36 | export class OccurrencesService { |
37 | private store: EditorStore; | 37 | private readonly store: EditorStore; |
38 | 38 | ||
39 | private webSocketClient: XtextWebSocketClient; | 39 | private readonly webSocketClient: XtextWebSocketClient; |
40 | 40 | ||
41 | private updateService: UpdateService; | 41 | private readonly updateService: UpdateService; |
42 | 42 | ||
43 | private hasOccurrences = false; | 43 | private hasOccurrences = false; |
44 | 44 | ||
45 | private findOccurrencesTimer = new Timer(() => { | 45 | private readonly findOccurrencesTimer = new Timer(() => { |
46 | this.handleFindOccurrences(); | 46 | this.handleFindOccurrences(); |
47 | }, FIND_OCCURRENCES_TIMEOUT_MS); | 47 | }, FIND_OCCURRENCES_TIMEOUT_MS); |
48 | 48 | ||
49 | private clearOccurrencesTimer = new Timer(() => { | 49 | private readonly clearOccurrencesTimer = new Timer(() => { |
50 | this.clearOccurrences(); | 50 | this.clearOccurrences(); |
51 | }, CLEAR_OCCURRENCES_TIMEOUT_MS); | 51 | }, CLEAR_OCCURRENCES_TIMEOUT_MS); |
52 | 52 | ||
diff --git a/language-web/src/main/js/xtext/UpdateService.ts b/language-web/src/main/js/xtext/UpdateService.ts index 838f9d5b..9b672e79 100644 --- a/language-web/src/main/js/xtext/UpdateService.ts +++ b/language-web/src/main/js/xtext/UpdateService.ts | |||
@@ -32,20 +32,27 @@ export class UpdateService { | |||
32 | 32 | ||
33 | xtextStateId: string | null = null; | 33 | xtextStateId: string | null = null; |
34 | 34 | ||
35 | private store: EditorStore; | 35 | private readonly store: EditorStore; |
36 | 36 | ||
37 | /** | ||
38 | * The changes being synchronized to the server if a full or delta text update is running, | ||
39 | * `null` otherwise. | ||
40 | */ | ||
37 | private pendingUpdate: ChangeDesc | null = null; | 41 | private pendingUpdate: ChangeDesc | null = null; |
38 | 42 | ||
43 | /** | ||
44 | * Local changes not yet sychronized to the server and not part of the running update, if any. | ||
45 | */ | ||
39 | private dirtyChanges: ChangeDesc; | 46 | private dirtyChanges: ChangeDesc; |
40 | 47 | ||
41 | private webSocketClient: XtextWebSocketClient; | 48 | private readonly webSocketClient: XtextWebSocketClient; |
42 | 49 | ||
43 | private updatedCondition = new ConditionVariable( | 50 | private readonly updatedCondition = new ConditionVariable( |
44 | () => this.pendingUpdate === null && this.xtextStateId !== null, | 51 | () => this.pendingUpdate === null && this.xtextStateId !== null, |
45 | WAIT_FOR_UPDATE_TIMEOUT_MS, | 52 | WAIT_FOR_UPDATE_TIMEOUT_MS, |
46 | ); | 53 | ); |
47 | 54 | ||
48 | private idleUpdateTimer = new Timer(() => { | 55 | private readonly idleUpdateTimer = new Timer(() => { |
49 | this.handleIdleUpdate(); | 56 | this.handleIdleUpdate(); |
50 | }, UPDATE_TIMEOUT_MS); | 57 | }, UPDATE_TIMEOUT_MS); |
51 | 58 | ||
@@ -56,9 +63,11 @@ export class UpdateService { | |||
56 | this.webSocketClient = webSocketClient; | 63 | this.webSocketClient = webSocketClient; |
57 | } | 64 | } |
58 | 65 | ||
59 | onConnect(): Promise<void> { | 66 | onReconnect(): void { |
60 | this.xtextStateId = null; | 67 | this.xtextStateId = null; |
61 | return this.updateFullText(); | 68 | this.updateFullText().catch((error) => { |
69 | log.error('Unexpected error during initial update', error); | ||
70 | }); | ||
62 | } | 71 | } |
63 | 72 | ||
64 | onTransaction(transaction: Transaction): void { | 73 | onTransaction(transaction: Transaction): void { |
@@ -68,6 +77,14 @@ export class UpdateService { | |||
68 | } | 77 | } |
69 | } | 78 | } |
70 | 79 | ||
80 | /** | ||
81 | * Computes the summary of any changes happened since the last complete update. | ||
82 | * | ||
83 | * The result reflects any changes that happened since the `xtextStateId` | ||
84 | * version was uploaded to the server. | ||
85 | * | ||
86 | * @return the summary of changes since the last update | ||
87 | */ | ||
71 | computeChangesSinceLastUpdate(): ChangeDesc { | 88 | computeChangesSinceLastUpdate(): ChangeDesc { |
72 | return this.pendingUpdate?.composeDesc(this.dirtyChanges) || this.dirtyChanges; | 89 | return this.pendingUpdate?.composeDesc(this.dirtyChanges) || this.dirtyChanges; |
73 | } | 90 | } |
@@ -106,6 +123,15 @@ export class UpdateService { | |||
106 | throw new Error('Full text update failed'); | 123 | throw new Error('Full text update failed'); |
107 | } | 124 | } |
108 | 125 | ||
126 | /** | ||
127 | * Makes sure that the document state on the server reflects recent | ||
128 | * local changes. | ||
129 | * | ||
130 | * Performs either an update with delta text or a full text update if needed. | ||
131 | * If there are not local dirty changes, the promise resolves immediately. | ||
132 | * | ||
133 | * @return a promise resolving when the update is completed | ||
134 | */ | ||
109 | async update(): Promise<void> { | 135 | async update(): Promise<void> { |
110 | await this.prepareForDeltaUpdate(); | 136 | await this.prepareForDeltaUpdate(); |
111 | const delta = this.computeDelta(); | 137 | const delta = this.computeDelta(); |
@@ -151,31 +177,36 @@ export class UpdateService { | |||
151 | return []; | 177 | return []; |
152 | } | 178 | } |
153 | const delta = this.computeDelta(); | 179 | const delta = this.computeDelta(); |
154 | if (delta === null) { | 180 | if (delta !== null) { |
155 | // Poscondition of `prepareForDeltaUpdate`: `xtextStateId !== null` | 181 | log.trace('Editor delta', delta); |
156 | return this.doFetchContentAssist(params, this.xtextStateId as string); | 182 | const entries = await this.withUpdate(async () => { |
157 | } | 183 | const result = await this.webSocketClient.send({ |
158 | log.trace('Editor delta', delta); | 184 | ...params, |
159 | return this.withUpdate(async () => { | 185 | requiredStateId: this.xtextStateId, |
160 | const result = await this.webSocketClient.send({ | 186 | ...delta, |
161 | ...params, | 187 | }); |
162 | requiredStateId: this.xtextStateId, | 188 | if (isContentAssistResult(result)) { |
163 | ...delta, | 189 | return [result.stateId, result.entries]; |
190 | } | ||
191 | if (isInvalidStateIdConflictResult(result)) { | ||
192 | const [newStateId] = await this.doFallbackToUpdateFullText(); | ||
193 | // We must finish this state update transaction to prepare for any push events | ||
194 | // before querying for content assist, so we just return `null` and will query | ||
195 | // the content assist service later. | ||
196 | return [newStateId, null]; | ||
197 | } | ||
198 | log.error('Unextpected content assist result with delta update', result); | ||
199 | throw new Error('Unexpexted content assist result with delta update'); | ||
164 | }); | 200 | }); |
165 | if (isContentAssistResult(result)) { | 201 | if (entries !== null) { |
166 | return [result.stateId, result.entries]; | 202 | return entries; |
167 | } | 203 | } |
168 | if (isInvalidStateIdConflictResult(result)) { | 204 | if (signal.aborted) { |
169 | const [newStateId] = await this.doFallbackToUpdateFullText(); | 205 | return []; |
170 | if (signal.aborted) { | ||
171 | return [newStateId, []]; | ||
172 | } | ||
173 | const entries = await this.doFetchContentAssist(params, newStateId); | ||
174 | return [newStateId, entries]; | ||
175 | } | 206 | } |
176 | log.error('Unextpected content assist result with delta update', result); | 207 | } |
177 | throw new Error('Unexpexted content assist result with delta update'); | 208 | // Poscondition of `prepareForDeltaUpdate`: `xtextStateId !== null` |
178 | }); | 209 | return this.doFetchContentAssist(params, this.xtextStateId as string); |
179 | } | 210 | } |
180 | 211 | ||
181 | private async doFetchContentAssist(params: Record<string, unknown>, expectedStateId: string) { | 212 | private async doFetchContentAssist(params: Record<string, unknown>, expectedStateId: string) { |
@@ -211,6 +242,27 @@ export class UpdateService { | |||
211 | }; | 242 | }; |
212 | } | 243 | } |
213 | 244 | ||
245 | /** | ||
246 | * Executes an asynchronous callback that updates the state on the server. | ||
247 | * | ||
248 | * Ensures that updates happen sequentially and manages `pendingUpdate` | ||
249 | * and `dirtyChanges` to reflect changes being synchronized to the server | ||
250 | * and not yet synchronized to the server, respectively. | ||
251 | * | ||
252 | * Optionally, `callback` may return a second value that is retured by this function. | ||
253 | * | ||
254 | * Once the remote procedure call to update the server state finishes | ||
255 | * and returns the new `stateId`, `callback` must return _immediately_ | ||
256 | * to ensure that the local `stateId` is updated likewise to be able to handle | ||
257 | * push messages referring to the new `stateId` from the server. | ||
258 | * If additional work is needed to compute the second value in some cases, | ||
259 | * use `T | null` instead of `T` as a return type and signal the need for additional | ||
260 | * computations by returning `null`. Thus additional computations can be performed | ||
261 | * outside of the critical section. | ||
262 | * | ||
263 | * @param callback the asynchronous callback that updates the server state | ||
264 | * @return a promise resolving to the second value returned by `callback` | ||
265 | */ | ||
214 | private async withUpdate<T>(callback: () => Promise<[string, T]>): Promise<T> { | 266 | private async withUpdate<T>(callback: () => Promise<[string, T]>): Promise<T> { |
215 | if (this.pendingUpdate !== null) { | 267 | if (this.pendingUpdate !== null) { |
216 | throw new Error('Another update is pending, will not perform update'); | 268 | throw new Error('Another update is pending, will not perform update'); |
@@ -239,6 +291,14 @@ export class UpdateService { | |||
239 | } | 291 | } |
240 | } | 292 | } |
241 | 293 | ||
294 | /** | ||
295 | * Ensures that there is some state available on the server (`xtextStateId`) | ||
296 | * and that there is not pending update. | ||
297 | * | ||
298 | * After this function resolves, a delta text update is possible. | ||
299 | * | ||
300 | * @return a promise resolving when there is a valid state id but no pending update | ||
301 | */ | ||
242 | private async prepareForDeltaUpdate() { | 302 | private async prepareForDeltaUpdate() { |
243 | // If no update is pending, but the full text hasn't been uploaded to the server yet, | 303 | // If no update is pending, but the full text hasn't been uploaded to the server yet, |
244 | // we must start a full text upload. | 304 | // we must start a full text upload. |
diff --git a/language-web/src/main/js/xtext/ValidationService.ts b/language-web/src/main/js/xtext/ValidationService.ts index 31c8f716..8e4934ac 100644 --- a/language-web/src/main/js/xtext/ValidationService.ts +++ b/language-web/src/main/js/xtext/ValidationService.ts | |||
@@ -8,9 +8,9 @@ import { isValidationResult } from './xtextServiceResults'; | |||
8 | const log = getLogger('xtext.ValidationService'); | 8 | const log = getLogger('xtext.ValidationService'); |
9 | 9 | ||
10 | export class ValidationService { | 10 | export class ValidationService { |
11 | private store: EditorStore; | 11 | private readonly store: EditorStore; |
12 | 12 | ||
13 | private updateService: UpdateService; | 13 | private readonly updateService: UpdateService; |
14 | 14 | ||
15 | constructor(store: EditorStore, updateService: UpdateService) { | 15 | constructor(store: EditorStore, updateService: UpdateService) { |
16 | this.store = store; | 16 | this.store = store; |
diff --git a/language-web/src/main/js/xtext/XtextClient.ts b/language-web/src/main/js/xtext/XtextClient.ts index 03b81b1c..28f3d0cc 100644 --- a/language-web/src/main/js/xtext/XtextClient.ts +++ b/language-web/src/main/js/xtext/XtextClient.ts | |||
@@ -16,21 +16,21 @@ import { XtextWebSocketClient } from './XtextWebSocketClient'; | |||
16 | const log = getLogger('xtext.XtextClient'); | 16 | const log = getLogger('xtext.XtextClient'); |
17 | 17 | ||
18 | export class XtextClient { | 18 | export class XtextClient { |
19 | private webSocketClient: XtextWebSocketClient; | 19 | private readonly webSocketClient: XtextWebSocketClient; |
20 | 20 | ||
21 | private updateService: UpdateService; | 21 | private readonly updateService: UpdateService; |
22 | 22 | ||
23 | private contentAssistService: ContentAssistService; | 23 | private readonly contentAssistService: ContentAssistService; |
24 | 24 | ||
25 | private highlightingService: HighlightingService; | 25 | private readonly highlightingService: HighlightingService; |
26 | 26 | ||
27 | private validationService: ValidationService; | 27 | private readonly validationService: ValidationService; |
28 | 28 | ||
29 | private occurrencesService: OccurrencesService; | 29 | private readonly occurrencesService: OccurrencesService; |
30 | 30 | ||
31 | constructor(store: EditorStore) { | 31 | constructor(store: EditorStore) { |
32 | this.webSocketClient = new XtextWebSocketClient( | 32 | this.webSocketClient = new XtextWebSocketClient( |
33 | () => this.updateService.onConnect(), | 33 | () => this.updateService.onReconnect(), |
34 | (resource, stateId, service, push) => this.onPush(resource, stateId, service, push), | 34 | (resource, stateId, service, push) => this.onPush(resource, stateId, service, push), |
35 | ); | 35 | ); |
36 | this.updateService = new UpdateService(store, this.webSocketClient); | 36 | this.updateService = new UpdateService(store, this.webSocketClient); |
@@ -52,15 +52,17 @@ export class XtextClient { | |||
52 | this.occurrencesService.onTransaction(transaction); | 52 | this.occurrencesService.onTransaction(transaction); |
53 | } | 53 | } |
54 | 54 | ||
55 | private async onPush(resource: string, stateId: string, service: string, push: unknown) { | 55 | private onPush(resource: string, stateId: string, service: string, push: unknown) { |
56 | const { resourceName, xtextStateId } = this.updateService; | 56 | const { resourceName, xtextStateId } = this.updateService; |
57 | if (resource !== resourceName) { | 57 | if (resource !== resourceName) { |
58 | log.error('Unknown resource name: expected:', resourceName, 'got:', resource); | 58 | log.error('Unknown resource name: expected:', resourceName, 'got:', resource); |
59 | return; | 59 | return; |
60 | } | 60 | } |
61 | if (stateId !== xtextStateId) { | 61 | if (stateId !== xtextStateId) { |
62 | log.error('Unexpected xtext state id: expected:', xtextStateId, 'got:', resource); | 62 | log.error('Unexpected xtext state id: expected:', xtextStateId, 'got:', stateId); |
63 | await this.updateService.updateFullText(); | 63 | // The current push message might be stale (referring to a previous state), |
64 | // so this is not neccessarily an error and there is no need to force-reconnect. | ||
65 | return; | ||
64 | } | 66 | } |
65 | switch (service) { | 67 | switch (service) { |
66 | case 'highlight': | 68 | case 'highlight': |
diff --git a/language-web/src/main/js/xtext/XtextWebSocketClient.ts b/language-web/src/main/js/xtext/XtextWebSocketClient.ts index 839d6518..488e4b3b 100644 --- a/language-web/src/main/js/xtext/XtextWebSocketClient.ts +++ b/language-web/src/main/js/xtext/XtextWebSocketClient.ts | |||
@@ -27,14 +27,14 @@ const REQUEST_TIMEOUT_MS = 1000; | |||
27 | 27 | ||
28 | const log = getLogger('xtext.XtextWebSocketClient'); | 28 | const log = getLogger('xtext.XtextWebSocketClient'); |
29 | 29 | ||
30 | type ReconnectHandler = () => Promise<void>; | 30 | export type ReconnectHandler = () => void; |
31 | 31 | ||
32 | type PushHandler = ( | 32 | export type PushHandler = ( |
33 | resourceId: string, | 33 | resourceId: string, |
34 | stateId: string, | 34 | stateId: string, |
35 | service: string, | 35 | service: string, |
36 | data: unknown, | 36 | data: unknown, |
37 | ) => Promise<void>; | 37 | ) => void; |
38 | 38 | ||
39 | enum State { | 39 | enum State { |
40 | Initial, | 40 | Initial, |
@@ -47,29 +47,29 @@ enum State { | |||
47 | } | 47 | } |
48 | 48 | ||
49 | export class XtextWebSocketClient { | 49 | export class XtextWebSocketClient { |
50 | nextMessageId = 0; | 50 | private nextMessageId = 0; |
51 | 51 | ||
52 | connection!: WebSocket; | 52 | private connection!: WebSocket; |
53 | 53 | ||
54 | pendingRequests = new Map<string, PendingTask<unknown>>(); | 54 | private readonly pendingRequests = new Map<string, PendingTask<unknown>>(); |
55 | 55 | ||
56 | onReconnect: ReconnectHandler; | 56 | private readonly onReconnect: ReconnectHandler; |
57 | 57 | ||
58 | onPush: PushHandler; | 58 | private readonly onPush: PushHandler; |
59 | 59 | ||
60 | state = State.Initial; | 60 | private state = State.Initial; |
61 | 61 | ||
62 | reconnectTryCount = 0; | 62 | private reconnectTryCount = 0; |
63 | 63 | ||
64 | idleTimer = new Timer(() => { | 64 | private readonly idleTimer = new Timer(() => { |
65 | this.handleIdleTimeout(); | 65 | this.handleIdleTimeout(); |
66 | }, BACKGROUND_IDLE_TIMEOUT_MS); | 66 | }, BACKGROUND_IDLE_TIMEOUT_MS); |
67 | 67 | ||
68 | pingTimer = new Timer(() => { | 68 | private readonly pingTimer = new Timer(() => { |
69 | this.sendPing(); | 69 | this.sendPing(); |
70 | }, PING_TIMEOUT_MS); | 70 | }, PING_TIMEOUT_MS); |
71 | 71 | ||
72 | reconnectTimer = new Timer(() => { | 72 | private readonly reconnectTimer = new Timer(() => { |
73 | this.handleReconnect(); | 73 | this.handleReconnect(); |
74 | }); | 74 | }); |
75 | 75 | ||
@@ -115,9 +115,7 @@ export class XtextWebSocketClient { | |||
115 | this.nextMessageId = 0; | 115 | this.nextMessageId = 0; |
116 | this.reconnectTryCount = 0; | 116 | this.reconnectTryCount = 0; |
117 | this.pingTimer.schedule(); | 117 | this.pingTimer.schedule(); |
118 | this.onReconnect().catch((error) => { | 118 | this.onReconnect(); |
119 | log.error('Unexpected error in onReconnect handler', error); | ||
120 | }); | ||
121 | }); | 119 | }); |
122 | this.connection.addEventListener('error', (event) => { | 120 | this.connection.addEventListener('error', (event) => { |
123 | log.error('Unexpected websocket error', event); | 121 | log.error('Unexpected websocket error', event); |
@@ -264,9 +262,7 @@ export class XtextWebSocketClient { | |||
264 | message.stateId, | 262 | message.stateId, |
265 | message.service, | 263 | message.service, |
266 | message.push, | 264 | message.push, |
267 | ).catch((error) => { | 265 | ); |
268 | log.error('Unexpected error in onPush handler', error); | ||
269 | }); | ||
270 | } else { | 266 | } else { |
271 | log.error('Unexpected websocket message', message); | 267 | log.error('Unexpected websocket message', message); |
272 | this.forceReconnectOnError(); | 268 | this.forceReconnectOnError(); |