@lvce-editor/pty-host 2.1.0 → 3.0.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 (41) hide show
  1. package/README.md +3 -1
  2. package/bin/ptyHost.js +1 -1
  3. package/dist/ptyHostMain.js +386 -0
  4. package/package.json +7 -45
  5. package/src/parts/Assert/Assert.js +0 -59
  6. package/src/parts/AssertionError/AssertionError.js +0 -6
  7. package/src/parts/Callback/Callback.js +0 -1
  8. package/src/parts/Character/Character.js +0 -11
  9. package/src/parts/Command/Command.js +0 -9
  10. package/src/parts/CommandMap/CommandMap.js +0 -17
  11. package/src/parts/CommandState/CommandState.js +0 -17
  12. package/src/parts/Debug/Debug.js +0 -3
  13. package/src/parts/ErrorCodes/ErrorCodes.js +0 -19
  14. package/src/parts/ErrorHandling/ErrorHandling.js +0 -75
  15. package/src/parts/ExitCode/ExitCode.js +0 -5
  16. package/src/parts/GetNewLineIndex/GetNewLineIndex.js +0 -11
  17. package/src/parts/HandleElectronMessagePort/HandleElectronMessagePort.js +0 -13
  18. package/src/parts/HandleIpc/HandleIpc.js +0 -15
  19. package/src/parts/HandleMessage/HandleMessage.js +0 -25
  20. package/src/parts/HandleNodeMessagePort/HandleNodeMessagePort.js +0 -11
  21. package/src/parts/HandleWebSocket/HandleWebSocket.js +0 -15
  22. package/src/parts/IpcChild/IpcChild.js +0 -15
  23. package/src/parts/IpcChildModule/IpcChildModule.js +0 -25
  24. package/src/parts/IpcChildType/IpcChildType.js +0 -20
  25. package/src/parts/IsIgnoredError/IsIgnoredError.js +0 -18
  26. package/src/parts/JsonRpc/JsonRpc.js +0 -1
  27. package/src/parts/Listen/Listen.js +0 -8
  28. package/src/parts/Logger/Logger.js +0 -50
  29. package/src/parts/Main/Main.js +0 -14
  30. package/src/parts/NodePty/NodePty.js +0 -72
  31. package/src/parts/PrettyError/PrettyError.js +0 -1
  32. package/src/parts/PrintPrettyError/PrintPrettyError.js +0 -7
  33. package/src/parts/Process/Process.js +0 -17
  34. package/src/parts/ProcessListeners/ProcessListeners.js +0 -17
  35. package/src/parts/Pty/Pty.js +0 -1
  36. package/src/parts/PtyController/PtyController.js +0 -57
  37. package/src/parts/PtyState/PtyState.js +0 -19
  38. package/src/parts/RequiresSocket/RequiresSocket.js +0 -5
  39. package/src/parts/TerminalProcessCommandType/TerminalProcessCommandType.js +0 -9
  40. package/src/parts/VError/VError.js +0 -1
  41. package/src/ptyHostMain.js +0 -3
