@theia/core 1.44.0 → 1.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/README.md +6 -6
  2. package/i18n/nls.cs.json +10 -3
  3. package/i18n/nls.de.json +10 -3
  4. package/i18n/nls.es.json +10 -3
  5. package/i18n/nls.fr.json +10 -3
  6. package/i18n/nls.hu.json +10 -3
  7. package/i18n/nls.it.json +10 -3
  8. package/i18n/nls.ja.json +10 -3
  9. package/i18n/nls.json +10 -3
  10. package/i18n/nls.pl.json +10 -3
  11. package/i18n/nls.pt-br.json +10 -3
  12. package/i18n/nls.pt-pt.json +10 -3
  13. package/i18n/nls.ru.json +10 -3
  14. package/i18n/nls.zh-cn.json +10 -3
  15. package/lib/browser/common-frontend-contribution.d.ts +6 -0
  16. package/lib/browser/common-frontend-contribution.d.ts.map +1 -1
  17. package/lib/browser/common-frontend-contribution.js +52 -9
  18. package/lib/browser/common-frontend-contribution.js.map +1 -1
  19. package/lib/browser/connection-status-service.d.ts +2 -2
  20. package/lib/browser/connection-status-service.d.ts.map +1 -1
  21. package/lib/browser/connection-status-service.js +3 -3
  22. package/lib/browser/connection-status-service.js.map +1 -1
  23. package/lib/browser/connection-status-service.spec.js +6 -6
  24. package/lib/browser/connection-status-service.spec.js.map +1 -1
  25. package/lib/browser/core-preferences.d.ts.map +1 -1
  26. package/lib/browser/core-preferences.js +16 -0
  27. package/lib/browser/core-preferences.js.map +1 -1
  28. package/lib/browser/dialogs.d.ts +0 -1
  29. package/lib/browser/dialogs.d.ts.map +1 -1
  30. package/lib/browser/dialogs.js +1 -34
  31. package/lib/browser/dialogs.js.map +1 -1
  32. package/lib/browser/frontend-application-module.d.ts.map +1 -1
  33. package/lib/browser/frontend-application-module.js +1 -0
  34. package/lib/browser/frontend-application-module.js.map +1 -1
  35. package/lib/browser/messaging/connection-source.d.ts +9 -0
  36. package/lib/browser/messaging/connection-source.d.ts.map +1 -0
  37. package/lib/browser/messaging/connection-source.js +20 -0
  38. package/lib/browser/messaging/connection-source.js.map +1 -0
  39. package/lib/browser/messaging/frontend-id-provider.d.ts +13 -0
  40. package/lib/browser/messaging/frontend-id-provider.d.ts.map +1 -0
  41. package/lib/browser/messaging/frontend-id-provider.js +40 -0
  42. package/lib/browser/messaging/frontend-id-provider.js.map +1 -0
  43. package/lib/browser/messaging/messaging-frontend-module.d.ts.map +1 -1
  44. package/lib/browser/messaging/messaging-frontend-module.js +18 -1
  45. package/lib/browser/messaging/messaging-frontend-module.js.map +1 -1
  46. package/lib/browser/messaging/service-connection-provider.d.ts +48 -0
  47. package/lib/browser/messaging/service-connection-provider.d.ts.map +1 -0
  48. package/lib/browser/messaging/service-connection-provider.js +115 -0
  49. package/lib/browser/messaging/service-connection-provider.js.map +1 -0
  50. package/lib/browser/messaging/ws-connection-provider.d.ts +7 -38
  51. package/lib/browser/messaging/ws-connection-provider.d.ts.map +1 -1
  52. package/lib/browser/messaging/ws-connection-provider.js +17 -121
  53. package/lib/browser/messaging/ws-connection-provider.js.map +1 -1
  54. package/lib/browser/messaging/ws-connection-source.d.ts +41 -0
  55. package/lib/browser/messaging/ws-connection-source.d.ts.map +1 -0
  56. package/lib/browser/messaging/ws-connection-source.js +210 -0
  57. package/lib/browser/messaging/ws-connection-source.js.map +1 -0
  58. package/lib/browser/preload/i18n-preload-contribution.js +1 -1
  59. package/lib/browser/preload/i18n-preload-contribution.js.map +1 -1
  60. package/lib/browser/shell/application-shell.js +1 -1
  61. package/lib/browser/shell/application-shell.js.map +1 -1
  62. package/lib/browser/tree/tree-compression/compressed-tree-widget.d.ts +1 -0
  63. package/lib/browser/tree/tree-compression/compressed-tree-widget.d.ts.map +1 -1
  64. package/lib/browser/tree/tree-compression/compressed-tree-widget.js +5 -0
  65. package/lib/browser/tree/tree-compression/compressed-tree-widget.js.map +1 -1
  66. package/lib/browser/tree/tree-widget.d.ts +6 -0
  67. package/lib/browser/tree/tree-widget.d.ts.map +1 -1
  68. package/lib/browser/tree/tree-widget.js +21 -11
  69. package/lib/browser/tree/tree-widget.js.map +1 -1
  70. package/lib/browser/user-working-directory-provider.d.ts +8 -1
  71. package/lib/browser/user-working-directory-provider.d.ts.map +1 -1
  72. package/lib/browser/user-working-directory-provider.js +22 -1
  73. package/lib/browser/user-working-directory-provider.js.map +1 -1
  74. package/lib/browser/window/default-secondary-window-service.d.ts +3 -0
  75. package/lib/browser/window/default-secondary-window-service.d.ts.map +1 -1
  76. package/lib/browser/window/default-secondary-window-service.js +55 -1
  77. package/lib/browser/window/default-secondary-window-service.js.map +1 -1
  78. package/lib/common/message-rpc/channel.d.ts.map +1 -1
  79. package/lib/common/message-rpc/channel.js +7 -1
  80. package/lib/common/message-rpc/channel.js.map +1 -1
  81. package/lib/common/message-rpc/message-buffer.d.ts +2 -0
  82. package/lib/common/message-rpc/message-buffer.d.ts.map +1 -1
  83. package/lib/common/message-rpc/message-buffer.js +4 -0
  84. package/lib/common/message-rpc/message-buffer.js.map +1 -1
  85. package/lib/common/message-rpc/uint8-array-message-buffer.d.ts +1 -0
  86. package/lib/common/message-rpc/uint8-array-message-buffer.d.ts.map +1 -1
  87. package/lib/common/message-rpc/uint8-array-message-buffer.js +6 -0
  88. package/lib/common/message-rpc/uint8-array-message-buffer.js.map +1 -1
  89. package/lib/common/messaging/connection-management.d.ts +25 -0
  90. package/lib/common/messaging/connection-management.d.ts.map +1 -0
  91. package/lib/common/messaging/connection-management.js +38 -0
  92. package/lib/common/messaging/connection-management.js.map +1 -0
  93. package/lib/common/messaging/handler.d.ts +1 -0
  94. package/lib/common/messaging/handler.d.ts.map +1 -1
  95. package/lib/common/messaging/handler.js +2 -1
  96. package/lib/common/messaging/handler.js.map +1 -1
  97. package/lib/common/messaging/socket-write-buffer.d.ts +11 -0
  98. package/lib/common/messaging/socket-write-buffer.d.ts.map +1 -0
  99. package/lib/common/messaging/socket-write-buffer.js +50 -0
  100. package/lib/common/messaging/socket-write-buffer.js.map +1 -0
  101. package/lib/common/messaging/web-socket-channel.d.ts +7 -35
  102. package/lib/common/messaging/web-socket-channel.d.ts.map +1 -1
  103. package/lib/common/messaging/web-socket-channel.js +20 -9
  104. package/lib/common/messaging/web-socket-channel.js.map +1 -1
  105. package/lib/electron-browser/messaging/electron-frontend-id-provider.d.ts +5 -0
  106. package/lib/electron-browser/messaging/electron-frontend-id-provider.d.ts.map +1 -0
  107. package/lib/{electron-node/token/electron-token-messaging-contribution.js → electron-browser/messaging/electron-frontend-id-provider.js} +9 -28
  108. package/lib/electron-browser/messaging/electron-frontend-id-provider.js.map +1 -0
  109. package/lib/electron-browser/messaging/electron-ipc-connection-source.d.ts +24 -0
  110. package/lib/electron-browser/messaging/electron-ipc-connection-source.d.ts.map +1 -0
  111. package/lib/electron-browser/messaging/{electron-ipc-connection-provider.js → electron-ipc-connection-source.js} +19 -19
  112. package/lib/electron-browser/messaging/electron-ipc-connection-source.js.map +1 -0
  113. package/lib/electron-browser/messaging/electron-local-ws-connection-source.d.ts +7 -0
  114. package/lib/electron-browser/messaging/electron-local-ws-connection-source.d.ts.map +1 -0
  115. package/lib/electron-browser/messaging/{electron-local-ws-connection-provider.js → electron-local-ws-connection-source.js} +7 -7
  116. package/lib/electron-browser/messaging/electron-local-ws-connection-source.js.map +1 -0
  117. package/lib/electron-browser/messaging/electron-messaging-frontend-module.d.ts.map +1 -1
  118. package/lib/electron-browser/messaging/electron-messaging-frontend-module.js +45 -13
  119. package/lib/electron-browser/messaging/electron-messaging-frontend-module.js.map +1 -1
  120. package/lib/electron-browser/messaging/electron-ws-connection-source.d.ts +12 -0
  121. package/lib/electron-browser/messaging/electron-ws-connection-source.d.ts.map +1 -0
  122. package/lib/electron-browser/messaging/{electron-ws-connection-provider.js → electron-ws-connection-source.js} +14 -21
  123. package/lib/electron-browser/messaging/electron-ws-connection-source.js.map +1 -0
  124. package/lib/electron-browser/preload.d.ts.map +1 -1
  125. package/lib/electron-browser/preload.js +10 -0
  126. package/lib/electron-browser/preload.js.map +1 -1
  127. package/lib/electron-browser/window/electron-window-module.js +2 -2
  128. package/lib/electron-browser/window/electron-window-module.js.map +1 -1
  129. package/lib/electron-browser/window/electron-window-service.d.ts +4 -0
  130. package/lib/electron-browser/window/electron-window-service.d.ts.map +1 -1
  131. package/lib/electron-browser/window/electron-window-service.js +13 -0
  132. package/lib/electron-browser/window/electron-window-service.js.map +1 -1
  133. package/lib/electron-common/electron-api.d.ts +6 -0
  134. package/lib/electron-common/electron-api.d.ts.map +1 -1
  135. package/lib/electron-common/electron-api.js +3 -1
  136. package/lib/electron-common/electron-api.js.map +1 -1
  137. package/lib/electron-main/electron-api-main.d.ts +1 -0
  138. package/lib/electron-main/electron-api-main.d.ts.map +1 -1
  139. package/lib/electron-main/electron-api-main.js +15 -0
  140. package/lib/electron-main/electron-api-main.js.map +1 -1
  141. package/lib/electron-main/electron-main-application-module.js +5 -5
  142. package/lib/electron-main/electron-main-application-module.js.map +1 -1
  143. package/lib/electron-main/electron-main-application.d.ts +7 -13
  144. package/lib/electron-main/electron-main-application.d.ts.map +1 -1
  145. package/lib/electron-main/electron-main-application.js +36 -26
  146. package/lib/electron-main/electron-main-application.js.map +1 -1
  147. package/lib/electron-main/messaging/electron-connection-handler.d.ts.map +1 -0
  148. package/lib/electron-main/messaging/electron-connection-handler.js.map +1 -0
  149. package/lib/electron-main/messaging/electron-messaging-contribution.d.ts +13 -22
  150. package/lib/electron-main/messaging/electron-messaging-contribution.d.ts.map +1 -1
  151. package/lib/electron-main/messaging/electron-messaging-contribution.js +39 -39
  152. package/lib/electron-main/messaging/electron-messaging-contribution.js.map +1 -1
  153. package/lib/electron-main/messaging/electron-messaging-service.d.ts.map +1 -1
  154. package/lib/electron-main/messaging/electron-messaging-service.js.map +1 -1
  155. package/lib/electron-main/theia-electron-window.d.ts +2 -2
  156. package/lib/electron-main/theia-electron-window.d.ts.map +1 -1
  157. package/lib/electron-main/theia-electron-window.js +3 -2
  158. package/lib/electron-main/theia-electron-window.js.map +1 -1
  159. package/lib/node/messaging/default-messaging-service.d.ts +29 -0
  160. package/lib/node/messaging/default-messaging-service.d.ts.map +1 -0
  161. package/lib/node/messaging/default-messaging-service.js +140 -0
  162. package/lib/node/messaging/default-messaging-service.js.map +1 -0
  163. package/lib/node/messaging/frontend-connection-service.d.ts +7 -0
  164. package/lib/node/messaging/frontend-connection-service.d.ts.map +1 -0
  165. package/lib/node/messaging/frontend-connection-service.js +19 -0
  166. package/lib/node/messaging/frontend-connection-service.js.map +1 -0
  167. package/lib/node/messaging/messaging-backend-module.d.ts.map +1 -1
  168. package/lib/node/messaging/messaging-backend-module.js +23 -9
  169. package/lib/node/messaging/messaging-backend-module.js.map +1 -1
  170. package/lib/node/messaging/messaging-service.d.ts +2 -3
  171. package/lib/node/messaging/messaging-service.d.ts.map +1 -1
  172. package/lib/node/messaging/test/test-web-socket-channel.d.ts +3 -3
  173. package/lib/node/messaging/test/test-web-socket-channel.d.ts.map +1 -1
  174. package/lib/node/messaging/test/test-web-socket-channel.js +38 -24
  175. package/lib/node/messaging/test/test-web-socket-channel.js.map +1 -1
  176. package/lib/node/messaging/websocket-endpoint.d.ts +21 -0
  177. package/lib/node/messaging/websocket-endpoint.d.ts.map +1 -0
  178. package/lib/node/messaging/websocket-endpoint.js +89 -0
  179. package/lib/node/messaging/websocket-endpoint.js.map +1 -0
  180. package/lib/node/messaging/websocket-frontend-connection-service.d.ts +30 -0
  181. package/lib/node/messaging/websocket-frontend-connection-service.d.ts.map +1 -0
  182. package/lib/node/messaging/websocket-frontend-connection-service.js +173 -0
  183. package/lib/node/messaging/websocket-frontend-connection-service.js.map +1 -0
  184. package/package.json +6 -6
  185. package/src/browser/common-frontend-contribution.ts +55 -9
  186. package/src/browser/connection-status-service.spec.ts +6 -6
  187. package/src/browser/connection-status-service.ts +2 -2
  188. package/src/browser/core-preferences.ts +16 -0
  189. package/src/browser/dialogs.ts +0 -34
  190. package/src/browser/frontend-application-module.ts +1 -0
  191. package/src/browser/messaging/connection-source.ts +26 -0
  192. package/src/browser/messaging/frontend-id-provider.ts +37 -0
  193. package/src/browser/messaging/messaging-frontend-module.ts +20 -2
  194. package/src/browser/messaging/service-connection-provider.ts +126 -0
  195. package/src/browser/messaging/ws-connection-provider.ts +16 -141
  196. package/src/browser/messaging/ws-connection-source.ts +210 -0
  197. package/src/browser/preload/i18n-preload-contribution.ts +1 -1
  198. package/src/browser/shell/application-shell.ts +1 -1
  199. package/src/browser/tree/tree-compression/compressed-tree-widget.tsx +27 -7
  200. package/src/browser/tree/tree-widget.tsx +21 -10
  201. package/src/browser/user-working-directory-provider.ts +32 -3
  202. package/src/browser/window/default-secondary-window-service.ts +54 -1
  203. package/src/common/i18n/nls.metadata.json +7208 -6923
  204. package/src/common/message-rpc/channel.ts +5 -1
  205. package/src/common/message-rpc/message-buffer.ts +6 -0
  206. package/src/common/message-rpc/uint8-array-message-buffer.ts +7 -0
  207. package/src/common/messaging/connection-management.ts +43 -0
  208. package/src/common/messaging/handler.ts +2 -0
  209. package/src/common/messaging/socket-write-buffer.ts +52 -0
  210. package/src/common/messaging/web-socket-channel.ts +28 -45
  211. package/src/electron-browser/messaging/electron-frontend-id-provider.ts +25 -0
  212. package/src/electron-browser/messaging/{electron-ipc-connection-provider.ts → electron-ipc-connection-source.ts} +17 -13
  213. package/src/electron-browser/messaging/{electron-local-ws-connection-provider.ts → electron-local-ws-connection-source.ts} +2 -2
  214. package/src/electron-browser/messaging/electron-messaging-frontend-module.ts +49 -12
  215. package/src/electron-browser/messaging/{electron-ws-connection-provider.ts → electron-ws-connection-source.ts} +6 -17
  216. package/src/electron-browser/preload.ts +15 -1
  217. package/src/electron-browser/window/electron-window-module.ts +1 -1
  218. package/src/electron-browser/window/electron-window-service.ts +11 -0
  219. package/src/electron-common/electron-api.ts +7 -0
  220. package/src/electron-main/electron-api-main.ts +20 -1
  221. package/src/electron-main/electron-main-application-module.ts +5 -5
  222. package/src/electron-main/electron-main-application.ts +46 -41
  223. package/src/electron-main/messaging/electron-messaging-contribution.ts +45 -43
  224. package/src/electron-main/messaging/electron-messaging-service.ts +1 -0
  225. package/src/electron-main/theia-electron-window.ts +4 -3
  226. package/src/node/messaging/default-messaging-service.ts +129 -0
  227. package/src/node/messaging/frontend-connection-service.ts +24 -0
  228. package/src/node/messaging/messaging-backend-module.ts +25 -10
  229. package/src/node/messaging/messaging-service.ts +3 -3
  230. package/src/node/messaging/test/test-web-socket-channel.ts +32 -27
  231. package/src/node/messaging/websocket-endpoint.ts +79 -0
  232. package/src/node/messaging/websocket-frontend-connection-service.ts +171 -0
  233. package/lib/common/messaging/abstract-connection-provider.d.ts +0 -45
  234. package/lib/common/messaging/abstract-connection-provider.d.ts.map +0 -1
  235. package/lib/common/messaging/abstract-connection-provider.js +0 -93
  236. package/lib/common/messaging/abstract-connection-provider.js.map +0 -1
  237. package/lib/electron-browser/messaging/electron-ipc-connection-provider.d.ts +0 -19
  238. package/lib/electron-browser/messaging/electron-ipc-connection-provider.d.ts.map +0 -1
  239. package/lib/electron-browser/messaging/electron-ipc-connection-provider.js.map +0 -1
  240. package/lib/electron-browser/messaging/electron-local-ws-connection-provider.d.ts +0 -7
  241. package/lib/electron-browser/messaging/electron-local-ws-connection-provider.d.ts.map +0 -1
  242. package/lib/electron-browser/messaging/electron-local-ws-connection-provider.js.map +0 -1
  243. package/lib/electron-browser/messaging/electron-ws-connection-provider.d.ts +0 -17
  244. package/lib/electron-browser/messaging/electron-ws-connection-provider.d.ts.map +0 -1
  245. package/lib/electron-browser/messaging/electron-ws-connection-provider.js.map +0 -1
  246. package/lib/electron-common/messaging/electron-connection-handler.d.ts.map +0 -1
  247. package/lib/electron-common/messaging/electron-connection-handler.js.map +0 -1
  248. package/lib/electron-node/token/electron-token-messaging-contribution.d.ts +0 -16
  249. package/lib/electron-node/token/electron-token-messaging-contribution.d.ts.map +0 -1
  250. package/lib/electron-node/token/electron-token-messaging-contribution.js.map +0 -1
  251. package/lib/node/messaging/messaging-contribution.d.ts +0 -44
  252. package/lib/node/messaging/messaging-contribution.d.ts.map +0 -1
  253. package/lib/node/messaging/messaging-contribution.js +0 -210
  254. package/lib/node/messaging/messaging-contribution.js.map +0 -1
  255. package/src/common/messaging/abstract-connection-provider.ts +0 -115
  256. package/src/electron-node/token/electron-token-messaging-contribution.ts +0 -41
  257. package/src/node/messaging/messaging-contribution.ts +0 -197
  258. /package/lib/{electron-common → electron-main}/messaging/electron-connection-handler.d.ts +0 -0
  259. /package/lib/{electron-common → electron-main}/messaging/electron-connection-handler.js +0 -0
  260. /package/src/{electron-common → electron-main}/messaging/electron-connection-handler.ts +0 -0
