polling testing some further mainscreen tinkering
This commit is contained in:
parent
4694f3838f
commit
74701e9431
67
API/api.cpp
67
API/api.cpp
@ -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)
|
||||
@ -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() {
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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];
|
||||
}
|
||||
|
10
API/codes.h
10
API/codes.h
@ -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);
|
||||
|
||||
}
|
||||
|
16
qml/Application/Assets.qml
Normal file
16
qml/Application/Assets.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
@ -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
16
qml/Application/Home.qml
Normal 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
81
qml/Application/Main.qml
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
16
qml/Application/Records.qml
Normal file
16
qml/Application/Records.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
qml/main.qml
13
qml/main.qml
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user