History

* refactor ScriptCache per FIXMEs * include error details in BatchLoader results * update EntityServerScript properties in edtior to reflect more granular statuses * ScriptEngine plumbing in prep for require/module integration

humbletim committed 9 years ago

Commit 831bf931 parent e6142d914 files · +286 −257Browse files

Showing the changes to libraries/script-engine/src/ScriptCache.cpp (1 of 14 files). Show all

Unified · Split

libraries/script-engine/src/ScriptCache.cpp+34−83
@@ -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
31const QString ScriptCache::STATUS_INLINE { "Inline" };
32const QString ScriptCache::STATUS_CACHED { "Cached" };
33
30ScriptCache::ScriptCache(QObject* parent) {34ScriptCache::ScriptCache(QObject* parent) {
31 // nothing to do here...35 // nothing to do here...
32}36}
33 37
34void ScriptCache::clearCache() {38void 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
52QString 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
81void ScriptCache::deleteScript(const QUrl& unnormalizedURL) {59void 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
90void ScriptCache::scriptDownloaded() {68void 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
120void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailableCallback contentAvailable, bool forceDownload) {
121 #ifdef THREAD_DEBUGGING69 #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 #endif71 #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_DEBUGGING109 #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 #endif111 #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
172static const int MAX_RETRIES = 5;121void ScriptCache::scriptContentAvailable(int maxRetries) {
173static int START_DELAY_BETWEEN_RETRIES = 200;
174
175void ScriptCache::scriptContentAvailable() {
176 #ifdef THREAD_DEBUGGING122 #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 #endif124 #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 enabling172 // 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}