Initial backend with MQTT support
This commit is contained in:
@@ -11,18 +11,20 @@ set(CMAKE_AUTOMOC ON)
|
|||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
set(CMAKE_AUTOUIC ON)
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
find_package(Qt6 COMPONENTS Widgets Qml QuickControls2 REQUIRED)
|
find_package(Qt6 COMPONENTS Widgets Qml QuickControls2 Mqtt REQUIRED)
|
||||||
|
|
||||||
add_executable(${PROJECT}
|
add_executable(${PROJECT}
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/FileIO.cpp
|
src/FileIO.cpp
|
||||||
|
src/Backend.cpp
|
||||||
src/resources.qrc
|
src/resources.qrc
|
||||||
src/Gui/Style/resources.qrc)
|
src/Gui/Style/resources.qrc)
|
||||||
|
|
||||||
target_link_libraries(${PROJECT}
|
target_link_libraries(${PROJECT}
|
||||||
Qt::Widgets
|
Qt::Widgets
|
||||||
Qt::Qml
|
Qt::Qml
|
||||||
Qt::QuickControls2)
|
Qt::QuickControls2
|
||||||
|
Qt::Mqtt)
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||||
set_property(TARGET ${PROJECT} PROPERTY WIN32_EXECUTABLE true)
|
set_property(TARGET ${PROJECT} PROPERTY WIN32_EXECUTABLE true)
|
||||||
|
|||||||
62
src/Backend.cpp
Normal file
62
src/Backend.cpp
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* @file Backend.cpp
|
||||||
|
* @author Juny <marisa@fwmari.net>
|
||||||
|
* @brief Implementation of backend module for QML
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2024-02-13
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Backend.hpp"
|
||||||
|
|
||||||
|
void Backend::registerTypes(const char *uri) {
|
||||||
|
qmlRegisterType<Backend>(uri, 0, 1, "Backend");
|
||||||
|
}
|
||||||
|
Backend::Backend(QObject *parent) : QObject(parent) {
|
||||||
|
this->m_client = new QMqttClient(this);
|
||||||
|
|
||||||
|
connect(this->m_client, &QMqttClient::hostnameChanged, this,
|
||||||
|
&Backend::brokerHostChanged);
|
||||||
|
connect(this->m_client, &QMqttClient::portChanged, this,
|
||||||
|
&Backend::brokerPortChanged);
|
||||||
|
connect(this->m_client, &QMqttClient::stateChanged, this,
|
||||||
|
&Backend::brokerStateChanged);
|
||||||
|
connect(this->m_client, &QMqttClient::stateChanged, this,
|
||||||
|
&Backend::onBrokerStateChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::connectToBroker() { this->m_client->connectToHost(); }
|
||||||
|
void Backend::disconnectFromBroker() { this->m_client->disconnectFromHost(); }
|
||||||
|
|
||||||
|
const QString Backend::brokerHost() const { return this->m_client->hostname(); }
|
||||||
|
void Backend::setBrokerHost(const QString &host) {
|
||||||
|
this->m_client->setHostname(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Backend::brokerPort() const { return this->m_client->port(); }
|
||||||
|
void Backend::setBrokerPort(int port) {
|
||||||
|
if (port < 0 || port > std::numeric_limits<quint16>::max()) {
|
||||||
|
qWarning() << "Invalid port: " << port;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_client->setPort(static_cast<quint16>(port));
|
||||||
|
}
|
||||||
|
|
||||||
|
const QMqttClient::ClientState Backend::brokerState() const {
|
||||||
|
return this->m_client->state();
|
||||||
|
}
|
||||||
|
void Backend::setBrokerState(const QMqttClient::ClientState &state) {
|
||||||
|
this->m_client->setState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::onBrokerStateChanged(const QMqttClient::ClientState &state) {
|
||||||
|
qWarning() << "State change" << state;
|
||||||
|
|
||||||
|
if (state != QMqttClient::Connected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: subscribe
|
||||||
|
}
|
||||||
61
src/Backend.hpp
Normal file
61
src/Backend.hpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* @file Backend.hpp
|
||||||
|
* @author Juny <marisa@fwmari.net>
|
||||||
|
* @brief Backend module for QML
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2024-02-13
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QMqttClient>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QtQml>
|
||||||
|
|
||||||
|
class Backend : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QString brokerHost READ brokerHost WRITE setBrokerHost NOTIFY
|
||||||
|
brokerHostChanged)
|
||||||
|
Q_PROPERTY(int brokerPort READ brokerPort WRITE setBrokerPort NOTIFY
|
||||||
|
brokerPortChanged)
|
||||||
|
Q_PROPERTY(QMqttClient::ClientState brokerState READ brokerState WRITE
|
||||||
|
setBrokerState NOTIFY brokerStateChanged)
|
||||||
|
QML_NAMED_ELEMENT(Backend)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Backend(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
static void registerTypes(const char *uri);
|
||||||
|
static QObject *singletonProvider(QQmlEngine *engine, QJSEngine *);
|
||||||
|
|
||||||
|
// QML functions
|
||||||
|
|
||||||
|
Q_INVOKABLE void connectToBroker();
|
||||||
|
Q_INVOKABLE void disconnectFromBroker();
|
||||||
|
|
||||||
|
// QML Properties
|
||||||
|
|
||||||
|
const QString brokerHost() const;
|
||||||
|
void setBrokerHost(const QString &host);
|
||||||
|
|
||||||
|
int brokerPort() const;
|
||||||
|
void setBrokerPort(int port);
|
||||||
|
|
||||||
|
const QMqttClient::ClientState brokerState() const;
|
||||||
|
void setBrokerState(const QMqttClient::ClientState &state);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void brokerHostChanged();
|
||||||
|
void brokerPortChanged();
|
||||||
|
void brokerStateChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onBrokerStateChanged(const QMqttClient::ClientState &state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(Backend)
|
||||||
|
QMqttClient *m_client;
|
||||||
|
};
|
||||||
@@ -4,12 +4,12 @@ import QtQuick
|
|||||||
|
|
||||||
import "Settings"
|
import "Settings"
|
||||||
|
|
||||||
QtObject {
|
import QSpec.Backend
|
||||||
|
|
||||||
|
Backend {
|
||||||
id: app
|
id: app
|
||||||
|
|
||||||
property string brokerURL: Settings._json.brokerURL || ""
|
property string brokerURL: Settings._json.brokerURL || ""
|
||||||
property string brokerHost
|
|
||||||
property string brokerPort
|
|
||||||
|
|
||||||
property string brokerUsername: Settings._json.brokerUsername || ""
|
property string brokerUsername: Settings._json.brokerUsername || ""
|
||||||
property string brokerPassword: Settings._json.brokerPassword || ""
|
property string brokerPassword: Settings._json.brokerPassword || ""
|
||||||
@@ -19,11 +19,13 @@ QtObject {
|
|||||||
brokerPort = brokerURL.split(":")[1] || 1883
|
brokerPort = brokerURL.split(":")[1] || 1883
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveBroker(url, user, pass) {
|
function tryConnect(url, user, pass) {
|
||||||
Settings._json.brokerURL = url
|
brokerURL = Settings._json.brokerURL = url
|
||||||
Settings._json.brokerUsername = user
|
brokerUsername = Settings._json.brokerUsername = user
|
||||||
Settings._json.brokerPassword = pass
|
brokerPassword = Settings._json.brokerPassword = pass
|
||||||
Settings.save()
|
Settings.save()
|
||||||
|
|
||||||
|
connectToBroker()
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup() {
|
function setup() {
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ ColumnLayout {
|
|||||||
|
|
||||||
signal tryConnect(url: string, username: string, password: string)
|
signal tryConnect(url: string, username: string, password: string)
|
||||||
|
|
||||||
|
Component.onCompleted: checkUrl(brokerURL.tfText)
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: focusTimer
|
id: focusTimer
|
||||||
running: true
|
running: true
|
||||||
@@ -40,19 +42,7 @@ ColumnLayout {
|
|||||||
tfText: App.brokerURL || ""
|
tfText: App.brokerURL || ""
|
||||||
|
|
||||||
onTfAccepted: _tryConnect()
|
onTfAccepted: _tryConnect()
|
||||||
|
onTfChanged: (text) => checkUrl(text)
|
||||||
onTfChanged: (text) => {
|
|
||||||
let url;
|
|
||||||
|
|
||||||
try {
|
|
||||||
url = new URL(`https://${text}`)
|
|
||||||
} catch (_) {
|
|
||||||
btn.enabled = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
btn.enabled = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +74,7 @@ ColumnLayout {
|
|||||||
id: btn
|
id: btn
|
||||||
text: qsTr("Connect")
|
text: qsTr("Connect")
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
// enabled: false
|
enabled: false
|
||||||
|
|
||||||
onClicked: _tryConnect()
|
onClicked: _tryConnect()
|
||||||
}
|
}
|
||||||
@@ -92,4 +82,22 @@ ColumnLayout {
|
|||||||
function _tryConnect() {
|
function _tryConnect() {
|
||||||
tryConnect(brokerURL.tfText, brokerUsername.tfText, brokerPassword.tfText)
|
tryConnect(brokerURL.tfText, brokerUsername.tfText, brokerPassword.tfText)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkUrl(text) {
|
||||||
|
let url;
|
||||||
|
|
||||||
|
if (text == "") {
|
||||||
|
btn.enabled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
url = new URL(`https://${text}`)
|
||||||
|
} catch (_) {
|
||||||
|
btn.enabled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.enabled = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ PStackView {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
||||||
onTryConnect: (url, user, pass) => {
|
onTryConnect: (url, user, pass) => {
|
||||||
App.saveBroker(url, user, pass)
|
App.tryConnect(url, user, pass)
|
||||||
login.push(loadInstance)
|
login.push(loadInstance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ pragma Singleton
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtCore
|
import QtCore
|
||||||
|
|
||||||
import QSpec
|
import QSpec.FileIO
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
property string configDir: StandardPaths.writableLocation(StandardPaths.AppConfigLocation)
|
property string configDir: StandardPaths.writableLocation(StandardPaths.AppConfigLocation)
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ Window {
|
|||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
App.setup()
|
App.setup()
|
||||||
loadingTimer.running = true
|
loadingTimer.running = true
|
||||||
|
|
||||||
|
App.brokerStateChanged.connect(() => {
|
||||||
|
if (App.brokerState == 2)
|
||||||
|
connectTimer.running = true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
@@ -23,11 +28,21 @@ Window {
|
|||||||
|
|
||||||
running: false
|
running: false
|
||||||
repeat: false
|
repeat: false
|
||||||
interval: 500
|
interval: 750
|
||||||
|
|
||||||
onTriggered: loader.source = "qrc:/Login/Login.qml"
|
onTriggered: loader.source = "qrc:/Login/Login.qml"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: connectTimer
|
||||||
|
|
||||||
|
running: false
|
||||||
|
repeat: false
|
||||||
|
interval: 750
|
||||||
|
|
||||||
|
onTriggered: loader.sourceComponent = mainPane
|
||||||
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: loader
|
id: loader
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -55,4 +70,15 @@ Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: mainPane
|
||||||
|
|
||||||
|
PBackground {
|
||||||
|
PText {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: qsTr("YAAAAY I AM CONNECTED")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <QQuickStyle>
|
#include <QQuickStyle>
|
||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
|
|
||||||
|
#include "Backend.hpp"
|
||||||
#include "FileIO.hpp"
|
#include "FileIO.hpp"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
@@ -35,7 +36,8 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
QObject::connect(engine, &QQmlEngine::quit, &QApplication::quit);
|
QObject::connect(engine, &QQmlEngine::quit, &QApplication::quit);
|
||||||
|
|
||||||
FileIO::registerTypes("QSpec");
|
FileIO::registerTypes("QSpec.FileIO");
|
||||||
|
Backend::registerTypes("QSpec.Backend");
|
||||||
|
|
||||||
engine->addImportPath("qrc:/");
|
engine->addImportPath("qrc:/");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user