Lua: Change fetch module access to async

Change-Id: I32bd760e347e2bd4465bd028e31fb3c4ff220aa5
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Marcus Tillmanns
2024-05-02 11:41:54 +02:00
parent d76082da59
commit 6ecd0f4023

View File

@@ -36,100 +36,98 @@ static QString opToString(QNetworkAccessManager::Operation op)
void addFetchModule() void addFetchModule()
{ {
LuaEngine::registerProvider("__fetch", [](sol::state_view lua) -> sol::object { LuaEngine::registerProvider(
sol::table fetch = lua.create_table(); "Fetch", [](sol::state_view lua) -> sol::object {
sol::table async = lua.script("return require('async')", "_fetch_").get<sol::table>();
sol::function wrap = async["wrap"];
auto networkReplyType = lua.new_usertype<QNetworkReply>( sol::table fetch = lua.create_table();
"QNetworkReply",
"error",
sol::property([](QNetworkReply *self) -> int { return self->error(); }),
"readAll",
[](QNetworkReply *r) { return r->readAll().toStdString(); },
"__tostring",
[](QNetworkReply *r) {
return QString("QNetworkReply(%1 \"%2\") => %3")
.arg(opToString(r->operation()))
.arg(r->url().toString())
.arg(r->error());
});
fetch["fetch_cb"] = [](const sol::table &options, const sol::function &callback, const sol::this_state &thisState) { auto networkReplyType = lua.new_usertype<QNetworkReply>(
auto url = options.get<QString>("url"); "QNetworkReply",
"error",
sol::property([](QNetworkReply *self) -> int { return self->error(); }),
"readAll",
[](QNetworkReply *r) { return r->readAll().toStdString(); },
"__tostring",
[](QNetworkReply *r) {
return QString("QNetworkReply(%1 \"%2\") => %3")
.arg(opToString(r->operation()))
.arg(r->url().toString())
.arg(r->error());
});
auto method = (options.get_or<QString>("method", "GET")).toLower(); fetch["fetch_cb"] = [](const sol::table &options,
auto headers = options.get_or<sol::table>("headers", {}); const sol::function &callback,
auto data = options.get_or<QString>("body", {}); const sol::this_state &thisState) {
bool convertToTable = options.get<std::optional<bool>>("convertToTable").value_or(false); auto url = options.get<QString>("url");
QNetworkRequest request((QUrl(url))); auto method = (options.get_or<QString>("method", "GET")).toLower();
if (headers && !headers.empty()) { auto headers = options.get_or<sol::table>("headers", {});
for (const auto &[k, v] : headers) { auto data = options.get_or<QString>("body", {});
request.setRawHeader(k.as<QString>().toUtf8(), v.as<QString>().toUtf8()); bool convertToTable
= options.get<std::optional<bool>>("convertToTable").value_or(false);
QNetworkRequest request((QUrl(url)));
if (headers && !headers.empty()) {
for (const auto &[k, v] : headers)
request.setRawHeader(k.as<QString>().toUtf8(), v.as<QString>().toUtf8());
} }
}
QNetworkReply *reply = nullptr; QNetworkReply *reply = nullptr;
if (method == "get") if (method == "get")
reply = Utils::NetworkAccessManager::instance()->get(request); reply = Utils::NetworkAccessManager::instance()->get(request);
else if (method == "post") else if (method == "post")
reply = Utils::NetworkAccessManager::instance()->post(request, data.toUtf8()); reply = Utils::NetworkAccessManager::instance()->post(request, data.toUtf8());
else else
throw std::runtime_error("Unknown method: " + method.toStdString()); throw std::runtime_error("Unknown method: " + method.toStdString());
if (convertToTable) { if (convertToTable) {
QObject::connect(reply, &QNetworkReply::finished, reply, [reply, thisState, callback]() { QObject::connect(
reply->deleteLater(); reply,
&QNetworkReply::finished,
&LuaEngine::instance(),
[reply, thisState, callback]() {
reply->deleteLater();
if (reply->error() != QNetworkReply::NoError) { if (reply->error() != QNetworkReply::NoError) {
callback(QString("%1 (%2)").arg(reply->errorString()).arg(reply->error())); callback(
return; QString("%1 (%2)").arg(reply->errorString()).arg(reply->error()));
} return;
}
QByteArray data = reply->readAll(); QByteArray data = reply->readAll();
QJsonParseError error; QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(data, &error); QJsonDocument doc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError) { if (error.error != QJsonParseError::NoError) {
callback(error.errorString()); callback(error.errorString());
return; return;
} }
if (doc.isObject()) { if (doc.isObject()) {
callback(LuaEngine::toTable(thisState, doc.object())); callback(LuaEngine::toTable(thisState, doc.object()));
} else if (doc.isArray()) { } else if (doc.isArray()) {
callback(LuaEngine::toTable(thisState, doc.array())); callback(LuaEngine::toTable(thisState, doc.array()));
} else { } else {
sol::state_view lua(thisState); sol::state_view lua(thisState);
callback(lua.create_table()); callback(lua.create_table());
} }
}); });
} else { } else {
QObject::connect(reply, &QNetworkReply::finished, reply, [reply, callback]() { QObject::connect(
// We don't want the network reply to be deleted by the manager, but reply, &QNetworkReply::finished, &LuaEngine::instance(), [reply, callback]() {
// by the Lua GC // We don't want the network reply to be deleted by the manager, but
reply->setParent(nullptr); // by the Lua GC
callback(std::unique_ptr<QNetworkReply>(reply)); reply->setParent(nullptr);
}); callback(std::unique_ptr<QNetworkReply>(reply));
} });
}; }
};
return fetch; fetch["fetch"] = wrap(fetch["fetch_cb"]);
});
LuaEngine::registerProvider("Fetch", [](sol::state_view lua) -> sol::object { return fetch;
return lua });
.script(
R"(
local f = require("__fetch")
local a = require("async")
return {
fetch_cb = f.fetch_cb,
fetch = a.wrap(f.fetch_cb)
}
)",
"_fetch_")
.get<sol::table>();
});
} }
} // namespace Lua::Internal } // namespace Lua::Internal