Showing the changes to libraries/script-engine/src/ScriptCache.cpp (1 of 14 files). Show all
Unified · Split
| @@ -19,6 +19,7 @@ · 18 unmodified lines | |||
| 19 | #include <QObject> | 19 | #include <QObject> |
| 20 | #include <QThread> | 20 | #include <QThread> |
| 21 | #include <QRegularExpression> | 21 | #include <QRegularExpression> |
| 22 | #include <QMetaEnum> | ||
| 22 | 23 | ||
| 23 | #include <assert.h> | 24 | #include <assert.h> |
| 24 | #include <SharedUtil.h> | 25 | #include <SharedUtil.h> |
| @@ -27,12 +28,18 @@ · 2 unmodified lines | |||
| 27 | #include "ScriptEngineLogging.h" | 28 | #include "ScriptEngineLogging.h" |
| 28 | #include <QtCore/QTimer> | 29 | #include <QtCore/QTimer> |
| 29 | 30 | ||
| 31 | const QString ScriptCache::STATUS_INLINE { "Inline" }; | ||
| 32 | const QString ScriptCache::STATUS_CACHED { "Cached" }; | ||
| 33 | |||
| 30 | ScriptCache::ScriptCache(QObject* parent) { | 34 | ScriptCache::ScriptCache(QObject* parent) { |
| 31 | // nothing to do here... | 35 | // nothing to do here... |
| 32 | } | 36 | } |
| 33 | 37 | ||
| 34 | void ScriptCache::clearCache() { | 38 | void ScriptCache::clearCache() { |
| 35 | Lock lock(_containerLock); | 39 | Lock lock(_containerLock); |
| 40 | foreach(auto& url, _scriptCache.keys()) { | ||
| 41 | qCDebug(scriptengine) << "clearing cache: " << url; | ||
| 42 | } | ||
| 36 | _scriptCache.clear(); | 43 | _scriptCache.clear(); |
| 37 | } | 44 | } |
| 38 | 45 | ||
| @@ -49,35 +56,6 @@ void ScriptCache::clearATPScriptsFromCache() { · 10 unmodified lines | |||
| 49 | } | 56 | } |
| 50 | } | 57 | } |
| 51 | 58 | ||
| 52 | QString ScriptCache::getScript(const QUrl& unnormalizedURL, ScriptUser* scriptUser, bool& isPending, bool reload) { | ||
| 53 | QUrl url = ResourceManager::normalizeURL(unnormalizedURL); | ||
| 54 | QString scriptContents; | ||
| 55 | |||
| 56 | Lock lock(_containerLock); | ||
| 57 | if (_scriptCache.contains(url) && !reload) { | ||
| 58 | qCDebug(scriptengine) << "Found script in cache:" << url.toString(); | ||
| 59 | scriptContents = _scriptCache[url]; | ||
| 60 | lock.unlock(); | ||
| 61 | scriptUser->scriptContentsAvailable(url, scriptContents); | ||
| 62 | isPending = false; | ||
| 63 | } else { | ||
| 64 | isPending = true; | ||
| 65 | bool alreadyWaiting = _scriptUsers.contains(url); | ||
| 66 | _scriptUsers.insert(url, scriptUser); | ||
| 67 | lock.unlock(); | ||
| 68 | |||
| 69 | if (alreadyWaiting) { | ||
| 70 | qCDebug(scriptengine) << "Already downloading script at:" << url.toString(); | ||
| 71 | } else { | ||
| 72 | auto request = ResourceManager::createResourceRequest(nullptr, url); | ||
| 73 | request->setCacheEnabled(!reload); | ||
| 74 | connect(request, &ResourceRequest::finished, this, &ScriptCache::scriptDownloaded); | ||
| 75 | request->send(); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | return scriptContents; | ||
| 79 | } | ||
| 80 | |||
| 81 | void ScriptCache::deleteScript(const QUrl& unnormalizedURL) { | 59 | void ScriptCache::deleteScript(const QUrl& unnormalizedURL) { |
| 82 | QUrl url = ResourceManager::normalizeURL(unnormalizedURL); | 60 | QUrl url = ResourceManager::normalizeURL(unnormalizedURL); |
| 83 | Lock lock(_containerLock); | 61 | Lock lock(_containerLock); |
| @@ -87,37 +65,7 @@ void ScriptCache::deleteScript(const QUrl& unnormalizedURL) { · 3 unmodified lines | |||
| 87 | } | 65 | } |
| 88 | } | 66 | } |
| 89 | 67 | ||
| 90 | void ScriptCache::scriptDownloaded() { | 68 | void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailableCallback contentAvailable, bool forceDownload, int maxRetries) { |
| 91 | ResourceRequest* req = qobject_cast<ResourceRequest*>(sender()); | ||
| 92 | QUrl url = req->getUrl(); | ||
| 93 | |||
| 94 | Lock lock(_containerLock); | ||
| 95 | QList<ScriptUser*> scriptUsers = _scriptUsers.values(url); | ||
| 96 | _scriptUsers.remove(url); | ||
| 97 | |||
| 98 | if (!DependencyManager::get<ScriptEngines>()->isStopped()) { | ||
| 99 | if (req->getResult() == ResourceRequest::Success) { | ||
| 100 | auto scriptContents = req->getData(); | ||
| 101 | _scriptCache[url] = scriptContents; | ||
| 102 | lock.unlock(); | ||
| 103 | qCDebug(scriptengine) << "Done downloading script at:" << url.toString(); | ||
| 104 | |||
| 105 | foreach(ScriptUser* user, scriptUsers) { | ||
| 106 | user->scriptContentsAvailable(url, scriptContents); | ||
| 107 | } | ||
| 108 | } else { | ||
| 109 | lock.unlock(); | ||
| 110 | qCWarning(scriptengine) << "Error loading script from URL " << url; | ||
| 111 | foreach(ScriptUser* user, scriptUsers) { | ||
| 112 | user->errorInLoadingScript(url); | ||
| 113 | } | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | req->deleteLater(); | ||
| 118 | } | ||
| 119 | |||
| 120 | void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailableCallback contentAvailable, bool forceDownload) { | ||
| 121 | #ifdef THREAD_DEBUGGING | 69 | #ifdef THREAD_DEBUGGING |
| 122 | qCDebug(scriptengine) << "ScriptCache::getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; | 70 | qCDebug(scriptengine) << "ScriptCache::getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; |
| 123 | #endif | 71 | #endif |
| @@ -128,7 +76,7 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable · 4 unmodified lines | |||
| 128 | // entityScript use case) | 76 | // entityScript use case) |
| 129 | if (unnormalizedURL.scheme().isEmpty() && | 77 | if (unnormalizedURL.scheme().isEmpty() && |
| 130 | scriptOrURL.simplified().replace(" ", "").contains(QRegularExpression(R"(\(function\([a-z]?[\w,]*\){)"))) { | 78 | scriptOrURL.simplified().replace(" ", "").contains(QRegularExpression(R"(\(function\([a-z]?[\w,]*\){)"))) { |
| 131 | contentAvailable(scriptOrURL, scriptOrURL, false, true); | 79 | contentAvailable(scriptOrURL, scriptOrURL, false, true, STATUS_INLINE); |
| 132 | return; | 80 | return; |
| 133 | } | 81 | } |
| 134 | 82 | ||
| @@ -136,7 +84,7 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable · 1 unmodified line | |||
| 136 | if (unnormalizedURL.scheme() == "javascript") { | 84 | if (unnormalizedURL.scheme() == "javascript") { |
| 137 | QString contents { scriptOrURL }; | 85 | QString contents { scriptOrURL }; |
| 138 | contents.replace(QRegularExpression("^javascript:"), ""); | 86 | contents.replace(QRegularExpression("^javascript:"), ""); |
| 139 | contentAvailable(scriptOrURL, contents, false, true); | 87 | contentAvailable(scriptOrURL, contents, false, true, STATUS_INLINE); |
| 140 | return; | 88 | return; |
| 141 | } | 89 | } |
| 142 | 90 | ||
| @@ -145,34 +93,32 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable · 2 unmodified lines | |||
| 145 | auto scriptContent = _scriptCache[url]; | 93 | auto scriptContent = _scriptCache[url]; |
| 146 | lock.unlock(); | 94 | lock.unlock(); |
| 147 | qCDebug(scriptengine) << "Found script in cache:" << url.toString(); | 95 | qCDebug(scriptengine) << "Found script in cache:" << url.toString(); |
| 148 | contentAvailable(url.toString(), scriptContent, true, true); | 96 | contentAvailable(url.toString(), scriptContent, true, true, STATUS_CACHED); |
| 149 | } else { | 97 | } else { |
| 150 | auto& scriptRequest = _activeScriptRequests[url]; | 98 | auto& scriptRequest = _activeScriptRequests[url]; |
| 151 | |||
| 152 | bool alreadyWaiting = scriptRequest.scriptUsers.size() > 0; | 99 | bool alreadyWaiting = scriptRequest.scriptUsers.size() > 0; |
| 153 | scriptRequest.scriptUsers.push_back(contentAvailable); | 100 | scriptRequest.scriptUsers.push_back(contentAvailable); |
| 154 | 101 | ||
| 155 | lock.unlock(); | 102 | lock.unlock(); |
| 156 | 103 | ||
| 157 | if (alreadyWaiting) { | 104 | if (alreadyWaiting) { |
| 158 | qCDebug(scriptengine) << "Already downloading script at:" << url.toString(); | 105 | qCDebug(scriptengine) << QString("Already downloading script at: %1 (retry: %2; scriptusers: %3)") |
| 106 | .arg(url.toString()).arg(scriptRequest.numRetries).arg(scriptRequest.scriptUsers.size()); | ||
| 159 | } else { | 107 | } else { |
| 108 | scriptRequest.maxRetries = maxRetries; | ||
| 160 | #ifdef THREAD_DEBUGGING | 109 | #ifdef THREAD_DEBUGGING |
| 161 | qCDebug(scriptengine) << "about to call: ResourceManager::createResourceRequest(this, url); on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; | 110 | qCDebug(scriptengine) << "about to call: ResourceManager::createResourceRequest(this, url); on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; |
| 162 | #endif | 111 | #endif |
| 163 | auto request = ResourceManager::createResourceRequest(nullptr, url); | 112 | auto request = ResourceManager::createResourceRequest(nullptr, url); |
| 164 | Q_ASSERT(request); | 113 | Q_ASSERT(request); |
| 165 | request->setCacheEnabled(!forceDownload); | 114 | request->setCacheEnabled(!forceDownload); |
| 166 | connect(request, &ResourceRequest::finished, this, &ScriptCache::scriptContentAvailable); | 115 | connect(request, &ResourceRequest::finished, this, [=]{ scriptContentAvailable(maxRetries); }); |
| 167 | request->send(); | 116 | request->send(); |
| 168 | } | 117 | } |
| 169 | } | 118 | } |
| 170 | } | 119 | } |
| 171 | 120 | ||
| 172 | static const int MAX_RETRIES = 5; | 121 | void ScriptCache::scriptContentAvailable(int maxRetries) { |
| 173 | static int START_DELAY_BETWEEN_RETRIES = 200; | ||
| 174 | |||
| 175 | void ScriptCache::scriptContentAvailable() { | ||
| 176 | #ifdef THREAD_DEBUGGING | 122 | #ifdef THREAD_DEBUGGING |
| 177 | qCDebug(scriptengine) << "ScriptCache::scriptContentAvailable() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; | 123 | qCDebug(scriptengine) << "ScriptCache::scriptContentAvailable() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; |
| 178 | #endif | 124 | #endif |
| @@ -181,7 +127,7 @@ void ScriptCache::scriptContentAvailable() { · 2 unmodified lines | |||
| 181 | 127 | ||
| 182 | QString scriptContent; | 128 | QString scriptContent; |
| 183 | std::vector<contentAvailableCallback> allCallbacks; | 129 | std::vector<contentAvailableCallback> allCallbacks; |
| 184 | bool finished { false }; | 130 | QString status = QMetaEnum::fromType<ResourceRequest::Result>().valueToKey(req->getResult()); |
| 185 | bool success { false }; | 131 | bool success { false }; |
| 186 | 132 | ||
| 187 | { | 133 | { |
| @@ -199,7 +145,6 @@ void ScriptCache::scriptContentAvailable() { · 11 unmodified lines | |||
| 199 | _activeScriptRequests.remove(url); | 145 | _activeScriptRequests.remove(url); |
| 200 | 146 | ||
| 201 | _scriptCache[url] = scriptContent = req->getData(); | 147 | _scriptCache[url] = scriptContent = req->getData(); |
| 202 | finished = true; | ||
| 203 | qCDebug(scriptengine) << "Done downloading script at:" << url.toString(); | 148 | qCDebug(scriptengine) << "Done downloading script at:" << url.toString(); |
| 204 | } else { | 149 | } else { |
| 205 | auto result = req->getResult(); | 150 | auto result = req->getResult(); |
| @@ -207,16 +152,19 @@ void ScriptCache::scriptContentAvailable() { · 1 unmodified line | |||
| 207 | result == ResourceRequest::AccessDenied || | 152 | result == ResourceRequest::AccessDenied || |
| 208 | result == ResourceRequest::InvalidURL || | 153 | result == ResourceRequest::InvalidURL || |
| 209 | result == ResourceRequest::NotFound || | 154 | result == ResourceRequest::NotFound || |
| 210 | scriptRequest.numRetries >= MAX_RETRIES; | 155 | scriptRequest.numRetries >= maxRetries; |
| 211 | 156 | ||
| 212 | if (!irrecoverable) { | 157 | if (!irrecoverable) { |
| 213 | ++scriptRequest.numRetries; | 158 | ++scriptRequest.numRetries; |
| 214 | 159 | ||
| 215 | qCDebug(scriptengine) << "Script request failed: " << url; | 160 | int timeout = exp(scriptRequest.numRetries) * ScriptRequest::START_DELAY_BETWEEN_RETRIES; |
| 161 | int attempt = scriptRequest.numRetries; | ||
| 162 | qCDebug(scriptengine) << QString("Script request failed [%1]: %2 (will retry %3 more times; attempt #%4 in %5ms...)") | ||
| 163 | .arg(status).arg(url.toString()).arg(maxRetries - attempt + 1).arg(attempt).arg(timeout); | ||
| 216 | 164 | ||
| 217 | int timeout = exp(scriptRequest.numRetries) * START_DELAY_BETWEEN_RETRIES; | 165 | QTimer::singleShot(timeout, this, [this, url, attempt, maxRetries]() { |
| 218 | QTimer::singleShot(timeout, this, [this, url]() { | 166 | qCDebug(scriptengine) << QString("Retrying script request [%1 / %2]: %3") |
| 219 | qCDebug(scriptengine) << "Retrying script request: " << url; | 167 | .arg(attempt).arg(maxRetries).arg(url.toString()); |
| 220 | 168 | ||
| 221 | auto request = ResourceManager::createResourceRequest(nullptr, url); | 169 | auto request = ResourceManager::createResourceRequest(nullptr, url); |
| 222 | Q_ASSERT(request); | 170 | Q_ASSERT(request); |
| @@ -224,7 +172,7 @@ void ScriptCache::scriptContentAvailable() { · 1 unmodified line | |||
| 224 | // We've already made a request, so the cache must be disabled or it wasn't there, so enabling | 172 | // We've already made a request, so the cache must be disabled or it wasn't there, so enabling |
| 225 | // it will do nothing. | 173 | // it will do nothing. |
| 226 | request->setCacheEnabled(false); | 174 | request->setCacheEnabled(false); |
| 227 | connect(request, &ResourceRequest::finished, this, &ScriptCache::scriptContentAvailable); | 175 | connect(request, &ResourceRequest::finished, this, [=]{ scriptContentAvailable(maxRetries); }); |
| 228 | request->send(); | 176 | request->send(); |
| 229 | }); | 177 | }); |
| 230 | } else { | 178 | } else { |
| @@ -232,9 +180,12 @@ void ScriptCache::scriptContentAvailable() { · 1 unmodified line | |||
| 232 | 180 | ||
| 233 | allCallbacks = scriptRequest.scriptUsers; | 181 | allCallbacks = scriptRequest.scriptUsers; |
| 234 | 182 | ||
| 235 | scriptContent = _scriptCache[url]; | 183 | if (_scriptCache.contains(url)) { |
| 236 | finished = true; | 184 | scriptContent = _scriptCache[url]; |
| 237 | qCWarning(scriptengine) << "Error loading script from URL " << url; | 185 | } |
| 186 | _activeScriptRequests.remove(url); | ||
| 187 | qCWarning(scriptengine) << "Error loading script from URL " << url << "(" << status <<")"; | ||
| 188 | |||
| 238 | } | 189 | } |
| 239 | } | 190 | } |
| 240 | } | 191 | } |
| @@ -242,9 +193,9 @@ void ScriptCache::scriptContentAvailable() { · 1 unmodified line | |||
| 242 | 193 | ||
| 243 | req->deleteLater(); | 194 | req->deleteLater(); |
| 244 | 195 | ||
| 245 | if (finished && !DependencyManager::get<ScriptEngines>()->isStopped()) { | 196 | if (allCallbacks.size() > 0 && !DependencyManager::get<ScriptEngines>()->isStopped()) { |
| 246 | foreach(contentAvailableCallback thisCallback, allCallbacks) { | 197 | foreach(contentAvailableCallback thisCallback, allCallbacks) { |
| 247 | thisCallback(url.toString(), scriptContent, true, success); | 198 | thisCallback(url.toString(), scriptContent, true, success, status); |
| 248 | } | 199 | } |
| 249 | } | 200 | } |
| 250 | } | 201 | } |