@@ -220,6 +220,8 @@ export class ChannelMultiplexer implements Disposable {
220
220
  this.openChannels.set(id, channel);
221
221
  resolve(channel);
222
222
  this.onOpenChannelEmitter.fire({ id, channel });
223
+ } else {
224
+ console.error(`not expecting ack-open on for ${id}`);
223
225
  }
224
226
  }
225
227
 
@@ -234,6 +236,8 @@ export class ChannelMultiplexer implements Disposable {
234
236
  }
235
237
  this.underlyingChannel.getWriteBuffer().writeUint8(MessageTypes.AckOpen).writeString(id).commit();
236
238
  this.onOpenChannelEmitter.fire({ id, channel });
239
+ } else {
240
+ console.error(`channel already open: ${id}`);
237
241
  }
238
242
  }
239
243
 
@@ -275,7 +279,7 @@ export class ChannelMultiplexer implements Disposable {
275
279
  }
276
280
 
277
281
  open(id: string): Promise<Channel> {
278
- if (this.openChannels.has(id)) {
282
+ if (this.openChannels.has(id) || this.pendingOpen.has(id)) {
279
283
  throw new Error(`Another channel with the id '${id}' is already open.`);
280
284
  }
281
285
  const result = new Promise<Channel>((resolve, reject) => {
@@ -25,6 +25,7 @@ export interface WriteBuffer {
25
25
  writeBytes(value: Uint8Array): this
26
26
  writeNumber(value: number): this
27
27
  writeLength(value: number): this
28
+ writeRaw(bytes: Uint8Array): this;
28
29
  /**
29
30
  * Makes any writes to the buffer permanent, for example by sending the writes over a channel.
30
31
  * You must obtain a new write buffer after committing
@@ -71,6 +72,11 @@ export class ForwardingWriteBuffer implements WriteBuffer {
71
72
  return this;
72
73
  }
73
74
 
75
+ writeRaw(bytes: Uint8Array): this {
76
+ this.underlying.writeRaw(bytes);
77
+ return this;
78
+ }
79
+
74
80
  commit(): void {
75
81
  this.underlying.commit();
76
82
  }
@@ -76,6 +76,13 @@ export class Uint8ArrayWriteBuffer implements WriteBuffer, Disposable {
76
76
  return this;
77
77
  }
78
78
 
79
+ writeRaw(bytes: Uint8Array): this {
80
+ this.ensureCapacity(bytes.byteLength);
81
+ this.buffer.set(bytes, this.offset);
82
+ this.offset += bytes.byteLength;
83
+ return this;
84
+ }
85
+
79
86
  writeUint16(value: number): this {
80
87
  this.ensureCapacity(2);
81
88
  this.msg.setUint16(this.offset, value);
@@ -0,0 +1,43 @@
1
+
2
+ // *****************************************************************************
3
+ // Copyright (C) 2017 TypeFox and others.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+
18
+ export const ConnectionCloseService = Symbol('ConnectionCloseService');
19
+ export const connectionCloseServicePath = '/services/ChannelCloseService';
20
+
21
+ /**
22
+ * These messages are used to negotiate service reconnection between a front ends and back end.
23
+ * Whenever a front end first connects to a back end, it sends the ${@link ConnectionManagementMessages#INITIAL_CONNECT} message
24
+ * together with its front end id.
25
+ * The back end then starts a new front end connection context for that front end. If the back end already had another connection context
26
+ * for the given front end id, it gets discarded.
27
+ * If the front end reconnects after a websocket disconnect, it sends the ${@link ConnectionManagementMessages#RECONNECT} message
28
+ * together with its front end id..
29
+ * If the back end still has a connection context for the front end id, the context is reconnected and the back end replies with the value true.
30
+ * If there is no context anymore, the back end replies with value false. The front end can then either do an initial connect or reload
31
+ * the whole UI.
32
+ */
33
+ export namespace ConnectionManagementMessages {
34
+ export const INITIAL_CONNECT = 'initialConnection';
35
+ export const RECONNECT = 'reconnect';
36
+ }
37
+
38
+ /**
39
+ * A service to mark a front end as unused. As soon as it disconnects from the back end, the connection context will be discarded.
40
+ */
41
+ export interface ConnectionCloseService {
42
+ markForClose(frontEndId: string): Promise<void>;
43
+ }
@@ -16,6 +16,8 @@
16
16
 
17
17
  import { Channel } from '../message-rpc/channel';
18
18
 
19
+ export const servicesPath = '/services';
20
+
19
21
  export const ConnectionHandler = Symbol('ConnectionHandler');
20
22
 
21
23
  export interface ConnectionHandler {
@@ -0,0 +1,52 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2018 TypeFox and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { WebSocket } from './web-socket-channel';
18
+
19
+ export class SocketWriteBuffer {
20
+ private static DISCONNECTED_BUFFER_SIZE = 100 * 1024;
21
+
22
+ private disconnectedBuffer: Uint8Array | undefined;
23
+ private bufferWritePosition = 0;
24
+
25
+ buffer(data: Uint8Array): void {
26
+ this.ensureWriteBuffer(data.byteLength);
27
+ this.disconnectedBuffer?.set(data, this.bufferWritePosition);
28
+ this.bufferWritePosition += data.byteLength;
29
+ }
30
+
31
+ protected ensureWriteBuffer(byteLength: number): void {
32
+ if (!this.disconnectedBuffer) {
33
+ this.disconnectedBuffer = new Uint8Array(SocketWriteBuffer.DISCONNECTED_BUFFER_SIZE);
34
+ this.bufferWritePosition = 0;
35
+ }
36
+
37
+ if (this.bufferWritePosition + byteLength > this.disconnectedBuffer.byteLength) {
38
+ throw new Error(`Max disconnected buffer size exceeded by adding ${byteLength} bytes`);
39
+ }
40
+ }
41
+
42
+ flush(socket: WebSocket): void {
43
+ if (this.disconnectedBuffer) {
44
+ socket.send(this.disconnectedBuffer.slice(0, this.bufferWritePosition));
45
+ this.disconnectedBuffer = undefined;
46
+ }
47
+ }
48
+
49
+ drain(): void {
50
+ this.disconnectedBuffer = undefined;
51
+ }
52
+ }
@@ -19,7 +19,11 @@
19
19
  import { WriteBuffer } from '../message-rpc';
20
20
  import { Uint8ArrayReadBuffer, Uint8ArrayWriteBuffer } from '../message-rpc/uint8-array-message-buffer';
21
21
  import { AbstractChannel } from '../message-rpc/channel';
22
- import { Disposable } from '../disposable';
22
+ import { Socket as ClientSocket } from 'socket.io-client';
23
+ import { Socket as ServerSocket } from 'socket.io';
24
+ import { Emitter } from 'vscode-languageserver-protocol';
25
+
26
+ export type WebSocket = ClientSocket | ServerSocket;
23
27
 
24
28
  /**
25
29
  * A channel that manages the main websocket connection between frontend and backend. All service channels
@@ -29,65 +33,44 @@ import { Disposable } from '../disposable';
29
33
  export class WebSocketChannel extends AbstractChannel {
30
34
  static wsPath = '/services';
31
35
 
32
- constructor(protected readonly socket: IWebSocket) {
36
+ private onDidConnectEmitter = new Emitter<void>();
37
+ onDidConnect = this.onDidConnectEmitter.event;
38
+
39
+ constructor(protected readonly socket: WebSocket) {
33
40
  super();
34
- this.toDispose.push(Disposable.create(() => socket.close()));
35
- socket.onClose((reason, code) => this.onCloseEmitter.fire({ reason, code }));
36
- socket.onClose(() => this.close());
37
- socket.onError(error => this.onErrorEmitter.fire(error));
38
- socket.onMessage(data => this.onMessageEmitter.fire(() => {
41
+ socket.on('connect', () => {
42
+ this.onDidConnectEmitter.fire();
43
+ });
44
+
45
+ socket.on('disconnect', reason => {
46
+ this.onCloseEmitter.fire({
47
+ reason: reason
48
+ });
49
+ });
50
+
51
+ socket.on('error', reason => this.onErrorEmitter.fire(reason));
52
+ socket.on('message', data => {
39
53
  // In the browser context socketIO receives binary messages as ArrayBuffers.
40
54
  // So we have to convert them to a Uint8Array before delegating the message to the read buffer.
41
55
  const buffer = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
42
- return new Uint8ArrayReadBuffer(buffer);
43
- }));
56
+ this.onMessageEmitter.fire(() => new Uint8ArrayReadBuffer(buffer));
57
+ });
44
58
  }
45
59
 
46
60
  getWriteBuffer(): WriteBuffer {
47
61
  const result = new Uint8ArrayWriteBuffer();
48
62
 
49
63
  result.onCommit(buffer => {
50
- if (this.socket.isConnected()) {
64
+ if (this.socket.connected) {
51
65
  this.socket.send(buffer);
52
66
  }
53
67
  });
54
68
 
55
69
  return result;
56
70
  }
57
- }
58
71
 
59
- /**
60
- * An abstraction that enables reuse of the `{@link WebSocketChannel} class in the frontend and backend
61
- * independent of the actual underlying socket implementation.
62
- */
63
- export interface IWebSocket {
64
- /**
65
- * Sends the given message over the web socket in binary format.
66
- * @param message The binary message.
67
- */
68
- send(message: Uint8Array): void;
69
- /**
70
- * Closes the websocket from the local side.
71
- */
72
- close(): void;
73
- /**
74
- * The connection state of the web socket.
75
- */
76
- isConnected(): boolean;
77
- /**
78
- * Listener callback to handle incoming messages.
79
- * @param cb The callback.
80
- */
81
- onMessage(cb: (message: Uint8Array) => void): void;
82
- /**
83
- * Listener callback to handle socket errors.
84
- * @param cb The callback.
85
- */
86
- onError(cb: (reason: any) => void): void;
87
- /**
88
- * Listener callback to handle close events (Remote side).
89
- * @param cb The callback.
90
- */
91
- onClose(cb: (reason: string, code?: number) => void): void;
72
+ override close(): void {
73
+ this.socket.disconnect();
74
+ super.close();
75
+ }
92
76
  }
93
-
@@ -0,0 +1,25 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2023 STMicroelectronics and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { injectable } from 'inversify';
18
+ import { FrontendIdProvider } from '../../browser/messaging/frontend-id-provider';
19
+
20
+ @injectable()
21
+ export class ElectronFrontendIdProvider implements FrontendIdProvider {
22
+ getId(): string {
23
+ return window.electronTheiaCore.WindowMetadata.webcontentId;
24
+ }
25
+ }
@@ -16,32 +16,36 @@
16
16
 
17
17
  import { injectable, interfaces } from 'inversify';
18
18
  import { RpcProxy } from '../../common/messaging';
19
- import { AbstractConnectionProvider } from '../../common/messaging/abstract-connection-provider';
20
- import { AbstractChannel, Channel, WriteBuffer } from '../../common';
19
+ import { AbstractChannel, Channel, Emitter, Event, MaybePromise, WriteBuffer } from '../../common';
21
20
  import { Uint8ArrayReadBuffer, Uint8ArrayWriteBuffer } from '../../common/message-rpc/uint8-array-message-buffer';
21
+ import { ServiceConnectionProvider } from '../../browser/messaging/service-connection-provider';
22
+ import { ConnectionSource } from '../../browser/messaging/connection-source';
23
+ import { FrontendApplicationContribution } from '../../browser';
22
24
 
23
25
  export interface ElectronIpcOptions {
24
26
  }
25
27
 
28
+ export const ElectronMainConnectionProvider = Symbol('ElectronMainConnectionProvider');
29
+
26
30
  /**
27
31
  * Connection provider between the Theia frontend and the electron-main process via IPC.
28
32
  */
29
- @injectable()
30
- export class ElectronIpcConnectionProvider extends AbstractConnectionProvider<ElectronIpcOptions> {
33
+ export namespace ElectronIpcConnectionProvider {
31
34
 
32
- static override createProxy<T extends object>(container: interfaces.Container, path: string, arg?: object): RpcProxy<T> {
33
- return container.get(ElectronIpcConnectionProvider).createProxy<T>(path, arg);
35
+ export function createProxy<T extends object>(container: interfaces.Container, path: string, arg?: object): RpcProxy<T> {
36
+ return container.get<ServiceConnectionProvider>(ElectronMainConnectionProvider).createProxy<T>(path, arg);
34
37
  }
38
+ }
35
39
 
36
- constructor() {
37
- super();
38
- this.initializeMultiplexer();
39
- }
40
+ @injectable()
41
+ export class ElectronIpcConnectionSource implements ConnectionSource, FrontendApplicationContribution {
42
+ protected readonly onConnectionDidOpenEmitter: Emitter<Channel> = new Emitter();
43
+ onConnectionDidOpen: Event<Channel> = this.onConnectionDidOpenEmitter.event;
40
44
 
41
- protected createMainChannel(): Channel {
42
- return new ElectronIpcRendererChannel();
45
+ onStart(): MaybePromise<void> {
46
+ const channel = new ElectronIpcRendererChannel();
47
+ this.onConnectionDidOpenEmitter.fire(channel);
43
48
  }
44
-
45
49
  }
46
50
 
47
51
  export class ElectronIpcRendererChannel extends AbstractChannel {
@@ -15,8 +15,8 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import { injectable } from 'inversify';
18
- import { WebSocketConnectionProvider } from '../../browser/messaging/ws-connection-provider';
19
18
  import { Endpoint } from '../../browser/endpoint';
19
+ import { WebSocketConnectionSource } from '../../browser/messaging/ws-connection-source';
20
20
 
21
21
  export function getLocalPort(): string | undefined {
22
22
  const params = new URLSearchParams(location.search);
@@ -24,7 +24,7 @@ export function getLocalPort(): string | undefined {
24
24
  }
25
25
 
26
26
  @injectable()
27
- export class ElectronLocalWebSocketConnectionProvider extends WebSocketConnectionProvider {
27
+ export class ElectronLocalWebSocketConnectionSource extends WebSocketConnectionSource {
28
28
 
29
29
  protected override createEndpoint(path: string): Endpoint {
30
30
  const localPort = getLocalPort();
@@ -16,26 +16,63 @@
16
16
 
17
17
  import { ContainerModule } from 'inversify';
18
18
  import { FrontendApplicationContribution } from '../../browser/frontend-application-contribution';
19
- import { LocalWebSocketConnectionProvider, WebSocketConnectionProvider } from '../../browser/messaging/ws-connection-provider';
20
- import { ElectronWebSocketConnectionProvider } from './electron-ws-connection-provider';
21
- import { ElectronIpcConnectionProvider } from './electron-ipc-connection-provider';
22
- import { ElectronLocalWebSocketConnectionProvider, getLocalPort } from './electron-local-ws-connection-provider';
19
+ import { ElectronWebSocketConnectionSource } from './electron-ws-connection-source';
20
+ import { ElectronIpcConnectionSource, ElectronMainConnectionProvider } from './electron-ipc-connection-source';
21
+ import { ElectronLocalWebSocketConnectionSource, getLocalPort } from './electron-local-ws-connection-source';
22
+ import { ElectronFrontendIdProvider } from './electron-frontend-id-provider';
23
+ import { FrontendIdProvider } from '../../browser/messaging/frontend-id-provider';
24
+ import { ConnectionSource } from '../../browser/messaging/connection-source';
25
+ import { LocalConnectionProvider, RemoteConnectionProvider, ServiceConnectionProvider } from '../../browser/messaging/service-connection-provider';
26
+ import { WebSocketConnectionProvider } from '../../browser';
27
+ import { ConnectionCloseService, connectionCloseServicePath } from '../../common/messaging/connection-management';
28
+ import { WebSocketConnectionSource } from '../../browser/messaging/ws-connection-source';
29
+
30
+ const backendServiceProvider = Symbol('backendServiceProvider2');
31
+ const localServiceProvider = Symbol('localServiceProvider');
23
32
 
24
33
  export const messagingFrontendModule = new ContainerModule(bind => {
25
- bind(ElectronWebSocketConnectionProvider).toSelf().inSingletonScope();
26
- bind(FrontendApplicationContribution).toService(ElectronWebSocketConnectionProvider);
27
- bind(WebSocketConnectionProvider).toService(ElectronWebSocketConnectionProvider);
28
- bind(ElectronLocalWebSocketConnectionProvider).toSelf().inSingletonScope();
29
- bind(LocalWebSocketConnectionProvider).toDynamicValue(ctx => {
34
+ bind(ConnectionCloseService).toDynamicValue(ctx => WebSocketConnectionProvider.createProxy(ctx.container, connectionCloseServicePath)).inSingletonScope();
35
+ bind(ElectronWebSocketConnectionSource).toSelf().inSingletonScope();
36
+ bind(WebSocketConnectionSource).toService(ElectronWebSocketConnectionSource);
37
+ bind(ElectronIpcConnectionSource).toSelf().inSingletonScope();
38
+ bind(FrontendApplicationContribution).toService(ElectronIpcConnectionSource);
39
+ bind(ElectronLocalWebSocketConnectionSource).toSelf().inSingletonScope();
40
+ bind(backendServiceProvider).toDynamicValue(ctx => {
41
+ const container = ctx.container.createChild();
42
+ container.bind(ServiceConnectionProvider).toSelf().inSingletonScope();
43
+ container.bind(ConnectionSource).toService(ElectronWebSocketConnectionSource);
44
+ return container.get(ServiceConnectionProvider);
45
+ }).inSingletonScope();
46
+
47
+ bind(localServiceProvider).toDynamicValue(ctx => {
48
+ const container = ctx.container.createChild();
49
+ container.bind(ServiceConnectionProvider).toSelf().inSingletonScope();
50
+ container.bind(ConnectionSource).toService(ElectronLocalWebSocketConnectionSource);
51
+ return container.get(ServiceConnectionProvider);
52
+ }).inSingletonScope();
53
+
54
+ bind(ElectronMainConnectionProvider).toDynamicValue(ctx => {
55
+ const container = ctx.container.createChild();
56
+ container.bind(ServiceConnectionProvider).toSelf().inSingletonScope();
57
+ container.bind(ConnectionSource).toService(ElectronIpcConnectionSource);
58
+ return container.get(ServiceConnectionProvider);
59
+ }).inSingletonScope();
60
+
61
+ bind(LocalConnectionProvider).toDynamicValue(ctx => {
30
62
  const localPort = getLocalPort();
31
63
  if (localPort) {
32
64
  // Return new web socket provider that connects to local app
33
- return ctx.container.get(ElectronLocalWebSocketConnectionProvider);
65
+ return ctx.container.get(localServiceProvider);
34
66
  } else {
35
67
  // Return the usual web socket provider that already established its connection
36
68
  // That way we don't create a second socket connection
37
- return ctx.container.get(WebSocketConnectionProvider);
69
+ return ctx.container.get(backendServiceProvider);
38
70
  }
39
71
  }).inSingletonScope();
40
- bind(ElectronIpcConnectionProvider).toSelf().inSingletonScope();
72
+ bind(RemoteConnectionProvider).toService(backendServiceProvider);
73
+
74
+ bind(FrontendApplicationContribution).toService(ElectronWebSocketConnectionSource);
75
+ bind(ElectronFrontendIdProvider).toSelf().inSingletonScope();
76
+ bind(FrontendIdProvider).toService(ElectronFrontendIdProvider);
77
+ bind(WebSocketConnectionProvider).toSelf().inSingletonScope();
41
78
  });
@@ -15,9 +15,8 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import { injectable } from 'inversify';
18
- import { WebSocketConnectionProvider, WebSocketOptions } from '../../browser/messaging/ws-connection-provider';
19
18
  import { FrontendApplicationContribution } from '../../browser/frontend-application-contribution';
20
- import { Channel } from '../../common';
19
+ import { WebSocketConnectionSource } from '../../browser/messaging/ws-connection-source';
21
20
 
22
21
  /**
23
22
  * Customized connection provider between the frontend and the backend in electron environment.
@@ -25,25 +24,15 @@ import { Channel } from '../../common';
25
24
  * once the electron-browser window is refreshed. Otherwise, backend resources are not disposed.
26
25
  */
27
26
  @injectable()
28
- export class ElectronWebSocketConnectionProvider extends WebSocketConnectionProvider implements FrontendApplicationContribution {
29
-
30
- /**
31
- * Do not try to reconnect when the frontend application is stopping. The browser is navigating away from this page.
32
- */
33
- protected stopping = false;
27
+ export class ElectronWebSocketConnectionSource extends WebSocketConnectionSource implements FrontendApplicationContribution {
28
+ constructor() {
29
+ super();
30
+ }
34
31
 
35
32
  onStop(): void {
36
- this.stopping = true;
37
33
  // Manually close the websocket connections `onStop`. Otherwise, the channels will be closed with 30 sec (`MessagingContribution#checkAliveTimeout`) delay.
38
34
  // https://github.com/eclipse-theia/theia/issues/6499
39
35
  // `1001` indicates that an endpoint is "going away", such as a server going down or a browser having navigated away from a page.
40
- this.channelMultiplexer?.onUnderlyingChannelClose({ reason: 'The frontend is "going away"', code: 1001 });
36
+ this.socket.close();
41
37
  }
42
-
43
- override async openChannel(path: string, handler: (channel: Channel) => void, options?: WebSocketOptions): Promise<void> {
44
- if (!this.stopping) {
45
- super.openChannel(path, handler, options);
46
- }
47
- }
48
-
49
38
  }
@@ -25,7 +25,8 @@ import {
25
25
  CHANNEL_ON_WINDOW_EVENT, CHANNEL_GET_ZOOM_LEVEL, CHANNEL_SET_ZOOM_LEVEL, CHANNEL_IS_FULL_SCREENABLE, CHANNEL_TOGGLE_FULL_SCREEN,
26
26
  CHANNEL_IS_FULL_SCREEN, CHANNEL_SET_MENU_BAR_VISIBLE, CHANNEL_REQUEST_CLOSE, CHANNEL_SET_TITLE_STYLE, CHANNEL_RESTART,
27
27
  CHANNEL_REQUEST_RELOAD, CHANNEL_APP_STATE_CHANGED, CHANNEL_SHOW_ITEM_IN_FOLDER, CHANNEL_READ_CLIPBOARD, CHANNEL_WRITE_CLIPBOARD,
28
- CHANNEL_KEYBOARD_LAYOUT_CHANGED, CHANNEL_IPC_CONNECTION, InternalMenuDto, CHANNEL_REQUEST_SECONDARY_CLOSE, CHANNEL_SET_BACKGROUND_COLOR
28
+ CHANNEL_KEYBOARD_LAYOUT_CHANGED, CHANNEL_IPC_CONNECTION, InternalMenuDto, CHANNEL_REQUEST_SECONDARY_CLOSE, CHANNEL_SET_BACKGROUND_COLOR,
29
+ CHANNEL_WC_METADATA, CHANNEL_ABOUT_TO_CLOSE
29
30
  } from '../electron-common/electron-api';
30
31
 
31
32
  // eslint-disable-next-line import/no-extraneous-dependencies
@@ -65,6 +66,7 @@ function convertMenu(menu: MenuDto[] | undefined, handlerMap: Map<number, () =>
65
66
  }
66
67
 
67
68
  const api: TheiaCoreAPI = {
69
+ WindowMetadata: { webcontentId: 'none' },
68
70
  setMenuBarVisible: (visible: boolean, windowName?: string) => ipcRenderer.send(CHANNEL_SET_MENU_BAR_VISIBLE, visible, windowName),
69
71
  setMenu: (menu: MenuDto[] | undefined) => {
70
72
  commandHandlers.delete(mainMenuId);
@@ -119,6 +121,17 @@ const api: TheiaCoreAPI = {
119
121
  close: function (): void {
120
122
  ipcRenderer.send(CHANNEL_CLOSE);
121
123
  },
124
+
125
+ onAboutToClose(handler: () => void): Disposable {
126
+ const h = (event: Electron.IpcRendererEvent, replyChannel: string) => {
127
+ handler();
128
+ event.sender.send(replyChannel);
129
+ };
130
+
131
+ ipcRenderer.on(CHANNEL_ABOUT_TO_CLOSE, h);
132
+ return Disposable.create(() => ipcRenderer.off(CHANNEL_ABOUT_TO_CLOSE, h));
133
+ },
134
+
122
135
  onWindowEvent: function (event: WindowEvent, handler: () => void): Disposable {
123
136
  const h = (_event: unknown, evt: WindowEvent) => {
124
137
  if (event === evt) {
@@ -227,6 +240,7 @@ export function preload(): void {
227
240
  }
228
241
  }
229
242
  });
243
+ api.WindowMetadata.webcontentId = ipcRenderer.sendSync(CHANNEL_WC_METADATA);
230
244
 
231
245
  contextBridge.exposeInMainWorld('electronTheiaCore', api);
232
246
  }
@@ -21,7 +21,7 @@ import { FrontendApplicationContribution } from '../../browser/frontend-applicat
21
21
  import { ElectronClipboardService } from '../electron-clipboard-service';
22
22
  import { ClipboardService } from '../../browser/clipboard-service';
23
23
  import { ElectronMainWindowService, electronMainWindowServicePath } from '../../electron-common/electron-main-window-service';
24
- import { ElectronIpcConnectionProvider } from '../messaging/electron-ipc-connection-provider';
24
+ import { ElectronIpcConnectionProvider } from '../messaging/electron-ipc-connection-source';
25
25
  import { bindWindowPreferences } from './electron-window-preferences';
26
26
  import { FrontendApplicationStateService } from '../../browser/frontend-application-state';
27
27
  import { ElectronFrontendApplicationStateService } from './electron-frontend-application-state';
@@ -19,6 +19,8 @@ import { NewWindowOptions, WindowSearchParams } from '../../common/window';
19
19
  import { DefaultWindowService } from '../../browser/window/default-window-service';
20
20
  import { ElectronMainWindowService } from '../../electron-common/electron-main-window-service';
21
21
  import { ElectronWindowPreferences } from './electron-window-preferences';
22
+ import { ConnectionCloseService } from '../../common/messaging/connection-management';
23
+ import { FrontendIdProvider } from '../../browser/messaging/frontend-id-provider';
22
24
 
23
25
  @injectable()
24
26
  export class ElectronWindowService extends DefaultWindowService {
@@ -33,12 +35,18 @@ export class ElectronWindowService extends DefaultWindowService {
33
35
  */
34
36
  protected closeOnUnload: boolean = false;
35
37
 
38
+ @inject(FrontendIdProvider)
39
+ protected readonly frontendIdProvider: FrontendIdProvider;
40
+
36
41
  @inject(ElectronMainWindowService)
37
42
  protected readonly delegate: ElectronMainWindowService;
38
43
 
39
44
  @inject(ElectronWindowPreferences)
40
45
  protected readonly electronWindowPreferences: ElectronWindowPreferences;
41
46
 
47
+ @inject(ConnectionCloseService)
48
+ protected readonly connectionCloseService: ConnectionCloseService;
49
+
42
50
  override openNewWindow(url: string, { external }: NewWindowOptions = {}): undefined {
43
51
  this.delegate.openNewWindow(url, { external });
44
52
  return undefined;
@@ -56,6 +64,9 @@ export class ElectronWindowService extends DefaultWindowService {
56
64
  this.updateWindowZoomLevel();
57
65
  }
58
66
  });
67
+ window.electronTheiaCore.onAboutToClose(() => {
68
+ this.connectionCloseService.markForClose(this.frontendIdProvider.getId());
69
+ });
59
70
  }
60
71
 
61
72
  protected override registerUnloadListeners(): void {
@@ -41,6 +41,9 @@ export type InternalMenuDto = Omit<MenuDto, 'execute' | 'submenu'> & {
41
41
  export type WindowEvent = 'maximize' | 'unmaximize' | 'focus';
42
42
 
43
43
  export interface TheiaCoreAPI {
44
+ WindowMetadata: {
45
+ webcontentId: string;
46
+ }
44
47
  getSecurityToken: () => string;
45
48
  attachSecurityToken: (endpoint: string) => Promise<void>;
46
49
 
@@ -63,6 +66,7 @@ export interface TheiaCoreAPI {
63
66
  unMaximize(): void;
64
67
  close(): void;
65
68
  onWindowEvent(event: WindowEvent, handler: () => void): Disposable;
69
+ onAboutToClose(handler: () => void): Disposable;
66
70
  setCloseRequestHandler(handler: (reason: StopReason) => Promise<boolean>): void;
67
71
 
68
72
  setSecondaryWindowCloseRequestHandler(windowName: string, handler: () => Promise<boolean>): void;
@@ -96,6 +100,7 @@ declare global {
96
100
  }
97
101
  }
98
102
 
103
+ export const CHANNEL_WC_METADATA = 'WebContentMetadata';
99
104
  export const CHANNEL_SET_MENU = 'SetMenu';
100
105
  export const CHANNEL_SET_MENU_BAR_VISIBLE = 'SetMenuBarVisible';
101
106
  export const CHANNEL_INVOKE_MENU = 'InvokeMenu';
@@ -117,6 +122,8 @@ export const CHANNEL_MINIMIZE = 'Minimize';
117
122
  export const CHANNEL_MAXIMIZE = 'Maximize';
118
123
  export const CHANNEL_IS_MAXIMIZED = 'IsMaximized';
119
124
 
125
+ export const CHANNEL_ABOUT_TO_CLOSE = 'AboutToClose';
126
+
120
127
  export const CHANNEL_UNMAXIMIZE = 'UnMaximize';
121
128
  export const CHANNEL_ON_WINDOW_EVENT = 'OnWindowEvent';
122
129
  export const CHANNEL_TOGGLE_DEVTOOLS = 'ToggleDevtools';
@@ -51,7 +51,9 @@ import {
51
51
  CHANNEL_TOGGLE_FULL_SCREEN,
52
52
  CHANNEL_IS_MAXIMIZED,
53
53
  CHANNEL_REQUEST_SECONDARY_CLOSE,
54
- CHANNEL_SET_BACKGROUND_COLOR
54
+ CHANNEL_SET_BACKGROUND_COLOR,
55
+ CHANNEL_WC_METADATA,
56
+ CHANNEL_ABOUT_TO_CLOSE
55
57
  } from '../electron-common/electron-api';
56
58
  import { ElectronMainApplication, ElectronMainApplicationContribution } from './electron-main-application';
57
59
  import { Disposable, DisposableCollection, isOSX, MaybePromise } from '../common';
@@ -65,6 +67,10 @@ export class TheiaMainApi implements ElectronMainApplicationContribution {
65
67
  protected readonly openPopups = new Map<number, Menu>();
66
68
 
67
69
  onStart(application: ElectronMainApplication): MaybePromise<void> {
70
+ ipcMain.on(CHANNEL_WC_METADATA, event => {
71
+ event.returnValue = event.sender.id.toString();
72
+ });
73
+
68
74
  // electron security token
69
75
  ipcMain.on(CHANNEL_GET_SECURITY_TOKEN, event => {
70
76
  event.returnValue = this.electronSecurityToken.value;
@@ -254,6 +260,19 @@ export namespace TheiaRendererAPI {
254
260
  wc.send(CHANNEL_ON_WINDOW_EVENT, event);
255
261
  }
256
262
 
263
+ export function sendAboutToClose(wc: WebContents): Promise<void> {
264
+ return new Promise<void>(resolve => {
265
+ const channelNr = nextReplyChannel++;
266
+ const replyChannel = `aboutToClose${channelNr}`;
267
+ const l = createDisposableListener(ipcMain, replyChannel, e => {
268
+ l.dispose();
269
+ resolve();
270
+ });
271
+
272
+ wc.send(CHANNEL_ABOUT_TO_CLOSE, replyChannel);
273
+ });
274
+ }
275
+
257
276
  export function requestClose(wc: WebContents, stopReason: StopReason): Promise<boolean> {
258
277
  const channelNr = nextReplyChannel++;
259
278
  const confirmChannel = `confirm-${channelNr}`;