package/README.md CHANGED
@@ -1 +1,3 @@
1
- # pty-host
1
+ # Pty Host
2
+
3
+ Terminal process used in Lvce Editor.
package/bin/ptyHost.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import '../src/ptyHostMain.js'
3
+ import '../dist/ptyHostMain.js'
@@ -0,0 +1,386 @@
1
+ import { execute, register } from '@lvce-editor/command';
2
+ import { object, string, array, number } from '@lvce-editor/assert';
3
+ import { handleJsonRpcMessage, resolve } from '@lvce-editor/json-rpc';
4
+ import { IpcChildWithElectronMessagePort, IpcChildWithElectronUtilityProcess, IpcChildWithWebSocket, IpcChildWithNodeWorker, IpcChildWithNodeForkedProcess } from '@lvce-editor/ipc';
5
+ import debugModule from 'debug';
6
+ import { spawn } from 'node-pty';
7
+ import { VError } from '@lvce-editor/verror';
8
+ import { Console } from 'node:console';
9
+ import { createWriteStream } from 'node:fs';
10
+ import { tmpdir } from 'node:os';
11
+ import { prepare } from '@lvce-editor/pretty-error';
12
+
13
+ const METHODS_THAT_REQUIRE_SOCKET = new Set(['Terminal.create']);
14
+ const requiresSocket = method => {
15
+ return METHODS_THAT_REQUIRE_SOCKET.has(method);
16
+ };
17
+
18
+ const preparePrettyError = error => {
19
+ return error;
20
+ };
21
+ const logError = () => {
22
+ // PrintPrettyError.printPrettyError(prettyError, `[terminal-process] `)
23
+ };
24
+ const handleMessage = event => {
25
+ return handleJsonRpcMessage(event.target, event.data, execute, resolve, preparePrettyError, logError, requiresSocket);
26
+ };
27
+
28
+ const handleIpc = ipc => {
29
+ object(ipc);
30
+ if ('addEventListener' in ipc) {
31
+ ipc.addEventListener('message', handleMessage);
32
+ } else if ('onmessage' in ipc) {
33
+ // deprecated
34
+ ipc.onmessage = handleMessage;
35
+ } else if ('on' in ipc) {
36
+ // deprecated
37
+ ipc.on('message', handleMessage);
38
+ }
39
+ };
40
+
41
+ const NodeWorker = 1;
42
+ const NodeForkedProcess = 2;
43
+ const WebSocket = 3;
44
+ const ElectronUtilityProcess = 4;
45
+ const ElectronMessagePort = 5;
46
+ const NodeMessagePort = 6;
47
+ const Auto = () => {
48
+ const {
49
+ argv
50
+ } = process;
51
+ if (argv.includes('--ipc-type=node-worker')) {
52
+ return NodeWorker;
53
+ }
54
+ if (argv.includes('--ipc-type=node-forked-process')) {
55
+ return NodeForkedProcess;
56
+ }
57
+ if (argv.includes('--ipc-type=electron-utility-process')) {
58
+ return ElectronUtilityProcess;
59
+ }
60
+ throw new Error(`[pty-host] unknown ipc type`);
61
+ };
62
+
63
+ const getModule = method => {
64
+ switch (method) {
65
+ case NodeForkedProcess:
66
+ return IpcChildWithNodeForkedProcess;
67
+ case NodeWorker:
68
+ return IpcChildWithNodeWorker;
69
+ case WebSocket:
70
+ return IpcChildWithWebSocket;
71
+ case ElectronUtilityProcess:
72
+ return IpcChildWithElectronUtilityProcess;
73
+ case ElectronMessagePort:
74
+ return IpcChildWithElectronMessagePort;
75
+ default:
76
+ throw new Error('unexpected ipc type');
77
+ }
78
+ };
79
+
80
+ const listen$1 = async ({
81
+ method,
82
+ ...params
83
+ }) => {
84
+ const module = getModule(method);
85
+ // @ts-ignore
86
+ const rawIpc = await module.listen(params);
87
+ // @ts-ignore
88
+ if (module.signal) {
89
+ // @ts-ignore
90
+ module.signal(rawIpc);
91
+ }
92
+ // @ts-ignore
93
+ const ipc = module.wrap(rawIpc);
94
+ return ipc;
95
+ };
96
+
97
+ const handleElectronMessagePort = async messagePort => {
98
+ object(messagePort);
99
+ const ipc = await listen$1({
100
+ method: ElectronMessagePort,
101
+ messagePort
102
+ });
103
+ handleIpc(ipc);
104
+ };
105
+
106
+ const handleNodeMessagePort = async messagePort => {
107
+ const ipc = await listen$1({
108
+ method: NodeMessagePort,
109
+ messagePort
110
+ });
111
+ handleIpc(ipc);
112
+ };
113
+
114
+ const handleWebSocket = async (handle, request) => {
115
+ object(handle);
116
+ object(request);
117
+ const ipc = await listen$1({
118
+ method: WebSocket,
119
+ request,
120
+ handle
121
+ });
122
+ handleIpc(ipc);
123
+ };
124
+
125
+ const debug = debugModule('pty-host');
126
+
127
+ class DataEvent extends Event {
128
+ constructor(data) {
129
+ super('data');
130
+ this.data = data;
131
+ }
132
+ }
133
+ class ExitEvent extends Event {
134
+ constructor(data) {
135
+ super('exit');
136
+ this.data = data;
137
+ }
138
+ }
139
+ class Pty extends EventTarget {
140
+ /**
141
+ *
142
+ * @param {import('node-pty').IPty} pty
143
+ */
144
+ constructor(pty) {
145
+ super();
146
+ this.pty = pty;
147
+ const handleData = data => {
148
+ this.dispatchEvent(new DataEvent(data));
149
+ };
150
+ const handleExit = data => {
151
+ this.dispatchEvent(new ExitEvent(data));
152
+ };
153
+ this.pty.onData(handleData);
154
+ this.pty.onExit(handleExit);
155
+ }
156
+ resize(columns, rows) {
157
+ this.pty.resize(columns, rows);
158
+ }
159
+ dispose() {
160
+ this.pty.kill();
161
+ }
162
+ write(data) {
163
+ this.pty.write(data);
164
+ }
165
+ }
166
+
167
+ /**
168
+ *
169
+ * @param {*} param0
170
+ * @returns {any}
171
+ */
172
+ const create$1 = ({
173
+ cwd,
174
+ command,
175
+ args
176
+ } = {}) => {
177
+ try {
178
+ string(cwd);
179
+ string(command);
180
+ array(args);
181
+ const pty = spawn(command, args, {
182
+ encoding: null,
183
+ cwd
184
+ // cols: 10,
185
+ // rows: 10,
186
+ });
187
+ const wrapped = new Pty(pty);
188
+ return wrapped;
189
+ } catch (error) {
190
+ throw new VError(error, `Failed to create terminal`);
191
+ }
192
+ };
193
+
194
+ const state$1 = {
195
+ ptyMap: Object.create(null)
196
+ };
197
+ const set = (id, pty) => {
198
+ state$1.ptyMap[id] = pty;
199
+ };
200
+ const get = id => {
201
+ return state$1.ptyMap[id];
202
+ };
203
+ const remove = id => {
204
+ delete state$1.ptyMap[id];
205
+ };
206
+
207
+ // TODO maybe merge pty and pty controller
208
+ const create = (ipc, id, cwd, command, args) => {
209
+ number(id);
210
+ string(cwd);
211
+ string(command);
212
+ array(args);
213
+ object(ipc);
214
+ debug(`create ${id} ${cwd}`);
215
+ // @ts-ignore
216
+ const pty = create$1({
217
+ cwd,
218
+ command,
219
+ args
220
+ });
221
+ const handleData = event => {
222
+ ipc.send({
223
+ jsonrpc: '2.0',
224
+ method: 'Viewlet.send',
225
+ params: [id, 'handleData', event.data]
226
+ });
227
+ };
228
+ pty.addEventListener('data', handleData);
229
+ set(id, pty);
230
+ };
231
+ const write = (id, data) => {
232
+ const pty = get(id);
233
+ if (!pty) {
234
+ throw new Error(`pty ${id} not found`);
235
+ }
236
+ pty.write(data);
237
+ };
238
+ const resize = (id, columns, rows) => {
239
+ const pty = get(id);
240
+ if (!pty) {
241
+ throw new Error(`pty ${id} not found`);
242
+ }
243
+ pty.resize(columns, rows);
244
+ };
245
+ const dispose = id => {
246
+ const pty = get(id);
247
+ if (!pty) {
248
+ throw new Error(`pty ${id} not found`);
249
+ }
250
+ pty.dispose();
251
+ remove(id);
252
+ };
253
+
254
+ const HandleElectronMessagePort = 'HandleElectronMessagePort.handleElectronMessagePort';
255
+ const HandleNodeMessagePort = 'HandleNodeMessagePort.handleNodeMessagePort';
256
+ const HandleWebSocket = 'HandleWebSocket.handleWebSocket';
257
+ const TerminalCreate = 'Terminal.create';
258
+ const TerminalResize = 'Terminal.resize';
259
+ const TerminalWrite = 'Terminal.write';
260
+ const TerminalDispose = 'Terminal.dispose';
261
+
262
+ const commandMap = {
263
+ [HandleElectronMessagePort]: handleElectronMessagePort,
264
+ [HandleNodeMessagePort]: handleNodeMessagePort,
265
+ [HandleWebSocket]: handleWebSocket,
266
+ [TerminalCreate]: create,
267
+ [TerminalResize]: resize,
268
+ [TerminalWrite]: write,
269
+ [TerminalDispose]: dispose
270
+ };
271
+
272
+ const listen = async () => {
273
+ const ipc = await listen$1({
274
+ method: Auto()
275
+ });
276
+ handleIpc(ipc);
277
+ };
278
+
279
+ const NewLine = '\n';
280
+
281
+ const Error$1 = 1;
282
+ const Success = 0;
283
+
284
+ /**
285
+ *
286
+ * @param {string} string
287
+ * @param {number|undefined} startIndex
288
+ * @returns
289
+ */
290
+ const getNewLineIndex = (string, startIndex = undefined) => {
291
+ return string.indexOf(NewLine, startIndex);
292
+ };
293
+
294
+ const EPIPE = 'EPIPE';
295
+ const ERR_IPC_CHANNEL_CLOSED = 'ERR_IPC_CHANNEL_CLOSED';
296
+
297
+ const exit = code => {
298
+ process.exit(code);
299
+ };
300
+ const setExitCode = exitCode => {
301
+ process.exitCode = exitCode;
302
+ };
303
+ const isConnected = () => {
304
+ return process.connected;
305
+ };
306
+
307
+ const isIgnoredError = error => {
308
+ if (error && error.code === EPIPE && !process.connected) {
309
+ // parent process is disposed, ignore
310
+ return true;
311
+ }
312
+ if (error && error.code === ERR_IPC_CHANNEL_CLOSED && !isConnected()) {
313
+ // parent process is disposed, ignore
314
+ return true;
315
+ }
316
+ return false;
317
+ };
318
+
319
+ // TODO mock this module when used in unit tests
320
+
321
+ const state = {
322
+ console: undefined
323
+ };
324
+ const createConsole = () => {
325
+ const logFile = `${tmpdir()}/log-terminal-process.txt`;
326
+ const writeStream = createWriteStream(logFile);
327
+ const logger = new Console(writeStream);
328
+ return logger;
329
+ };
330
+ const getOrCreateLogger = () => {
331
+ if (!state.console) {
332
+ state.console = createConsole();
333
+ }
334
+ return state.console;
335
+ };
336
+ const info = (...args) => {
337
+ const logger = getOrCreateLogger();
338
+ logger.info(...args);
339
+ console.info(...args);
340
+ };
341
+ const error = (...args) => {
342
+ const logger = getOrCreateLogger();
343
+ logger.error(...args);
344
+ console.error(...args);
345
+ };
346
+
347
+ const firstErrorLine = error => {
348
+ if (error.stack) {
349
+ return error.stack.slice(0, getNewLineIndex(error.stack));
350
+ }
351
+ if (error.message) {
352
+ return error.message;
353
+ }
354
+ return `${error}`;
355
+ };
356
+
357
+ // @ts-ignore
358
+ const handleUncaughtExceptionMonitor$1 = error$1 => {
359
+ info(`[pty host] uncaught exception: ${firstErrorLine(error$1)}`);
360
+ if (isIgnoredError(error$1)) {
361
+ return;
362
+ }
363
+ const prettyError = prepare(error$1);
364
+ error(
365
+ // @ts-ignore
366
+ prettyError.codeFrame + NewLine + prettyError.stack + NewLine);
367
+ setExitCode(Error$1);
368
+ };
369
+
370
+ const handleDisconnect = () => {
371
+ console.info('[pty host] disconnected');
372
+ exit(Success);
373
+ };
374
+ const handleUncaughtExceptionMonitor = error => {
375
+ // @ts-ignore
376
+ handleUncaughtExceptionMonitor$1(error);
377
+ };
378
+
379
+ const main = async () => {
380
+ process.on('uncaughtExceptionMonitor', handleUncaughtExceptionMonitor);
381
+ process.on('disconnect', handleDisconnect);
382
+ register(commandMap);
383
+ await listen();
384
+ };
385
+
386
+ main();
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@lvce-editor/pty-host",
3
- "version": "2.1.0",
3
+ "version": "3.0.0",
4
4
  "description": "",
