isomorfeus-speednode 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,46 @@
1
+ require 'socket'
2
+
3
+ module Isomorfeus
4
+ module Speednode
5
+ class AttachSocket
6
+
7
+ attr_reader :socket
8
+
9
+ def initialize(socket_path, block)
10
+ @socket_path = socket_path
11
+ @run_block = block
12
+ end
13
+
14
+ def run
15
+ @running = true
16
+ client = nil
17
+ ret = nil
18
+ @socket = UNIXServer.new(@socket_path)
19
+
20
+ while @running do
21
+ if ret
22
+ begin
23
+ client = @socket.accept_nonblock
24
+ request = client.gets("\x04")
25
+ result = @run_block.call(request)
26
+ client.write result
27
+ client.flush
28
+ client.close
29
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK
30
+ end
31
+ end
32
+ sleep 0.005
33
+ ret = begin
34
+ IO.select([@socket], nil, nil, 1) || next
35
+ rescue Errno::EBADF
36
+ end
37
+ end
38
+ end
39
+
40
+ def stop
41
+ @running = false
42
+ @socket.close
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,23 @@
1
+ module Isomorfeus
2
+ class << self
3
+ attr_accessor :node_paths
4
+
5
+ def set_node_paths
6
+ np_sep = Gem.win_platform? ? ';' : ':'
7
+ existing_node_path = ENV['NODE_PATH']
8
+ temp_node_path = ''
9
+ if existing_node_path.nil? || existing_node_path.empty?
10
+ temp_node_path = Isomorfeus.node_paths.join(np_sep)
11
+ else
12
+ if existing_node_path.end_with?(np_sep)
13
+ temp_node_path = existing_node_path + Isomorfeus.node_paths.join(np_sep)
14
+ else
15
+ temp_node_path = existing_node_path + np_sep + Isomorfeus.node_paths.join(np_sep)
16
+ end
17
+ end
18
+ ENV['NODE_PATH'] = temp_node_path.split(np_sep).uniq.join(np_sep)
19
+ end
20
+ end
21
+
22
+ self.node_paths = []
23
+ end
@@ -1,239 +1,324 @@
1
- 'use strict';
2
-
3
- const vm = require('vm');
4
- const net = require('net');
5
- const os = require('os');
6
- let contexts = {};
7
- let process_exit = false;
8
-
9
- /*** circular-json, originally taken from https://raw.githubusercontent.com/WebReflection/circular-json/
10
- Copyright (C) 2013-2017 by Andrea Giammarchi - @WebReflection
11
-
12
- Permission is hereby granted, free of charge, to any person obtaining a copy
13
- of this software and associated documentation files (the "Software"), to deal
14
- in the Software without restriction, including without limitation the rights
15
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
- copies of the Software, and to permit persons to whom the Software is
17
- furnished to do so, subject to the following conditions:
18
-
19
- The above copyright notice and this permission notice shall be included in
20
- all copies or substantial portions of the Software.
21
-
22
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28
- THE SOFTWARE.
29
-
30
- ***
31
-
32
- the original version has been restructured and modified to fit in here,
33
- only stringify is used, unused parts removed.
34
-
35
- */
36
-
37
- const CircularJSON = {};
38
- CircularJSON.specialChar = '~';
39
- CircularJSON.safeSpecialChar = '\\x' + ('0' + CircularJSON.specialChar.charCodeAt(0).toString(16)).slice(-2);
40
- CircularJSON.escapedSafeSpecialChar = '\\' + CircularJSON.safeSpecialChar;
41
- CircularJSON.specialCharRG = new RegExp(CircularJSON.safeSpecialChar, 'g');
42
- CircularJSON.indexOf = [].indexOf || function(v){
43
- for(let i=this.length;i--&&this[i]!==v;);
44
- return i;
45
- };
46
-
47
- CircularJSON.generateReplacer = function (value, replacer, resolve) {
48
- let
49
- doNotIgnore = false,
50
- inspect = !!replacer,
51
- path = [],
52
- all = [value],
53
- seen = [value],
54
- mapp = [resolve ? CircularJSON.specialChar : '[Circular]'],
55
- last = value,
56
- lvl = 1,
57
- i, fn
58
- ;
59
- if (inspect) {
60
- fn = typeof replacer === 'object' ?
61
- function (key, value) {
62
- return key !== '' && CircularJSON.indexOf.call(replacer, key) < 0 ? void 0 : value;
63
- } :
64
- replacer;
65
- }
66
- return function(key, value) {
67
- // the replacer has rights to decide
68
- // if a new object should be returned
69
- // or if there's some key to drop
70
- // let's call it here rather than "too late"
71
- if (inspect) value = fn.call(this, key, value);
72
-
73
- // first pass should be ignored, since it's just the initial object
74
- if (doNotIgnore) {
75
- if (last !== this) {
76
- i = lvl - CircularJSON.indexOf.call(all, this) - 1;
77
- lvl -= i;
78
- all.splice(lvl, all.length);
79
- path.splice(lvl - 1, path.length);
80
- last = this;
81
- }
82
- // console.log(lvl, key, path);
83
- if (typeof value === 'object' && value) {
84
- // if object isn't referring to parent object, add to the
85
- // object path stack. Otherwise it is already there.
86
- if (CircularJSON.indexOf.call(all, value) < 0) {
87
- all.push(last = value);
88
- }
89
- lvl = all.length;
90
- i = CircularJSON.indexOf.call(seen, value);
91
- if (i < 0) {
92
- i = seen.push(value) - 1;
93
- if (resolve) {
94
- // key cannot contain specialChar but could be not a string
95
- path.push(('' + key).replace(CircularJSON.specialCharRG, CircularJSON.safeSpecialChar));
96
- mapp[i] = CircularJSON.specialChar + path.join(CircularJSON.specialChar);
97
- } else {
98
- mapp[i] = mapp[0];
99
- }
100
- } else {
101
- value = mapp[i];
102
- }
103
- } else {
104
- if (typeof value === 'string' && resolve) {
105
- // ensure no special char involved on deserialization
106
- // in this case only first char is important
107
- // no need to replace all value (better performance)
108
- value = value
109
- .replace(CircularJSON.safeSpecialChar, CircularJSON.escapedSafeSpecialChar)
110
- .replace(CircularJSON.specialChar, CircularJSON.safeSpecialChar);
111
- }
112
- }
113
- } else {
114
- doNotIgnore = true;
115
- }
116
- return value;
117
- };
118
- };
119
- CircularJSON.stringify = function stringify(value, replacer, space, doNotResolve) {
120
- return JSON.stringify(
121
- value,
122
- CircularJSON.generateReplacer(value, replacer, !doNotResolve),
123
- space
124
- );
125
- };
126
- /*** end of circular-json ***/
127
-
128
- /*
129
- * Versions of node before 0.12 (notably 0.10) didn't properly propagate
130
- * syntax errors.
131
- * This also regressed in the node 4.0 releases.
132
- *
133
- * To get around this, if it looks like we are missing the location of the
134
- * error, we guess it is (execjs):1
135
- *
136
- * This is obviously not ideal, but only affects syntax errors, and only on
137
- * these versions.
138
- */
139
- function massageStackTrace(stack) {
140
- if (stack && stack.indexOf("SyntaxError") == 0) {
141
- return "(execjs):1\n" + stack;
142
- } else {
143
- return stack;
144
- }
145
- }
146
-
147
- function createCompatibleContext() {
148
- let c = vm.createContext();
149
- vm.runInContext('delete this.console', c, "(execjs)");
150
- return c;
151
- }
152
-
153
- function createPermissiveContext() {
154
- return vm.createContext({ global: {}, process: {release: {name: "node"}}, Buffer, clearTimeout, require, setTimeout });
155
- }
156
-
157
- function getCompatibleContext(uuid) {
158
- return contexts[uuid] || (contexts[uuid] = createCompatibleContext());
159
- }
160
-
161
- function getPermissiveContext(uuid) {
162
- return contexts[uuid] || (contexts[uuid] = createPermissiveContext());
163
- }
164
-
165
- let commands = {
166
- deleteContext: function(uuid) {
167
- delete contexts[uuid];
168
- return [1];
169
- },
170
- exit: function(code) {
171
- process_exit = code;
172
- return ['ok'];
173
- },
174
- execp: function execJS(input) {
175
- let context = getPermissiveContext(input.context);
176
- let result = vm.runInContext(input.source, context, "(execjs)");
177
- if (typeof result === 'undefined' && result !== null) { return ['ok']; }
178
- else {
179
- try { return ['ok', result]; }
180
- catch (err) { return ['err', ['', err].join(''), err.stack]; }
181
- }
182
- },
183
- exec: function execJS(input) {
184
- let context = getCompatibleContext(input.context);
185
- let result = vm.runInContext(input.source, context, "(execjs)");
186
- if (typeof result === 'undefined' && result !== null) { return ['ok']; }
187
- else {
188
- try { return ['ok', result]; }
189
- catch (err) { return ['err', ['', err].join(''), err.stack]; }
190
- }
191
- }
192
- };
193
-
194
- let server = net.createServer(function(s) {
195
- let received_data = [];
196
-
197
- s.on('data', function (data) {
198
- received_data.push(data);
199
- if (data[data.length - 1] !== 4) { return; }
200
-
201
- let request = received_data.join('').toString('utf8');
202
- request = request.substr(0, request.length - 1);
203
- received_data = [];
204
-
205
- let input, result;
206
- let outputJSON = '';
207
-
208
- try { input = JSON.parse(request); }
209
- catch(err) {
210
- outputJSON = JSON.stringify(['err', ['', err].join(''), err.stack]);
211
- s.write([outputJSON, "\x04"].join(''));
212
- return;
213
- }
214
-
215
- try { result = commands[input.cmd].apply(null, input.args); }
216
- catch (err) {
217
- outputJSON = JSON.stringify(['err', ['', err].join(''), massageStackTrace(err.stack)]);
218
- s.write([outputJSON, "\x04"].join(''));
219
- return;
220
- }
221
-
222
- try { outputJSON = JSON.stringify(result); }
223
- catch(err) {
224
- if (err.message.includes('circular')) { outputJSON = CircularJSON.stringify(result); }
225
- else { outputJSON = JSON.stringify([['', err].join(''), err.stack]); }
226
- s.write([outputJSON, "\x04"].join(''));
227
- return;
228
- }
229
-
230
- s.write([outputJSON, "\x04"].join(''));
231
- if (process_exit !== false) { process.exit(process_exit); }
232
- });
233
- });
234
-
235
- let socket_path = process.env.SOCKET_PATH;
236
- if (!socket_path) { throw 'No SOCKET_PATH given!'; };
237
- if (os.platform().indexOf('win') > -1) { server.listen('\\\\.\\pipe\\' + socket_path); }
238
- else { server.listen(socket_path); }
239
-
1
+ 'use strict';
2
+
3
+ const vm = require('vm');
4
+ const net = require('net');
5
+ const os = require('os');
6
+ const fs = require('fs');
7
+ let contexts = {};
8
+ let process_exit = false;
9
+
10
+ /*** circular-json, originally taken from https://raw.githubusercontent.com/WebReflection/circular-json/
11
+ Copyright (C) 2013-2017 by Andrea Giammarchi - @WebReflection
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in
21
+ all copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
+ THE SOFTWARE.
30
+
31
+ ***
32
+
33
+ the original version has been restructured and modified to fit in here,
34
+ only stringify is used, unused parts removed.
35
+
36
+ */
37
+
38
+ const CircularJSON = {};
39
+ CircularJSON.specialChar = '~';
40
+ CircularJSON.safeSpecialChar = '\\x' + ('0' + CircularJSON.specialChar.charCodeAt(0).toString(16)).slice(-2);
41
+ CircularJSON.escapedSafeSpecialChar = '\\' + CircularJSON.safeSpecialChar;
42
+ CircularJSON.specialCharRG = new RegExp(CircularJSON.safeSpecialChar, 'g');
43
+ CircularJSON.indexOf = [].indexOf || function(v){
44
+ for(let i=this.length;i--&&this[i]!==v;);
45
+ return i;
46
+ };
47
+
48
+ CircularJSON.generateReplacer = function (value, replacer, resolve) {
49
+ let
50
+ doNotIgnore = false,
51
+ inspect = !!replacer,
52
+ path = [],
53
+ all = [value],
54
+ seen = [value],
55
+ mapp = [resolve ? CircularJSON.specialChar : '[Circular]'],
56
+ last = value,
57
+ lvl = 1,
58
+ i, fn
59
+ ;
60
+ if (inspect) {
61
+ fn = typeof replacer === 'object' ?
62
+ function (key, value) {
63
+ return key !== '' && CircularJSON.indexOf.call(replacer, key) < 0 ? void 0 : value;
64
+ } :
65
+ replacer;
66
+ }
67
+ return function(key, value) {
68
+ // the replacer has rights to decide
69
+ // if a new object should be returned
70
+ // or if there's some key to drop
71
+ // let's call it here rather than "too late"
72
+ if (inspect) value = fn.call(this, key, value);
73
+
74
+ // first pass should be ignored, since it's just the initial object
75
+ if (doNotIgnore) {
76
+ if (last !== this) {
77
+ i = lvl - CircularJSON.indexOf.call(all, this) - 1;
78
+ lvl -= i;
79
+ all.splice(lvl, all.length);
80
+ path.splice(lvl - 1, path.length);
81
+ last = this;
82
+ }
83
+ // console.log(lvl, key, path);
84
+ if (typeof value === 'object' && value) {
85
+ // if object isn't referring to parent object, add to the
86
+ // object path stack. Otherwise it is already there.
87
+ if (CircularJSON.indexOf.call(all, value) < 0) {
88
+ all.push(last = value);
89
+ }
90
+ lvl = all.length;
91
+ i = CircularJSON.indexOf.call(seen, value);
92
+ if (i < 0) {
93
+ i = seen.push(value) - 1;
94
+ if (resolve) {
95
+ // key cannot contain specialChar but could be not a string
96
+ path.push(('' + key).replace(CircularJSON.specialCharRG, CircularJSON.safeSpecialChar));
97
+ mapp[i] = CircularJSON.specialChar + path.join(CircularJSON.specialChar);
98
+ } else {
99
+ mapp[i] = mapp[0];
100
+ }
101
+ } else {
102
+ value = mapp[i];
103
+ }
104
+ } else {
105
+ if (typeof value === 'string' && resolve) {
106
+ // ensure no special char involved on deserialization
107
+ // in this case only first char is important
108
+ // no need to replace all value (better performance)
109
+ value = value
110
+ .replace(CircularJSON.safeSpecialChar, CircularJSON.escapedSafeSpecialChar)
111
+ .replace(CircularJSON.specialChar, CircularJSON.safeSpecialChar);
112
+ }
113
+ }
114
+ } else {
115
+ doNotIgnore = true;
116
+ }
117
+ return value;
118
+ };
119
+ };
120
+ CircularJSON.stringify = function stringify(value, replacer, space, doNotResolve) {
121
+ return JSON.stringify(
122
+ value,
123
+ CircularJSON.generateReplacer(value, replacer, !doNotResolve),
124
+ space
125
+ );
126
+ };
127
+ /*** end of circular-json ***/
128
+
129
+ function attachFunctionSource(responder_path, context, func) {
130
+ return func + " = async function(...method_args) {\n\
131
+ let context = \"" + context + "\";\n\
132
+ let func = \"" + func +"\";\n\
133
+ let request = [context, func, method_args];\n\
134
+ let responder_path = '" + responder_path + "';\n\
135
+ if (!global.__responder_socket) {\n\
136
+ return new Promise(function(resolve, reject) {\n\
137
+ setTimeout(function(){\n\
138
+ if (os.platform().indexOf('win') > -1) {\n\
139
+ let socket = net.connect(responder_path);\n\
140
+ socket.on('connect', function(){\n\
141
+ global.__responder_socket = true;\n\
142
+ socket.destroy();\n\
143
+ resolve(" + func + "(...method_args));\n\
144
+ })\n\
145
+ socket.on('error', function (err) {\n\
146
+ resolve(" + func + "(...method_args));\n\
147
+ });\n\
148
+ } else {\n\
149
+ if (fs.existsSync(responder_path)) { global.__responder_socket = true; }\n\
150
+ resolve(" + func + "(...method_args));\n\
151
+ }\n\
152
+ }, 10)\n\
153
+ });\n\
154
+ }\n\
155
+ return new Promise(function(resolve, reject) {\n\
156
+ let request_json = JSON.stringify(request);\n\
157
+ let buffer = Buffer.alloc(0);\n\
158
+ let socket = net.connect(responder_path);\n\
159
+ socket.setTimeout(2000);\n\
160
+ socket.on('error', function (err) {\n\
161
+ if (err.syscall === 'connect') {\n\
162
+ // ignore, close will handle\n\
163
+ } else if (os.platform().indexOf('win') > -1 && err.message.includes('read EPIPE')) {\n\
164
+ // ignore, close will handle\n\
165
+ } else if (os.platform().indexOf('win') > -1 && err.message.includes('write EPIPE')) {\n\
166
+ // ignore, close will handle\n\
167
+ } else { reject(err); }\n\
168
+ });\n\
169
+ socket.on('ready', function () {\n\
170
+ socket.write(request_json + \"\x04\");\n\
171
+ });\n\
172
+ socket.on('data', function (data) {\n\
173
+ buffer = Buffer.concat([buffer, data]);\n\
174
+ });\n\
175
+ socket.on('timeout', function() {\n\
176
+ socket.destroy();\n\
177
+ reject();\n\
178
+ });\n\
179
+ socket.on('close', function() {\n\
180
+ if (buffer.length > 0) {\n\
181
+ let method_result = JSON.parse(buffer.toString('utf8'));\n\
182
+ if (method_result[0] == 'err') {\n\
183
+ reject(method_result);\n\
184
+ } else {\n\
185
+ resolve(method_result[1]);\n\
186
+ }\n\
187
+ } else {\n\
188
+ resolve(null);\n\
189
+ }\n\
190
+ });\n\
191
+ });\n\
192
+ }\n";
193
+ }
194
+
195
+ function createCompatibleContext(uuid, options) {
196
+ let c = vm.createContext();
197
+ vm.runInContext('delete this.console', c, "(execjs)");
198
+ contexts[uuid] = { context: c, options: options };
199
+ return c;
200
+ }
201
+
202
+ function createPermissiveContext(uuid, options) {
203
+ let c = vm.createContext({ global: { __responder_socket: false }, process: { release: { name: "node" }, env: process.env }, Buffer, clearTimeout, fs, net, os, require, setTimeout });
204
+ contexts[uuid] = { context: c, options: options };
205
+ return c;
206
+ }
207
+
208
+ function formatResult(result) {
209
+ if (typeof result === 'undefined' && result !== null) { return ['ok']; }
210
+ else {
211
+ try { return ['ok', result]; }
212
+ catch (err) { return ['err', ['', err].join(''), err.stack]; }
213
+ }
214
+ }
215
+
216
+ function getContext(uuid) {
217
+ if (contexts[uuid]) { return contexts[uuid].context; }
218
+ else { return null; }
219
+ }
220
+
221
+ function getContextOptions(uuid) {
222
+ let options = { filename: "(execjs)", displayErrors: true };
223
+ if (contexts[uuid].options.timeout) {
224
+ options.timeout = contexts[uuid].options.timeout;
225
+ }
226
+ return options;
227
+ }
228
+
229
+ function massageStackTrace(stack) {
230
+ if (stack && stack.indexOf("SyntaxError") == 0) {
231
+ return "(execjs):1\n" + stack;
232
+ } else {
233
+ return stack;
234
+ }
235
+ }
236
+
237
+ let socket_path = process.env.SOCKET_PATH;
238
+ if (!socket_path) { throw 'No SOCKET_PATH given!'; };
239
+
240
+ let commands = {
241
+ attach: function(input) {
242
+ let context = getContext(input.context);
243
+ let responder_path;
244
+ if (os.platform().indexOf('win') > -1) { responder_path = '\\\\\\\\.\\\\pipe\\\\' + socket_path + '_responder'; }
245
+ else { responder_path = socket_path + '_responder' }
246
+ let result = vm.runInContext(attachFunctionSource(responder_path, input.context, input.func), context, { filename: "(execjs)", displayErrors: true });
247
+ return formatResult(result);
248
+ },
249
+ create: function (input) {
250
+ let context = createCompatibleContext(input.context, input.options);
251
+ let result = vm.runInContext(input.source, context, getContextOptions(input.context));
252
+ return formatResult(result);
253
+ },
254
+ createp: function (input) {
255
+ let context = createPermissiveContext(input.context, input.options);
256
+ let result = vm.runInContext(input.source, context, getContextOptions(input.context));
257
+ return formatResult(result);
258
+ },
259
+ deleteContext: function(uuid) {
260
+ delete contexts[uuid];
261
+ return [1];
262
+ },
263
+ exit: function(code) {
264
+ process_exit = code;
265
+ return ['ok'];
266
+ },
267
+ exec: function (input) {
268
+ let result = vm.runInContext(input.source, getContext(input.context), getContextOptions(input.context));
269
+ return formatResult(result);
270
+ },
271
+ eval: function (input) {
272
+ if (input.source.match(/^\s*{/)) { input.source = "(" + input.source + ")"; }
273
+ else if (input.source.match(/^\s*function\s*\(/)) { input.source = "(" + input.source + ")"; }
274
+ let result = vm.runInContext(input.source, getContext(input.context), getContextOptions(input.context));
275
+ return formatResult(result);
276
+ },
277
+ // ctxo: function (input) {
278
+ // return formatResult(getContextOptions(input.context));
279
+ // },
280
+ };
281
+
282
+ let server = net.createServer(function(s) {
283
+ let received_data = [];
284
+
285
+ s.on('data', function (data) {
286
+ received_data.push(data);
287
+ if (data[data.length - 1] !== 4) { return; }
288
+
289
+ let request = received_data.join('').toString('utf8');
290
+ request = request.substr(0, request.length - 1);
291
+ received_data = [];
292
+
293
+ let input, result;
294
+ let outputJSON = '';
295
+
296
+ try { input = JSON.parse(request); }
297
+ catch(err) {
298
+ outputJSON = JSON.stringify(['err', ['', err].join(''), err.stack]);
299
+ s.write([outputJSON, "\x04"].join(''));
300
+ return;
301
+ }
302
+
303
+ try { result = commands[input.cmd].apply(null, input.args); }
304
+ catch (err) {
305
+ outputJSON = JSON.stringify(['err', ['', err].join(''), massageStackTrace(err.stack)]);
306
+ s.write([outputJSON, "\x04"].join(''));
307
+ return;
308
+ }
309
+
310
+ try { outputJSON = JSON.stringify(result); }
311
+ catch(err) {
312
+ if (err.message.includes('circular')) { outputJSON = CircularJSON.stringify(result); }
313
+ else { outputJSON = JSON.stringify([['', err].join(''), err.stack]); }
314
+ s.write([outputJSON, "\x04"].join(''));
315
+ return;
316
+ }
317
+
318
+ s.write([outputJSON, "\x04"].join(''));
319
+ if (process_exit !== false) { process.exit(process_exit); }
320
+ });
321
+ });
322
+
323
+ if (os.platform().indexOf('win') > -1) { server.listen('\\\\.\\pipe\\' + socket_path); }
324
+ else { server.listen(socket_path); }