| [1073] | 1 | #include "xmlcustomcode.h"
|
|---|
| 2 |
|
|---|
| 3 | XmlCustomCode* XmlCustomCode::uniqueInstance = NULL;
|
|---|
| 4 |
|
|---|
| 5 | QScriptValue echo(QScriptContext *context, QScriptEngine*)
|
|---|
| 6 | {
|
|---|
| 7 | std::cout << context->argument(0).toString().toUtf8().constData() << std::endl;
|
|---|
| 8 |
|
|---|
| 9 | return "";
|
|---|
| 10 | }
|
|---|
| 11 |
|
|---|
| 12 | XmlCustomCode::XmlCustomCode(): numThreads(QThread::idealThreadCount())
|
|---|
| 13 | {
|
|---|
| 14 | myThreadPool.setMaxThreadCount(numThreads);
|
|---|
| 15 | myThreadPool.setExpiryTimeout(-1); // don't let threads expire
|
|---|
| 16 |
|
|---|
| 17 | // create individual thread script engines
|
|---|
| 18 | this->jsScriptEngines.reserve(this->numThreads);
|
|---|
| 19 |
|
|---|
| 20 | QString jsxmlString;
|
|---|
| 21 | QFile jsxmlfile(":/resources/libs/jsxml.js");
|
|---|
| 22 |
|
|---|
| 23 | jsxmlfile.open(QFile::ReadOnly | QFile::Text);
|
|---|
| 24 |
|
|---|
| 25 | jsxmlString=QTextStream(&jsxmlfile).readAll();
|
|---|
| 26 |
|
|---|
| 27 | for(int i=0; i<this->numThreads; i++){
|
|---|
| 28 |
|
|---|
| 29 | jsCustomCodeEngine e;
|
|---|
| 30 |
|
|---|
| 31 | e.scriptEngine = new QScriptEngine();
|
|---|
| 32 | e.jsFunction = new QScriptValue();
|
|---|
| 33 |
|
|---|
| 34 | // main needs to be called so the user code is evaluated
|
|---|
| 35 | // alternatively you can do: myFunc=engine.evaluate('(function main(){})'); myFunc.call();
|
|---|
| 36 | // Note the () around the function
|
|---|
| 37 | e.getXmlDataFunction = new QScriptValue(e.scriptEngine->evaluate("(function getXmlData() { return $xmlData; })"));
|
|---|
| 38 | e.setXmlDataFunction = new QScriptValue(e.scriptEngine->evaluate("(function setXmlData(newXmlData) { $xmlData=newXmlData; })"));
|
|---|
| [1112] | 39 | e.mutexForEngine = new QMutex;
|
|---|
| [1073] | 40 |
|
|---|
| 41 | // Add echo function so user can debug the code
|
|---|
| 42 | QScriptValue echoFunction = e.scriptEngine->newFunction(echo);
|
|---|
| 43 | e.scriptEngine->globalObject().setProperty("echo", echoFunction);
|
|---|
| 44 |
|
|---|
| 45 | // Add the js library for XmlEditing
|
|---|
| 46 | e.scriptEngine->evaluate(jsxmlString);
|
|---|
| 47 |
|
|---|
| 48 | this->jsScriptEngines.append(e);
|
|---|
| 49 | }
|
|---|
| 50 | }
|
|---|
| 51 |
|
|---|
| 52 | XmlCustomCode* XmlCustomCode::getInstance(){
|
|---|
| 53 |
|
|---|
| 54 | if (uniqueInstance==NULL){ // allow only one instance
|
|---|
| 55 | uniqueInstance = new XmlCustomCode();
|
|---|
| 56 | }
|
|---|
| 57 |
|
|---|
| 58 | return uniqueInstance;
|
|---|
| 59 | }
|
|---|
| 60 |
|
|---|
| 61 | void XmlCustomCode::executeCustomCode(const QString &jsString, const QVector<QString> &filesToProcess, const bool backupsEnabled, const bool verboseEnabled){
|
|---|
| 62 |
|
|---|
| 63 | // Reconstruct script functions
|
|---|
| 64 | for(int i=0; i<this->numThreads; i++){
|
|---|
| 65 | *(jsScriptEngines[i].jsFunction) = jsScriptEngines.at(i).scriptEngine->evaluate("(function main() {"+jsString+"})");
|
|---|
| 66 | }
|
|---|
| 67 |
|
|---|
| 68 | QString currXmlFileString;
|
|---|
| 69 |
|
|---|
| 70 | QScriptValue engineResult; // variable to check for js_errors
|
|---|
| 71 | double elapsed_secs=0; // elapsed seconds that a user script took
|
|---|
| 72 | clock_t begin; // seconds that a script started
|
|---|
| 73 |
|
|---|
| 74 | // Single tread if small number of files or number of threads = 1
|
|---|
| 75 | if(filesToProcess.size()<=CUSTOM_FILES_PER_THREAD || numThreads == 1){
|
|---|
| 76 |
|
|---|
| [1112] | 77 | jsCustomCodeEngine &jsEngine = this->jsScriptEngines.first();
|
|---|
| [1073] | 78 |
|
|---|
| 79 | // Process all XmlFiles
|
|---|
| 80 | for(int i=0; i<filesToProcess.size(); i++){
|
|---|
| 81 | customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*jsEngine.scriptEngine,begin,elapsed_secs,engineResult,
|
|---|
| 82 | *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
|
|---|
| 83 | }
|
|---|
| 84 | }
|
|---|
| 85 | else{ // Multithread if there are many files
|
|---|
| 86 | // Process all XmlFiles
|
|---|
| 87 |
|
|---|
| 88 | QVector<QFuture<void>> executingThreads;
|
|---|
| 89 |
|
|---|
| [1112] | 90 | for(int i=0, iteration = 0; i<=filesToProcess.size()-CUSTOM_FILES_PER_THREAD; i+=CUSTOM_FILES_PER_THREAD, ++iteration){
|
|---|
| [1073] | 91 |
|
|---|
| [1112] | 92 | executingThreads << QtConcurrent::run(&this->myThreadPool, [=]()
|
|---|
| [1073] | 93 | {
|
|---|
| 94 |
|
|---|
| [1112] | 95 | const int indexJsEngine = iteration % this->numThreads;
|
|---|
| 96 |
|
|---|
| 97 | jsCustomCodeEngine &jsEngine = this->jsScriptEngines[indexJsEngine];
|
|---|
| 98 |
|
|---|
| 99 | jsEngine.mutexForEngine->lock();
|
|---|
| 100 |
|
|---|
| [1073] | 101 | QString currXmlFileStringThread;
|
|---|
| 102 |
|
|---|
| 103 | QScriptValue engineResultThread; // variable to check for js_errors
|
|---|
| 104 | double elapsedSecsThread=0; // elapsed seconds that a user script took
|
|---|
| 105 | clock_t beginThread; // seconds that a script started
|
|---|
| 106 |
|
|---|
| 107 | customCodeUnwinding(filesToProcess.at(i),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread,
|
|---|
| 108 | *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
|
|---|
| 109 |
|
|---|
| 110 | customCodeUnwinding(filesToProcess.at(i+1),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread,
|
|---|
| 111 | *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
|
|---|
| 112 |
|
|---|
| 113 | customCodeUnwinding(filesToProcess.at(i+2),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread,
|
|---|
| 114 | *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
|
|---|
| 115 |
|
|---|
| 116 | customCodeUnwinding(filesToProcess.at(i+3),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread,
|
|---|
| 117 | *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
|
|---|
| 118 |
|
|---|
| [1112] | 119 | jsEngine.mutexForEngine->unlock();
|
|---|
| [1073] | 120 | });
|
|---|
| 121 | }
|
|---|
| 122 |
|
|---|
| 123 | // Wait for all threads to finish
|
|---|
| 124 | for(QFuture<void> &f :executingThreads){
|
|---|
| 125 | f.waitForFinished();
|
|---|
| 126 | }
|
|---|
| 127 |
|
|---|
| 128 | if(filesToProcess.size()%CUSTOM_FILES_PER_THREAD!=0){
|
|---|
| 129 |
|
|---|
| 130 | int alreadyProcessedFiles=(filesToProcess.size()/CUSTOM_FILES_PER_THREAD)*CUSTOM_FILES_PER_THREAD;
|
|---|
| 131 |
|
|---|
| [1112] | 132 | jsCustomCodeEngine &jsEngine = this->jsScriptEngines.first();
|
|---|
| [1073] | 133 |
|
|---|
| 134 | for(int i=alreadyProcessedFiles; i<filesToProcess.size(); i++){
|
|---|
| 135 |
|
|---|
| 136 | customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*jsEngine.scriptEngine,begin,elapsed_secs,engineResult,
|
|---|
| 137 | *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
|
|---|
| 138 | }
|
|---|
| 139 | }
|
|---|
| 140 | }
|
|---|
| 141 | }
|
|---|
| 142 |
|
|---|
| 143 | void XmlCustomCode::displayJsException(QScriptEngine &engine, QScriptValue &engineResult){
|
|---|
| 144 | if (engine.hasUncaughtException()) {
|
|---|
| 145 | UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Uncaught js exception (user code) at line " +QString::number(engine.uncaughtExceptionLineNumber()) + ":\n" + engineResult.toString());
|
|---|
| 146 | }
|
|---|
| 147 | }
|
|---|