1
- import path from 'path' ;
2
- import fs from 'fs' ;
3
- // eslint-disable-next-line camelcase
4
- import child_process from 'child_process' ;
5
- import crypto from 'crypto' ;
6
- import electron from 'electron' ;
7
- import worker from 'inline-entry-loader!./worker' ;
1
+ import { once } from 'events' ;
2
+ import { spawn } from 'child_process' ;
8
3
import { createCaller , exposeAll } from './rpc' ;
9
4
10
- function createChildFromSource ( src ) {
11
- const tmpFile = path . resolve (
12
- ( electron . app || electron . remote . app ) . getPath ( 'temp' ) ,
13
- `worker-runtime-${ crypto . randomBytes ( 32 ) . toString ( 'hex' ) } `
14
- ) ;
5
+ import childSrc from 'inline-entry-loader!./child' ;
15
6
16
- // eslint-disable-next-line no-sync
17
- fs . writeFileSync ( tmpFile , src , 'utf8' ) ;
18
-
19
- const childProcess = child_process . spawn ( process . execPath , [ tmpFile ] , {
20
- stdio : [ 'inherit' , 'inherit' , 'inherit' , 'ipc' ] ,
7
+ async function createChildFromSource ( src ) {
8
+ const childProcess = spawn ( process . execPath , [ ] , {
9
+ stdio : [ 'pipe' , 'inherit' , 'inherit' , 'ipc' ] ,
21
10
env : { ...process . env , ELECTRON_RUN_AS_NODE : 1 } ,
22
11
/**
23
12
* This would be awesome, but only supported since node 12.16.0, compass
@@ -27,22 +16,34 @@ function createChildFromSource(src) {
27
16
serialization : 'advanced' ,
28
17
} ) ;
29
18
19
+ childProcess . stdin . write ( src ) ;
20
+ childProcess . stdin . end ( ) ;
21
+
22
+ // First message is a "ready" message
23
+ await once ( childProcess , 'message' ) ;
24
+
30
25
return childProcess ;
31
26
}
32
27
33
28
class WorkerRuntime {
34
29
constructor ( uri , options , cliOptions ) {
35
30
this . initOptions = { uri, options, cliOptions } ;
31
+ // Creating worker is an async process, we want to "lock"
32
+ // evaluate/getCompletions methods until worker is initiated from the get-go
33
+ this . initPromiseResolve = null ;
34
+ this . initPromise = new Promise ( ( resolve ) => {
35
+ this . initPromiseResolve = resolve ;
36
+ } ) ;
36
37
this . evaluationListener = null ;
37
38
this . cancelEvaluate = ( ) => { } ;
38
39
this . initWorker ( ) ;
39
40
}
40
41
41
- initWorker ( ) {
42
+ async initWorker ( ) {
42
43
const { uri, options, cliOptions } = this . initOptions ;
43
- this . childProcess = createChildFromSource ( worker ) ;
44
+ this . childProcess = await createChildFromSource ( childSrc ) ;
44
45
this . worker = createCaller (
45
- [ 'init' , 'evaluate' , 'getCompletions' ] ,
46
+ [ 'init' , 'evaluate' , 'getCompletions' , 'ping' ] ,
46
47
this . childProcess
47
48
) ;
48
49
this . workerEvaluationListener = exposeAll (
@@ -68,7 +69,7 @@ class WorkerRuntime {
68
69
} ,
69
70
this . childProcess
70
71
) ;
71
- this . initPromise = this . worker . init ( uri , options , cliOptions ) ;
72
+ this . initPromiseResolve ( await this . worker . init ( uri , options , cliOptions ) ) ;
72
73
}
73
74
74
75
async evaluate ( code ) {
@@ -108,18 +109,23 @@ class WorkerRuntime {
108
109
return prev ;
109
110
}
110
111
112
+ interruptWorker ( ) {
113
+ this . childProcess . kill ( 'SIGINT' ) ;
114
+ }
115
+
111
116
terminateWorker ( ) {
112
117
this . cancelEvaluate ( ) ;
113
118
this . childProcess . kill ( ) ;
119
+ this . childProcess = null ;
114
120
}
115
121
116
- restart ( ) {
122
+ restartWorker ( ) {
117
123
this . terminateWorker ( ) ;
118
124
this . initWorker ( ) ;
119
125
}
120
126
121
127
waitForCancelEvaluate ( ) {
122
- return new Promise ( ( resolve , reject ) => {
128
+ return new Promise ( ( _resolve , reject ) => {
123
129
this . cancelEvaluate = ( ) => {
124
130
reject ( new Error ( 'Script execution was interrupted' ) ) ;
125
131
} ;
0 commit comments