@lvce-editor/shared-process 0.15.17 → 0.15.18

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 (54) hide show
  1. package/config/builtinCommands.json +4 -0
  2. package/package.json +4 -4
  3. package/src/parts/AttachDebugger/AttachDebugger.ipc.js +7 -0
  4. package/src/parts/AttachDebugger/AttachDebugger.js +6 -0
  5. package/src/parts/Callback/Callback.js +17 -26
  6. package/src/parts/CleanStack/CleanStack.js +4 -0
  7. package/src/parts/CommandNotFoundError/CommandNotFoundError.js +2 -1
  8. package/src/parts/CreateCpuProfile/CreateCpuProfile.js +59 -0
  9. package/src/parts/DestroySocket/DestroySocket.js +5 -0
  10. package/src/parts/DevtoolsProtocolRpc/DevtoolsProtocolRpc.js +32 -0
  11. package/src/parts/ElectronInitialize/ElectronInitialize.js +9 -38
  12. package/src/parts/ErrorHandling/ErrorHandling.js +12 -14
  13. package/src/parts/GetActualPath/GetActualPath.js +8 -0
  14. package/src/parts/GetErrorResponse/GetErrorResponse.js +5 -3
  15. package/src/parts/GetFirstWebSocketEvent/GetFirstWebSocketEvent.js +41 -0
  16. package/src/parts/GetResponse/GetResponse.js +3 -3
  17. package/src/parts/HandleElectronMessagePort/HandleElectronMessagePort.ipc.js +7 -0
  18. package/src/parts/HandleElectronMessagePort/HandleElectronMessagePort.js +14 -0
  19. package/src/parts/HandleIpc/HandleIpc.js +4 -4
  20. package/src/parts/HandleNodeMessagePort/HandleNodeMessagePort.ipc.js +7 -0
  21. package/src/parts/HandleNodeMessagePort/HandleNodeMessagePort.js +12 -0
  22. package/src/parts/HandleWebSocket/HandleWebSocket.js +15 -14
  23. package/src/parts/HandleWebSocketForSharedProcess/HandleWebSocketForSharedProcess.js +10 -3
  24. package/src/parts/Id/Id.js +7 -0
  25. package/src/parts/IpcChild/IpcChild.js +3 -2
  26. package/src/parts/IpcChildModule/IpcChildModule.js +6 -0
  27. package/src/parts/IpcChildType/IpcChildType.js +3 -0
  28. package/src/parts/IpcChildWithElectronMessagePort/IpcChildWithElectronMessagePort.js +41 -0
  29. package/src/parts/IpcChildWithElectronUtilityProcess/IpcChildWithElectronUtilityProcess.js +25 -1
  30. package/src/parts/IpcChildWithNodeForkedProcess/IpcChildWithNodeForkedProcess.js +21 -1
  31. package/src/parts/IpcChildWithNodeMessagePort/IpcChildWithNodeMessagePort.js +41 -0
  32. package/src/parts/IpcChildWithNodeWorker/IpcChildWithNodeWorker.js +17 -1
  33. package/src/parts/IpcChildWithWebSocket/IpcChildWithWebSocket.js +51 -0
  34. package/src/parts/IpcError/IpcError.js +6 -0
  35. package/src/parts/IsMessagePort/IsMessagePort.js +3 -0
  36. package/src/parts/IsMessagePortMain/IsMessagePortMain.js +3 -0
  37. package/src/parts/IsSocket/IsSocket.js +5 -0
  38. package/src/parts/IsWebSocketOpen/IsWebSocketOpen.js +5 -0
  39. package/src/parts/JsonRpc/JsonRpc.js +18 -22
  40. package/src/parts/Module/Module.js +8 -0
  41. package/src/parts/ModuleId/ModuleId.js +4 -0
  42. package/src/parts/ModuleMap/ModuleMap.js +12 -0
  43. package/src/parts/PrettyError/PrettyError.js +3 -19
  44. package/src/parts/Process/Process.ipc.js +1 -0
  45. package/src/parts/Process/Process.js +8 -0
  46. package/src/parts/ProcessDisplayName/ProcessDisplayName.js +1 -0
  47. package/src/parts/RequiresSocket/RequiresSocket.js +0 -1
  48. package/src/parts/Signal/Signal.js +2 -0
  49. package/src/parts/Terminal/Terminal.js +29 -16
  50. package/src/parts/TerminalState/TerminalState.js +15 -0
  51. package/src/parts/WebSocketServer/WebSocketServer.js +7 -2
  52. package/src/sharedProcessMain.cjs +1 -0
  53. package/src/sharedProcessMain.js +2 -1
  54. package/src/parts/Socket/Socket.js +0 -77
