3 #include "cachedhttp.h"
9 CachedHttp *cachedHttp = new CachedHttp(Http::instance(), "js");
10 cachedHttp->setMaxSeconds(3600);
11 // Avoid expiring the cached js
12 cachedHttp->setMaxSize(0);
14 cachedHttp->getValidators().insert("application/javascript", [](const auto &reply) -> bool {
15 return !reply.body().isEmpty();
25 static thread_local JS i;
29 JS::JS(QObject *parent) : QObject(parent), engine(nullptr) {}
31 void JS::initialize(const QUrl &url) {
36 bool JS::checkError(const QJSValue &value) {
37 if (value.isError()) {
38 qWarning() << "Error" << value.toString();
39 qDebug() << value.property("stack").toString().splitRef('\n');
45 bool JS::isInitialized() {
46 if (ready) return true;
51 JSResult &JS::callFunction(JSResult *result, const QString &name, const QJSValueList &args) {
52 if (!isInitialized()) {
53 qDebug() << "Not initialized";
54 QTimer::singleShot(1000, this,
55 [this, result, name, args] { callFunction(result, name, args); });
59 auto function = engine->evaluate(name);
60 if (!function.isCallable()) {
61 qWarning() << function.toString() << " is not callable";
62 QTimer::singleShot(0, result, [result, function] { result->setError(function); });
67 args2.prepend(engine->newQObject(result));
68 qDebug() << "Calling" << function.toString();
69 auto v = function.call(args2);
70 if (checkError(v)) QTimer::singleShot(0, result, [result, v] { result->setError(v); });
76 class MyCookieJar : public QNetworkCookieJar {
77 bool insertCookie(const QNetworkCookie &cookie) {
78 if (cookie.name().contains("CONSENT")) {
79 qDebug() << "Fixing CONSENT cookie" << cookie;
80 auto cookie2 = cookie;
81 cookie2.setValue(cookie.value().replace("PENDING", "YES"));
82 return QNetworkCookieJar::insertCookie(cookie2);
84 return QNetworkCookieJar::insertCookie(cookie);
88 auto nam = getEngine().networkAccessManager();
89 nam->clearAccessCache();
90 nam->setCookieJar(new MyCookieJar());
93 void JS::initialize() {
95 qDebug() << "No js url set";
99 if (initializing) return;
101 qDebug() << "Initializing";
103 if (engine) engine->deleteLater();
104 engine = new QQmlEngine(this);
105 engine->setNetworkAccessManagerFactory(&namFactory);
106 engine->globalObject().setProperty("global", engine->globalObject());
108 QJSValue timer = engine->newQObject(new JSTimer(engine));
109 engine->globalObject().setProperty("setTimeoutQt", timer.property("setTimeout"));
110 QJSValue setTimeoutWrapperFunction =
111 engine->evaluate("function setTimeout(cb, delay) {"
112 "const args = Array.prototype.slice.call(arguments, 2);"
113 "return setTimeoutQt(cb, delay, args);"
115 checkError(setTimeoutWrapperFunction);
116 engine->globalObject().setProperty("clearTimeout", timer.property("clearTimeout"));
118 QJSValue vm = engine->newQObject(new JSVM(engine));
119 engine->globalObject().setProperty("runInContextQt", vm.property("runInContext"));
121 connect(cachedHttp().get(url), &HttpReply::finished, this, [this](auto &reply) {
122 if (!reply.isSuccessful()) {
123 emit initFailed("Cannot load JS");
124 qDebug() << "Cannot load JS";
125 initializing = false;
128 auto value = engine->evaluate(reply.body());
129 if (!checkError(value)) {
130 qDebug() << "Initialized";
135 initializing = false;