1 | const cp = require('child_process');
|
2 | const EOL = require('os').EOL;
|
3 |
|
4 | function close(process) {
|
5 | return new Promise((resolve) => {
|
6 | process.on('close', (code, signal) => {
|
7 | resolve(code);
|
8 | });
|
9 | process.stdin.write(`-stay_open${EOL}`);
|
10 | process.stdin.write(`false${EOL}`);
|
11 | });
|
12 | }
|
13 |
|
14 | function writeStdIn(process, data) {
|
15 |
|
16 | process.stdin.write(data);
|
17 | process.stdin.write(EOL);
|
18 | }
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | function execute(process, command, commandNumber, args) {
|
28 | args = args !== undefined ? args : [];
|
29 | const argsString = args.length ? args.map(arg => `-${arg}`).join(EOL) : '';
|
30 |
|
31 | command = command !== undefined ? command : '';
|
32 |
|
33 | if (argsString) writeStdIn(process, argsString);
|
34 | writeStdIn(process, '-json');
|
35 | writeStdIn(process, '-s');
|
36 | writeStdIn(process, command);
|
37 | writeStdIn(process, '-echo1');
|
38 | writeStdIn(process, `{begin${commandNumber}}`);
|
39 | writeStdIn(process, '-echo2');
|
40 | writeStdIn(process, `{begin${commandNumber}}`);
|
41 | writeStdIn(process, '-echo4');
|
42 | writeStdIn(process, `{ready${commandNumber}}`);
|
43 | writeStdIn(process, `-execute${commandNumber}`);
|
44 | }
|
45 |
|
46 | function getCommandNumber() {
|
47 | return Math.floor(Math.random() * 1000000);
|
48 | }
|
49 |
|
50 | function createHandler(commandNumber, snitch, cb) {
|
51 | const handler = (data) => {
|
52 | if (data.commandNumber === commandNumber) {
|
53 | snitch.removeListener('data', handler)
|
54 | cb(data.data)
|
55 | }
|
56 | }
|
57 | snitch.on('data', handler)
|
58 | }
|
59 |
|
60 | function executeCommand(process, stdoutSnitch, stderrSnitch, command, args) {
|
61 | const commandNumber = getCommandNumber();
|
62 |
|
63 | const dataPromise = new Promise(resolve =>
|
64 | createHandler(commandNumber, stdoutSnitch, resolve)
|
65 | );
|
66 |
|
67 | const errPromise = new Promise(resolve =>
|
68 | createHandler(commandNumber, stderrSnitch, resolve)
|
69 | );
|
70 |
|
71 | execute(process, command, commandNumber, args);
|
72 |
|
73 | return Promise.all([
|
74 | dataPromise,
|
75 | errPromise
|
76 | ])
|
77 | .then(res => ({
|
78 | data: res[0] ? JSON.parse(res[0]) : null,
|
79 | error: res[1] || null,
|
80 | }));
|
81 | }
|
82 |
|
83 | function spawn(bin) {
|
84 | return new Promise((resolve, reject) => {
|
85 | const echoString = Date.now().toString();
|
86 | const process = cp.spawn(bin, ['-echo2', echoString, '-stay_open', 'True', '-@', '-']);
|
87 | process.once('error', reject);
|
88 | const echoHandler = (data) => {
|
89 | const d = data.toString().trim();
|
90 |
|
91 | if (d === echoString) {
|
92 | resolve(process);
|
93 | } else {
|
94 | reject(new Error(`Unexpected string on start: ${d}`))
|
95 | }
|
96 | }
|
97 | process.stderr.once('data', echoHandler);
|
98 | });
|
99 | }
|
100 |
|
101 | module.exports = {
|
102 | spawn,
|
103 | close,
|
104 | executeCommand,
|
105 | }
|