Axivion: Begin to use QNetworkAccessManager instead of curl for HTTP

Change-Id: I2fd7ba2a72e749bdc5407d222057cb66ff341b04
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Andreas Loth
2023-08-29 15:42:08 +02:00
parent 4cd48c84ae
commit 5f02cadeab
6 changed files with 143 additions and 29 deletions

View File

@@ -13,4 +13,5 @@ add_qtc_plugin(Axivion
axiviontr.h
dashboard/dto.cpp dashboard/dto.h
dashboard/concat.cpp dashboard/concat.h
dashboard/dashboardclient.cpp dashboard/dashboardclient.h
)

View File

@@ -26,6 +26,8 @@ QtcPlugin {
"axivionsettings.cpp",
"axivionsettings.h",
"axiviontr.h",
"dashboard/dashboardclient.cpp",
"dashboard/dashboardclient.h",
]
cpp.includePaths: base.concat(["."]) // needed for the generated stuff below

View File

@@ -8,6 +8,7 @@
#include "axivionquery.h"
#include "axivionresultparser.h"
#include "axiviontr.h"
#include "dashboard/dashboardclient.h"
#include "dashboard/dto.h"
#include <coreplugin/editormanager/documentmodel.h>
@@ -26,10 +27,12 @@
#include <texteditor/textmark.h>
#include <utils/expected.h>
#include <utils/networkaccessmanager.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
#include <QAction>
#include <QFutureWatcher>
#include <QTimer>
#include <exception>
@@ -44,7 +47,7 @@ class AxivionPluginPrivate : public QObject
public:
void onStartupProjectChanged();
void fetchProjectInfo(const QString &projectName);
void handleProjectInfo(const QByteArray &result);
void handleProjectInfo(Utils::expected_str<Dto::ProjectInfoDto> rawInfo);
void handleOpenedDocs(ProjectExplorer::Project *project);
void onDocumentOpened(Core::IDocument *doc);
void onDocumentClosed(Core::IDocument * doc);
@@ -52,6 +55,7 @@ public:
void handleIssuesForFile(const IssuesList &issues);
void fetchRuleInfo(const QString &id);
Utils::NetworkAccessManager *m_networkAccessManager = Utils::NetworkAccessManager::instance();
AxivionOutputPane m_axivionOutputPane;
std::shared_ptr<const Dto::ProjectInfoDto> m_currentProjectInfo;
bool m_runningQuery = false;
@@ -151,14 +155,16 @@ void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName)
return;
}
m_runningQuery = true;
AxivionQuery query(AxivionQuery::ProjectInfo, {projectName});
AxivionQueryRunner *runner = new AxivionQueryRunner(query, this);
connect(runner, &AxivionQueryRunner::resultRetrieved, this, [this](const QByteArray &result){
handleProjectInfo(result);
});
connect(runner, &AxivionQueryRunner::finished, [runner]{ runner->deleteLater(); });
runner->start();
DashboardClient client { *this->m_networkAccessManager };
QFuture<DashboardClient::RawProjectInfo> response = client.fetchProjectInfo(projectName);
auto responseWatcher = std::make_shared<QFutureWatcher<DashboardClient::RawProjectInfo>>();
connect(responseWatcher.get(),
&QFutureWatcher<DashboardClient::RawProjectInfo>::finished,
this,
[this, responseWatcher]() {
handleProjectInfo(responseWatcher->result());
});
responseWatcher->setFuture(response);
}
void AxivionPluginPrivate::fetchRuleInfo(const QString &id)
@@ -201,15 +207,14 @@ void AxivionPluginPrivate::clearAllMarks()
onDocumentClosed(doc);
}
void AxivionPluginPrivate::handleProjectInfo(const QByteArray &result)
void AxivionPluginPrivate::handleProjectInfo(Utils::expected_str<Dto::ProjectInfoDto> rawInfo)
{
Utils::expected_str<Dto::ProjectInfoDto> raw_info = ResultParser::parseProjectInfo(result);
m_runningQuery = false;
if (!raw_info) {
Core::MessageManager::writeFlashing(QStringLiteral(u"Axivion: ") + raw_info.error());
if (!rawInfo) {
Core::MessageManager::writeFlashing(QStringLiteral(u"Axivion: ") + rawInfo.error());
return;
}
m_currentProjectInfo = std::make_shared<const Dto::ProjectInfoDto>(std::move(raw_info.value()));
m_currentProjectInfo = std::make_shared<const Dto::ProjectInfoDto>(std::move(rawInfo.value()));
m_axivionOutputPane.updateDashboard();
// handle already opened documents
if (auto buildSystem = ProjectExplorer::ProjectManager::startupBuildSystem();

View File

@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "axivionresultparser.h"
#include "dashboard/dto.h"
#include <utils/qtcassert.h>
@@ -120,20 +119,6 @@ DashboardInfo parseDashboardInfo(const QByteArray &input)
return result;
}
Utils::expected_str<Dto::ProjectInfoDto> parseProjectInfo(const QByteArray &input)
{
auto [header, body] = splitHeaderAndBody(input);
auto [error, doc] = prehandleHeaderAndBody(header, body);
if (!error.error.isEmpty())
return tl::make_unexpected(std::move(error.error));
try
{
return { Dto::ProjectInfoDto::deserialize(body) };
} catch (const Dto::invalid_dto_exception &e) {
return tl::make_unexpected(QString::fromUtf8(e.what()));
}
}
static QRegularExpression issueCsvLineRegex(const QByteArray &firstCsvLine)
{
QString pattern = "^";

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2022-current by Axivion GmbH
* https://www.axivion.com/
*
* SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
*/
#include "dashboardclient.h"
#include "axivionsettings.h"
#include <QByteArray>
#include <QCoreApplication>
#include <QLatin1String>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <memory>
namespace Axivion::Internal
{
DashboardClient::DashboardClient(Utils::NetworkAccessManager &networkAccessManager)
: m_networkAccessManager(networkAccessManager)
{
}
static void deleteLater(QObject *obj)
{
obj->deleteLater();
}
using RawBody = Utils::expected_str<QByteArray>;
class RawBodyReader final
{
public:
RawBodyReader(std::shared_ptr<QNetworkReply> reply)
: m_reply(std::move(reply))
{ }
~RawBodyReader() { }
RawBody operator()()
{
QNetworkReply::NetworkError error = m_reply->error();
if (error != QNetworkReply::NetworkError::NoError)
return tl::make_unexpected(QString::number(error)
+ QLatin1String(": ")
+ m_reply->errorString());
return m_reply->readAll();
}
private:
std::shared_ptr<QNetworkReply> m_reply;
};
template<typename T>
static Utils::expected_str<T> RawBodyParser(RawBody rawBody)
{
if (!rawBody)
return tl::make_unexpected(std::move(rawBody.error()));
try {
return { T::deserialize(rawBody.value()) };
} catch (const Dto::invalid_dto_exception &e) {
return tl::make_unexpected(QString::fromUtf8(e.what()));
}
}
QFuture<DashboardClient::RawProjectInfo> DashboardClient::fetchProjectInfo(const QString &projectName)
{
const AxivionServer &server = settings().server;
QUrl url { server.dashboard + QStringLiteral(u"/api/projects/") + QUrl::toPercentEncoding(projectName) };
QNetworkRequest request{ url };
request.setRawHeader(QByteArrayLiteral(u8"Authorization"),
QByteArrayLiteral(u8"AxToken ") + server.token.toUtf8());
QByteArray ua = QByteArrayLiteral(u8"Axivion")
+ QCoreApplication::applicationName().toUtf8()
+ QByteArrayLiteral(u8"Plugin/")
+ QCoreApplication::applicationVersion().toUtf8();
request.setRawHeader(QByteArrayLiteral(u8"X-Axivion-User-Agent"), ua);
std::shared_ptr<QNetworkReply> reply{ this->m_networkAccessManager.get(request), deleteLater };
return QtFuture::connect(reply.get(), &QNetworkReply::finished)
.then(RawBodyReader(reply))
.then(QtFuture::Launch::Async, &RawBodyParser<Dto::ProjectInfoDto>);
}
}

View File

@@ -0,0 +1,33 @@
#pragma once
/*
* Copyright (C) 2022-current by Axivion GmbH
* https://www.axivion.com/
*
* SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
*/
#include "dashboard/dto.h"
#include <utils/expected.h>
#include <utils/networkaccessmanager.h>
#include <QFuture>
namespace Axivion::Internal
{
class DashboardClient
{
public:
using RawProjectInfo = Utils::expected_str<Dto::ProjectInfoDto>;
DashboardClient(Utils::NetworkAccessManager &networkAccessManager);
QFuture<RawProjectInfo> fetchProjectInfo(const QString &projectName);
private:
Utils::NetworkAccessManager &m_networkAccessManager;
};
} // namespace Axivion::Internal