@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.
- package/config/builtinCommands.json +4 -0
- package/package.json +4 -4
- package/src/parts/AttachDebugger/AttachDebugger.ipc.js +7 -0
- package/src/parts/AttachDebugger/AttachDebugger.js +6 -0
- package/src/parts/Callback/Callback.js +17 -26
- package/src/parts/CleanStack/CleanStack.js +4 -0
- package/src/parts/CommandNotFoundError/CommandNotFoundError.js +2 -1
- package/src/parts/CreateCpuProfile/CreateCpuProfile.js +59 -0
- package/src/parts/DestroySocket/DestroySocket.js +5 -0
- package/src/parts/DevtoolsProtocolRpc/DevtoolsProtocolRpc.js +32 -0
- package/src/parts/ElectronInitialize/ElectronInitialize.js +9 -38
- package/src/parts/ErrorHandling/ErrorHandling.js +12 -14
- package/src/parts/GetActualPath/GetActualPath.js +8 -0
- package/src/parts/GetErrorResponse/GetErrorResponse.js +5 -3
- package/src/parts/GetFirstWebSocketEvent/GetFirstWebSocketEvent.js +41 -0
- package/src/parts/GetResponse/GetResponse.js +3 -3
- package/src/parts/HandleElectronMessagePort/HandleElectronMessagePort.ipc.js +7 -0
- package/src/parts/HandleElectronMessagePort/HandleElectronMessagePort.js +14 -0
- package/src/parts/HandleIpc/HandleIpc.js +4 -4
- package/src/parts/HandleNodeMessagePort/HandleNodeMessagePort.ipc.js +7 -0
- package/src/parts/HandleNodeMessagePort/HandleNodeMessagePort.js +12 -0
- package/src/parts/HandleWebSocket/HandleWebSocket.js +15 -14
- package/src/parts/HandleWebSocketForSharedProcess/HandleWebSocketForSharedProcess.js +10 -3
- package/src/parts/Id/Id.js +7 -0
- package/src/parts/IpcChild/IpcChild.js +3 -2
- package/src/parts/IpcChildModule/IpcChildModule.js +6 -0
- package/src/parts/IpcChildType/IpcChildType.js +3 -0
- package/src/parts/IpcChildWithElectronMessagePort/IpcChildWithElectronMessagePort.js +41 -0
- package/src/parts/IpcChildWithElectronUtilityProcess/IpcChildWithElectronUtilityProcess.js +25 -1
- package/src/parts/IpcChildWithNodeForkedProcess/IpcChildWithNodeForkedProcess.js +21 -1
- package/src/parts/IpcChildWithNodeMessagePort/IpcChildWithNodeMessagePort.js +41 -0
- package/src/parts/IpcChildWithNodeWorker/IpcChildWithNodeWorker.js +17 -1
- package/src/parts/IpcChildWithWebSocket/IpcChildWithWebSocket.js +51 -0
- package/src/parts/IpcError/IpcError.js +6 -0
- package/src/parts/IsMessagePort/IsMessagePort.js +3 -0
- package/src/parts/IsMessagePortMain/IsMessagePortMain.js +3 -0
- package/src/parts/IsSocket/IsSocket.js +5 -0
- package/src/parts/IsWebSocketOpen/IsWebSocketOpen.js +5 -0
- package/src/parts/JsonRpc/JsonRpc.js +18 -22
- package/src/parts/Module/Module.js +8 -0
- package/src/parts/ModuleId/ModuleId.js +4 -0
- package/src/parts/ModuleMap/ModuleMap.js +12 -0
- package/src/parts/PrettyError/PrettyError.js +3 -19
- package/src/parts/Process/Process.ipc.js +1 -0
- package/src/parts/Process/Process.js +8 -0
- package/src/parts/ProcessDisplayName/ProcessDisplayName.js +1 -0
- package/src/parts/RequiresSocket/RequiresSocket.js +0 -1
- package/src/parts/Signal/Signal.js +2 -0
- package/src/parts/Terminal/Terminal.js +29 -16
- package/src/parts/TerminalState/TerminalState.js +15 -0
- package/src/parts/WebSocketServer/WebSocketServer.js +7 -2
- package/src/sharedProcessMain.cjs +1 -0
- package/src/sharedProcessMain.js +2 -1
- package/src/parts/Socket/Socket.js +0 -77
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as IsElectron from '../IsElectron/IsElectron.js'
|
|
2
|
+
|
|
1
3
|
export const listen = () => {
|
|
2
4
|
// @ts-ignore
|
|
3
5
|
const parentPort = process.parentPort
|
|
@@ -8,11 +10,33 @@ export const listen = () => {
|
|
|
8
10
|
return parentPort
|
|
9
11
|
}
|
|
10
12
|
|
|
13
|
+
const getActualData = (event) => {
|
|
14
|
+
const { data, ports } = event
|
|
15
|
+
if (ports.length === 0) {
|
|
16
|
+
return data
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
...data,
|
|
20
|
+
params: [...data.params, ...ports],
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
11
24
|
export const wrap = (parentPort) => {
|
|
12
25
|
return {
|
|
26
|
+
shouldLogError: !IsElectron.isElectron(),
|
|
13
27
|
parentPort,
|
|
14
28
|
on(event, listener) {
|
|
15
|
-
|
|
29
|
+
if (event === 'message') {
|
|
30
|
+
const wrappedListener = (event) => {
|
|
31
|
+
const actualData = getActualData(event)
|
|
32
|
+
listener(actualData)
|
|
33
|
+
}
|
|
34
|
+
this.parentPort.on(event, wrappedListener)
|
|
35
|
+
} else if (event === 'close') {
|
|
36
|
+
this.parentPort.on('close', listener)
|
|
37
|
+
} else {
|
|
38
|
+
throw new Error('unsupported event type')
|
|
39
|
+
}
|
|
16
40
|
},
|
|
17
41
|
off(event, listener) {
|
|
18
42
|
this.parentPort.off(event, listener)
|
|
@@ -6,11 +6,31 @@ export const listen = async () => {
|
|
|
6
6
|
return process
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
const getActualData = (message, handle) => {
|
|
10
|
+
if (handle) {
|
|
11
|
+
return {
|
|
12
|
+
...message,
|
|
13
|
+
params: [...message.params, handle],
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return message
|
|
17
|
+
}
|
|
18
|
+
|
|
9
19
|
export const wrap = (process) => {
|
|
10
20
|
return {
|
|
11
21
|
process,
|
|
12
22
|
on(event, listener) {
|
|
13
|
-
|
|
23
|
+
if (event === 'message') {
|
|
24
|
+
const wrappedListener = (event, handle) => {
|
|
25
|
+
const actualData = getActualData(event, handle)
|
|
26
|
+
listener(actualData)
|
|
27
|
+
}
|
|
28
|
+
this.process.on(event, wrappedListener)
|
|
29
|
+
} else if (event === 'close') {
|
|
30
|
+
this.process.on('close', listener)
|
|
31
|
+
} else {
|
|
32
|
+
throw new Error('unsupported event type')
|
|
33
|
+
}
|
|
14
34
|
},
|
|
15
35
|
off(event, listener) {
|
|
16
36
|
this.process.off(event, listener)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { IpcError } from '../IpcError/IpcError.js'
|
|
2
|
+
import * as IsMessagePort from '../IsMessagePort/IsMessagePort.js'
|
|
3
|
+
|
|
4
|
+
export const listen = ({ messagePort }) => {
|
|
5
|
+
if (!IsMessagePort.isMessagePort(messagePort)) {
|
|
6
|
+
throw new IpcError('port must be of type MessagePort')
|
|
7
|
+
}
|
|
8
|
+
return messagePort
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const getActualData = (message) => {
|
|
12
|
+
return message
|
|
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 ${event}`)
|
|
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
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { parentPort } from 'node:worker_threads'
|
|
2
|
+
import * as IsElectron from '../IsElectron/IsElectron.js'
|
|
2
3
|
|
|
3
4
|
export const listen = async () => {
|
|
4
5
|
if (!parentPort) {
|
|
@@ -8,11 +9,26 @@ export const listen = async () => {
|
|
|
8
9
|
return parentPort
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
const getActualData = (message) => {
|
|
13
|
+
return message
|
|
14
|
+
}
|
|
15
|
+
|
|
11
16
|
export const wrap = (parentPort) => {
|
|
12
17
|
return {
|
|
18
|
+
shouldLogError: !IsElectron.isElectron(),
|
|
13
19
|
parentPort,
|
|
14
20
|
on(event, listener) {
|
|
15
|
-
|
|
21
|
+
if (event === 'message') {
|
|
22
|
+
const wrappedListener = (event) => {
|
|
23
|
+
const actualData = getActualData(event)
|
|
24
|
+
listener(actualData)
|
|
25
|
+
}
|
|
26
|
+
this.parentPort.on(event, wrappedListener)
|
|
27
|
+
} else if (event === 'close') {
|
|
28
|
+
this.parentPort.on('close', listener)
|
|
29
|
+
} else {
|
|
30
|
+
throw new Error('unsupported event type')
|
|
31
|
+
}
|
|
16
32
|
},
|
|
17
33
|
off(event, listener) {
|
|
18
34
|
this.parentPort.off(event, listener)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as GetFirstWebSocketEvent from '../GetFirstWebSocketEvent/GetFirstWebSocketEvent.js'
|
|
2
|
+
import * as IsWebSocketOpen from '../IsWebSocketOpen/IsWebSocketOpen.js'
|
|
3
|
+
|
|
4
|
+
export const listen = async ({ webSocket }) => {
|
|
5
|
+
if (!IsWebSocketOpen.isWebSocketOpen(webSocket)) {
|
|
6
|
+
const { type, event } = await GetFirstWebSocketEvent.getFirstWebSocketEvent(webSocket)
|
|
7
|
+
console.log({ type, event })
|
|
8
|
+
}
|
|
9
|
+
return webSocket
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const getActualData = (message) => {
|
|
13
|
+
const data = JSON.parse(message.toString())
|
|
14
|
+
return data
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const wrap = (webSocket) => {
|
|
18
|
+
return {
|
|
19
|
+
webSocket,
|
|
20
|
+
/**
|
|
21
|
+
* @type {any}
|
|
22
|
+
*/
|
|
23
|
+
wrappedListener: undefined,
|
|
24
|
+
on(event, listener) {
|
|
25
|
+
switch (event) {
|
|
26
|
+
case 'message':
|
|
27
|
+
const wrappedListener = (message) => {
|
|
28
|
+
const data = getActualData(message)
|
|
29
|
+
listener(data)
|
|
30
|
+
}
|
|
31
|
+
webSocket.on('message', wrappedListener)
|
|
32
|
+
break
|
|
33
|
+
case 'close':
|
|
34
|
+
webSocket.on('close', listener)
|
|
35
|
+
break
|
|
36
|
+
default:
|
|
37
|
+
throw new Error('unknown event listener type')
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
off(event, listener) {
|
|
41
|
+
this.webSocket.off(event, listener)
|
|
42
|
+
},
|
|
43
|
+
send(message) {
|
|
44
|
+
const stringifiedMessage = JSON.stringify(message)
|
|
45
|
+
this.webSocket.send(stringifiedMessage)
|
|
46
|
+
},
|
|
47
|
+
dispose() {
|
|
48
|
+
this.webSocket.close()
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -10,30 +10,26 @@ export const send = (transport, method, ...params) => {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export const invoke = (ipc, method, ...params) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
params,
|
|
20
|
-
id: callbackId,
|
|
21
|
-
})
|
|
13
|
+
const { id, promise } = Callback.registerPromise()
|
|
14
|
+
ipc.send({
|
|
15
|
+
jsonrpc: JsonRpcVersion.Two,
|
|
16
|
+
method,
|
|
17
|
+
params,
|
|
18
|
+
id,
|
|
22
19
|
})
|
|
20
|
+
return promise
|
|
23
21
|
}
|
|
24
22
|
|
|
25
23
|
export const invokeAndTransfer = (ipc, handle, method, ...params) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
)
|
|
38
|
-
})
|
|
24
|
+
const { id, promise } = Callback.registerPromise()
|
|
25
|
+
ipc.sendAndTransfer(
|
|
26
|
+
{
|
|
27
|
+
jsonrpc: JsonRpcVersion.Two,
|
|
28
|
+
method,
|
|
29
|
+
params,
|
|
30
|
+
id,
|
|
31
|
+
},
|
|
32
|
+
handle
|
|
33
|
+
)
|
|
34
|
+
return promise
|
|
39
35
|
}
|
|
@@ -2,6 +2,8 @@ import * as ModuleId from '../ModuleId/ModuleId.js'
|
|
|
2
2
|
|
|
3
3
|
export const load = (moduleId) => {
|
|
4
4
|
switch (moduleId) {
|
|
5
|
+
case ModuleId.AttachDebugger:
|
|
6
|
+
return import('../AttachDebugger/AttachDebugger.ipc.js')
|
|
5
7
|
case ModuleId.AutoUpdater:
|
|
6
8
|
return import('../AutoUpdater/AutoUpdater.ipc.js')
|
|
7
9
|
case ModuleId.AutoUpdaterAppImage:
|
|
@@ -40,6 +42,8 @@ export const load = (moduleId) => {
|
|
|
40
42
|
return import('../Platform/Platform.ipc.js')
|
|
41
43
|
case ModuleId.Preferences:
|
|
42
44
|
return import('../Preferences/Preferences.ipc.js')
|
|
45
|
+
case ModuleId.Process:
|
|
46
|
+
return import('../Process/Process.ipc.js')
|
|
43
47
|
case ModuleId.RecentlyOpened:
|
|
44
48
|
return import('../RecentlyOpened/RecentlyOpened.ipc.js')
|
|
45
49
|
case ModuleId.SearchFile:
|
|
@@ -58,6 +62,10 @@ export const load = (moduleId) => {
|
|
|
58
62
|
return import('../RebuildNodePty/RebuildNodePty.ipc.js')
|
|
59
63
|
case ModuleId.HandleWebSocket:
|
|
60
64
|
return import('../HandleWebSocket/HandleWebSocket.ipc.js')
|
|
65
|
+
case ModuleId.HandleElectronMessagePort:
|
|
66
|
+
return import('../HandleElectronMessagePort/HandleElectronMessagePort.ipc.js')
|
|
67
|
+
case ModuleId.HandleNodeMessagePort:
|
|
68
|
+
return import('../HandleNodeMessagePort/HandleNodeMessagePort.ipc.js')
|
|
61
69
|
default:
|
|
62
70
|
throw new Error(`module ${moduleId} not found`)
|
|
63
71
|
}
|
|
@@ -26,3 +26,7 @@ export const AutoUpdaterWindowsNsis = 25
|
|
|
26
26
|
export const RebuildNodePty = 26
|
|
27
27
|
export const ElectronInitialize = 27
|
|
28
28
|
export const HandleWebSocket = 28
|
|
29
|
+
export const Process = 29
|
|
30
|
+
export const AttachDebugger = 30
|
|
31
|
+
export const HandleElectronMessagePort = 31
|
|
32
|
+
export const HandleNodeMessagePort = 32
|
|
@@ -3,6 +3,8 @@ import * as ModuleId from '../ModuleId/ModuleId.js'
|
|
|
3
3
|
|
|
4
4
|
export const getModuleId = (commandId) => {
|
|
5
5
|
switch (commandId) {
|
|
6
|
+
case 'AttachDebugger.attachDebugger':
|
|
7
|
+
return ModuleId.AttachDebugger
|
|
6
8
|
case 'AutoUpdater.getAutoUpdateType':
|
|
7
9
|
case 'AutoUpdater.getLatestVersion':
|
|
8
10
|
return ModuleId.AutoUpdater
|
|
@@ -112,6 +114,10 @@ export const getModuleId = (commandId) => {
|
|
|
112
114
|
return ModuleId.GitLsFiles
|
|
113
115
|
case 'HandleWebSocket.handleWebSocket':
|
|
114
116
|
return ModuleId.HandleWebSocket
|
|
117
|
+
case 'HandleElectronMessagePort.handleElectronMessagePort':
|
|
118
|
+
return ModuleId.HandleElectronMessagePort
|
|
119
|
+
case 'HandleNodeMessagePort.handleNodeMessagePort':
|
|
120
|
+
return ModuleId.HandleNodeMessagePort
|
|
115
121
|
case 'InstallExtension.installExtension':
|
|
116
122
|
return ModuleId.InstallExtension
|
|
117
123
|
case 'IsAutoUpdateSupported.isAutoUpdateSupported':
|
|
@@ -161,6 +167,12 @@ export const getModuleId = (commandId) => {
|
|
|
161
167
|
return ModuleId.Workspace
|
|
162
168
|
case 'RebuildNodePty.rebuildNodePty':
|
|
163
169
|
return ModuleId.RebuildNodePty
|
|
170
|
+
case 'Process.getPid':
|
|
171
|
+
return ModuleId.Process
|
|
172
|
+
case 'HandleNodeMessagePort.handleNodeMessagePort':
|
|
173
|
+
return ModuleId.HandleNodeMessagePort
|
|
174
|
+
case 'HandleElectronMessagePort.handleElectronMessagePort':
|
|
175
|
+
return ModuleId.HandleElectronMessagePort
|
|
164
176
|
default:
|
|
165
177
|
throw new CommandNotFoundError(commandId)
|
|
166
178
|
}
|
|
@@ -1,22 +1,14 @@
|
|
|
1
1
|
import { codeFrameColumns } from '@babel/code-frame'
|
|
2
2
|
import { LinesAndColumns } from 'lines-and-columns'
|
|
3
3
|
import { readFileSync } from 'node:fs'
|
|
4
|
-
import { fileURLToPath } from 'node:url'
|
|
5
|
-
import { AssertionError } from '../AssertionError/AssertionError.js'
|
|
6
4
|
import * as CleanStack from '../CleanStack/CleanStack.js'
|
|
7
5
|
import * as EncodingType from '../EncodingType/EncodingType.js'
|
|
8
6
|
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
7
|
+
import * as GetActualPath from '../GetActualPath/GetActualPath.js'
|
|
9
8
|
import * as JoinLines from '../JoinLines/JoinLines.js'
|
|
10
9
|
import * as Json from '../Json/Json.js'
|
|
11
10
|
import * as SplitLines from '../SplitLines/SplitLines.js'
|
|
12
11
|
|
|
13
|
-
const getActualPath = (fileUri) => {
|
|
14
|
-
if (fileUri.startsWith('file://')) {
|
|
15
|
-
return fileURLToPath(fileUri)
|
|
16
|
-
}
|
|
17
|
-
return fileUri
|
|
18
|
-
}
|
|
19
|
-
|
|
20
12
|
const RE_MODULE_NOT_FOUND_STACK = /Cannot find package '([^']+)' imported from (.+)$/
|
|
21
13
|
|
|
22
14
|
const prepareModuleNotFoundError = (error) => {
|
|
@@ -61,13 +53,6 @@ const prepareModuleNotFoundError = (error) => {
|
|
|
61
53
|
}
|
|
62
54
|
}
|
|
63
55
|
|
|
64
|
-
const getStackLinesToCut = (error) => {
|
|
65
|
-
if (error instanceof AssertionError) {
|
|
66
|
-
return 1
|
|
67
|
-
}
|
|
68
|
-
return 0
|
|
69
|
-
}
|
|
70
|
-
|
|
71
56
|
export const prepare = (error) => {
|
|
72
57
|
if (error && error.code === ErrorCodes.ERR_MODULE_NOT_FOUND) {
|
|
73
58
|
return prepareModuleNotFoundError(error)
|
|
@@ -79,8 +64,7 @@ export const prepare = (error) => {
|
|
|
79
64
|
error = cause
|
|
80
65
|
}
|
|
81
66
|
}
|
|
82
|
-
const
|
|
83
|
-
const lines = CleanStack.cleanStack(error.stack).slice(linesToCut)
|
|
67
|
+
const lines = CleanStack.cleanStack(error.stack)
|
|
84
68
|
const file = lines[0]
|
|
85
69
|
let codeFrame = ''
|
|
86
70
|
if (error.codeFrame) {
|
|
@@ -92,7 +76,7 @@ export const prepare = (error) => {
|
|
|
92
76
|
}
|
|
93
77
|
if (match) {
|
|
94
78
|
const [_, path, line, column] = match
|
|
95
|
-
const actualPath = getActualPath(path)
|
|
79
|
+
const actualPath = GetActualPath.getActualPath(path)
|
|
96
80
|
const rawLines = readFileSync(actualPath, EncodingType.Utf8)
|
|
97
81
|
const location = {
|
|
98
82
|
start: {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const processDisplayName = 'shared process'
|
|
@@ -1,10 +1,31 @@
|
|
|
1
1
|
import * as Assert from '../Assert/Assert.js'
|
|
2
2
|
import * as JsonRpcVersion from '../JsonRpcVersion/JsonRpcVersion.js'
|
|
3
3
|
import * as PtyHost from '../PtyHost/PtyHost.js'
|
|
4
|
+
import * as TerminalState from '../TerminalState/TerminalState.js'
|
|
4
5
|
import { VError } from '../VError/VError.js'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
const createTerminal = (ptyHost, socket) => {
|
|
8
|
+
const handleMessage = (message) => {
|
|
9
|
+
socket.send(message)
|
|
10
|
+
}
|
|
11
|
+
const handleClose = () => {
|
|
12
|
+
// socket.off('close', handleClose)
|
|
13
|
+
ptyHost.off('message', handleMessage)
|
|
14
|
+
ptyHost.dispose()
|
|
15
|
+
}
|
|
16
|
+
const dispose = () => {
|
|
17
|
+
ptyHost.off('message', handleMessage)
|
|
18
|
+
socket.off('close', handleClose)
|
|
19
|
+
}
|
|
20
|
+
ptyHost.on('message', handleMessage)
|
|
21
|
+
socket.on('close', handleClose)
|
|
22
|
+
return {
|
|
23
|
+
ptyHost,
|
|
24
|
+
socket,
|
|
25
|
+
handleMessage,
|
|
26
|
+
handleClose,
|
|
27
|
+
dispose,
|
|
28
|
+
}
|
|
8
29
|
}
|
|
9
30
|
|
|
10
31
|
export const create = async (socket, id, cwd) => {
|
|
@@ -12,21 +33,10 @@ export const create = async (socket, id, cwd) => {
|
|
|
12
33
|
Assert.object(socket)
|
|
13
34
|
Assert.number(id)
|
|
14
35
|
Assert.string(cwd)
|
|
15
|
-
// TODO
|
|
16
|
-
state.socketMap[id] = socket
|
|
36
|
+
// TODO race condition because of await
|
|
17
37
|
const ptyHost = await PtyHost.getOrCreate()
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
socket.send(message)
|
|
21
|
-
}
|
|
22
|
-
const handleClose = () => {
|
|
23
|
-
// socket.off('close', handleClose)
|
|
24
|
-
ptyHost.off('message', handleMessage)
|
|
25
|
-
ptyHost.dispose()
|
|
26
|
-
}
|
|
27
|
-
ptyHost.on('message', handleMessage)
|
|
28
|
-
socket.on('close', handleClose)
|
|
29
|
-
|
|
38
|
+
const terminal = createTerminal(ptyHost, socket)
|
|
39
|
+
TerminalState.add(id, terminal)
|
|
30
40
|
// TODO use invoke
|
|
31
41
|
ptyHost.send({
|
|
32
42
|
jsonrpc: JsonRpcVersion.Two,
|
|
@@ -59,6 +69,9 @@ export const resize = (state, columns, rows) => {
|
|
|
59
69
|
}
|
|
60
70
|
|
|
61
71
|
export const dispose = async (id) => {
|
|
72
|
+
const terminal = TerminalState.get(id)
|
|
73
|
+
terminal.dispose()
|
|
74
|
+
TerminalState.remove(id)
|
|
62
75
|
const ptyHost = await PtyHost.getOrCreate()
|
|
63
76
|
// TODO use invoke
|
|
64
77
|
ptyHost.send({
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const state = {
|
|
2
|
+
terminals: Object.create(null),
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export const add = (id, terminal) => {
|
|
6
|
+
state.terminals[id] = terminal
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const get = (id) => {
|
|
10
|
+
return state.terminals[id]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const remove = (id) => {
|
|
14
|
+
delete state.terminals[id]
|
|
15
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer'
|
|
2
2
|
import * as _ws from 'ws'
|
|
3
|
+
import * as IsSocket from '../IsSocket/IsSocket.js'
|
|
3
4
|
|
|
4
5
|
// workaround for jest or node bug
|
|
5
6
|
const WebSocketServer = _ws.WebSocketServer
|
|
@@ -14,11 +15,15 @@ const webSocketServer = new WebSocketServer({
|
|
|
14
15
|
// perMessageDeflate: true
|
|
15
16
|
})
|
|
16
17
|
|
|
17
|
-
export const handleUpgrade = (request, socket) => {
|
|
18
|
-
|
|
18
|
+
export const handleUpgrade = async (request, socket) => {
|
|
19
|
+
if (!IsSocket.isSocket(socket)) {
|
|
20
|
+
throw new TypeError(`socket must be of type Socket`)
|
|
21
|
+
}
|
|
22
|
+
const webSocket = await new Promise((resolve, reject) => {
|
|
19
23
|
const upgradeCallback = (ws) => {
|
|
20
24
|
resolve(ws)
|
|
21
25
|
}
|
|
22
26
|
webSocketServer.handleUpgrade(request, socket, Buffer.alloc(0), upgradeCallback)
|
|
23
27
|
})
|
|
28
|
+
return webSocket
|
|
24
29
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import('./sharedProcessMain.js')
|
package/src/sharedProcessMain.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as ErrorHandling from './parts/ErrorHandling/ErrorHandling.js'
|
|
|
3
3
|
import * as Module from './parts/Module/Module.js'
|
|
4
4
|
import * as ParentIpc from './parts/ParentIpc/ParentIpc.js'
|
|
5
5
|
import * as Process from './parts/Process/Process.js'
|
|
6
|
+
import * as Signal from './parts/Signal/Signal.js'
|
|
6
7
|
// TODO handle structure: one shared process multiple extension hosts
|
|
7
8
|
|
|
8
9
|
// TODO use named functions here
|
|
@@ -34,7 +35,7 @@ const main = async () => {
|
|
|
34
35
|
console.log('[shared process] started')
|
|
35
36
|
// process.on('beforeExit', handleBeforeExit)
|
|
36
37
|
process.on('disconnect', handleDisconnect)
|
|
37
|
-
process.on(
|
|
38
|
+
process.on(Signal.SIGTERM, handleSigTerm)
|
|
38
39
|
|
|
39
40
|
process.on('uncaughtExceptionMonitor', ErrorHandling.handleUncaughtExceptionMonitor)
|
|
40
41
|
await ParentIpc.listen()
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import * as Command from '../Command/Command.js'
|
|
2
|
-
import * as GetResponse from '../GetResponse/GetResponse.js'
|
|
3
|
-
import { VError } from '../VError/VError.js'
|
|
4
|
-
|
|
5
|
-
export const state = {
|
|
6
|
-
/**
|
|
7
|
-
* @type {any}
|
|
8
|
-
*/
|
|
9
|
-
socket: undefined,
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const send = (message) => {
|
|
13
|
-
if (!state.socket) {
|
|
14
|
-
console.warn('socket not yet available')
|
|
15
|
-
return
|
|
16
|
-
}
|
|
17
|
-
state.socket.send(message)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const handleMessage = async (event) => {
|
|
21
|
-
const object = JSON.parse(event.data)
|
|
22
|
-
if (object.id) {
|
|
23
|
-
if (!object.params) {
|
|
24
|
-
console.warn('[shared-process] invalid message 1', typeof object, object.params, object)
|
|
25
|
-
return
|
|
26
|
-
}
|
|
27
|
-
const response = await GetResponse.getResponse(object, state.socket)
|
|
28
|
-
send(response)
|
|
29
|
-
} else {
|
|
30
|
-
if (!object.params) {
|
|
31
|
-
console.warn('invalid message', typeof object, object.params, object)
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
Command.execute(object.method, state.socket, ...object.params)
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const handleError = (error) => {
|
|
39
|
-
// console.error(error)
|
|
40
|
-
throw new VError(error, 'Shared Process Socket Error')
|
|
41
|
-
|
|
42
|
-
// console.error('[Shared Process: Socket Error]', event)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// TODO
|
|
46
|
-
const createAbstractSocket = (socket) => {
|
|
47
|
-
return {
|
|
48
|
-
_socket: socket,
|
|
49
|
-
send(message) {
|
|
50
|
-
socket.send(JSON.stringify(message))
|
|
51
|
-
},
|
|
52
|
-
on(event, listener) {
|
|
53
|
-
switch (event) {
|
|
54
|
-
case 'message':
|
|
55
|
-
socket.on('message', listener)
|
|
56
|
-
break
|
|
57
|
-
case 'close':
|
|
58
|
-
socket.on('close', listener)
|
|
59
|
-
break
|
|
60
|
-
default:
|
|
61
|
-
console.warn('socket event not implemented', event, listener)
|
|
62
|
-
break
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export const set = (socket) => {
|
|
69
|
-
socket.on('close', () => {
|
|
70
|
-
console.log('[shared-process] socket closed')
|
|
71
|
-
})
|
|
72
|
-
socket.onmessage = handleMessage
|
|
73
|
-
// socket.onerror = handleError
|
|
74
|
-
socket.on('error', handleError)
|
|
75
|
-
const abstractSocket = createAbstractSocket(socket)
|
|
76
|
-
state.socket = abstractSocket
|
|
77
|
-
}
|