polling testing some further mainscreen tinkering

This commit is contained in:
Blue 2024-01-10 16:27:03 -03:00
parent 4694f3838f
commit 74701e9431
Signed by: blue
GPG Key ID: 9B203B252A63EE38
11 changed files with 233 additions and 40 deletions

View File

@ -40,7 +40,8 @@ API::API(const QUrl& address, QObject* parent):
state(NoServer),
accessToken(),
renewToken(),
firstPoll()
firstPoll(),
pollReply()
{
firstPoll.setSingleShot(true);
firstPoll.setInterval(2000);
@ -67,21 +68,8 @@ void API::startPolling() {
if (state != Authenticating)
throw std::runtime_error("Can not start polling in this state: " + std::to_string(state));
if (accessToken.isEmpty())
throw std::runtime_error("Can not start polling: access token is empty");
QByteArray authorizationHeader = "Bearer " + accessToken.toUtf8();
QNetworkRequest request(createUrl("/poll"));
request.setHeader(QNetworkRequest::ContentTypeHeader, json);
request.setRawHeader(QByteArray("Authorization"), authorizationHeader);
request.setTransferTimeout(30000);
sendPoll();
firstPoll.start();
QNetworkReply* reply = network.get(request);
connect(reply, &QNetworkReply::finished,
std::bind(&API::onPollFinished, this, reply)
);
}
void API::setAddress(const QUrl& path) {
@ -146,6 +134,24 @@ QUrl API::createUrl(const QString &path) const {
return url;
}
void API::sendPoll() {
if (accessToken.isEmpty())
throw std::runtime_error("Can not start polling: access token is empty");
QByteArray authorizationHeader = "Bearer " + accessToken.toUtf8();
QNetworkRequest request(createUrl("/poll"));
request.setHeader(QNetworkRequest::ContentTypeHeader, json);
request.setRawHeader("Authorization", authorizationHeader);
request.setTransferTimeout(30000);
pollReply = std::unique_ptr<QNetworkReply>(network.get(request));
connect(
pollReply.get(), &QNetworkReply::finished,
this, &API::onPollFinished,
Qt::QueuedConnection
);
}
void API::test(const QString& path, const QJSValue& finished) {
qDebug() << "Testing" << path;
if (state == Offline)
@ -218,7 +224,7 @@ void API::sendLogin(const QString& login, const QString& password, const QJSValu
setState(Authenticating);
QNetworkReply* reply = network.post(request, params.toString(QUrl::FullyEncoded).toUtf8());
connect(reply, &QNetworkReply::finished,
std::bind(&API::onLoginFinished, this, reply, finished)
std::bind(&API::onLoginFinished, this, reply, finished)
);
}
@ -283,19 +289,32 @@ void API::onLoginFinished(QNetworkReply* reply, const QJSValue& finished) {
startPolling();
}
void API::onPollFinished(QNetworkReply *reply) {
void API::onPollFinished() {
firstPoll.stop();
std::unique_ptr<QNetworkReply, NetworkReplyDeleter> rpl(reply);
QNetworkReply::NetworkError error = reply->error();
std::optional<QVariantMap> data = readResult(reply);
QNetworkReply::NetworkError error = pollReply->error();
std::optional<QVariantMap> data = readResult(pollReply.get());
Codes::Poll code = Codes::Poll::unknownError;
if (validateResponse(data, resultStructure))
code = Codes::convertPoll(data->value("result").toInt());
QString detail = Codes::description(code);
if (error != QNetworkReply::NoError)
qDebug() << reply->errorString();
qDebug() << pollReply->errorString() + ": " + detail;
else
qDebug() << "Poll finished: " + detail;
if (data)
qDebug() << data.value();
setState(NotAuthenticated);
switch (code) {
case Codes::Poll::success:
//todo handle the result
case Codes::Poll::timeout:
return sendPoll();
case Codes::Poll::tokenProblem:
case Codes::Poll::replace:
case Codes::Poll::unknownError: //todo this one doesn't actually mean that we can't work for now, the network may be temporarily down or something
pollReply.reset();
return setState(NotAuthenticated);
}
}
void API::onFirstPollSuccess() {

View File

@ -56,7 +56,7 @@ private slots:
void onTestFinished(QNetworkReply* reply, const QUrl& addr, const QJSValue& finished);
void onRegisterFinished(QNetworkReply* reply, const QJSValue& finished) const;
void onLoginFinished(QNetworkReply* reply, const QJSValue& finished);
void onPollFinished(QNetworkReply* reply);
void onPollFinished();
void onFirstPollSuccess();
@ -67,6 +67,7 @@ private:
static bool validateResponse(const std::optional<QVariantMap>& data, const std::map<QString, QMetaType::Type>& structure);
void setState(State newState);
QUrl createUrl(const QString& path) const;
void sendPoll();
private:
QUrl address;
@ -75,4 +76,5 @@ private:
QString accessToken;
QString renewToken;
QTimer firstPoll;
std::unique_ptr<QNetworkReply> pollReply;
};

View File

@ -27,6 +27,14 @@ constexpr std::array<const char*, uint8_t(Codes::Login::unknownError) + 1> login
"Unknown login error"
});
constexpr std::array<const char*, uint8_t(Codes::Poll::unknownError) + 1> pollErrors({
"New data from poll",
"Couldn't authorize polling: token error",
"Other device was authorized with the same token",
"Poll timeout, no new data",
"Unknown poll error"
});
Codes::Register Codes::convertRegister (int source) {
if (source < 0) {
std::cerr << "Converting Register response code which is smaller than zero, falling back to unknownError" << std::endl;
@ -62,3 +70,21 @@ Codes::Login Codes::convertLogin(int source) {
QString Codes::description(Login code) {
return loginErrors[(uint8_t)code];
}
Codes::Poll Codes::convertPoll(int source) {
if (source < 0) {
std::cerr << "Converting Poll response code which is smaller than zero, falling back to unknownError" << std::endl;
return Poll::unknownError;
}
if (source > (int)Poll::unknownError) {
std::cerr << "Converting Poll response code which is bigger than biggest known, falling back to unknownError" << std::endl;
return Poll::unknownError;
}
return static_cast<Poll>(source);
}
QString Codes::description(Poll code) {
return pollErrors[(uint8_t)code];
}

View File

@ -28,10 +28,20 @@ enum class Login {
unknownError
};
enum class Poll {
success,
tokenProblem,
replace,
timeout,
unknownError
};
Register convertRegister (int source);
Login convertLogin (int source);
Poll convertPoll (int source);
QString description (Register code);
QString description (Login code);
QString description (Poll code);
}

View File

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: 2023 Yury Gubich <blue@macaw.me>
// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick
import QtQuick.Controls
Item {
Label {
anchors.centerIn: parent
text: "This is Assets screen"
font {
pixelSize: 24
bold: true
}
}
}

View File

@ -10,6 +10,10 @@ qt_add_qml_module(magpieApplication
NO_PLUGIN
QML_FILES
Root.qml
Main.qml
Home.qml
Assets.qml
Records.qml
)
target_link_libraries(magpie PRIVATE magpieApplication)

16
qml/Application/Home.qml Normal file
View File

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: 2023 Yury Gubich <blue@macaw.me>
// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick
import QtQuick.Controls
Item {
Label {
anchors.centerIn: parent
text: "This is a Home screen"
font {
pixelSize: 24
bold: true
}
}
}

81
qml/Application/Main.qml Normal file
View File

@ -0,0 +1,81 @@
// SPDX-FileCopyrightText: 2023 Yury Gubich <blue@macaw.me>
// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Item {
property string currentPage: "home"
RowLayout {
anchors.fill: parent
Column {
id: menu
Layout.fillWidth: true
Layout.minimumWidth: 50
Layout.preferredWidth: 100
Layout.maximumWidth: 100
Layout.alignment: Qt.AlignTop
MenuItem {
width: parent.width
text: qsTr("Home")
icon.name: "home"
highlighted: currentPage === "home"
onTriggered: {
if (!this.highlighted)
content.replace(home)
}
}
MenuItem {
width: parent.width
text: qsTr("Assets")
icon.name: "document-properties"
highlighted: currentPage === "assets"
onTriggered: {
if (!this.highlighted)
content.replace(assets)
}
}
MenuItem {
width: parent.width
text: qsTr("Records")
icon.name: "system-search"
highlighted: currentPage === "records"
onTriggered: {
if (!this.highlighted)
content.replace(records)
}
}
}
StackView {
id: content
initialItem: home
Layout.fillWidth: true
Layout.fillHeight: true
Component {
id: home
Home {
StackView.onActivating: currentPage = "home"
}
}
Component {
id: assets
Assets {
StackView.onActivating: currentPage = "assets"
}
}
Component {
id: records
Records {
StackView.onActivating: currentPage = "records"
}
}
}
}
}

View File

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: 2023 Yury Gubich <blue@macaw.me>
// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick
import QtQuick.Controls
Item {
Label {
anchors.centerIn: parent
text: "This is Records screen"
font {
pixelSize: 24
bold: true
}
}
}

View File

@ -4,13 +4,17 @@
import QtQuick
import QtQuick.Controls
Page {
Label {
anchors.centerIn: parent
text: "Here we go!"
font {
pixelSize: 24
bold: true
Item {
StackView {
id: stack
initialItem: main
anchors.fill: parent
}
Component {
id: main
Main {
}
}
}

View File

@ -13,17 +13,13 @@ import magpie.Application as Application
ApplicationWindow {
property int counter: 0
property bool pickingServer: false
property bool runningApp: false
width: 640
height: 480
visible: true
title: "Magpie"
header: Label {
text: stack.currentItem.title
horizontalAlignment: Text.AlignHCenter
}
StackView {
id: stack
initialItem: welcome
@ -49,7 +45,8 @@ ApplicationWindow {
Component {
id: app
Application.Root {
StackView.onActivating: runningApp = true;
StackView.onDeactivating: runningApp = false;
}
}
}
@ -62,7 +59,9 @@ ApplicationWindow {
}
function onStateChanged (state) {
if (state === API.Authenticated)
stack.push(app)
stack.push(app);
else if (runningApp && state === API.NotAuthenticated)
stack.pop();
}
}
}