/
runLoop.js
72 lines (68 loc) · 3.11 KB
/
runLoop.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
const {Arborist} = require('flast');
const generateHash = require(__dirname + '/generateHash');
const logger = require(__dirname + '/../utils/logger');
const {defaultMaxIterations, getGlobalMaxIterations} = require(__dirname + '/../config');
let globalIterationsCounter = 0;
/**
* @returns {boolean} false if iterations limiting is disabled (-1)
* or the global iterations counter hasn't reached its maximum allowed iterations; true otherwise.
*/
function hasGlobalMaxIterationBeenReached() {
return getGlobalMaxIterations() === -1 ? false : globalIterationsCounter >= getGlobalMaxIterations();
}
/**
* Run functions which modify the script in a loop until they are no long effective or the maximum number of cycles is reached.
* @param {string} script The target script to run the functions on.
* @param {function[]} funcs
* @param {number?} maxIterations (optional) Stop the loop after this many iterations at most.
* @return {string} The possibly modified script.
*/
function runLoop(script, funcs, maxIterations = defaultMaxIterations) {
let scriptSnapshot = '';
let currentIteration = 0;
let changesCounter = 0;
try {
let scriptHash = generateHash(script);
let arborist = new Arborist(script, logger.log);
while (arborist.ast?.length && scriptSnapshot !== script && currentIteration < maxIterations && !hasGlobalMaxIterationBeenReached()) {
const cycleStartTime = Date.now();
scriptSnapshot = script;
// Mark each node with the script hash to distinguish cache of different scripts.
for (let i = 0; i < arborist.ast.length; i++) arborist.ast[i].scriptHash = scriptHash;
for (let i = 0; i < funcs.length; i++) {
const func = funcs[i];
const funcStartTime = +new Date();
try {
logger.debug(`\t[!] Running ${func.name}...`);
arborist = func(arborist);
if (!arborist.ast?.length) break;
// If the hash doesn't exist it means the Arborist was replaced
const numberOfNewChanges = arborist.getNumberOfChanges() + +!arborist.ast[0].scriptHash;
if (numberOfNewChanges) {
changesCounter += numberOfNewChanges;
logger.log(`\t[+] ${func.name} committed ${numberOfNewChanges} new changes!`);
arborist.applyChanges();
script = arborist.script;
scriptHash = generateHash(script);
for (let j = 0; j < arborist.ast.length; j++) arborist.ast[j].scriptHash = scriptHash;
}
} catch (e) {
logger.error(`[-] Error in ${func.name} (iteration #${globalIterationsCounter}): ${e}\n${e.stack}`);
} finally {
logger.debug(`\t\t[!] Running ${func.name} completed in ` +
`${((+new Date() - funcStartTime) / 1000).toFixed(3)} seconds`);
}
}
++currentIteration;
++globalIterationsCounter;
logger.log(`[+] ==> Cycle ${globalIterationsCounter} completed in ${(Date.now() - cycleStartTime) / 1000} seconds` +
` with ${changesCounter ? changesCounter : 'no'} changes (${arborist.ast?.length || '???'} nodes)`);
changesCounter = 0;
}
if (changesCounter) script = arborist.script;
} catch (e) {
logger.error(`[-] Error on loop #${globalIterationsCounter}: ${e}\n${e.stack}`);
}
return script;
}
module.exports = runLoop;