5
- "main": "src/ptyHostMain.js",
5
+ "main": "dist/ptyHostMain.js",
6
6
  "bin": "bin/ptyHost.js",
7
7
  "type": "module",
8
8
  "keywords": [
@@ -19,53 +19,15 @@
19
19
  "node": ">=18"
20
20
  },
21
21
  "dependencies": {
22
- "@lvce-editor/ipc": "^11.0.1",
23
- "@lvce-editor/json-rpc": "^4.1.0",
22
+ "@lvce-editor/assert": "^1.3.0",
23
+ "@lvce-editor/command": "^1.2.0",
24
+ "@lvce-editor/ipc": "^11.3.0",
25
+ "@lvce-editor/json-rpc": "^5.2.0",
24
26
  "@lvce-editor/pretty-error": "^1.6.0",
25
- "@lvce-editor/verror": "^1.4.0",
27
+ "@lvce-editor/verror": "^1.6.0",
26
28
  "debug": "^4.3.7"
27
29
  },
28
30
  "optionalDependencies": {
29
31
  "node-pty": "^1.1.0-beta20"
30
- },
31
- "xo": {
32
- "rules": {
33
- "unicorn/filename-case": "off",
34
- "indent": "off",
35
- "semi": "off",
36
- "no-unused-vars": "off",
37
- "unicorn/numeric-separators-style": "off",
38
- "no-extra-semi": "off",
39
- "arrow-body-style": "off",
40
- "padded-blocks": "off",
41
- "capitalized-comments": "off",
42
- "padding-line-between-statements": "off",
43
- "arrow-parens": "off",
44
- "no-warning-comments": "off",
45
- "array-bracket-spacing": "off",
46
- "comma-spacing": "off",
47
- "unicorn/no-array-callback-reference": "off",
48
- "comma-dangle": "off",
49
- "operator-linebreak": "off",
50
- "no-case-declarations": "off",
51
- "no-undef": "off",
52
- "object-curly-spacing": "off",
53
- "object-shorthand": "off",
54
- "complexity": "off",
55
- "no-labels": "off",
56
- "no-multi-assign": "off",
57
- "max-params": "off",
58
- "no-bitwise": "off",
59
- "unicorn/prefer-math-trunc": "off",
60
- "no-await-in-loop": "off",
61
- "unicorn/prefer-add-event-listener": "off",
62
- "no-unused-expressions": "off",
63
- "node/prefer-global/process": "off",
64
- "unicorn/no-for-loop": "off",
65
- "unicorn/prevent-abbreviations": "off"
66
- },
67
- "ignores": [
68
- "distmin"
69
- ]
70
32
  }
