@inteli.city/node-red-contrib-exec-collection 1.0.3 → 1.0.5
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.
- package/README.md +836 -5
- package/async.pg.js +1 -0
- package/exec.queue.html +228 -38
- package/exec.queue.js +554 -538
- package/exec.service.html +342 -229
- package/exec.service.js +325 -487
- package/node.queue.html +359 -0
- package/node.queue.js +569 -0
- package/package.json +19 -19
- package/python.config.html +55 -0
- package/python.config.js +24 -0
- package/python.queue.html +360 -0
- package/python.queue.js +555 -0
- package/utils/context.js +54 -0
- package/async.gpt.html +0 -327
- package/async.gpt.js +0 -615
- package/async.latex.html +0 -319
- package/async.latex.js +0 -618
- package/module.njk.html +0 -45
- package/module.njk.js +0 -12
- package/template.njk.html +0 -201
- package/template.njk.js +0 -138
- package/thrd.function.html +0 -312
- package/thrd.function.js +0 -586
- package/thread.queue.html +0 -311
- package/thread.queue.js +0 -586
package/thread.queue.js
DELETED
|
@@ -1,586 +0,0 @@
|
|
|
1
|
-
/** ////
|
|
2
|
-
* Copyright JS Foundation and other contributors, http://js.foundation
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
**///
|
|
16
|
-
module.exports = function(RED) {
|
|
17
|
-
//* libraries
|
|
18
|
-
"use strict";
|
|
19
|
-
var mustache = require("mustache");
|
|
20
|
-
var fs = require('fs');
|
|
21
|
-
var tmp = require('tmp-promise');
|
|
22
|
-
var fsPromises = require('fs').promises;
|
|
23
|
-
var terminate = require("terminate");
|
|
24
|
-
var yaml = require("js-yaml");
|
|
25
|
-
var convertXML = require('xml-js');
|
|
26
|
-
var exec = require('child_process').exec;
|
|
27
|
-
var spawn = require('child_process').spawn;
|
|
28
|
-
var Queue = require('queue');
|
|
29
|
-
//* auxiliary functions
|
|
30
|
-
//** function: extractTokens
|
|
31
|
-
function extractTokens(tokens, set) {
|
|
32
|
-
set = set || new Set();
|
|
33
|
-
tokens.forEach(function(token) {
|
|
34
|
-
if (token[0] !== 'text') {
|
|
35
|
-
set.add(token[1]);
|
|
36
|
-
if (token.length > 4) {
|
|
37
|
-
extractTokens(token[4], set);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
return set;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
//** function: parseContext
|
|
45
|
-
function parseContext(key) {
|
|
46
|
-
var match = /^(flow|global)(\[(\w+)\])?\.(.+)/.exec(key);
|
|
47
|
-
if (match) {
|
|
48
|
-
var parts = {};
|
|
49
|
-
parts.type = match[1];
|
|
50
|
-
parts.store = (match[3] === '') ? "default" : match[3];
|
|
51
|
-
parts.field = match[4];
|
|
52
|
-
return parts;
|
|
53
|
-
}
|
|
54
|
-
return undefined;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
//** function: parseEnv
|
|
58
|
-
function parseEnv(key) {
|
|
59
|
-
var match = /^env\.(.+)/.exec(key);
|
|
60
|
-
if (match) {
|
|
61
|
-
return match[1];
|
|
62
|
-
}
|
|
63
|
-
return undefined;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Custom Mustache Context capable to collect message property and node
|
|
69
|
-
* flow and global context
|
|
70
|
-
*/
|
|
71
|
-
|
|
72
|
-
//** function: remove_by_value (prototype)
|
|
73
|
-
Array.prototype.remove_by_value = function(val) {
|
|
74
|
-
for (var i = 0; i < this.length; i++) {
|
|
75
|
-
if (this[i] === val) {
|
|
76
|
-
this.splice(i, 1);
|
|
77
|
-
i--;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return this;
|
|
81
|
-
}
|
|
82
|
-
//** function: NodeContext
|
|
83
|
-
class NodeContext extends mustache.Context {
|
|
84
|
-
constructor(msg, nodeContext, parent, escapeStrings, cachedContextTokens) {
|
|
85
|
-
super(msg, parent);
|
|
86
|
-
this.nodeContext = nodeContext;
|
|
87
|
-
this.escapeStrings = escapeStrings;
|
|
88
|
-
this.cachedContextTokens = cachedContextTokens;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
lookup(name) {
|
|
92
|
-
try {
|
|
93
|
-
var value = super.lookup(name);
|
|
94
|
-
if (value !== undefined) {
|
|
95
|
-
if (typeof value === "object") {
|
|
96
|
-
value = JSON.stringify(value);
|
|
97
|
-
}
|
|
98
|
-
if (this.escapeStrings && typeof value === "string") {
|
|
99
|
-
value = value.replace(/\\/g, "\\\\")
|
|
100
|
-
.replace(/\n/g, "\\n")
|
|
101
|
-
.replace(/\t/g, "\\t")
|
|
102
|
-
.replace(/\r/g, "\\r")
|
|
103
|
-
.replace(/\f/g, "\\f")
|
|
104
|
-
.replace(/[\b]/g, "\\b");
|
|
105
|
-
}
|
|
106
|
-
return value;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (parseEnv(name)) {
|
|
110
|
-
return this.cachedContextTokens[name];
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
var context = parseContext(name);
|
|
114
|
-
if (context) {
|
|
115
|
-
var target = this.nodeContext[context.type];
|
|
116
|
-
if (target) {
|
|
117
|
-
return this.cachedContextTokens[name];
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return '';
|
|
121
|
-
} catch (err) {
|
|
122
|
-
throw err;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
push(view) {
|
|
127
|
-
return new NodeContext(view, this.nodeContext, this, undefined, this.cachedContextTokens);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
//* ExecQueueNode
|
|
132
|
-
function ExecQueueNode(n) {
|
|
133
|
-
//** setting values
|
|
134
|
-
RED.nodes.createNode(this, n);
|
|
135
|
-
this.name = n.name;
|
|
136
|
-
this.field = n.field || "payload";
|
|
137
|
-
// this.template = n.template;
|
|
138
|
-
this.template = n.template === "" ? " " : n.template; // gambiarra (arrumar)
|
|
139
|
-
this.syntax = n.syntax || "javascript";
|
|
140
|
-
this.fieldType = n.fieldType || "msg";
|
|
141
|
-
this.outputFormat = n.output || "str";
|
|
142
|
-
|
|
143
|
-
this.cmd = (n.command || "").trim();
|
|
144
|
-
this.append = (n.append || "").trim();
|
|
145
|
-
this.useSpawn = n.useSpawn
|
|
146
|
-
this.count = 0
|
|
147
|
-
this.state = ""
|
|
148
|
-
this.queue = n.queue
|
|
149
|
-
this.executingCode = 0
|
|
150
|
-
this.waitingForExecuting = 0
|
|
151
|
-
this.processKilled = false
|
|
152
|
-
this.statusTimerUp = new Date()
|
|
153
|
-
this.statusTimerDown = new Date()
|
|
154
|
-
// this.addpayCB = n.addpayCB
|
|
155
|
-
this.cmdTemplate = n.cmdTemplate
|
|
156
|
-
this.cmd = (n.command || "").trim();
|
|
157
|
-
//this.parsedJSON = n.parsedJSON
|
|
158
|
-
this.splitLine = n.splitLine
|
|
159
|
-
this.cleanQueue = n.cleanQueue
|
|
160
|
-
|
|
161
|
-
if (n.addpay === undefined) { n.addpay = true; }
|
|
162
|
-
this.addpay = n.addpay;
|
|
163
|
-
this.append = (n.append || "").trim();
|
|
164
|
-
this.useSpawn = (n.useSpawn == "true");
|
|
165
|
-
this.timer = Number(n.timer || 0) * 1000;
|
|
166
|
-
this.activeProcesses = {};
|
|
167
|
-
this.tempFiles = []
|
|
168
|
-
this.oldrc = (n.oldrc || false).toString();
|
|
169
|
-
//this.execOpt = {maxBuffer:50000000, windowsHide: (n.winHide === true)};
|
|
170
|
-
//this.execOpt = {encoding:'binary', maxBuffer:50000000, windowsHide: (n.winHide === true)};
|
|
171
|
-
this.execOpt = { maxBuffer: 50000000, windowsHide: (n.winHide === true), detached: true };
|
|
172
|
-
this.spawnOpt = { windowsHide: (n.winHide === true), detached: true }
|
|
173
|
-
|
|
174
|
-
// this.timer = Number(n.timer || 0)*1000;
|
|
175
|
-
// this.activeProcesses = {};
|
|
176
|
-
// this.oldrc = (n.oldrc || false).toString();
|
|
177
|
-
// this.execOpt = {encoding:'binary', maxBuffer:50000000, windowsHide: (n.winHide === true)};
|
|
178
|
-
// this.spawnOpt = {windowsHide: (n.winHide === true) }
|
|
179
|
-
var node = this;
|
|
180
|
-
//** node initialization setup
|
|
181
|
-
if (process.platform === 'linux' && fs.existsSync('/bin/bash')) { node.execOpt.shell = '/bin/bash'; }
|
|
182
|
-
|
|
183
|
-
var queue = Queue({ results: [], concurrency: node.queue, autostart: true })
|
|
184
|
-
node.status({ fill: "blue", shape: "ring", text: `0 (0/${node.queue})` });
|
|
185
|
-
|
|
186
|
-
setInterval(() => {
|
|
187
|
-
if (node.executingCode !== 0 || node.waitingForExecuting !== 0) {
|
|
188
|
-
node.status({ fill: "blue", shape: "ring", text: `${node.waitingForExecuting} (${node.executingCode}/${node.queue})` });
|
|
189
|
-
}
|
|
190
|
-
}, 1000)
|
|
191
|
-
|
|
192
|
-
//** node.on('input')
|
|
193
|
-
node.on("input", async function(msg, send, done) {
|
|
194
|
-
try {
|
|
195
|
-
msg.nodeName = node.name;
|
|
196
|
-
|
|
197
|
-
if (msg._msgid === undefined) {
|
|
198
|
-
output(msg, msg.message, send, done);
|
|
199
|
-
delete msg.message;
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const millisecondsUp = ((new Date()).getTime() - node.statusTimerUp.getTime());
|
|
204
|
-
node.statusTimerUp = new Date();
|
|
205
|
-
|
|
206
|
-
// resolving templates
|
|
207
|
-
const resolvedTokens = await resolveTemplate(msg);
|
|
208
|
-
|
|
209
|
-
// queue logic
|
|
210
|
-
if (node.useSpawn === false) {
|
|
211
|
-
msg.lastMessage = false;
|
|
212
|
-
}
|
|
213
|
-
if (node.executingCode < node.queue) {
|
|
214
|
-
node.executingCode++;
|
|
215
|
-
} else {
|
|
216
|
-
node.waitingForExecuting++;
|
|
217
|
-
}
|
|
218
|
-
if (millisecondsUp > 100) {
|
|
219
|
-
node.status({ fill: "blue", shape: "ring", text: `${node.waitingForExecuting} (${node.executingCode}/${node.queue})` });
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
await new Promise(resolve => {
|
|
223
|
-
queue.push(async () => {
|
|
224
|
-
try {
|
|
225
|
-
const millisecondsDown = ((new Date()).getTime() - node.statusTimerDown.getTime());
|
|
226
|
-
await executeCode(msg, send, done, node, resolvedTokens);
|
|
227
|
-
node.statusTimerDown = new Date();
|
|
228
|
-
|
|
229
|
-
if (node.waitingForExecuting > 0) {
|
|
230
|
-
node.waitingForExecuting--;
|
|
231
|
-
} else if (node.executingCode > 0) {
|
|
232
|
-
node.executingCode--;
|
|
233
|
-
if (node.executingCode === 0 && node.useSpawn === false) {
|
|
234
|
-
msg.lastMessage = true;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
if (node.processKilled === false && (millisecondsDown > 100 || node.executingCode === 0)) {
|
|
238
|
-
node.status({ fill: "blue", shape: "ring", text: `${node.waitingForExecuting} (${node.executingCode}/${node.queue})` });
|
|
239
|
-
}
|
|
240
|
-
resolve();
|
|
241
|
-
} catch (error) {
|
|
242
|
-
reject(error);
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
} catch (err) {
|
|
248
|
-
done(err.message);
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
//** node.on('close')
|
|
254
|
-
node.on('close', async function() {
|
|
255
|
-
//// KILL PROCESSES AND ERASE FILES
|
|
256
|
-
queue.end()
|
|
257
|
-
node.executingCode = 0
|
|
258
|
-
node.waitingForExecuting = 0
|
|
259
|
-
node.processKilled = true
|
|
260
|
-
for (var pid in node.activeProcesses) {
|
|
261
|
-
/* istanbul ignore else */
|
|
262
|
-
if (node.activeProcesses.hasOwnProperty(pid)) {
|
|
263
|
-
// process.kill(-pid, 9)
|
|
264
|
-
terminate(pid)
|
|
265
|
-
node.activeProcesses[pid] = null;
|
|
266
|
-
node.warn(`Killing pid ${pid}`)
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
for (let i = 0, len = node.tempFiles.length; i < len; i++) {
|
|
271
|
-
await fsPromises.unlink(file);
|
|
272
|
-
}
|
|
273
|
-
node.activeProcesses = {};
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
//** executeCode
|
|
277
|
-
async function executeCode(msg, send, done, node, resolvedTokens) {
|
|
278
|
-
|
|
279
|
-
// Create a temporary file asynchronously
|
|
280
|
-
const is_json = (node.outputFormat === "parsedJSON");
|
|
281
|
-
let template = node.template || msg.template;
|
|
282
|
-
const value = mustache.render(template, new NodeContext(msg, node.context(), null, is_json, resolvedTokens));
|
|
283
|
-
const tmpObj = await tmp.file();
|
|
284
|
-
await fsPromises.writeFile(tmpObj.path, value, 'utf8');
|
|
285
|
-
|
|
286
|
-
let shellcode;
|
|
287
|
-
let resolvedCommand
|
|
288
|
-
if ( node.cmdTemplate ){
|
|
289
|
-
resolvedCommand = await resolveCommand(node.cmd, msg);
|
|
290
|
-
} else {
|
|
291
|
-
resolvedCommand = node.cmd
|
|
292
|
-
}
|
|
293
|
-
if (process.platform === 'win32') { // For Windows
|
|
294
|
-
shellcode = `${resolvedCommand} ${addPayload} ${tmpObj.path}`;
|
|
295
|
-
} else { // For Linux and macOS
|
|
296
|
-
shellcode = `
|
|
297
|
-
export NODE_PATH="$NODE_PATH:$HOME/.node-red/node_modules:/usr/local/lib/node_modules"
|
|
298
|
-
file="${tmpObj.path}"
|
|
299
|
-
${resolvedCommand}
|
|
300
|
-
`;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
try {
|
|
304
|
-
if (!node.useSpawn) {
|
|
305
|
-
await executeWithExec(shellcode, node, msg, send, done);
|
|
306
|
-
} else {
|
|
307
|
-
await executeWithSpawn(shellcode, node, msg, send, done);
|
|
308
|
-
}
|
|
309
|
-
} finally {
|
|
310
|
-
await tmpObj.cleanup();
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
async function executeWithExec(shellcode, node, msg, send, done) {
|
|
315
|
-
return new Promise((resolve) => {
|
|
316
|
-
const child = exec(shellcode, node.execOpt, (err, stdout, stderr) => {
|
|
317
|
-
if (err) {
|
|
318
|
-
const error = {
|
|
319
|
-
type: 'error',
|
|
320
|
-
code: err.code,
|
|
321
|
-
killed: err.killed
|
|
322
|
-
};
|
|
323
|
-
msg.error_info = error;
|
|
324
|
-
node.error(`error (${msg.nodeName})\n\n${stderr}`, msg);
|
|
325
|
-
} else {
|
|
326
|
-
if (stderr) {
|
|
327
|
-
node.error(`warning (${msg.nodeName})\n\n${stderr}`, msg);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
if (stdout) {
|
|
331
|
-
stdout = stdout.trim();
|
|
332
|
-
if (node.splitLine === false) {
|
|
333
|
-
output(msg, stdout, send, done);
|
|
334
|
-
} else {
|
|
335
|
-
stdout = stdout.split('\n');
|
|
336
|
-
for (let i = 0; i < stdout.length; i++) {
|
|
337
|
-
node.emit("input", { "message": stdout[i] });
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
delete node.activeProcesses[child.pid];
|
|
343
|
-
resolve();
|
|
344
|
-
});
|
|
345
|
-
node.activeProcesses[child.pid] = child.pid;
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
async function executeWithSpawn(shellcode, node, msg, send, done) {
|
|
350
|
-
return new Promise((resolve, reject) => {
|
|
351
|
-
const child = spawn('/bin/bash', ['-c', shellcode], node.spawnOpt);
|
|
352
|
-
node.activeProcesses[child.pid] = child.pid;
|
|
353
|
-
|
|
354
|
-
child.stdout.on('data', (data) => {
|
|
355
|
-
data = data.toString();
|
|
356
|
-
if (node.splitLine === false) {
|
|
357
|
-
output(msg, data, send, done);
|
|
358
|
-
} else {
|
|
359
|
-
const lines = data.split('\n');
|
|
360
|
-
for (let line of lines) {
|
|
361
|
-
if (line) {
|
|
362
|
-
node.emit("input", { "message": line });
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
child.stderr.on('data', (data) => {
|
|
369
|
-
node.error(`warning (${msg.nodeName})\n\n${data.toString()}`, msg);
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
child.on('close', (code) => {
|
|
373
|
-
if (code !== 0) {
|
|
374
|
-
const error = {
|
|
375
|
-
type: 'error',
|
|
376
|
-
code: code
|
|
377
|
-
};
|
|
378
|
-
msg.error_info = error;
|
|
379
|
-
node.error(`error (${msg.nodeName}): The node hasn't finished its execution`, msg);
|
|
380
|
-
reject(new Error(`Child process exited with code ${code}`));
|
|
381
|
-
}
|
|
382
|
-
delete node.activeProcesses[child.pid];
|
|
383
|
-
resolve();
|
|
384
|
-
});
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
//** resolveTemplate
|
|
389
|
-
async function resolveTemplate(msg) {
|
|
390
|
-
var template = node.template;
|
|
391
|
-
if (msg.hasOwnProperty("template")) {
|
|
392
|
-
if (template == "" || template === null) {
|
|
393
|
-
template = msg.template;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
var resolvedTokens = {};
|
|
398
|
-
var tokens = extractTokens(mustache.parse(template));
|
|
399
|
-
|
|
400
|
-
// Iterate over the extracted tokens to resolve their values.
|
|
401
|
-
for (let name of tokens) {
|
|
402
|
-
let env_name = parseEnv(name);
|
|
403
|
-
if (env_name) {
|
|
404
|
-
resolvedTokens[name] = RED.util.evaluateNodeProperty(env_name, 'env', node);
|
|
405
|
-
continue;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
// Check if the token refers to a flow or global context variable.
|
|
409
|
-
let context = parseContext(name);
|
|
410
|
-
if (context) {
|
|
411
|
-
let type = context.type;
|
|
412
|
-
let store = context.store;
|
|
413
|
-
let field = context.field;
|
|
414
|
-
let target = node.context()[type];
|
|
415
|
-
if (target) {
|
|
416
|
-
resolvedTokens[name] = await new Promise((resolve, reject) => {
|
|
417
|
-
target.get(field, store, (err, val) => {
|
|
418
|
-
if (err) reject(err);
|
|
419
|
-
else resolve(val);
|
|
420
|
-
});
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
return resolvedTokens;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
//** resolveCommand
|
|
430
|
-
async function resolveCommand(command, msg) {
|
|
431
|
-
return new Promise(async (resolve, reject) => {
|
|
432
|
-
try {
|
|
433
|
-
// Extract tokens from the command string
|
|
434
|
-
var tokens = extractTokens(mustache.parse(command));
|
|
435
|
-
|
|
436
|
-
var resolvedTokens = {};
|
|
437
|
-
|
|
438
|
-
// Iterate over the extracted tokens to resolve their values.
|
|
439
|
-
for (let name of tokens) {
|
|
440
|
-
let env_name = parseEnv(name);
|
|
441
|
-
if (env_name) {
|
|
442
|
-
resolvedTokens[name] = RED.util.evaluateNodeProperty(env_name, 'env', node);
|
|
443
|
-
continue;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// Check if the token refers to a flow or global context variable.
|
|
447
|
-
let context = parseContext(name);
|
|
448
|
-
if (context) {
|
|
449
|
-
let type = context.type;
|
|
450
|
-
let store = context.store;
|
|
451
|
-
let field = context.field;
|
|
452
|
-
let target = node.context()[type];
|
|
453
|
-
if (target) {
|
|
454
|
-
resolvedTokens[name] = await new Promise((innerResolve, innerReject) => {
|
|
455
|
-
target.get(field, store, (err, val) => {
|
|
456
|
-
if (err) innerReject(err);
|
|
457
|
-
else innerResolve(val);
|
|
458
|
-
});
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
var parsedCommand = mustache.parse(command);
|
|
465
|
-
|
|
466
|
-
// Extract the variable names from the parsed tokens.
|
|
467
|
-
var variableNames = parsedCommand
|
|
468
|
-
.filter(token => token[0] === '&')
|
|
469
|
-
.map(token => token[1]);
|
|
470
|
-
|
|
471
|
-
var resolvedValues = {};
|
|
472
|
-
|
|
473
|
-
// Resolve the values for each variable.
|
|
474
|
-
for (let variableName of variableNames) {
|
|
475
|
-
let env_name = parseEnv(variableName);
|
|
476
|
-
if (env_name) {
|
|
477
|
-
resolvedValues[variableName] = RED.util.evaluateNodeProperty(env_name, 'env', node);
|
|
478
|
-
continue;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
// Check if the variable refers to a flow or global context variable.
|
|
482
|
-
let context = parseContext(variableName);
|
|
483
|
-
if (context) {
|
|
484
|
-
let type = context.type;
|
|
485
|
-
let store = context.store;
|
|
486
|
-
let field = context.field;
|
|
487
|
-
let target = node.context()[type];
|
|
488
|
-
if (target) {
|
|
489
|
-
resolvedValues[variableName] = await new Promise((innerResolve, innerReject) => {
|
|
490
|
-
target.get(field, store, (err, val) => {
|
|
491
|
-
if (err) innerReject(err);
|
|
492
|
-
else innerResolve(val);
|
|
493
|
-
});
|
|
494
|
-
});
|
|
495
|
-
}
|
|
496
|
-
} else {
|
|
497
|
-
// If the variable is not in the context or an env variable, try to get it from the msg object.
|
|
498
|
-
resolvedValues[variableName] = msg[variableName];
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// Replace the variables in the original command with their resolved values.
|
|
503
|
-
for (let variableName in resolvedValues) {
|
|
504
|
-
command = command.replace(`{{{${variableName}}}}`, resolvedValues[variableName]);
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
console.log(command);
|
|
508
|
-
resolve(command); // Use the resolve here
|
|
509
|
-
} catch (error) {
|
|
510
|
-
console.error("Error in resolveCommand:", error);
|
|
511
|
-
reject(error); // Use the reject here
|
|
512
|
-
}
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
//** function: output
|
|
517
|
-
function output(msg, value, send, done) {
|
|
518
|
-
/* istanbul ignore else */
|
|
519
|
-
let parseError = false
|
|
520
|
-
//*** parse json
|
|
521
|
-
if (node.outputFormat === "parsedJSON") {
|
|
522
|
-
try {
|
|
523
|
-
value = JSON.parse(value);
|
|
524
|
-
if (typeof value === 'number') {
|
|
525
|
-
parseError = true
|
|
526
|
-
node.error('Error parsing JSON: \n\n' + error)
|
|
527
|
-
}
|
|
528
|
-
} catch (error) {
|
|
529
|
-
parseError = true
|
|
530
|
-
node.error('Error parsing JSON: \n\n' + error)
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
//*** parse xml
|
|
535
|
-
if (node.outputFormat === "parsedXML") {
|
|
536
|
-
try {
|
|
537
|
-
//value = JSON.parse(convertXML.xml2json(value, {compact: true, spaces: 4}))
|
|
538
|
-
value = convertXML.xml2js(value, { compact: true, spaces: 4 })
|
|
539
|
-
} catch (error) {
|
|
540
|
-
parseError = true
|
|
541
|
-
node.error('Error parsing XML: \n\n' + error)
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
//*** parse yaml
|
|
546
|
-
if (node.outputFormat === "parsedYAML") {
|
|
547
|
-
try {
|
|
548
|
-
value = yaml.load(value);
|
|
549
|
-
if (typeof value === 'number') {
|
|
550
|
-
parseError = true
|
|
551
|
-
node.error('Error parsing YAML: \n\n' + error)
|
|
552
|
-
}
|
|
553
|
-
} catch (error) {
|
|
554
|
-
parseError = true
|
|
555
|
-
node.error('Error parsing YAML: \n\n' + error)
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
//*** parse error
|
|
560
|
-
if (parseError === false) {
|
|
561
|
-
if (node.fieldType === 'msg') {
|
|
562
|
-
RED.util.setMessageProperty(msg, node.field, value);
|
|
563
|
-
send(msg);
|
|
564
|
-
done();
|
|
565
|
-
} else if ((node.fieldType === 'flow') ||
|
|
566
|
-
(node.fieldType === 'global')) {
|
|
567
|
-
var context = RED.util.parseContextStore(node.field);
|
|
568
|
-
var target = node.context()[node.fieldType];
|
|
569
|
-
target.set(context.key, value, context.store, function(err) {
|
|
570
|
-
if (err) {
|
|
571
|
-
done(err);
|
|
572
|
-
} else {
|
|
573
|
-
send(msg);
|
|
574
|
-
done();
|
|
575
|
-
}
|
|
576
|
-
});
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
//* end
|
|
584
|
-
RED.nodes.registerType("thread.queue", ExecQueueNode);
|
|
585
|
-
RED.library.register("templates");
|
|
586
|
-
}
|