Skip to content

Commit c7e5b0e

Browse files
committed
abstracted away parent.ts into a class
refs #51
1 parent 4b7c096 commit c7e5b0e

File tree

9 files changed

+317
-260
lines changed

9 files changed

+317
-260
lines changed

lib/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"./typings/tsd.d.ts",
6161
"./worker/child.ts",
6262
"./worker/messages.ts",
63-
"./worker/parent.ts"
63+
"./worker/parent.ts",
64+
"./worker/workerLib.ts"
6465
]
6566
}

lib/worker/child.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
var messages = require('./messages');
2-
setInterval(function () {
3-
if (!process.connected) {
4-
process.exit(messages.orphanExitCode);
5-
}
6-
}, 1000);
1+
var messages = require('./workerLib');
2+
messages.keepAlive();
73
var responders = {};
84
function processData(m) {
95
var parsed = m;

lib/worker/child.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
///ts:ref=globals
22
/// <reference path="../globals.ts"/> ///ts:ref:generated
33

4-
import messages = require('./messages');
4+
import messages = require('./workerLib');
55

66
// Keepalive
7-
setInterval(() => {
8-
// We have been orphaned
9-
if(!(<any>process).connected){
10-
process.exit(messages.orphanExitCode);
11-
}
12-
}, 1000);
7+
messages.keepAlive();
138

149
var responders: { [message: string]: (query: any) => any } = {};
1510

lib/worker/messages.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
exports.orphanExitCode = 100;

lib/worker/messages.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +0,0 @@
1-
export var orphanExitCode = 100;
2-
3-
// Parent makes queries<T>
4-
// Child responds<T>
5-
export interface Message<T> {
6-
message: string;
7-
id: string;
8-
data?: T;
9-
error?: {
10-
method: string;
11-
message: string;
12-
stack: string;
13-
details: any;
14-
};
15-
}

lib/worker/parent.js

Lines changed: 19 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,17 @@
11
var childprocess = require('child_process');
22
var exec = childprocess.exec;
33
var spawn = childprocess.spawn;
4-
var messages = require('./messages');
5-
var gotENOENTonSpawnNode = false;
6-
var child;
7-
var currentListeners = {};
4+
var workerLib = require('./workerLib');
5+
var parent = new workerLib.Parent();
86
function startWorker() {
9-
try {
10-
var node = process.execPath;
11-
child = spawn(node, [
12-
__dirname + '/child.js'
13-
], { cwd: __dirname, env: { ATOM_SHELL_INTERNAL_RUN_AS_NODE: '1' }, stdio: ['ipc'] });
14-
child.on('error', function (err) {
15-
if (err.code === "ENOENT" && err.path === node) {
16-
gotENOENTonSpawnNode = true;
17-
}
18-
console.log('CHILD ERR ONERROR:', err.message, err.stack, err);
19-
child = null;
20-
});
21-
console.log('ts worker started');
22-
function processResponse(m) {
23-
var parsed = m;
24-
if (!parsed.message || !parsed.id) {
25-
console.log('PARENT ERR: Invalid JSON data from child:', m);
26-
}
27-
if (!currentListeners[parsed.message] || !currentListeners[parsed.message][parsed.id]) {
28-
console.log('PARENT ERR: No one was listening:', parsed.message, parsed.data);
29-
return;
30-
}
31-
else {
32-
if (parsed.error) {
33-
currentListeners[parsed.message][parsed.id].reject(parsed.error);
34-
}
35-
else {
36-
currentListeners[parsed.message][parsed.id].resolve(parsed.data);
37-
}
38-
delete currentListeners[parsed.message][parsed.id];
39-
}
40-
}
41-
child.on('message', function (resp) { return processResponse(resp); });
42-
child.stderr.on('data', function (err) {
43-
console.log("CHILD ERR STDERR:", err.toString());
44-
});
45-
child.on('close', function (code) {
46-
console.log('ts worker exited with code:', code);
47-
if (code === messages.orphanExitCode) {
48-
console.log('ts worker restarting');
49-
startWorker();
50-
}
51-
else if (gotENOENTonSpawnNode) {
52-
showError();
53-
}
54-
else {
55-
console.log('ts worker restarting');
56-
startWorker();
57-
}
58-
});
59-
}
60-
catch (ex) {
61-
showError(ex);
62-
}
7+
parent.startWorker(__dirname + '/child.js', showError);
8+
console.log('AtomTS worker started');
639
}
6410
exports.startWorker = startWorker;
6511
function stopWorker() {
66-
if (!child)
67-
return;
68-
try {
69-
child.kill('SIGTERM');
70-
}
71-
catch (ex) {
72-
console.error('failed to kill worker child');
73-
}
74-
child = null;
12+
parent.stopWorker();
7513
}
7614
exports.stopWorker = stopWorker;
77-
function createId() {
78-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
79-
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
80-
return v.toString(16);
81-
});
82-
}
83-
function childQuery(func) {
84-
return function (data) {
85-
var message = func.name;
86-
if (!child) {
87-
console.log('PARENT ERR: no child when you tried to send :', message);
88-
return Promise.reject(new Error("No worker active to recieve message: " + message));
89-
}
90-
if (!currentListeners[message])
91-
currentListeners[message] = {};
92-
var id = createId();
93-
var defer = Promise.defer();
94-
currentListeners[message][id] = defer;
95-
child.send({ message: message, id: id, data: data });
96-
return defer.promise;
97-
};
98-
}
9915
function showError(error) {
10016
var message = "Failed to start a child TypeScript worker. Atom-TypeScript is disabled.";
10117
if (process.platform === "win32") {
@@ -107,17 +23,17 @@ function showError(error) {
10723
}
10824
}
10925
var projectService = require('../main/lang/projectService');
110-
exports.echo = childQuery(projectService.echo);
111-
exports.quickInfo = childQuery(projectService.quickInfo);
112-
exports.build = childQuery(projectService.build);
113-
exports.errorsForFileFiltered = childQuery(projectService.errorsForFileFiltered);
114-
exports.getCompletionsAtPosition = childQuery(projectService.getCompletionsAtPosition);
115-
exports.emitFile = childQuery(projectService.emitFile);
116-
exports.regenerateProjectGlob = childQuery(projectService.regenerateProjectGlob);
117-
exports.formatDocument = childQuery(projectService.formatDocument);
118-
exports.formatDocumentRange = childQuery(projectService.formatDocumentRange);
119-
exports.getDefinitionsAtPosition = childQuery(projectService.getDefinitionsAtPosition);
120-
exports.updateText = childQuery(projectService.updateText);
121-
exports.errorsForFile = childQuery(projectService.errorsForFile);
122-
exports.getSignatureHelps = childQuery(projectService.getSignatureHelps);
123-
exports.getRenameInfo = childQuery(projectService.getRenameInfo);
26+
exports.echo = parent.childQuery(projectService.echo);
27+
exports.quickInfo = parent.childQuery(projectService.quickInfo);
28+
exports.build = parent.childQuery(projectService.build);
29+
exports.errorsForFileFiltered = parent.childQuery(projectService.errorsForFileFiltered);
30+
exports.getCompletionsAtPosition = parent.childQuery(projectService.getCompletionsAtPosition);
31+
exports.emitFile = parent.childQuery(projectService.emitFile);
32+
exports.regenerateProjectGlob = parent.childQuery(projectService.regenerateProjectGlob);
33+
exports.formatDocument = parent.childQuery(projectService.formatDocument);
34+
exports.formatDocumentRange = parent.childQuery(projectService.formatDocumentRange);
35+
exports.getDefinitionsAtPosition = parent.childQuery(projectService.getDefinitionsAtPosition);
36+
exports.updateText = parent.childQuery(projectService.updateText);
37+
exports.errorsForFile = parent.childQuery(projectService.errorsForFile);
38+
exports.getSignatureHelps = parent.childQuery(projectService.getSignatureHelps);
39+
exports.getRenameInfo = parent.childQuery(projectService.getRenameInfo);

lib/worker/parent.ts

Lines changed: 20 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -5,128 +5,21 @@ import childprocess = require('child_process');
55
var exec = childprocess.exec;
66
var spawn = childprocess.spawn;
77

8-
///ts:import=messages
9-
import messages = require('./messages'); ///ts:import:generated
8+
import workerLib = require('./workerLib');
109
import tsconfig = require('../main/tsconfig/tsconfig');
1110

1211

13-
var gotENOENTonSpawnNode = false;
14-
var child: childprocess.ChildProcess;
15-
var currentListeners: { [messages: string]: { [id: string]: PromiseDeferred<any> } } = {};
12+
var parent = new workerLib.Parent();
1613
export function startWorker() {
17-
try {
18-
var node = process.execPath; // We will run atom as node
19-
20-
child = spawn(node, [
21-
// '--debug', // Uncomment if you want to debug the child process
22-
__dirname + '/child.js'
23-
], { cwd: __dirname, env: { ATOM_SHELL_INTERNAL_RUN_AS_NODE: '1' }, stdio: ['ipc'] });
24-
25-
child.on('error',(err) => {
26-
if (err.code === "ENOENT" && err.path === node) {
27-
gotENOENTonSpawnNode = true;
28-
}
29-
console.log('CHILD ERR ONERROR:', err.message, err.stack, err);
30-
child = null;
31-
});
32-
33-
console.log('ts worker started');
34-
function processResponse(m: any) {
35-
var parsed: messages.Message<any> = m;
36-
37-
if (!parsed.message || !parsed.id) {
38-
console.log('PARENT ERR: Invalid JSON data from child:', m);
39-
}
40-
if (!currentListeners[parsed.message] || !currentListeners[parsed.message][parsed.id]) {
41-
console.log('PARENT ERR: No one was listening:', parsed.message, parsed.data);
42-
return;
43-
}
44-
else { // Alright nothing *weird* happened
45-
if (parsed.error) {
46-
currentListeners[parsed.message][parsed.id].reject(parsed.error);
47-
}
48-
else {
49-
currentListeners[parsed.message][parsed.id].resolve(parsed.data);
50-
}
51-
delete currentListeners[parsed.message][parsed.id];
52-
}
53-
}
54-
55-
child.on('message',(resp) => processResponse(resp));
56-
57-
58-
child.stderr.on('data',(err) => {
59-
console.log("CHILD ERR STDERR:", err.toString());
60-
});
61-
child.on('close',(code) => {
62-
// Handle process dropping
63-
console.log('ts worker exited with code:', code);
64-
65-
// If orphaned then Definitely restart
66-
if (code === messages.orphanExitCode) {
67-
console.log('ts worker restarting');
68-
startWorker();
69-
}
70-
// If we got ENOENT. Restarting will not help.
71-
else if (gotENOENTonSpawnNode) {
72-
showError();
73-
}
74-
// We haven't found a reson to not start worker yet
75-
else {
76-
console.log('ts worker restarting');
77-
startWorker();
78-
}
79-
});
80-
}
81-
catch (ex) {
82-
showError(ex);
83-
}
14+
parent.startWorker(__dirname + '/child.js', showError);
15+
console.log('AtomTS worker started')
8416
}
8517

8618
export function stopWorker() {
87-
if (!child) return;
88-
try {
89-
child.kill('SIGTERM');
90-
}
91-
catch (ex) {
92-
console.error('failed to kill worker child');
93-
}
94-
child = null;
95-
}
96-
97-
// Creates a Guid (UUID v4)
98-
function createId(): string {
99-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
100-
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
101-
return v.toString(16);
102-
});
103-
}
104-
105-
function childQuery<Query, Response>(func: (query: Query) => Response): (data: Query) => Promise<Response> {
106-
return (data) => {
107-
var message = func.name;
108-
109-
// If we don't have a child exit
110-
if (!child) {
111-
console.log('PARENT ERR: no child when you tried to send :', message);
112-
return <any>Promise.reject(new Error("No worker active to recieve message: " + message));
113-
}
114-
115-
// Initialize if this is the first call of this type
116-
if (!currentListeners[message]) currentListeners[message] = {};
117-
118-
// Create an id unique to this call and store the defered against it
119-
var id = createId();
120-
var defer = Promise.defer<Response>();
121-
currentListeners[message][id] = defer;
122-
123-
// Send data to worker
124-
child.send({ message: message, id: id, data: data });
125-
return defer.promise;
126-
};
19+
parent.stopWorker();
12720
}
12821

