@lvce-editor/shared-process 0.11.4 → 0.11.5
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/defaultKeyBindings.json +4 -0
- package/package.json +4 -4
- package/src/parts/Cli/Cli.js +5 -2
- package/src/parts/CliInstall/CliInstall.js +2 -1
- package/src/parts/CliLink/CliLink.js +4 -2
- package/src/parts/CliUnlink/CliUnlink.js +2 -1
- package/src/parts/Developer/Developer.js +2 -1
- package/src/parts/ErrorCodes/ErrorCodes.js +12 -0
- package/src/parts/ErrorHandling/ErrorHandling.js +39 -0
- package/src/parts/ExtensionManagement/ExtensionManagementColorTheme.js +3 -2
- package/src/parts/ExtensionManagement/ExtensionManagementIconTheme.js +2 -1
- package/src/parts/Logger/Logger.js +50 -0
- package/src/parts/ParentIpc/ParentIpc.js +2 -1
- package/src/parts/Process/Process.js +24 -0
- package/src/parts/Socket/Socket.js +0 -1
- package/src/sharedProcessMain.js +7 -32
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvce-editor/shared-process",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.5",
|
|
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.18.6",
|
|
20
|
-
"@lvce-editor/extension-host": "0.11.
|
|
21
|
-
"@lvce-editor/extension-host-helper-process": "0.11.
|
|
22
|
-
"@lvce-editor/pty-host": "0.11.
|
|
20
|
+
"@lvce-editor/extension-host": "0.11.5",
|
|
21
|
+
"@lvce-editor/extension-host-helper-process": "0.11.5",
|
|
22
|
+
"@lvce-editor/pty-host": "0.11.5",
|
|
23
23
|
"debug": "^4.3.4",
|
|
24
24
|
"execa": "^6.1.0",
|
|
25
25
|
"exit-hook": "^3.1.2",
|
package/src/parts/Cli/Cli.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import * as Logger from '../Logger/Logger.js'
|
|
2
|
+
import * as Process from '../Process/Process.js'
|
|
3
|
+
|
|
1
4
|
const getModule = (argv0) => {
|
|
2
5
|
switch (argv0) {
|
|
3
6
|
case 'install':
|
|
@@ -20,7 +23,7 @@ export const handleCliArgs = async (argv, console, process) => {
|
|
|
20
23
|
try {
|
|
21
24
|
await module.handleCliArgs(argv, console, process)
|
|
22
25
|
} catch (error) {
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
Logger.error(error)
|
|
27
|
+
Process.setExitCode(1)
|
|
25
28
|
}
|
|
26
29
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as ExtensionInstall from '../ExtensionInstall/ExtensionInstall.js'
|
|
2
|
+
import * as Logger from '../Logger/Logger.js'
|
|
2
3
|
|
|
3
4
|
export const handleCliArgs = async (argv, console) => {
|
|
4
5
|
const extension = argv[1]
|
|
5
6
|
if (!extension) {
|
|
6
|
-
|
|
7
|
+
Logger.error('extension argument is required')
|
|
7
8
|
return
|
|
8
9
|
}
|
|
9
10
|
await ExtensionInstall.install(extension)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as ExtensionLink from '../ExtensionLink/ExtensionLink.js'
|
|
2
2
|
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
3
|
+
import * as Logger from '../Logger/Logger.js'
|
|
4
|
+
import * as Process from '../Process/Process.js'
|
|
3
5
|
|
|
4
6
|
export const handleCliArgs = async (argv) => {
|
|
5
7
|
try {
|
|
@@ -7,8 +9,8 @@ export const handleCliArgs = async (argv) => {
|
|
|
7
9
|
await ExtensionLink.link(path)
|
|
8
10
|
} catch (error) {
|
|
9
11
|
if (error && error.code === ErrorCodes.E_MANIFEST_NOT_FOUND) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
Logger.error(error.message)
|
|
13
|
+
Process.setExitCode(128)
|
|
12
14
|
return
|
|
13
15
|
}
|
|
14
16
|
throw error
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as ExtensionUnlink from '../ExtensionUnlink/ExtensionUnlink.js'
|
|
2
|
+
import * as Process from '../Process/Process.js'
|
|
2
3
|
|
|
3
4
|
export const handleCliArgs = async (argv, console, process) => {
|
|
4
|
-
const path = argv.length > 1 ? argv[1] :
|
|
5
|
+
const path = argv.length > 1 ? argv[1] : Process.cwd()
|
|
5
6
|
await ExtensionUnlink.unlink(path)
|
|
6
7
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createWriteStream, writeFileSync } from 'node:fs'
|
|
2
2
|
import { performance } from 'node:perf_hooks'
|
|
3
3
|
import * as ExtensionHost from '../ExtensionHost/ExtensionHost.js'
|
|
4
|
+
import * as Process from '../Process/Process.js'
|
|
4
5
|
|
|
5
6
|
export const measureLatencyBetweenExtensionHostAndSharedProcess = async (
|
|
6
7
|
socket,
|
|
@@ -63,7 +64,7 @@ export const getNodeStartupTiming = () => {
|
|
|
63
64
|
|
|
64
65
|
export const sharedProcessMemoryUsage = () => {
|
|
65
66
|
// TODO also print out number of watched files
|
|
66
|
-
return
|
|
67
|
+
return Process.memoryUsage()
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
// TODO not sure if this is actually useful
|
|
@@ -7,3 +7,15 @@ export const EEXIST = 'EEXIST'
|
|
|
7
7
|
export const ENOTDIR = 'ENOTDIR'
|
|
8
8
|
|
|
9
9
|
export const E_MANIFEST_NOT_FOUND = 'E_MANIFEST_NOT_FOUND'
|
|
10
|
+
|
|
11
|
+
export const EPIPE = 'EPIPE'
|
|
12
|
+
|
|
13
|
+
export const ERR_IPC_CHANNEL_CLOSED = 'ERR_IPC_CHANNEL_CLOSED'
|
|
14
|
+
|
|
15
|
+
export const E_COLOR_THEME_NOT_FOUND = 'E_COLOR_THEME_NOT_FOUND'
|
|
16
|
+
|
|
17
|
+
export const E_ICON_THEME_NOT_FOUND = 'E_ICON_THEME_NOT_FOUND'
|
|
18
|
+
|
|
19
|
+
export const ECONNRESET = 'ECONNRESET'
|
|
20
|
+
|
|
21
|
+
export const EPERM = 'EPERM'
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
2
|
+
import * as PrettyError from '../PrettyError/PrettyError.js'
|
|
1
3
|
import * as Socket from '../Socket/Socket.js'
|
|
4
|
+
import * as Process from '../Process/Process.js'
|
|
2
5
|
|
|
3
6
|
export const state = {
|
|
4
7
|
seenErrors: [],
|
|
@@ -38,3 +41,39 @@ export const handleError = (error) => {
|
|
|
38
41
|
})
|
|
39
42
|
printPrettyError(prettyError)
|
|
40
43
|
}
|
|
44
|
+
|
|
45
|
+
// TODO handle structure: one shared process multiple extension hosts
|
|
46
|
+
|
|
47
|
+
// TODO use named functions here
|
|
48
|
+
|
|
49
|
+
const firstErrorLine = (error) => {
|
|
50
|
+
if (error.stack) {
|
|
51
|
+
return error.stack.slice(0, error.stack.indexOf('\n'))
|
|
52
|
+
}
|
|
53
|
+
if (error.message) {
|
|
54
|
+
return error.message
|
|
55
|
+
}
|
|
56
|
+
return `${error}`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const handleUncaughtExceptionMonitor = (error, origin) => {
|
|
60
|
+
console.info(`[shared process] uncaught exception: ${firstErrorLine(error)}`)
|
|
61
|
+
if (error && error.code === ErrorCodes.EPIPE && !process.connected) {
|
|
62
|
+
// parent process is disposed, ignore
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
if (
|
|
66
|
+
error &&
|
|
67
|
+
error.code === ErrorCodes.ERR_IPC_CHANNEL_CLOSED &&
|
|
68
|
+
!Process.isConnected()
|
|
69
|
+
) {
|
|
70
|
+
// parent process is disposed, ignore
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
// console.log(error)
|
|
74
|
+
const prettyError = PrettyError.prepare(error)
|
|
75
|
+
// console.error(prettyError.message)
|
|
76
|
+
console.error(prettyError.codeFrame)
|
|
77
|
+
console.error(prettyError.stack)
|
|
78
|
+
Process.exit(1)
|
|
79
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import VError from 'verror'
|
|
2
2
|
import * as Error from '../Error/Error.js'
|
|
3
|
+
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
4
|
+
import * as FileSystemWatch from '../FileSystemWatch/FileSystemWatch.js'
|
|
3
5
|
import * as ReadJson from '../JsonFile/JsonFile.js'
|
|
4
6
|
import * as Path from '../Path/Path.js'
|
|
5
7
|
import * as ExtensionManagement from './ExtensionManagement.js'
|
|
6
|
-
import * as FileSystemWatch from '../FileSystemWatch/FileSystemWatch.js'
|
|
7
8
|
|
|
8
9
|
// TODO test this function
|
|
9
10
|
// TODO very similar with getIconTheme
|
|
@@ -29,7 +30,7 @@ export const getColorThemeJson = async (colorThemeId) => {
|
|
|
29
30
|
const colorThemePath = await getColorThemePath(extensions, colorThemeId)
|
|
30
31
|
if (!colorThemePath) {
|
|
31
32
|
throw new Error.OperationalError({
|
|
32
|
-
code:
|
|
33
|
+
code: ErrorCodes.E_COLOR_THEME_NOT_FOUND,
|
|
33
34
|
message: `Color theme "${colorThemeId}" not found in extensions folder`,
|
|
34
35
|
})
|
|
35
36
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import VError from 'verror'
|
|
2
2
|
import * as Error from '../Error/Error.js'
|
|
3
|
+
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
3
4
|
import * as ReadJson from '../JsonFile/JsonFile.js'
|
|
4
5
|
import * as Path from '../Path/Path.js'
|
|
5
6
|
import * as ExtensionManagement from './ExtensionManagement.js'
|
|
@@ -27,7 +28,7 @@ export const getIconTheme = async (iconThemeId) => {
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
throw new Error.OperationalError({
|
|
30
|
-
code:
|
|
31
|
+
code: ErrorCodes.E_ICON_THEME_NOT_FOUND,
|
|
31
32
|
message: `Icon theme "${iconThemeId}" not found in extensions folder`,
|
|
32
33
|
})
|
|
33
34
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Console } from 'node:console'
|
|
2
|
+
import { createWriteStream } from 'node:fs'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
|
|
5
|
+
// TODO mock this module when used in unit tests
|
|
6
|
+
|
|
7
|
+
const state = {
|
|
8
|
+
/**
|
|
9
|
+
* @type {Console|undefined}
|
|
10
|
+
*/
|
|
11
|
+
console: undefined,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const createConsole = () => {
|
|
15
|
+
const logFile = `${tmpdir()}/log-shared-process.txt`
|
|
16
|
+
const writeStream = createWriteStream(logFile)
|
|
17
|
+
const logger = new Console(writeStream)
|
|
18
|
+
return logger
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const getOrCreateLogger = () => {
|
|
22
|
+
if (!state.console) {
|
|
23
|
+
state.console = createConsole()
|
|
24
|
+
}
|
|
25
|
+
return state.console
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const log = (...args) => {
|
|
29
|
+
const logger = getOrCreateLogger()
|
|
30
|
+
logger.log(...args)
|
|
31
|
+
console.log(...args)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const info = (...args) => {
|
|
35
|
+
const logger = getOrCreateLogger()
|
|
36
|
+
logger.info(...args)
|
|
37
|
+
console.info(...args)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const warn = (...args) => {
|
|
41
|
+
const logger = getOrCreateLogger()
|
|
42
|
+
logger.warn(...args)
|
|
43
|
+
console.warn(...args)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const error = (...args) => {
|
|
47
|
+
const logger = getOrCreateLogger()
|
|
48
|
+
logger.error(...args)
|
|
49
|
+
console.error(...args)
|
|
50
|
+
}
|
|
@@ -3,6 +3,7 @@ import VError from 'verror'
|
|
|
3
3
|
import * as Callback from '../Callback/Callback.js'
|
|
4
4
|
import * as Command from '../Command/Command.js'
|
|
5
5
|
import * as Debug from '../Debug/Debug.js'
|
|
6
|
+
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
6
7
|
import * as ExtensionHostHelperProcessIpc from '../ExtensionHostHelperProcessIpc/ExtensionHostHelperProcessIpc.js'
|
|
7
8
|
import * as ExtensionHostIpc from '../ExtensionHostIpc/ExtensionHostIpc.js'
|
|
8
9
|
import * as ExtensionHostRpc from '../ExtensionHostRpc/ExtensionHostRpc.js'
|
|
@@ -36,7 +37,7 @@ export const electronSend = (message) => {
|
|
|
36
37
|
const handleWebSocketSharedProcess = (message, handle) => {
|
|
37
38
|
// TODO when it is an extension host websocket, spawn extension host
|
|
38
39
|
handle.on('error', (error) => {
|
|
39
|
-
if (error && error.code ===
|
|
40
|
+
if (error && error.code === ErrorCodes.ECONNRESET) {
|
|
40
41
|
return
|
|
41
42
|
}
|
|
42
43
|
console.info('[info shared process: handle error]', error)
|
|
@@ -5,3 +5,27 @@ export const crash = (message) => {
|
|
|
5
5
|
export const crashAsync = async (message) => {
|
|
6
6
|
throw new Error(message)
|
|
7
7
|
}
|
|
8
|
+
|
|
9
|
+
export const exit = (code) => {
|
|
10
|
+
process.exit(code)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const setExitCode = (exitCode) => {
|
|
14
|
+
process.exitCode = exitCode
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const argv = process.argv
|
|
18
|
+
|
|
19
|
+
export const cwd = () => {
|
|
20
|
+
return process.cwd()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const memoryUsage = () => {
|
|
24
|
+
return process.memoryUsage()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const isConnected = () => {
|
|
28
|
+
return process.connected
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const platform = process.platform
|
package/src/sharedProcessMain.js
CHANGED
|
@@ -1,40 +1,12 @@
|
|
|
1
1
|
import * as Command from './parts/Command/Command.js'
|
|
2
|
+
import * as ErrorHandling from './parts/ErrorHandling/ErrorHandling.js'
|
|
2
3
|
import * as Module from './parts/Module/Module.js'
|
|
3
4
|
import * as ParentIpc from './parts/ParentIpc/ParentIpc.js'
|
|
4
|
-
import * as
|
|
5
|
-
|
|
5
|
+
import * as Process from './parts/Process/Process.js'
|
|
6
6
|
// TODO handle structure: one shared process multiple extension hosts
|
|
7
7
|
|
|
8
8
|
// TODO use named functions here
|
|
9
9
|
|
|
10
|
-
const firstErrorLine = (error) => {
|
|
11
|
-
if (error.stack) {
|
|
12
|
-
return error.stack.slice(0, error.stack.indexOf('\n'))
|
|
13
|
-
}
|
|
14
|
-
if (error.message) {
|
|
15
|
-
return error.message
|
|
16
|
-
}
|
|
17
|
-
return `${error}`
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const handleUncaughtExceptionMonitor = (error, origin) => {
|
|
21
|
-
console.info(`[shared process] uncaught exception: ${firstErrorLine(error)}`)
|
|
22
|
-
if (error && error.code === 'EPIPE' && !process.connected) {
|
|
23
|
-
// parent process is disposed, ignore
|
|
24
|
-
return
|
|
25
|
-
}
|
|
26
|
-
if (error && error.code === 'ERR_IPC_CHANNEL_CLOSED' && !process.connected) {
|
|
27
|
-
// parent process is disposed, ignore
|
|
28
|
-
return
|
|
29
|
-
}
|
|
30
|
-
// console.log(error)
|
|
31
|
-
const prettyError = PrettyError.prepare(error)
|
|
32
|
-
// console.error(prettyError.message)
|
|
33
|
-
console.error(prettyError.codeFrame)
|
|
34
|
-
console.error(prettyError.stack)
|
|
35
|
-
process.exit(1)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
10
|
const handleDisconnect = () => {
|
|
39
11
|
console.info('[shared process] disconnected')
|
|
40
12
|
}
|
|
@@ -51,7 +23,7 @@ const knownCliArgs = ['install', 'list', 'link', 'unlink']
|
|
|
51
23
|
|
|
52
24
|
const main = async () => {
|
|
53
25
|
Command.setLoad(Module.load)
|
|
54
|
-
const argv =
|
|
26
|
+
const argv = Process.argv.slice(2)
|
|
55
27
|
const argv0 = argv[0]
|
|
56
28
|
if (knownCliArgs.includes(argv0)) {
|
|
57
29
|
const module = await import('./parts/Cli/Cli.js')
|
|
@@ -64,7 +36,10 @@ const main = async () => {
|
|
|
64
36
|
process.on('disconnect', handleDisconnect)
|
|
65
37
|
process.on('SIGTERM', handleSigTerm)
|
|
66
38
|
|
|
67
|
-
process.on(
|
|
39
|
+
process.on(
|
|
40
|
+
'uncaughtExceptionMonitor',
|
|
41
|
+
ErrorHandling.handleUncaughtExceptionMonitor
|
|
42
|
+
)
|
|
68
43
|
ParentIpc.listen()
|
|
69
44
|
|
|
70
45
|
// ExtensionHost.start() // TODO start on demand, e.g. not when extensions should be disabled
|