@@ -230,6 +230,10 @@
230
230
  "id": "RebuildNodePty.rebuildNodePty",
231
231
  "label": "Developer: Rebuild Node Pty"
232
232
  },
233
+ {
234
+ "id": "DebugSharedProcess.debugSharedProcess",
235
+ "label": "Developer: Debug Shared Process"
236
+ },
233
237
  {
234
238
  "id": "Window.reload",
235
239
  "label": "Window: Reload",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/shared-process",
3
- "version": "0.15.17",
3
+ "version": "0.15.18",
4
4
  "description": "Utility package for @lvce-editor/server",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -17,9 +17,9 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@babel/code-frame": "^7.21.4",
20
- "@lvce-editor/extension-host": "0.15.17",
21
- "@lvce-editor/extension-host-helper-process": "0.15.17",
22
- "@lvce-editor/pty-host": "0.15.17",
20
+ "@lvce-editor/extension-host": "0.15.18",
21
+ "@lvce-editor/extension-host-helper-process": "0.15.18",
22
+ "@lvce-editor/pty-host": "0.15.18",
23
23
  "debug": "^4.3.4",
24
24
  "execa": "^7.1.1",
25
25
  "exit-hook": "^3.2.0",
@@ -0,0 +1,7 @@
1
+ import * as AttachDebugger from './AttachDebugger.js'
2
+
3
+ export const name = 'AttachDebugger'
4
+
5
+ export const Commands = {
6
+ attachDebugger: AttachDebugger.attachDebugger,
7
+ }
@@ -0,0 +1,6 @@
1
+ import * as Process from '../Process/Process.js'
2
+ import * as Signal from '../Signal/Signal.js'
3
+
4
+ export const attachDebugger = (pid) => {
5
+ Process.kill(pid, Signal.SIGUSR1)
6
+ }
@@ -1,48 +1,39 @@
1
+ import * as Id from '../Id/Id.js'
2
+
1
3
  export const state = {
2
4
  callbacks: Object.create(null),
3
5
  onceListeners: new Set(),
4
- id: 2,
5
- }
6
-
7
- export const register = (resolve, reject) => {
8
- state.callbacks[++state.id] = {
9
- resolve,
10
- reject,
11
- }
12
- return state.id
13
6
  }
14
7
 
15
- export const unregister = (id) => {
16
- delete state.callbacks[id]
8
+ export const registerPromise = () => {
9
+ const id = Id.create()
10
+ const promise = new Promise((resolve, reject) => {
11
+ state.callbacks[id] = { resolve, reject }
12
+ })
13
+ return { id, promise }
17
14
  }
18
15
 
19
16
  // TODO merge resolve and resolveEmpty
20
17
  export const resolve = (id, args) => {
21
- if (!(id in state.callbacks)) {
18
+ const { callbacks } = state
19
+ if (!(id in callbacks)) {
22
20
  console.warn(`callback ${id} may already be disposed`)
23
21
  return
24
22
  }
25
- state.callbacks[id].resolve(args)
26
- }
27
-
28
- export const resolveEmpty = (id) => {
29
- if (!(id in state.callbacks)) {
30
- console.warn(`callback (resolved) ${id} may already be disposed`)
31
- return
32
- }
33
- state.callbacks[id].resolve()
23
+ callbacks[id].resolve(args)
24
+ delete callbacks[id]
34
25
  }
35
26
 
36
27
  export const reject = (id, error) => {
37
- if (!(id in state.callbacks)) {
28
+ const { callbacks } = state
29
+ if (!(id in callbacks)) {
38
30
  console.warn(`callback (rejected) ${id} may already be disposed`)
39
31
  return
40
32
  }
41
- state.callbacks[id].reject(error)
33
+ callbacks[id].reject(error)
34
+ delete callbacks[id]
42
35
  }
43
36
 
44
37
  export const isAllEmpty = () => {
45
- return (
46
- Object.keys(state.callbacks).length === 0 && state.onceListeners.size === 0
47
- )
38
+ return Object.keys(state.callbacks).length === 0 && state.onceListeners.size === 0
48
39
  }
@@ -7,6 +7,7 @@ const RE_GET_RESPONSE = /^\s*at async getResponse/
7
7
  const RE_WEBSOCKET_HANDLE_MESSAGE = /^\s*at async WebSocket.handleMessage/
8
8
  const RE_EXECUTE_COMMAND_ASYNC = /^\s*at executeCommandAsync/
9
9
  const RE_HANDLE_OTHER_MESSAGES_FROM_MESSAGE_PORT = /^\s*at async MessagePort\.handleOtherMessagesFromMessagePort/
10
+ const RE_ASSERT = /^\s*at .*\/Assert\.js/
10
11
 
11
12
  const isInternalLine = (line) => {
12
13
  return line.includes('node:') || RE_AT_PROMISE_INDEX.test(line) || line.includes('node_modules/ws')
@@ -18,6 +19,9 @@ const isRelevantLine = (line) => {
18
19
 
19
20
  const isApplicationUsefulLine = (line, index) => {
20
21
  if (index === 0) {
22
+ if (RE_ASSERT.test(line)) {
23
+ return false
24
+ }
21
25
  return true
22
26
  }
23
27
  if (RE_GET_RESPONSE.test(line)) {
@@ -1,8 +1,9 @@
1
1
  import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
2
+ import * as ProcessDisplayName from '../ProcessDisplayName/ProcessDisplayName.js'
2
3
 
3
4
  export class CommandNotFoundError extends Error {
4
5
  constructor(id) {
5
- super(`command ${id} not found`)
6
+ super(`command ${id} not found in ${ProcessDisplayName.processDisplayName}`)
6
7
  this.name = 'CommandNotFoundError'
7
8
  this.code = ErrorCodes.E_COMMAND_NOT_FOUND
8
9
  }
@@ -0,0 +1,59 @@
1
+ import { writeFile } from 'fs/promises'
2
+ import got from 'got'
3
+ import { tmpdir } from 'os'
4
+ import { join } from 'path'
5
+ import { WebSocket } from 'ws'
6
+ import * as DevtoolsProtocolRpc from '../DevtoolsProtocolRpc/DevtoolsProtocolRpc.js'
7
+
8
+ const createConnection = (webSocketDebuggerUrl) => {
9
+ const webSocket = new WebSocket(webSocketDebuggerUrl)
10
+ // console.log({ webSocket })
11
+ return {
12
+ on(event, listener) {
13
+ if (event === 'message') {
14
+ const wrappedListener = (string) => {
15
+ listener(JSON.parse(string))
16
+ }
17
+ webSocket.on(event, wrappedListener)
18
+ } else {
19
+ webSocket.on(event, listener)
20
+ }
21
+ },
22
+ send(message) {
23
+ webSocket.send(JSON.stringify(message))
24
+ },
25
+ }
26
+ }
27
+
28
+ export const createCpuProfile = async (pid) => {
29
+ // AttachDebugger.attachDebugger(pid)
30
+ const response = await got('http://localhost:9229/json/list').json()
31
+ const first = response[0]
32
+ const webSocketDebuggerUrl = first.webSocketDebuggerUrl
33
+ const ipc = createConnection(webSocketDebuggerUrl)
34
+
35
+ await new Promise((r) => {
36
+ ipc.on('open', r)
37
+ })
38
+ const rpc = DevtoolsProtocolRpc.create(ipc)
39
+ const result = await rpc.invoke('Debugger.enable')
40
+ const debuggerId = result.result.debuggerId
41
+ console.log({ debuggerId })
42
+ const p = await rpc.invoke('Profiler.enable')
43
+ await rpc.invoke('Profiler.start')
44
+ await new Promise((r) => {
45
+ setTimeout(r, 10000)
46
+ })
47
+ const profileResult = await rpc.invoke('Profiler.stop')
48
+ console.log({ profileResult })
49
+ const profile = profileResult.result.profile
50
+ const profilePath = join(tmpdir(), 'node-profile.cpuprofile')
51
+ const profileString = JSON.stringify(profile)
52
+ await writeFile(profilePath, profileString)
53
+ console.log('finished')
54
+ // const value = await rpc.invoke('Runtime.evaluate', {
55
+ // expression: '1+1',
56
+ // })
57
+ // await rpc.invoke('Debugger.pause')
58
+ // console.log({ value })
59
+ }
@@ -0,0 +1,5 @@
1
+ export const destroySocket = (socket) => {
2
+ try {
3
+ socket.destroy()
4
+ } catch {}
5
+ }
@@ -0,0 +1,32 @@
1
+ const Id = {
2
+ id: 1,
3
+ create() {
4
+ return this.id++
5
+ },
6
+ }
7
+
8
+ export const create = (ipc) => {
9
+ const callbacks = Object.create(null)
10
+ const handleMessage = (message) => {
11
+ if ('result' in message) {
12
+ const callback = callbacks[message.id]
13
+ callback(message)
14
+ delete callbacks[message.id]
15
+ }
16
+ }
17
+ ipc.on('message', handleMessage)
18
+ return {
19
+ invoke(method, params = {}) {
20
+ const id = Id.create()
21
+ const promise = new Promise((resolve, reject) => {
22
+ callbacks[id] = resolve
23
+ })
24
+ ipc.send({
25
+ method,
26
+ id,
27
+ params,
28
+ })
29
+ return promise
30
+ },
31
+ }
32
+ }
@@ -1,40 +1,11 @@
1
- import * as Callback from '../Callback/Callback.js'
2
- import * as Command from '../Command/Command.js'
3
- import * as GetResponse from '../GetResponse/GetResponse.js'
1
+ import * as HandleIpc from '../HandleIpc/HandleIpc.js'
2
+ import * as IpcChild from '../IpcChild/IpcChild.js'
3
+ import * as IpcChildType from '../IpcChildType/IpcChildType.js'
4
4
 
5
- export const electronInitialize = (port, folder) => {
6
- // TODO handle error
7
- const fakeSocket = {
8
- send: port.postMessage.bind(port),
9
- on(event, listener) {
10
- switch (event) {
11
- case 'close':
12
- port.on('close', listener)
13
- break
14
- case 'message':
15
- port.on('message', listener)
16
- break
17
- default:
18
- console.warn('socket event not implemented', event, listener)
19
- break
20
- }
21
- },
22
- }
23
- const handleOtherMessagesFromMessagePort = async (message) => {
24
- // console.log('got port message', message)
25
- if (message.result) {
26
- Callback.resolve(message.id, message.result)
27
- } else if (message.method) {
28
- if (message.id) {
29
- const response = await GetResponse.getResponse(message, fakeSocket)
30
- port.postMessage(response)
31
- } else {
32
- console.warn(`[shared process] sending messages without id is deprecated: ${message.method}`)
33
- Command.execute(message.method, fakeSocket, ...message.params)
34
- }
35
- } else {
36
- console.warn('unknown message', message)
37
- }
38
- }
39
- port.on('message', handleOtherMessagesFromMessagePort)
5
+ export const electronInitialize = async (port, folder) => {
6
+ const ipc = await IpcChild.listen({
7
+ method: IpcChildType.NodeMessagePort,
8
+ messagePort: port,
9
+ })
10
+ HandleIpc.handleIpc(ipc)
40
11
  }
@@ -1,11 +1,9 @@
1
1
  import * as ExitCode from '../ExitCode/ExitCode.js'
2
+ import * as GetNewLineIndex from '../GetNewLineIndex/GetNewLineIndex.js'
2
3
  import * as IsIgnoredError from '../IsIgnoredError/IsIgnoredError.js'
3
- import * as JsonRpcVersion from '../JsonRpcVersion/JsonRpcVersion.js'
4
4
  import * as Logger from '../Logger/Logger.js'
5
5
  import * as PrettyError from '../PrettyError/PrettyError.js'
6
6
  import * as Process from '../Process/Process.js'
7
- import * as Socket from '../Socket/Socket.js'
8
- import * as GetNewLineIndex from '../GetNewLineIndex/GetNewLineIndex.js'
9
7
 
10
8
  export const state = {
11
9
  seenErrors: [],
@@ -30,17 +28,17 @@ export const handleError = (error) => {
30
28
  }
31
29
  state.seenErrors.push(error.message)
32
30
  const prettyError = preparePrettyError(error)
33
- Socket.send({
34
- jsonrpc: JsonRpcVersion.Two,
35
- method: /* Dialog.showErrorDialogWithOptions */ 'Dialog.showMessage',
36
- params: [
37
- {
38
- message: prettyError.message,
39
- codeFrame: prettyError.codeFrame,
40
- stack: prettyError.stack,
41
- },
42
- ],
43
- })
31
+ // Socket.send({
32
+ // jsonrpc: JsonRpcVersion.Two,
33
+ // method: /* Dialog.showErrorDialogWithOptions */ 'Dialog.showMessage',
34
+ // params: [
35
+ // {
36
+ // message: prettyError.message,
37
+ // codeFrame: prettyError.codeFrame,
38
+ // stack: prettyError.stack,
39
+ // },
40
+ // ],
41
+ // })
44
42
  printPrettyError(prettyError)
45
43
  }
46
44
 
@@ -0,0 +1,8 @@
1
+ import { fileURLToPath } from 'node:url'
2
+
3
+ export const getActualPath = (fileUri) => {
4
+ if (fileUri.startsWith('file://')) {
5
+ return fileURLToPath(fileUri)
6
+ }
7
+ return fileUri
8
+ }
@@ -12,7 +12,11 @@ const shouldLogError = (error) => {
12
12
  return true
13
13
  }
14
14
 
15
- export const getErrorResponse = (message, error) => {
15
+ export const getErrorResponse = (message, error, ipc) => {
16
+ const prettyError = PrettyError.prepare(error)
17
+ if (shouldLogError(error) && (!ipc || ipc.shouldLogError !== false)) {
18
+ PrintPrettyError.printPrettyError(prettyError, `[shared-process] `)
19
+ }
16
20
  if (error && error instanceof CommandNotFoundError) {
17
21
  return {
18
22
  jsonrpc: JsonRpcVersion.Two,
@@ -37,8 +41,6 @@ export const getErrorResponse = (message, error) => {
37
41
  },
38
42
  }
39
43
  }
40
- const prettyError = PrettyError.prepare(error)
41
- PrintPrettyError.printPrettyError(prettyError, `[shared-process] `)
42
44
  return {
43
45
  jsonrpc: JsonRpcVersion.Two,
44
46
  id: message.id,
@@ -0,0 +1,41 @@
1
+ import * as FirstWebSocketEventType from '../FirstWebSocketEventType/FirstWebSocketEventType.js'
2
+ import { WebSocket } from 'ws'
3
+
4
+ export const getFirstWebSocketEvent = async (webSocket) => {
5
+ switch (webSocket.readyState) {
6
+ case WebSocket.OPEN:
7
+ return {
8
+ type: FirstWebSocketEventType.Open,
9
+ event: undefined,
10
+ }
11
+ case WebSocket.CLOSED:
12
+ return {
13
+ type: FirstWebSocketEventType.Close,
14
+ event: undefined,
15
+ }
16
+ default:
17
+ break
18
+ }
19
+ const { type, event } = await new Promise((resolve) => {
20
+ const cleanup = (value) => {
21
+ webSocket.off('open', handleOpen)
22
+ webSocket.off('close', handleClose)
23
+ resolve(value)
24
+ }
25
+ const handleOpen = (event) => {
26
+ cleanup({
27
+ type: FirstWebSocketEventType.Open,
28
+ event,
29
+ })
30
+ }
31
+ const handleClose = (event) => {
32
+ cleanup({
33
+ type: FirstWebSocketEventType.Close,
34
+ event,
35
+ })
36
+ }
37
+ webSocket.on('open', handleOpen)
38
+ webSocket.on('close', handleClose)
39
+ })
40
+ return { type, event }
41
+ }
@@ -3,13 +3,13 @@ import * as GetErrorResponse from '../GetErrorResponse/GetErrorResponse.js'
3
3
  import * as GetSuccessResponse from '../GetSuccessResponse/GetSuccessResponse.js'
4
4
  import * as RequiresSocket from '../RequiresSocket/RequiresSocket.js'
5
5
 
6
- export const getResponse = async (message, handle) => {
6
+ export const getResponse = async (message, ipc) => {
7
7
  try {
8
8
  const result = RequiresSocket.requiresSocket(message.method)
9
- ? await Command.execute(message.method, handle, ...message.params)
9
+ ? await Command.execute(message.method, ipc, ...message.params)
10
10
  : await Command.execute(message.method, ...message.params)
11
11
  return GetSuccessResponse.getSuccessResponse(message, result)
12
12
  } catch (error) {
13
- return GetErrorResponse.getErrorResponse(message, error)
13
+ return GetErrorResponse.getErrorResponse(message, error, ipc)
14
14
  }
15
15
  }
@@ -0,0 +1,7 @@
1
+ import * as HandleElectronMessagePort from './HandleElectronMessagePort.js'
2
+
3
+ export const name = 'HandleElectronMessagePort'
4
+
5
+ export const Commands = {
6
+ handleElectronMessagePort: HandleElectronMessagePort.handleElectronMessagePort,
7
+ }
@@ -0,0 +1,14 @@
1
+ import * as Assert from '../Assert/Assert.js'
2
+ import * as HandleIpc from '../HandleIpc/HandleIpc.js'
3
+ import * as IpcChild from '../IpcChild/IpcChild.js'
4
+ import * as IpcChildType from '../IpcChildType/IpcChildType.js'
5
+
6
+ export const handleElectronMessagePort = async (messagePort) => {
7
+ Assert.object(messagePort)
8
+ const ipc = await IpcChild.listen({
9
+ method: IpcChildType.ElectronMessagePort,
10
+ messagePort,
11
+ })
12
+ HandleIpc.handleIpc(ipc)
13
+ messagePort.start()
14
+ }
@@ -7,9 +7,9 @@ const handleJsonRpcResult = (message) => {
7
7
  }
8
8
 
9
9
  export const handleIpc = (ipc) => {
10
- const handleJsonRpcMessage = async (message, handle) => {
10
+ const handleJsonRpcMessage = async (message) => {
11
11
  if (message.method) {
12
- const response = await GetResponse.getResponse(message, handle)
12
+ const response = await GetResponse.getResponse(message, ipc)
13
13
  ipc.send(response)
14
14
  } else {
15
15
  // TODO handle error
@@ -17,12 +17,12 @@ export const handleIpc = (ipc) => {
17
17
  }
18
18
  }
19
19
 
20
- const handleMessageFromParentProcess = async (message, handle) => {
20
+ const handleMessageFromParentProcess = async (message) => {
21
21
  if (message.result) {
22
22
  return handleJsonRpcResult(message)
23
23
  }
24
24
  if (message.method) {
25
- return handleJsonRpcMessage(message, handle)
25
+ return handleJsonRpcMessage(message)
26
26
  }
27
27
  console.warn('unknown message', message)
28
28
  }
@@ -0,0 +1,7 @@
1
+ import * as HandleNodeMessagePort from './HandleNodeMessagePort.js'
2
+
3
+ export const name = 'HandleNodeMessagePort'
4
+
5
+ export const Commands = {
6
+ handleNodeMessagePort: HandleNodeMessagePort.handleNodeMessagePort,
7
+ }
@@ -0,0 +1,12 @@
1
+ import * as HandleIpc from '../HandleIpc/HandleIpc.js'
2
+ import * as IpcChild from '../IpcChild/IpcChild.js'
3
+ import * as IpcChildType from '../IpcChildType/IpcChildType.js'
4
+
5
+ export const handleNodeMessagePort = async (messagePort) => {
6
+ const ipc = await IpcChild.listen({
7
+ method: IpcChildType.NodeMessagePort,
8
+ messagePort,
9
+ })
10
+ HandleIpc.handleIpc(ipc)
11
+ messagePort.start()
12
+ }
@@ -1,25 +1,26 @@
1
1
  import * as Assert from '../Assert/Assert.js'
2
+ import * as DestroyWebSocket from '../DestroySocket/DestroySocket.js'
2
3
  import * as HandleWebSocketModule from '../HandleWebSocketModule/HandleWebSocketModule.js'
3
4
  import { VError } from '../VError/VError.js'
4
5
 
5
- export const handleWebSocket = async (handle, message) => {
6
- Assert.object(message)
7
- Assert.object(handle)
8
- const headers = message.headers
9
- if (!headers) {
10
- throw new VError('missing websocket headers')
11
- }
12
- const protocol = headers['sec-websocket-protocol']
13
- if (!protocol) {
14
- throw new VError('missing sec websocket protocol header')
15
- }
6
+ export const handleWebSocket = async (message, handle) => {
16
7
  try {
8
+ Assert.object(message)
9
+ Assert.object(handle)
10
+ const headers = message.headers
11
+ if (!headers) {
12
+ throw new VError('missing websocket headers')
13
+ }
14
+ const protocol = headers['sec-websocket-protocol']
15
+ if (!protocol) {
16
+ throw new VError('missing sec websocket protocol header')
17
+ }
18
+ handle.pause()
17
19
  const module = await HandleWebSocketModule.load(protocol)
18
20
  await module.handleWebSocket(message, handle, protocol)
21
+ handle.resume()
19
22
  } catch (error) {
20
- try {
21
- handle.destroy()
22
- } catch {}
23
+ DestroyWebSocket.destroySocket(handle)
23
24
  throw new VError(error, `Failed to connect to websocket`)
24
25
  }
25
26
  }
@@ -1,16 +1,23 @@
1
1
  import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
2
- import * as Socket from '../Socket/Socket.js'
2
+ import * as HandleIpc from '../HandleIpc/HandleIpc.js'
3
+ import * as IpcChild from '../IpcChild/IpcChild.js'
4
+ import * as IpcChildType from '../IpcChildType/IpcChildType.js'
5
+ import * as Logger from '../Logger/Logger.js'
3
6
  import * as WebSocketServer from '../WebSocketServer/WebSocketServer.js'
4
7
 
5
8
  const handleSocketError = (error) => {
6
9
  if (error && error.code === ErrorCodes.ECONNRESET) {
7
10
  return
8
11
  }
9
- console.info('[info shared process: handle error]', error)
12
+ Logger.info('[info shared process: handle error]', error)
10
13
  }
11
14
 
12
15
  export const handleWebSocket = async (message, handle) => {
13
16
  handle.on('error', handleSocketError)
14
17
  const webSocket = await WebSocketServer.handleUpgrade(message, handle)
15
- Socket.set(webSocket)
18
+ const ipc = await IpcChild.listen({
19
+ method: IpcChildType.WebSocket,
20
+ webSocket,
21
+ })
22
+ HandleIpc.handleIpc(ipc)
16
23
  }
@@ -0,0 +1,7 @@
1
+ export const state = {
2
+ id: 0,
3
+ }
4
+
5
+ export const create = () => {
6
+ return ++state.id
7
+ }
@@ -1,8 +1,9 @@
1
1
  import * as IpcChildModule from '../IpcChildModule/IpcChildModule.js'
2
2
 
3
- export const listen = async ({ method }) => {
3
+ export const listen = async ({ method, ...params }) => {
4
4
  const module = await IpcChildModule.getModule(method)
5
- const rawIpc = await module.listen()
5
+ // @ts-ignore
6
+ const rawIpc = await module.listen(params)
6
7
  const ipc = module.wrap(rawIpc)
7
8
  return ipc
8
9
  }
@@ -8,6 +8,12 @@ export const getModule = (method) => {
8
8
  return import('../IpcChildWithNodeWorker/IpcChildWithNodeWorker.js')
9
9
  case IpcChildType.ElectronUtilityProcess:
10
10
  return import('../IpcChildWithElectronUtilityProcess/IpcChildWithElectronUtilityProcess.js')
11
+ case IpcChildType.ElectronMessagePort:
12
+ return import('../IpcChildWithElectronMessagePort/IpcChildWithElectronMessagePort.js')
13
+ case IpcChildType.NodeMessagePort:
14
+ return import('../IpcChildWithNodeMessagePort/IpcChildWithNodeMessagePort.js')
15
+ case IpcChildType.WebSocket:
16
+ return import('../IpcChildWithWebSocket/IpcChildWithWebSocket.js')
11
17
  default:
12
18
  throw new Error('unexpected ipc type')
13
19
  }
@@ -1,6 +1,9 @@
1
1
  export const NodeWorker = 1
2
2
  export const NodeForkedProcess = 2
3
3
  export const ElectronUtilityProcess = 3
4
+ export const ElectronMessagePort = 4
5
+ export const NodeMessagePort = 5
6
+ export const WebSocket = 6
4
7
 
5
8
  export const Auto = () => {
6
9
  const { argv } = process
@@ -0,0 +1,41 @@
1
+ import { IpcError } from '../IpcError/IpcError.js'
2
+ import * as IsMessagePortMain from '../IsMessagePortMain/IsMessagePortMain.js'
3
+
4
+ export const listen = ({ messagePort }) => {
5
+ if (!IsMessagePortMain.isMessagePortMain(messagePort)) {
6
+ throw new IpcError('port must be of type MessagePortMain')
7
+ }
8
+ return messagePort
9
+ }
10
+
11
+ const getActualData = (event) => {
12
+ return event.data
13
+ }
14
+
15
+ export const wrap = (messagePort) => {
16
+ return {
17
+ messagePort,
18
+ on(event, listener) {
19
+ if (event === 'message') {
20
+ const wrappedListener = (event) => {
21
+ const actualData = getActualData(event)
22
+ listener(actualData)
23
+ }
24
+ this.messagePort.on(event, wrappedListener)
25
+ } else if (event === 'close') {
26
+ this.messagePort.on('close', listener)
27
+ } else {
28
+ throw new Error('unsupported event type')
29
+ }
30
+ },
31
+ off(event, listener) {
32
+ this.messagePort.off(event, listener)
33
+ },
34
+ send(message) {
35
+ this.messagePort.postMessage(message)
36
+ },
37
+ dispose() {
38
+ this.messagePort.close()
39
+ },
40
+ }
41
+ }