129-
function showError(error?: Error) {
22+
function showError(error: Error) {
13023
var message = "Failed to start a child TypeScript worker. Atom-TypeScript is disabled.";
13124
// Sad panda : https://github.com/TypeStrong/atom-typescript/issues/50
13225
if (process.platform === "win32") {
@@ -144,17 +37,17 @@ function showError(error?: Error) {
14437
///ts:import=projectService
14538
import projectService = require('../main/lang/projectService'); ///ts:import:generated
14639

147-
export var echo = childQuery(projectService.echo);
148-
export var quickInfo = childQuery(projectService.quickInfo);
149-
export var build = childQuery(projectService.build);
150-
export var errorsForFileFiltered = childQuery(projectService.errorsForFileFiltered);
151-
export var getCompletionsAtPosition = childQuery(projectService.getCompletionsAtPosition);
152-
export var emitFile = childQuery(projectService.emitFile);
153-
export var regenerateProjectGlob = childQuery(projectService.regenerateProjectGlob);
154-
export var formatDocument = childQuery(projectService.formatDocument);
155-
export var formatDocumentRange = childQuery(projectService.formatDocumentRange);
156-
export var getDefinitionsAtPosition = childQuery(projectService.getDefinitionsAtPosition);
157-
export var updateText = childQuery(projectService.updateText);
158-
export var errorsForFile = childQuery(projectService.errorsForFile);
159-
export var getSignatureHelps = childQuery(projectService.getSignatureHelps);
160-
export var getRenameInfo = childQuery(projectService.getRenameInfo);
40+
export var echo = parent.childQuery(projectService.echo);
41+
export var quickInfo = parent.childQuery(projectService.quickInfo);
42+
export var build = parent.childQuery(projectService.build);
43+
export var errorsForFileFiltered = parent.childQuery(projectService.errorsForFileFiltered);
44+
export var getCompletionsAtPosition = parent.childQuery(projectService.getCompletionsAtPosition);
45+
export var emitFile = parent.childQuery(projectService.emitFile);
46+
export var regenerateProjectGlob = parent.childQuery(projectService.regenerateProjectGlob);
47+
export var formatDocument = parent.childQuery(projectService.formatDocument);
48+
export var formatDocumentRange = parent.childQuery(projectService.formatDocumentRange);
49+
export var getDefinitionsAtPosition = parent.childQuery(projectService.getDefinitionsAtPosition);
50+
export var updateText = parent.childQuery(projectService.updateText);
51+
export var errorsForFile = parent.childQuery(projectService.errorsForFile);
52+
export var getSignatureHelps = parent.childQuery(projectService.getSignatureHelps);
53+
export var getRenameInfo = parent.childQuery(projectService.getRenameInfo);

0 commit comments

Comments
 (0)