@ejfdelgado/ejflab-common 1.0.0
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/LICENSE +201 -0
- package/README.md +2 -0
- package/package.json +29 -0
- package/src/CollisionsEngine.js +252 -0
- package/src/CsvFormatter.js +54 -0
- package/src/CsvFormatter.test.js +119 -0
- package/src/CsvFormatterFilters.js +79 -0
- package/src/CsvParser.js +51 -0
- package/src/CsvParser.test.js +41 -0
- package/src/CsvWithFilters.js +114 -0
- package/src/FaceEncoder.js +64 -0
- package/src/FlowChartDiagram.js +503 -0
- package/src/IdGen.js +211 -0
- package/src/ModuloDatoSeguro.js +142 -0
- package/src/ModuloDatoSeguro.test.js +29 -0
- package/src/ModuloDatoSeguro.test.mjs +45 -0
- package/src/ModuloDatoSeguroBack.mjs +55 -0
- package/src/ModuloDatoSeguroFront.js +73 -0
- package/src/ModuloSonido.js +83 -0
- package/src/ModuloVideos.js +51 -0
- package/src/MyColor.js +136 -0
- package/src/MyColor.test.js +37 -0
- package/src/MyConstants.js +147 -0
- package/src/MyCookies.js +34 -0
- package/src/MyDates.js +412 -0
- package/src/MyDates.test.js +26 -0
- package/src/MyDatesBack.mjs +21 -0
- package/src/MyDatesFront.js +41 -0
- package/src/MyJsPdf.js +52 -0
- package/src/MyRoutes.js +29 -0
- package/src/MyTemplate.js +272 -0
- package/src/MyTemplate.test.js +90 -0
- package/src/MyTensorflow.js +248 -0
- package/src/MyTensorflow.test.js +19 -0
- package/src/MyTensorflowBack.mjs +33 -0
- package/src/MyThrottle.js +80 -0
- package/src/MyTuples.js +445 -0
- package/src/MyTuples.test.js +330 -0
- package/src/MyUtilities.js +137 -0
- package/src/SimpleObj.js +153 -0
- package/src/SimpleObj.test.js +58 -0
- package/src/TriangulacionGeometric.js +335 -0
- package/src/changePath.js +38 -0
- package/src/data/case0.csv +3 -0
- package/src/data/case0.json +24 -0
- package/src/data/case1.csv +2 -0
- package/src/data/case1.json +24 -0
- package/src/data/case2.csv +3 -0
- package/src/data/case2.json +24 -0
- package/src/data/case3.csv +3 -0
- package/src/data/case3.json +24 -0
- package/src/data/format0.json +0 -0
- package/src/data/format0.txt +1 -0
- package/src/data/tensordata.csv +10 -0
- package/src/data/tensordata.json +37 -0
- package/src/data/tensordata.test.csv +10 -0
- package/src/data/tensormodel.json +113 -0
- package/src/fft.js +224 -0
- package/src/flowchart/FlowChartExec.js +763 -0
- package/src/flowchart/steps/CommandBasic.js +32 -0
- package/src/flowchart/steps/CommandInc.js +19 -0
- package/src/flowchart/steps/CommandMilvus.js +47 -0
- package/src/flowchart/steps/CommandMinio.js +28 -0
- package/src/flowchart/steps/CommandMongo.js +59 -0
- package/src/flowchart/steps/CommandPrint.js +12 -0
- package/src/flowchart/steps/CommandSet.js +14 -0
- package/src/flowchart/steps/CommandTimeline.js +21 -0
- package/src/flowchart/steps/CommandTimelineNext.js +28 -0
- package/src/flowchart/steps/StepBasic.js +184 -0
- package/src/flowchart/steps/StepCheckProcessor.js +26 -0
- package/src/flowchart/steps/StepCheckSrc.js +42 -0
- package/src/flowchart/steps/StepIsTrue.js +12 -0
- package/src/flowchart/steps/StepOneTime.js +21 -0
- package/src/flowchart/steps/StepProcess.js +163 -0
- package/src/flowchart/steps/StepReadSrc.js +66 -0
- package/src/flowchart/steps/StepSleep.js +22 -0
- package/src/flowchart/steps/StepTimeLineEnds.js +21 -0
- package/src/flowchart/steps/StepTimeLineHasMore.js +16 -0
- package/src/gif/index.d.ts +20 -0
- package/src/gif/index.mjs +85 -0
- package/src/gif/utils/checkTypes.d.ts +2 -0
- package/src/gif/utils/checkTypes.mjs +11 -0
- package/src/js-colormaps.js +19484 -0
- package/src/sortify.js +75 -0
- package/src/sqlmodelparser/SqlModelParser.js +22 -0
- package/src/test/csv/test_1000_20230429204538700.csv +1001 -0
- package/src/test/csv/test_5_20230429204525930.csv +6 -0
- package/src/test/svg/test.html +5 -0
|
@@ -0,0 +1,763 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
|
|
3
|
+
const he = require('he');
|
|
4
|
+
const { XMLParser } = require("fast-xml-parser");
|
|
5
|
+
const { MyUtilities } = require("../MyUtilities");
|
|
6
|
+
const { MyTemplate } = require("../MyTemplate");
|
|
7
|
+
const { FlowChartDiagram } = require("../FlowChartDiagram.js");
|
|
8
|
+
|
|
9
|
+
const { StepSleep } = require("./steps/StepSleep");
|
|
10
|
+
const { StepOneTime } = require("./steps/StepOneTime");
|
|
11
|
+
const { StepIsTrue } = require("./steps/StepIsTrue");
|
|
12
|
+
const { StepCheckSrc } = require("./steps/StepCheckSrc");
|
|
13
|
+
|
|
14
|
+
const { CommandInc } = require("./steps/CommandInc");
|
|
15
|
+
const { CommandSet } = require("./steps/CommandSet");
|
|
16
|
+
const { StepReadSrc } = require('./steps/StepReadSrc');
|
|
17
|
+
const { StepTimeLineEnds } = require('./steps/StepTimeLineEnds');
|
|
18
|
+
const { StepTimeLineHasMore } = require('./steps/StepTimeLineHasMore');
|
|
19
|
+
const { StepProcess } = require('./steps/StepProcess');
|
|
20
|
+
const { CommandTimeline } = require('./steps/CommandTimeline');
|
|
21
|
+
const { CommandTimelineNext } = require('./steps/CommandTimelineNext');
|
|
22
|
+
const { CommandMilvus } = require('./steps/CommandMilvus');
|
|
23
|
+
const { StepCheckProcessor } = require('./steps/StepCheckProcessor');
|
|
24
|
+
const { MyColor } = require('../MyColor');
|
|
25
|
+
const { SimpleObj } = require("../SimpleObj");
|
|
26
|
+
const { CommandPrint } = require('./steps/CommandPrint');
|
|
27
|
+
const { CommandMongo } = require('./steps/CommandMongo');
|
|
28
|
+
const { CommandMinio } = require('./steps/CommandMinio');
|
|
29
|
+
|
|
30
|
+
class FlowChartExec {
|
|
31
|
+
executionPromise = null;
|
|
32
|
+
io = null;
|
|
33
|
+
supercontext = null;
|
|
34
|
+
data = {};
|
|
35
|
+
instances = {};
|
|
36
|
+
renderer = new MyTemplate();
|
|
37
|
+
registry = {};
|
|
38
|
+
flowchart = null;
|
|
39
|
+
actualNodes = [];
|
|
40
|
+
nodesById = {};
|
|
41
|
+
conf = {
|
|
42
|
+
debug: false,
|
|
43
|
+
sleep: 100,
|
|
44
|
+
retries: 4,
|
|
45
|
+
timeout: 50 //seconds
|
|
46
|
+
};
|
|
47
|
+
bufferData = {};
|
|
48
|
+
pendingsCalls = {};
|
|
49
|
+
constructor() {
|
|
50
|
+
// Arrows
|
|
51
|
+
this.registry["sleep"] = StepSleep;
|
|
52
|
+
this.registry["oneTime"] = StepOneTime;
|
|
53
|
+
this.registry["isTrue"] = StepIsTrue;
|
|
54
|
+
this.registry["checkSrc"] = StepCheckSrc;
|
|
55
|
+
this.registry["readSrc"] = StepReadSrc;
|
|
56
|
+
this.registry["timelineEnds"] = StepTimeLineEnds;
|
|
57
|
+
this.registry["timelineHasMore"] = StepTimeLineHasMore;
|
|
58
|
+
this.registry["process"] = StepProcess;
|
|
59
|
+
this.registry["require"] = StepCheckProcessor;
|
|
60
|
+
|
|
61
|
+
// Nodes
|
|
62
|
+
this.registry["inc"] = CommandInc;
|
|
63
|
+
this.registry["set"] = CommandSet;
|
|
64
|
+
this.registry["timeline"] = CommandTimeline;
|
|
65
|
+
this.registry["timelineNext"] = CommandTimelineNext;
|
|
66
|
+
this.registry["milvus"] = CommandMilvus;
|
|
67
|
+
this.registry["mongo"] = CommandMongo;
|
|
68
|
+
this.registry["print"] = CommandPrint;
|
|
69
|
+
this.registry["minio"] = CommandMinio;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
registerTimeline(id, timeline) {
|
|
73
|
+
SimpleObj.recreate(this.data, `state.timelines.${id}`, timeline);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
getTimeLine(id) {
|
|
77
|
+
return SimpleObj.getValue(this.data, `state.timelines.${id}`, null);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
saveBufferData(sourceId, pathId, buffer) {
|
|
81
|
+
//console.log(`saveBufferData ${sourceId} ${pathId}`, buffer);
|
|
82
|
+
if (!this.bufferData[sourceId]) {
|
|
83
|
+
this.bufferData[sourceId] = {};
|
|
84
|
+
}
|
|
85
|
+
this.bufferData[sourceId][pathId] = buffer;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
readBufferData(sourceId, pathId) {
|
|
89
|
+
//console.log(`readBufferData ${sourceId} ${pathId}`);
|
|
90
|
+
if (!this.bufferData[sourceId]) {
|
|
91
|
+
this.bufferData[sourceId] = {};
|
|
92
|
+
}
|
|
93
|
+
return this.bufferData[sourceId][pathId];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
registerPendingCall(id, val = true) {
|
|
97
|
+
this.pendingsCalls[id] = val;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
existsPendingCall(id) {
|
|
101
|
+
return id in this.pendingsCalls;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
clearPendingCall(id) {
|
|
105
|
+
delete this.pendingsCalls[id];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async canRetry(id, error) {
|
|
109
|
+
//console.log(`Check retry for ${error.message}...`);
|
|
110
|
+
if (!this.existsPendingCall(id)) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
const stepInstance = this.pendingsCalls[id];
|
|
114
|
+
await stepInstance.handleError(error);
|
|
115
|
+
if (stepInstance.reachMaxErrors()) {
|
|
116
|
+
return false;
|
|
117
|
+
} else {
|
|
118
|
+
stepInstance.firstTime = true;
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
setSocketIO(io, room) {
|
|
124
|
+
this.io = io;
|
|
125
|
+
this.room = room;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
getRoom() {
|
|
129
|
+
return this.room;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
getSuperContextModel() {
|
|
133
|
+
const roomData = this.getSuperContext().getRoomLiveTupleModel(this.room);
|
|
134
|
+
return roomData.model;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
getProcessorsModel() {
|
|
138
|
+
const roomData = this.getSuperContext().getRoomLiveTupleModel("processors");
|
|
139
|
+
return roomData.model;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
processFlowChart(xmlFlow, prefix = "") {
|
|
143
|
+
const nodos = xmlFlow?.mxfile?.diagram?.mxGraphModel?.root?.mxCell;
|
|
144
|
+
return FlowChartDiagram.processFlowChart(nodos, he, prefix);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
interpretColor(nodes) {
|
|
148
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
149
|
+
const node = nodes[i];
|
|
150
|
+
if (node.style && node.style.fillColor) {
|
|
151
|
+
const hexColor = node.style.fillColor;
|
|
152
|
+
const colorRGB = MyColor.colorhex2int(hexColor);
|
|
153
|
+
if (colorRGB) {
|
|
154
|
+
const { r, g, b } = colorRGB;
|
|
155
|
+
const { h, s, v } = MyColor.rgb2hsv(r, g, b);
|
|
156
|
+
if (15 < s && 50 < v) {
|
|
157
|
+
if (77 < h && h < 145) {
|
|
158
|
+
node.feature = "green";
|
|
159
|
+
} else if (160 < h && h < 255) {
|
|
160
|
+
node.feature = "blue";
|
|
161
|
+
} else if (h < 31 || 340 < h) {
|
|
162
|
+
node.feature = "red";
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
getFlowChartType(flowchart) {
|
|
171
|
+
let type = "default";
|
|
172
|
+
const { shapes } = flowchart;
|
|
173
|
+
|
|
174
|
+
// Verifico si hay un nodo que diga type:algo
|
|
175
|
+
for (let i = 0; i < shapes.length; i++) {
|
|
176
|
+
const nodo = shapes[i];
|
|
177
|
+
const { txt } = nodo;
|
|
178
|
+
const partes = /^\s*type\s*:\s*(.*)$/.exec(txt);
|
|
179
|
+
if (partes) {
|
|
180
|
+
type = partes[1];
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return type;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
processFluxChart(flowchart) {
|
|
188
|
+
const { shapes } = flowchart;
|
|
189
|
+
const connections = {};
|
|
190
|
+
// Iterate shapes
|
|
191
|
+
shapes.forEach((node) => {
|
|
192
|
+
node.mode = "flux";
|
|
193
|
+
const { txt } = node;
|
|
194
|
+
const lines = txt.split(/\r?\n/).filter((line) => {
|
|
195
|
+
return line.trim().length > 0;
|
|
196
|
+
});
|
|
197
|
+
const partes = /^\s*([a-zA-Z]+\d*|[a-zA-Z]+\d*\.[a-zA-Z]+)$/.exec(lines[0]);
|
|
198
|
+
if (partes) {
|
|
199
|
+
// Define un processor
|
|
200
|
+
let keyProcessor = partes[1];
|
|
201
|
+
const inputArrows = this.getInputArrows(node, flowchart);
|
|
202
|
+
const outputArrows = this.getOutputArrows(node, flowchart);
|
|
203
|
+
//console.log(`${keyProcessor} in x: ${inputArrows.length} out x: ${outputArrows.length}`);
|
|
204
|
+
const currentConnections = {
|
|
205
|
+
in: [],
|
|
206
|
+
out: [],
|
|
207
|
+
metadata: {},
|
|
208
|
+
};
|
|
209
|
+
if (keyProcessor.indexOf(".") < 0) {
|
|
210
|
+
connections[keyProcessor + ".main"] = currentConnections;
|
|
211
|
+
} else {
|
|
212
|
+
connections[keyProcessor] = currentConnections;
|
|
213
|
+
}
|
|
214
|
+
const processArrow = (isInput, arrow) => {
|
|
215
|
+
const { src, tar } = arrow;
|
|
216
|
+
let idNode;
|
|
217
|
+
if (isInput) {
|
|
218
|
+
idNode = src;
|
|
219
|
+
} else {
|
|
220
|
+
idNode = tar;
|
|
221
|
+
}
|
|
222
|
+
const referencedNode = this.getNodesWithId(idNode, flowchart)[0];
|
|
223
|
+
if (referencedNode) {
|
|
224
|
+
const partesOrigen = /^\s*([^:]+)\s*:\s*([a-zA-Z\.\d_]+)$/.exec(referencedNode.txt);
|
|
225
|
+
if (partesOrigen) {
|
|
226
|
+
const argName = partesOrigen[1];
|
|
227
|
+
const argValue = partesOrigen[2];
|
|
228
|
+
if (isInput) {
|
|
229
|
+
currentConnections.in.push({ key: argName, val: argValue });
|
|
230
|
+
} else {
|
|
231
|
+
currentConnections.out.push({ key: argName, val: argValue });
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
console.log(`Err: No match ${referencedNode.txt}`);
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
237
|
+
console.log(`Err in idNode ${idNode}`)
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
inputArrows.forEach((arrow) => {
|
|
241
|
+
processArrow(true, arrow);
|
|
242
|
+
});
|
|
243
|
+
outputArrows.forEach((arrow) => {
|
|
244
|
+
processArrow(false, arrow);
|
|
245
|
+
});
|
|
246
|
+
// Read extra argument if they exists
|
|
247
|
+
for (let k = 1; k < lines.length; k++) {
|
|
248
|
+
const someLine = lines[k];
|
|
249
|
+
const paramGroups = /^\s*([^:]+):(.+)$/.exec(someLine);
|
|
250
|
+
if (paramGroups) {
|
|
251
|
+
const paramName = paramGroups[1];
|
|
252
|
+
const paramValue = paramGroups[2];
|
|
253
|
+
currentConnections.metadata[paramName] = paramValue;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
return connections;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
checkTypeOfChart(flowchart) {
|
|
262
|
+
const type = this.getFlowChartType(flowchart);
|
|
263
|
+
const response = {};
|
|
264
|
+
if (type == "flux") {
|
|
265
|
+
response.flux = this.processFluxChart(flowchart);
|
|
266
|
+
}
|
|
267
|
+
return response;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
loadFlowChart(paths) {
|
|
271
|
+
this.flowchart = {
|
|
272
|
+
shapes: [],
|
|
273
|
+
arrows: [],
|
|
274
|
+
prefixes: [],
|
|
275
|
+
flux: {},
|
|
276
|
+
};
|
|
277
|
+
this.nodesById = {};
|
|
278
|
+
const options = {
|
|
279
|
+
ignoreAttributes: false,
|
|
280
|
+
};
|
|
281
|
+
const llaves = Object.keys(paths);
|
|
282
|
+
llaves.forEach((prefix) => {
|
|
283
|
+
const path = paths[prefix];
|
|
284
|
+
const xmlFlowText = fs.readFileSync(path, 'utf8');
|
|
285
|
+
const parser = new XMLParser(options);
|
|
286
|
+
const xmlFlow = parser.parse(xmlFlowText);
|
|
287
|
+
const localFlowChart = this.processFlowChart(xmlFlow, prefix);
|
|
288
|
+
this.interpretColor(localFlowChart.shapes);
|
|
289
|
+
//
|
|
290
|
+
const check = this.checkTypeOfChart(localFlowChart);
|
|
291
|
+
this.flowchart.shapes.push(...localFlowChart.shapes);
|
|
292
|
+
this.flowchart.arrows.push(...localFlowChart.arrows);
|
|
293
|
+
this.flowchart.prefixes.push(prefix);
|
|
294
|
+
if (check.flux) {
|
|
295
|
+
for (let key in check.flux) {
|
|
296
|
+
this.flowchart.flux[key] = check.flux[key];
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
//console.log(JSON.stringify(this.flowchart.flux, null, 4));
|
|
302
|
+
|
|
303
|
+
// Se indexan los nodos por id
|
|
304
|
+
const BLACK_LIST = ["flux"];
|
|
305
|
+
this.flowchart.shapes.forEach((node) => {
|
|
306
|
+
if (BLACK_LIST.indexOf(node.mode) < 0) {
|
|
307
|
+
this.nodesById[node.id] = node;
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
if (this.conf.debug === true) {
|
|
311
|
+
console.log(JSON.stringify(this.flowchart, null, 4));
|
|
312
|
+
}
|
|
313
|
+
return this.flowchart;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
setData(data) {
|
|
317
|
+
this.data = data;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
getData() {
|
|
321
|
+
return this.data;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
setSuperContext(supercontext) {
|
|
325
|
+
this.supercontext = supercontext;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
getSuperContext() {
|
|
329
|
+
return this.supercontext;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
createInstance(commandName, nodeId, argsTxt, args) {
|
|
333
|
+
//console.log(`Creating instance with ${JSON.stringify(args)}`);
|
|
334
|
+
const reference = this.registry[commandName];
|
|
335
|
+
if (!reference) {
|
|
336
|
+
throw new Error(`No step registered for ${commandName} in node id ${nodeId}`);
|
|
337
|
+
}
|
|
338
|
+
const instance = new reference(this, nodeId, commandName, argsTxt);
|
|
339
|
+
let timeout = this.conf.timeout;
|
|
340
|
+
let retries = this.conf.retries;
|
|
341
|
+
instance.setTimeout(timeout);
|
|
342
|
+
instance.setMaxTries(retries);
|
|
343
|
+
//console.log(`Using timeout:${timeout}s retries:${retries}`);
|
|
344
|
+
return instance;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
interpretArguments(argTxt) {
|
|
348
|
+
//console.log(`Interpret ${argTxt}`);
|
|
349
|
+
const tokens = argTxt.split(";");
|
|
350
|
+
const args = [];
|
|
351
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
352
|
+
const token = tokens[i];
|
|
353
|
+
// Interpret with template
|
|
354
|
+
if (token.trim().length > 0) {
|
|
355
|
+
const rendered = this.renderer.render(token, this.data);
|
|
356
|
+
let value;
|
|
357
|
+
try {
|
|
358
|
+
value = eval(rendered);
|
|
359
|
+
} catch (err) {
|
|
360
|
+
console.log(`Error parsing ${typeof rendered} ${rendered}`);
|
|
361
|
+
throw err;
|
|
362
|
+
}
|
|
363
|
+
args.push(value);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return args;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async executeAsNode(node) {
|
|
370
|
+
const { id, txt } = node;
|
|
371
|
+
if (txt == undefined || txt == null || txt.trim().length == 0) {
|
|
372
|
+
return true;
|
|
373
|
+
}
|
|
374
|
+
let index = 0;
|
|
375
|
+
const answered = await MyUtilities.replaceAsync2(txt, /(([a-z]+)«([^»]*)»)/ig, async (match, g1, commandName, argsTxt) => {
|
|
376
|
+
const args = this.interpretArguments(argsTxt);
|
|
377
|
+
let instance = this.createInstance(commandName, id, txt, args);
|
|
378
|
+
index++;
|
|
379
|
+
const response1 = `${commandName}${JSON.stringify(args)}`;
|
|
380
|
+
const { canContinue, abort } = await instance.executeAsNode(args);
|
|
381
|
+
if (abort) {
|
|
382
|
+
// Panic and halt all
|
|
383
|
+
this.mustEnd = true;
|
|
384
|
+
}
|
|
385
|
+
return [response1, canContinue];
|
|
386
|
+
});
|
|
387
|
+
if (this.conf.debug === true) {
|
|
388
|
+
console.log(`${id})\n${txt}\n${answered.first}`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async executeAsArrow(node) {
|
|
393
|
+
const { id, txt } = node;
|
|
394
|
+
if (txt == undefined || txt == null || txt.trim().length == 0) {
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
let create = false;
|
|
398
|
+
if (!(id in this.instances)) {
|
|
399
|
+
create = true;
|
|
400
|
+
this.instances[id] = {};
|
|
401
|
+
}
|
|
402
|
+
let index = 0;
|
|
403
|
+
const answered = await MyUtilities.replaceAsync2(txt, /(([a-z]+)«([^»]*)»)/ig, async (match, g1, commandName, argsTxt) => {
|
|
404
|
+
const args = this.interpretArguments(argsTxt);
|
|
405
|
+
let instance = null;
|
|
406
|
+
if (create || !this.instances[id][`${index}`]) {
|
|
407
|
+
instance = this.createInstance(commandName, id, txt, args);
|
|
408
|
+
this.instances[id][`${index}`] = instance;
|
|
409
|
+
} else {
|
|
410
|
+
instance = this.instances[id][`${index}`];
|
|
411
|
+
if (!instance) {
|
|
412
|
+
throw Error(`Can't find instance at id:${id} index:${index} at commandName:${txt} in ${commandName}`);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
index++;
|
|
416
|
+
const response1 = `${commandName}${JSON.stringify(args)}`;
|
|
417
|
+
const { canContinue, abort } = await instance.executeAsArrow(args);
|
|
418
|
+
if (abort) {
|
|
419
|
+
// Panic and halt all
|
|
420
|
+
this.mustEnd = true;
|
|
421
|
+
}
|
|
422
|
+
return [response1, canContinue];
|
|
423
|
+
});
|
|
424
|
+
if (this.conf.debug === true) {
|
|
425
|
+
console.log(`${id})\n${txt}\n${answered.first}\n${answered.second}`);
|
|
426
|
+
}
|
|
427
|
+
const canContinue = eval(answered.second);
|
|
428
|
+
if (canContinue) {
|
|
429
|
+
// Delete only those instances that can be deleted
|
|
430
|
+
const instances = this.instances[id];
|
|
431
|
+
const llaves = Object.keys(instances);
|
|
432
|
+
const promesasAccepted = [];
|
|
433
|
+
llaves.forEach((llave, i) => {
|
|
434
|
+
const instance = instances[llave];
|
|
435
|
+
promesasAccepted.push(instance.arrowAccepted());
|
|
436
|
+
});
|
|
437
|
+
await Promise.all(promesasAccepted);
|
|
438
|
+
const promesasDestroy = [];
|
|
439
|
+
llaves.forEach((llave, i) => {
|
|
440
|
+
const instance = instances[llave];
|
|
441
|
+
if (instance.autoDelete == true) {
|
|
442
|
+
promesasDestroy.push(new Promise(async (resolve, reject) => {
|
|
443
|
+
try {
|
|
444
|
+
await instances[llave].destroy();
|
|
445
|
+
delete instances[llave];
|
|
446
|
+
resolve();
|
|
447
|
+
} catch (err) {
|
|
448
|
+
reject(err);
|
|
449
|
+
}
|
|
450
|
+
}));
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
await Promise.all(promesasDestroy);
|
|
454
|
+
}
|
|
455
|
+
return canContinue;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
async sleep(milis) {
|
|
459
|
+
if (milis == 0) {
|
|
460
|
+
return Promise.resolve();
|
|
461
|
+
}
|
|
462
|
+
return new Promise((resolve) => {
|
|
463
|
+
setTimeout(() => {
|
|
464
|
+
resolve();
|
|
465
|
+
}, milis);
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
getNodesWithText(name, type = ["ellipse", "box"], flowchart = null) {
|
|
470
|
+
if (!flowchart) {
|
|
471
|
+
flowchart = this.flowchart;
|
|
472
|
+
}
|
|
473
|
+
return flowchart.shapes.filter((value) => {
|
|
474
|
+
if (typeof value.txt == "string") {
|
|
475
|
+
return name == value.txt.trim() && type.indexOf(value.type) >= 0;
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
getNodesWithId(id, flowchart = null) {
|
|
481
|
+
if (!flowchart) {
|
|
482
|
+
flowchart = this.flowchart;
|
|
483
|
+
}
|
|
484
|
+
return flowchart.shapes.filter((value) => {
|
|
485
|
+
return id == value.id
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
getOutputArrows(node, flowchart = null) {
|
|
490
|
+
if (!flowchart) {
|
|
491
|
+
flowchart = this.flowchart;
|
|
492
|
+
}
|
|
493
|
+
const { id } = node;
|
|
494
|
+
return flowchart.arrows.filter((value) => {
|
|
495
|
+
return value.src == id;
|
|
496
|
+
})
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
getInputArrows(node, flowchart = null) {
|
|
500
|
+
if (!flowchart) {
|
|
501
|
+
flowchart = this.flowchart;
|
|
502
|
+
}
|
|
503
|
+
const { id } = node;
|
|
504
|
+
return flowchart.arrows.filter((value) => {
|
|
505
|
+
return value.tar == id;
|
|
506
|
+
})
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
setConf(conf) {
|
|
510
|
+
Object.assign(this.conf, conf);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
async pause() {
|
|
514
|
+
if (!this.executionPromise) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
this.isPaused = true;
|
|
518
|
+
await this.executionPromise;
|
|
519
|
+
this.executionPromise = null;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
async stop() {
|
|
523
|
+
const hasPromise = (!!this.executionPromise);
|
|
524
|
+
//console.log(`FlowChartExec.stop() ${hasPromise}`);
|
|
525
|
+
let callbackRef = null;
|
|
526
|
+
this.isPaused = true;
|
|
527
|
+
if (hasPromise) {
|
|
528
|
+
const { callback } = await this.executionPromise;
|
|
529
|
+
callbackRef = callback;
|
|
530
|
+
this.executionPromise = null;
|
|
531
|
+
}
|
|
532
|
+
this.tempHistory = [];
|
|
533
|
+
this.tempHistoryIncommingArrows = {};
|
|
534
|
+
this.status = {
|
|
535
|
+
currentNodes: [],
|
|
536
|
+
history: [],
|
|
537
|
+
};
|
|
538
|
+
this.bufferData = {};
|
|
539
|
+
this.pendingsCalls = {};
|
|
540
|
+
if (callbackRef) {
|
|
541
|
+
callbackRef(this.status);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
isRunning() {
|
|
546
|
+
return this.executionPromise !== null;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
async executeIteration(callback) {
|
|
550
|
+
if (this.isRunning()) {
|
|
551
|
+
console.log("Can't start if it's running.");
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
this.executionPromise = this.executeIterationLocal(callback);
|
|
555
|
+
return this.executionPromise;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
async executeIterationLocal(callback) {
|
|
559
|
+
console.log("executeIterationLocal...");
|
|
560
|
+
let status;
|
|
561
|
+
if (this.actualNodes.length == 0) {
|
|
562
|
+
// Se debe relanzar todo
|
|
563
|
+
this.startDate = new Date().getTime();
|
|
564
|
+
this.mustEnd = false;
|
|
565
|
+
this.isPaused = false;
|
|
566
|
+
this.tempHistory = [];
|
|
567
|
+
this.tempHistoryIncommingArrows = {};
|
|
568
|
+
this.instances = {};
|
|
569
|
+
status = {
|
|
570
|
+
currentNodes: [],
|
|
571
|
+
history: [],
|
|
572
|
+
};
|
|
573
|
+
// Search starting points
|
|
574
|
+
this.actualNodes = this.getNodesWithText("start");
|
|
575
|
+
if (this.actualNodes.length == 0) {
|
|
576
|
+
console.log(`WARN: No start nodes found`);
|
|
577
|
+
} else {
|
|
578
|
+
console.log(`Found ${this.actualNodes.length} start points`);
|
|
579
|
+
}
|
|
580
|
+
this.status = status;
|
|
581
|
+
} else {
|
|
582
|
+
status = this.status;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const addToHistory = (id) => {
|
|
586
|
+
if (this.tempHistory.indexOf(id) < 0) {
|
|
587
|
+
this.tempHistory.push(id);
|
|
588
|
+
status.history.push({ id });
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
const addCurrentNodeTo = (id, list) => {
|
|
592
|
+
if (list.indexOf(id) < 0) {
|
|
593
|
+
list.push(id);
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
const removeCurrentNodeFrom = (id, list) => {
|
|
597
|
+
const index = list.indexOf(id);
|
|
598
|
+
if (index >= 0) {
|
|
599
|
+
list.splice(index, 1);
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
do {
|
|
603
|
+
status.currentNodes = [];
|
|
604
|
+
const promesas = [];
|
|
605
|
+
//loop
|
|
606
|
+
this.actualNodes.forEach((node) => {
|
|
607
|
+
addCurrentNodeTo(node.id, status.currentNodes);
|
|
608
|
+
addToHistory(node.id);
|
|
609
|
+
//search outside arrows and checkthem
|
|
610
|
+
const outputArrows = this.getOutputArrows(node);
|
|
611
|
+
//console.log(`Found ${outputArrows.length} output arrows`);
|
|
612
|
+
outputArrows.forEach((arrow) => {
|
|
613
|
+
promesas.push(new Promise(async (resolve) => {
|
|
614
|
+
try {
|
|
615
|
+
const canContinue = await this.executeAsArrow(arrow);
|
|
616
|
+
if (canContinue) {
|
|
617
|
+
removeCurrentNodeFrom(node.id, status.currentNodes);
|
|
618
|
+
addToHistory(arrow.id);
|
|
619
|
+
// Agrego la evidencia que el nodo tar recibe la flecha id
|
|
620
|
+
if (!this.tempHistoryIncommingArrows[arrow.tar]) {
|
|
621
|
+
this.tempHistoryIncommingArrows[arrow.tar] = [];
|
|
622
|
+
}
|
|
623
|
+
this.tempHistoryIncommingArrows[arrow.tar].push(arrow.id);
|
|
624
|
+
}
|
|
625
|
+
resolve(
|
|
626
|
+
{
|
|
627
|
+
node,
|
|
628
|
+
arrow,
|
|
629
|
+
canContinue,
|
|
630
|
+
error: false,
|
|
631
|
+
}
|
|
632
|
+
);
|
|
633
|
+
} catch (err) {
|
|
634
|
+
console.log(err);
|
|
635
|
+
resolve(
|
|
636
|
+
{
|
|
637
|
+
error: err,
|
|
638
|
+
}
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
}));
|
|
642
|
+
});
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
//If any outside arrow is true, then remove node and add new node
|
|
646
|
+
const responses = await Promise.all(promesas);
|
|
647
|
+
|
|
648
|
+
const newNodes = [];
|
|
649
|
+
responses.forEach((respose) => {
|
|
650
|
+
const { node, arrow, canContinue, error } = respose;
|
|
651
|
+
if (error !== false) {
|
|
652
|
+
// Arrow fail
|
|
653
|
+
// Maybe handle to set maximum retries and exponetial back off
|
|
654
|
+
// Add visibility in somewhere
|
|
655
|
+
console.log(error);
|
|
656
|
+
} else {
|
|
657
|
+
if (canContinue) {
|
|
658
|
+
// Saco el nodo
|
|
659
|
+
removeCurrentNodeFrom(node, this.actualNodes);
|
|
660
|
+
// Busco el destino de la flecha y lo agrego a los pendientes
|
|
661
|
+
const { tar } = arrow;
|
|
662
|
+
const nextNode = this.nodesById[tar];
|
|
663
|
+
const oldIndex = this.actualNodes.indexOf(nextNode);
|
|
664
|
+
if (nextNode && oldIndex < 0) {
|
|
665
|
+
// Si es un nodo green, chequeo que todas las flechas entrantes estén hechas
|
|
666
|
+
if (nextNode.feature == "green") {
|
|
667
|
+
// Leo las flechas que llegan aquí
|
|
668
|
+
const incomingArrows = this.getInputArrows(nextNode);
|
|
669
|
+
let allDone = true;
|
|
670
|
+
if (this.tempHistoryIncommingArrows[nextNode.id]) {
|
|
671
|
+
for (let k = 0; k < incomingArrows.length; k++) {
|
|
672
|
+
const incomingArrow = incomingArrows[k];
|
|
673
|
+
if (this.tempHistoryIncommingArrows[nextNode.id].indexOf(incomingArrow.id) < 0) {
|
|
674
|
+
allDone = false;
|
|
675
|
+
break;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
if (allDone) {
|
|
680
|
+
this.actualNodes.push(nextNode);
|
|
681
|
+
newNodes.push(nextNode);
|
|
682
|
+
}
|
|
683
|
+
} else {
|
|
684
|
+
this.actualNodes.push(nextNode);
|
|
685
|
+
newNodes.push(nextNode);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
// Execute new nodes
|
|
693
|
+
for (let i = 0; i < newNodes.length; i++) {
|
|
694
|
+
const node = newNodes[i];
|
|
695
|
+
addCurrentNodeTo(node.id, status.currentNodes);
|
|
696
|
+
addToHistory(node.id);
|
|
697
|
+
try {
|
|
698
|
+
await this.executeAsNode(node);
|
|
699
|
+
if (node.feature == "green") {
|
|
700
|
+
this.tempHistoryIncommingArrows[node.id] = [];
|
|
701
|
+
}
|
|
702
|
+
if (node.txt == "end") {
|
|
703
|
+
this.mustEnd = true;
|
|
704
|
+
}
|
|
705
|
+
if (["ok", "end"].indexOf(node.txt.toLocaleLowerCase()) >= 0) {
|
|
706
|
+
removeCurrentNodeFrom(node, this.actualNodes);
|
|
707
|
+
}
|
|
708
|
+
} catch (err) {
|
|
709
|
+
// Node fail
|
|
710
|
+
// Maybe handle to set maximum retries and exponetial back off
|
|
711
|
+
// Add visibility in somewhere
|
|
712
|
+
console.log(err);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
await this.sleep(this.conf.sleep);
|
|
716
|
+
//Finish when no more nodes are in the list
|
|
717
|
+
await callback(status);
|
|
718
|
+
} while (this.actualNodes.length > 0 && !this.mustEnd && !this.isPaused);
|
|
719
|
+
this.executionPromise = null;
|
|
720
|
+
|
|
721
|
+
return {
|
|
722
|
+
callback
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
static async test() {
|
|
727
|
+
const pruebas = [
|
|
728
|
+
{
|
|
729
|
+
conf: { sleep: 500, debug: false },
|
|
730
|
+
data: {
|
|
731
|
+
person: {
|
|
732
|
+
name: "Edgar",
|
|
733
|
+
age: 38,
|
|
734
|
+
male: true
|
|
735
|
+
}
|
|
736
|
+
},
|
|
737
|
+
flowchartUrl: {
|
|
738
|
+
"": "../../src/assets/flowcharts/flow01.drawio",
|
|
739
|
+
"Step": "../../src/assets/flowcharts/flow01b.drawio"
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
];
|
|
743
|
+
|
|
744
|
+
for (let i = 0; i < pruebas.length; i++) {
|
|
745
|
+
const prueba = pruebas[i];
|
|
746
|
+
const { nodes, conf, data, flowchartUrl } = prueba;
|
|
747
|
+
const instance = new FlowChartExec();
|
|
748
|
+
instance.setConf(conf);
|
|
749
|
+
instance.setData(data);
|
|
750
|
+
instance.loadFlowChart(flowchartUrl);
|
|
751
|
+
await instance.executeIteration(async (status) => {
|
|
752
|
+
console.log(JSON.stringify(status, null, 4));
|
|
753
|
+
});
|
|
754
|
+
console.log(JSON.stringify(data, null, 4));
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
//FlowChartExec.test();
|
|
760
|
+
|
|
761
|
+
module.exports = {
|
|
762
|
+
FlowChartExec
|
|
763
|
+
}
|