@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.
Files changed (88) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +2 -0
  3. package/package.json +29 -0
  4. package/src/CollisionsEngine.js +252 -0
  5. package/src/CsvFormatter.js +54 -0
  6. package/src/CsvFormatter.test.js +119 -0
  7. package/src/CsvFormatterFilters.js +79 -0
  8. package/src/CsvParser.js +51 -0
  9. package/src/CsvParser.test.js +41 -0
  10. package/src/CsvWithFilters.js +114 -0
  11. package/src/FaceEncoder.js +64 -0
  12. package/src/FlowChartDiagram.js +503 -0
  13. package/src/IdGen.js +211 -0
  14. package/src/ModuloDatoSeguro.js +142 -0
  15. package/src/ModuloDatoSeguro.test.js +29 -0
  16. package/src/ModuloDatoSeguro.test.mjs +45 -0
  17. package/src/ModuloDatoSeguroBack.mjs +55 -0
  18. package/src/ModuloDatoSeguroFront.js +73 -0
  19. package/src/ModuloSonido.js +83 -0
  20. package/src/ModuloVideos.js +51 -0
  21. package/src/MyColor.js +136 -0
  22. package/src/MyColor.test.js +37 -0
  23. package/src/MyConstants.js +147 -0
  24. package/src/MyCookies.js +34 -0
  25. package/src/MyDates.js +412 -0
  26. package/src/MyDates.test.js +26 -0
  27. package/src/MyDatesBack.mjs +21 -0
  28. package/src/MyDatesFront.js +41 -0
  29. package/src/MyJsPdf.js +52 -0
  30. package/src/MyRoutes.js +29 -0
  31. package/src/MyTemplate.js +272 -0
  32. package/src/MyTemplate.test.js +90 -0
  33. package/src/MyTensorflow.js +248 -0
  34. package/src/MyTensorflow.test.js +19 -0
  35. package/src/MyTensorflowBack.mjs +33 -0
  36. package/src/MyThrottle.js +80 -0
  37. package/src/MyTuples.js +445 -0
  38. package/src/MyTuples.test.js +330 -0
  39. package/src/MyUtilities.js +137 -0
  40. package/src/SimpleObj.js +153 -0
  41. package/src/SimpleObj.test.js +58 -0
  42. package/src/TriangulacionGeometric.js +335 -0
  43. package/src/changePath.js +38 -0
  44. package/src/data/case0.csv +3 -0
  45. package/src/data/case0.json +24 -0
  46. package/src/data/case1.csv +2 -0
  47. package/src/data/case1.json +24 -0
  48. package/src/data/case2.csv +3 -0
  49. package/src/data/case2.json +24 -0
  50. package/src/data/case3.csv +3 -0
  51. package/src/data/case3.json +24 -0
  52. package/src/data/format0.json +0 -0
  53. package/src/data/format0.txt +1 -0
  54. package/src/data/tensordata.csv +10 -0
  55. package/src/data/tensordata.json +37 -0
  56. package/src/data/tensordata.test.csv +10 -0
  57. package/src/data/tensormodel.json +113 -0
  58. package/src/fft.js +224 -0
  59. package/src/flowchart/FlowChartExec.js +763 -0
  60. package/src/flowchart/steps/CommandBasic.js +32 -0
  61. package/src/flowchart/steps/CommandInc.js +19 -0
  62. package/src/flowchart/steps/CommandMilvus.js +47 -0
  63. package/src/flowchart/steps/CommandMinio.js +28 -0
  64. package/src/flowchart/steps/CommandMongo.js +59 -0
  65. package/src/flowchart/steps/CommandPrint.js +12 -0
  66. package/src/flowchart/steps/CommandSet.js +14 -0
  67. package/src/flowchart/steps/CommandTimeline.js +21 -0
  68. package/src/flowchart/steps/CommandTimelineNext.js +28 -0
  69. package/src/flowchart/steps/StepBasic.js +184 -0
  70. package/src/flowchart/steps/StepCheckProcessor.js +26 -0
  71. package/src/flowchart/steps/StepCheckSrc.js +42 -0
  72. package/src/flowchart/steps/StepIsTrue.js +12 -0
  73. package/src/flowchart/steps/StepOneTime.js +21 -0
  74. package/src/flowchart/steps/StepProcess.js +163 -0
  75. package/src/flowchart/steps/StepReadSrc.js +66 -0
  76. package/src/flowchart/steps/StepSleep.js +22 -0
  77. package/src/flowchart/steps/StepTimeLineEnds.js +21 -0
  78. package/src/flowchart/steps/StepTimeLineHasMore.js +16 -0
  79. package/src/gif/index.d.ts +20 -0
  80. package/src/gif/index.mjs +85 -0
  81. package/src/gif/utils/checkTypes.d.ts +2 -0
  82. package/src/gif/utils/checkTypes.mjs +11 -0
  83. package/src/js-colormaps.js +19484 -0
  84. package/src/sortify.js +75 -0
  85. package/src/sqlmodelparser/SqlModelParser.js +22 -0
  86. package/src/test/csv/test_1000_20230429204538700.csv +1001 -0
  87. package/src/test/csv/test_5_20230429204525930.csv +6 -0
  88. 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
+ }