71
33
  }
@@ -1,59 +0,0 @@
1
- import { AssertionError } from '../AssertionError/AssertionError.js'
2
-
3
- const getType = (value) => {
4
- switch (typeof value) {
5
- case 'number':
6
- return 'number'
7
- case 'function':
8
- return 'function'
9
- case 'string':
10
- return 'string'
11
- case 'object':
12
- if (value === null) {
13
- return 'null'
14
- }
15
- if (Array.isArray(value)) {
16
- return 'array'
17
- }
18
- return 'object'
19
- case 'boolean':
20
- return 'boolean'
21
- default:
22
- return 'unknown'
23
- }
24
- }
25
-
26
- export const object = (value) => {
27
- const type = getType(value)
28
- if (type !== 'object') {
29
- throw new AssertionError('expected value to be of type object')
30
- }
31
- }
32
-
33
- export const number = (value) => {
34
- const type = getType(value)
35
- if (type !== 'number') {
36
- throw new AssertionError('expected value to be of type number')
37
- }
38
- }
39
-
40
- export const array = (value) => {
41
- const type = getType(value)
42
- if (type !== 'array') {
43
- throw new AssertionError('expected value to be of type array')
44
- }
45
- }
46
-
47
- export const string = (value) => {
48
- const type = getType(value)
49
- if (type !== 'string') {
50
- throw new AssertionError('expected value to be of type string')
51
- }
52
- }
53
-
54
- export const boolean = (value) => {
55
- const type = getType(value)
56
- if (type !== 'boolean') {
57
- throw new AssertionError('expected value to be of type boolean')
58
- }
59
- }
@@ -1,6 +0,0 @@
1
- export class AssertionError extends Error {
2
- constructor(message) {
3
- super(message)
4
- this.name = 'AssertionError'
5
- }
6
- }
@@ -1 +0,0 @@
1
- export { resolve } from '@lvce-editor/json-rpc'
@@ -1,11 +0,0 @@
1
- export const Backslash = '\\'
2
- export const Dash = '-'
3
- export const Dot = '.'
4
- export const EmptyString = ''
5
- export const NewLine = '\n'
6
- export const OpenAngleBracket = '<'
7
- export const Slash = '/'
8
- export const Space = ' '
9
- export const Tab = '\t'
10
- export const Underline = '_'
11
- export const T = 't'
@@ -1,9 +0,0 @@
1
- import * as CommandState from '../CommandState/CommandState.js'
2
-
3
- export const execute = (command, ...args) => {
4
- const fn = CommandState.getCommand(command)
5
- if (!fn) {
6
- throw new Error(`Command not found ${command}`)
7
- }
8
- return fn(...args)
9
- }
@@ -1,17 +0,0 @@
1
- import * as HandleElectronMessagePort from '../HandleElectronMessagePort/HandleElectronMessagePort.js'
2
- import * as HandleNodeMessagePort from '../HandleNodeMessagePort/HandleNodeMessagePort.js'
3
- import * as HandleWebSocket from '../HandleWebSocket/HandleWebSocket.js'
4
- import * as PtyController from '../PtyController/PtyController.js'
5
- import * as TerminalProcessCommandType from '../TerminalProcessCommandType/TerminalProcessCommandType.js'
6
-
7
- export const commandMap = {
8
- [TerminalProcessCommandType.HandleElectronMessagePort]:
9
- HandleElectronMessagePort.handleElectronMessagePort,
10
- [TerminalProcessCommandType.HandleNodeMessagePort]:
11
- HandleNodeMessagePort.handleNodeMessagePort,
12
- [TerminalProcessCommandType.HandleWebSocket]: HandleWebSocket.handleWebSocket,
13
- [TerminalProcessCommandType.TerminalCreate]: PtyController.create,
14
- [TerminalProcessCommandType.TerminalResize]: PtyController.resize,
15
- [TerminalProcessCommandType.TerminalWrite]: PtyController.write,
16
- [TerminalProcessCommandType.TerminalDispose]: PtyController.dispose,
17
- }
@@ -1,17 +0,0 @@
1
- export const state = {
2
- commands: Object.create(null),
3
- }
4
-
5
- export const registerCommand = (key, fn) => {
6
- state.commands[key] = fn
7
- }
8
-
9
- export const registerCommands = (commandMap) => {
10
- for (const [key, value] of Object.entries(commandMap)) {
11
- registerCommand(key, value)
12
- }
13
- }
14
-
15
- export const getCommand = (key) => {
16
- return state.commands[key]
17
- }
@@ -1,3 +0,0 @@
1
- import debugModule from 'debug'
2
-
3
- export const debug = debugModule('pty-host')
@@ -1,19 +0,0 @@
1
- export const E_COLOR_THEME_NOT_FOUND = 'E_COLOR_THEME_NOT_FOUND'
2
- export const E_COMMAND_NOT_FOUND = 'E_COMMAND_NOT_FOUND'
3
- export const E_ICON_THEME_NOT_FOUND = 'E_ICON_THEME_NOT_FOUND'
4
- export const E_INCOMPATIBLE_NATIVE_MODULE = 'E_INCOMPATIBLE_NATIVE_MODULE'
5
- export const E_MANIFEST_NOT_FOUND = 'E_MANIFEST_NOT_FOUND'
6
- export const E_MODULES_NOT_SUPPORTED_IN_ELECTRON =
7
- 'E_MODULES_NOT_SUPPORTED_IN_ELECTRON'
8
- export const EACCES = 'EACCES'
9
- export const ECONNRESET = 'ECONNRESET'
10
- export const EEXIST = 'EEXIST'
11
- export const EISDIR = 'EISDIR'
12
- export const ELOOP = 'ELOOP'
13
- export const ENOENT = 'ENOENT'
14
- export const ENOTDIR = 'ENOTDIR'
15
- export const EPERM = 'EPERM'
16
- export const EPIPE = 'EPIPE'
17
- export const ERR_IPC_CHANNEL_CLOSED = 'ERR_IPC_CHANNEL_CLOSED'
18
- export const ERR_MODULE_NOT_FOUND = 'ERR_MODULE_NOT_FOUND'
19
- export const EXDEV = 'EXDEV'
@@ -1,75 +0,0 @@
1
- import * as Character from '../Character/Character.js'
2
- import * as ExitCode from '../ExitCode/ExitCode.js'
3
- import * as GetNewLineIndex from '../GetNewLineIndex/GetNewLineIndex.js'
4
- import * as IsIgnoredError from '../IsIgnoredError/IsIgnoredError.js'
5
- import * as Logger from '../Logger/Logger.js'
6
- import * as PrettyError from '../PrettyError/PrettyError.js'
7
- import * as Process from '../Process/Process.js'
8
-
9
- export const state = {
10
- seenErrors: [],
11
- }
12
-
13
- const preparePrettyError = (error) => {
14
- const cause = error.cause()
15
- return {
16
- message: error.message,
17
- codeFrame: cause.codeFrame,
18
- stack: cause.stack,
19
- }
20
- }
21
-
22
- const printPrettyError = (prettyError) => {
23
- console.error(
24
- `${prettyError.message}\n${prettyError.codeFrame}\n${prettyError.stack}`,
25
- )
26
- }
27
-
28
- export const handleError = (error) => {
29
- // @ts-ignore
30
- if (state.seenErrors.includes(error.message)) {
31
- return
32
- }
33
- // @ts-ignore
34
- state.seenErrors.push(error.message)
35
- const prettyError = preparePrettyError(error)
36
- // Socket.send({
37
- // jsonrpc: JsonRpcVersion.Two,
38
- // method: /* Dialog.showErrorDialogWithOptions */ 'Dialog.showMessage',
39
- // params: [
40
- // {
41
- // message: prettyError.message,
42
- // codeFrame: prettyError.codeFrame,
43
- // stack: prettyError.stack,
44
- // },
45
- // ],
46
- // })
47
- printPrettyError(prettyError)
48
- }
49
-
50
- const firstErrorLine = (error) => {
51
- if (error.stack) {
52
- return error.stack.slice(0, GetNewLineIndex.getNewLineIndex(error.stack))
53
- }
54
- if (error.message) {
55
- return error.message
56
- }
57
- return `${error}`
58
- }
59
-
60
- // @ts-ignore
61
- export const handleUncaughtExceptionMonitor = (error, origin) => {
62
- Logger.info(`[pty host] uncaught exception: ${firstErrorLine(error)}`)
63
- if (IsIgnoredError.isIgnoredError(error)) {
64
- return
65
- }
66
- const prettyError = PrettyError.prepare(error)
67
- Logger.error(
68
- // @ts-ignore
69
- prettyError.codeFrame +
70
- Character.NewLine +
71
- prettyError.stack +
72
- Character.NewLine,
73
- )
74
- Process.setExitCode(ExitCode.Error)
75
- }
@@ -1,5 +0,0 @@
1
- export const Error = 1
2
-
3
- export const ExpectedError = 128
4
-
5
- export const Success = 0
@@ -1,11 +0,0 @@
1
- import * as Character from '../Character/Character.js'
2
-
3
- /**
4
- *
5
- * @param {string} string
6
- * @param {number|undefined} startIndex
7
- * @returns
8
- */
9
- export const getNewLineIndex = (string, startIndex = undefined) => {
10
- return string.indexOf(Character.NewLine, startIndex)
11
- }
@@ -1,13 +0,0 @@
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
- }
@@ -1,15 +0,0 @@
1
- import * as Assert from '../Assert/Assert.js'
2
- import * as HandleMessage from '../HandleMessage/HandleMessage.js'
3
-
4
- export const handleIpc = (ipc) => {
5
- Assert.object(ipc)
6
- if ('addEventListener' in ipc) {
7
- ipc.addEventListener('message', HandleMessage.handleMessage)
8
- } else if ('onmessage' in ipc) {
9
- // deprecated
10
- ipc.onmessage = HandleMessage.handleMessage
11
- } else if ('on' in ipc) {
12
- // deprecated
13
- ipc.on('message', HandleMessage.handleMessage)
14
- }
15
- }
@@ -1,25 +0,0 @@
1
- import * as Callback from '../Callback/Callback.js'
2
- import * as Command from '../Command/Command.js'
3
- import * as JsonRpc from '../JsonRpc/JsonRpc.js'
4
- import * as PrintPrettyError from '../PrintPrettyError/PrintPrettyError.js'
5
- import * as RequiresSocket from '../RequiresSocket/RequiresSocket.js'
6
-
7
- const preparePrettyError = (error) => {
8
- return error
9
- }
10
-
11
- const logError = (error, prettyError) => {
12
- PrintPrettyError.printPrettyError(prettyError, `[terminal-process] `)
13
- }
14
-
15
- export const handleMessage = (event) => {
16
- return JsonRpc.handleJsonRpcMessage(
17
- event.target,
18
- event.data,
19
- Command.execute,
20
- Callback.resolve,
21
- preparePrettyError,
22
- logError,
23
- RequiresSocket.requiresSocket,
24
- )
25
- }
@@ -1,11 +0,0 @@
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
- }
@@ -1,15 +0,0 @@
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 handleWebSocket = async (handle, request) => {
7
- Assert.object(handle)
8
- Assert.object(request)
9
- const ipc = await IpcChild.listen({
10
- method: IpcChildType.WebSocket,
11
- request,
12
- handle,
13
- })
14
- HandleIpc.handleIpc(ipc)
15
- }
@@ -1,15 +0,0 @@
1
- import * as IpcChildModule from '../IpcChildModule/IpcChildModule.js'
2
-
3
- export const listen = async ({ method, ...params }) => {
4
- const module = await IpcChildModule.getModule(method)
5
- // @ts-ignore
6
- const rawIpc = await module.listen(params)
7
- // @ts-ignore
8
- if (module.signal) {
9
- // @ts-ignore
10
- module.signal(rawIpc)
11
- }
12
- // @ts-ignore
13
- const ipc = module.wrap(rawIpc)
14
- return ipc
15
- }
@@ -1,25 +0,0 @@
1
- import {
2
- IpcChildWithElectronMessagePort,
3
- IpcChildWithElectronUtilityProcess,
4
- IpcChildWithNodeForkedProcess,
5
- IpcChildWithNodeWorker,
6
- IpcChildWithWebSocket,
7
- } from '@lvce-editor/ipc'
8
- import * as IpcChildType from '../IpcChildType/IpcChildType.js'
9
-
10
- export const getModule = (method) => {
11
- switch (method) {
12
- case IpcChildType.NodeForkedProcess:
13
- return IpcChildWithNodeForkedProcess
14
- case IpcChildType.NodeWorker:
15
- return IpcChildWithNodeWorker
16
- case IpcChildType.WebSocket:
17
- return IpcChildWithWebSocket
18
- case IpcChildType.ElectronUtilityProcess:
19
- return IpcChildWithElectronUtilityProcess
20
- case IpcChildType.ElectronMessagePort:
21
- return IpcChildWithElectronMessagePort
22
- default:
23
- throw new Error('unexpected ipc type')
24
- }
25
- }
@@ -1,20 +0,0 @@
1
- export const NodeWorker = 1
2
- export const NodeForkedProcess = 2
3
- export const WebSocket = 3
4
- export const ElectronUtilityProcess = 4
5
- export const ElectronMessagePort = 5
6
- export const NodeMessagePort = 6
7
-
8
- export const Auto = () => {
9
- const { argv } = process
10
- if (argv.includes('--ipc-type=node-worker')) {
11
- return NodeWorker
12
- }
13
- if (argv.includes('--ipc-type=node-forked-process')) {
14
- return NodeForkedProcess
15
- }
16
- if (argv.includes('--ipc-type=electron-utility-process')) {
17
- return ElectronUtilityProcess
18
- }
19
- throw new Error(`[pty-host] unknown ipc type`)
20
- }
@@ -1,18 +0,0 @@
1
- import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
2
- import * as Process from '../Process/Process.js'
3
-
4
- export const isIgnoredError = (error) => {
5
- if (error && error.code === ErrorCodes.EPIPE && !process.connected) {
6
- // parent process is disposed, ignore
7
- return true
8
- }
9
- if (
10
- error &&
11
- error.code === ErrorCodes.ERR_IPC_CHANNEL_CLOSED &&
12
- !Process.isConnected()
13
- ) {
14
- // parent process is disposed, ignore
15
- return true
16
- }
17
- return false
18
- }
@@ -1 +0,0 @@
1
- export * from '@lvce-editor/json-rpc'
@@ -1,8 +0,0 @@
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 listen = async () => {
6
- const ipc = await IpcChild.listen({ method: IpcChildType.Auto() })
7
- HandleIpc.handleIpc(ipc)
8
- }
@@ -1,50 +0,0 @@
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-terminal-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
- }
@@ -1,14 +0,0 @@
1
- import * as CommandMap from '../CommandMap/CommandMap.js'
2
- import * as CommandState from '../CommandState/CommandState.js'
3
- import * as Listen from '../Listen/Listen.js'
4
- import * as ProcessListeners from '../ProcessListeners/ProcessListeners.js'
5
-
6
- export const main = async () => {
7
- process.on(
8
- 'uncaughtExceptionMonitor',
9
- ProcessListeners.handleUncaughtExceptionMonitor,
10
- )
11
- process.on('disconnect', ProcessListeners.handleDisconnect)
12
- CommandState.registerCommands(CommandMap.commandMap)
13
- await Listen.listen()
14
- }
@@ -1,72 +0,0 @@
1
- import { spawn } from 'node-pty'
2
- import { VError } from '../VError/VError.js'
3
- import * as Assert from '../Assert/Assert.js'
4
-
5
- class DataEvent extends Event {
6
- constructor(data) {
7
- super('data')
8
- this.data = data
9
- }
10
- }
11
-
12
- class ExitEvent extends Event {
13
- constructor(data) {
14
- super('exit')
15
- this.data = data
16
- }
17
- }
18
-
19
- class Pty extends EventTarget {
20
- /**
21
- *
22
- * @param {import('node-pty').IPty} pty
23
- */
24
- constructor(pty) {
25
- super()
26
- this.pty = pty
27
-
28
- const handleData = (data) => {
29
- this.dispatchEvent(new DataEvent(data))
30
- }
31
- const handleExit = (data) => {
32
- this.dispatchEvent(new ExitEvent(data))
33
- }
34
- this.pty.onData(handleData)
35
- this.pty.onExit(handleExit)
36
- }
37
-
38
- resize(columns, rows) {
39
- this.pty.resize(columns, rows)
40
- }
41
-
42
- dispose() {
43
- this.pty.kill()
44
- }
45
-
46
- write(data) {
47
- this.pty.write(data)
48
- }
49
- }
50
-
51
- /**
52
- *
53
- * @param {*} param0
54
- * @returns {any}
55
- */
56
- export const create = ({ env = {}, cwd, command, args } = {}) => {
57
- try {
58
- Assert.string(cwd)
59
- Assert.string(command)
60
- Assert.array(args)
61
- const pty = spawn(command, args, {
62
- encoding: null,
63
- cwd,
64
- // cols: 10,
65
- // rows: 10,
66
- })
67
- const wrapped = new Pty(pty)
68
- return wrapped
69
- } catch (error) {
70
- throw new VError(error, `Failed to create terminal`)
71
- }
72
- }
@@ -1 +0,0 @@
1
- export { prepare, prepareJsonError } from '@lvce-editor/pretty-error'
@@ -1,7 +0,0 @@
1
- import * as Logger from '../Logger/Logger.js'
2
-
3
- export const printPrettyError = (prettyError, prefix = '') => {
4
- Logger.error(
5
- `${prefix}${prettyError.type}: ${prettyError.message}\n\n${prettyError.codeFrame}\n\n${prettyError.stack}\n`,
6
- )
7
- }
@@ -1,17 +0,0 @@
1
- export const exit = (code) => {
2
- process.exit(code)
3
- }
4
-
5
- export const setExitCode = (exitCode) => {
6
- process.exitCode = exitCode
7
- }
8
-
9
- export const { argv } = process
10
-
11
- export const isConnected = () => {
12
- return process.connected
13
- }
14
-
15
- export const getPid = () => {
16
- return process.pid
17
- }
@@ -1,17 +0,0 @@
1
- import * as ErrorHandling from '../ErrorHandling/ErrorHandling.js'
2
- import * as ExitCode from '../ExitCode/ExitCode.js'
3
- import * as Process from '../Process/Process.js'
4
-
5
- export const handleDisconnect = () => {
6
- console.info('[pty host] disconnected')
7
- Process.exit(ExitCode.Success)
8
- }
9
-
10
- export const handleSigTerm = () => {
11
- console.info('[pty host] sigterm')
12
- Process.exit(ExitCode.Success)
13
- }
14
-
15
- export const handleUncaughtExceptionMonitor = (error) => {
16
- ErrorHandling.handleUncaughtExceptionMonitor(error)
17
- }
@@ -1 +0,0 @@
1
- export * from '../NodePty/NodePty.js'
@@ -1,57 +0,0 @@
1
- import * as Assert from '../Assert/Assert.js'
2
- import * as Debug from '../Debug/Debug.js'
3
- import * as Pty from '../Pty/Pty.js'
4
- import * as PtyState from '../PtyState/PtyState.js'
5
-
6
- // TODO maybe merge pty and pty controller
7
- export const create = (ipc, id, cwd, command, args) => {
8
- Assert.number(id)
9
- Assert.string(cwd)
10
- Assert.string(command)
11
- Assert.array(args)
12
- Assert.object(ipc)
13
- Debug.debug(`create ${id} ${cwd}`)
14
- // @ts-ignore
15
- const pty = Pty.create({ cwd, command, args })
16
- const handleData = (event) => {
17
- ipc.send({
18
- jsonrpc: '2.0',
19
- method: 'Viewlet.send',
20
- params: [id, 'handleData', event.data],
21
- })
22
- }
23
-
24
- pty.addEventListener('data', handleData)
25
- PtyState.set(id, pty)
26
- }
27
-
28
- export const write = (id, data) => {
29
- const pty = PtyState.get(id)
30
- if (!pty) {
31
- throw new Error(`pty ${id} not found`)
32
- }
33
- pty.write(data)
34
- }
35
-
36
- export const resize = (id, columns, rows) => {
37
- const pty = PtyState.get(id)
38
- if (!pty) {
39
- throw new Error(`pty ${id} not found`)
40
- }
41
- pty.resize(columns, rows)
42
- }
43
-
44
- export const dispose = (id) => {
45
- const pty = PtyState.get(id)
46
- if (!pty) {
47
- throw new Error(`pty ${id} not found`)
48
- }
49
- pty.dispose()
50
- PtyState.remove(id)
51
- }
52
-
53
- export const disposeAll = () => {
54
- for (const id in PtyState.getAll()) {
55
- dispose(id)
56
- }
57
- }
@@ -1,19 +0,0 @@
1
- export const state = {
2
- ptyMap: Object.create(null),
3
- }
4
-
5
- export const set = (id, pty) => {
6
- state.ptyMap[id] = pty
7
- }
8
-
9
- export const get = (id) => {
10
- return state.ptyMap[id]
11
- }
12
-
13
- export const remove = (id) => {
14
- delete state.ptyMap[id]
15
- }
16
-
17
- export const getAll = () => {
18
- return state.ptyMap
19
- }
@@ -1,5 +0,0 @@
1
- const METHODS_THAT_REQUIRE_SOCKET = new Set(['Terminal.create'])
2
-
3
- export const requiresSocket = (method) => {
4
- return METHODS_THAT_REQUIRE_SOCKET.has(method)
5
- }
@@ -1,9 +0,0 @@
1
- export const HandleElectronMessagePort =
2
- 'HandleElectronMessagePort.handleElectronMessagePort'
3
- export const HandleNodeMessagePort =
4
- 'HandleNodeMessagePort.handleNodeMessagePort'
5
- export const HandleWebSocket = 'HandleWebSocket.handleWebSocket'
6
- export const TerminalCreate = 'Terminal.create'
7
- export const TerminalResize = 'Terminal.resize'
8
- export const TerminalWrite = 'Terminal.write'
9
- export const TerminalDispose = 'Terminal.dispose'
@@ -1 +0,0 @@
1
- export * from '@lvce-editor/verror'
@@ -1,3 +0,0 @@
1
- import * as Main from './parts/Main/Main.js'
2
-
3
- Main.main()