From 36c07e4a6f1fe4354a92a255f030e51be6385d0f Mon Sep 17 00:00:00 2001 From: Sander Speetjens Date: Sun, 25 Aug 2024 15:53:07 +0200 Subject: [PATCH] add websocket wrapper --- Qt/CMakeLists.txt | 7 +- Qt/web_socket_wrapper.cpp | 130 ++++++++++++++++++++++++++++++++++++++ Qt/web_socket_wrapper.h | 57 +++++++++++++++++ 3 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 Qt/web_socket_wrapper.cpp create mode 100644 Qt/web_socket_wrapper.h diff --git a/Qt/CMakeLists.txt b/Qt/CMakeLists.txt index 58b2353..75d313f 100644 --- a/Qt/CMakeLists.txt +++ b/Qt/CMakeLists.txt @@ -10,6 +10,8 @@ include(FetchContent) FetchContent_Declare(magic_enum URL https://github.com/Neargye/magic_enum/releases/download/v0.9.6/magic_enum-v0.9.6.tar.gz DOWNLOAD_EXTRACT_TIMESTAMP TRUE) FetchContent_MakeAvailable(magic_enum) +FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.2/json.tar.xz DOWNLOAD_EXTRACT_TIMESTAMP TRUE) +FetchContent_MakeAvailable(json) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -45,6 +47,9 @@ set(PROJECT_SOURCES networkerror.cpp networkerror.ui + web_socket_wrapper.h + web_socket_wrapper.cpp + mainwindow.h mainwindow.cpp mainwindow.ui @@ -79,7 +84,7 @@ target_include_directories(Simulator-CVS_I10 ${PROJECT_BINARY_DIR}/ ) -target_link_libraries(Simulator-CVS_I10 PRIVATE qwt Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::WebSockets) +target_link_libraries(Simulator-CVS_I10 PRIVATE qwt Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::WebSockets magic_enum::magic_enum nlohmann_json::nlohmann_json) # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. # If you are developing for iOS or macOS you should consider setting an diff --git a/Qt/web_socket_wrapper.cpp b/Qt/web_socket_wrapper.cpp new file mode 100644 index 0000000..444b2e3 --- /dev/null +++ b/Qt/web_socket_wrapper.cpp @@ -0,0 +1,130 @@ +#include "web_socket_wrapper.h" +#include "magic_enum.hpp" + +Web_socket_wrapper::Web_socket_wrapper(const QUrl &url, QObject *parent) : + QObject(parent), + m_web_socket(new QWebSocket("", QWebSocketProtocol::VersionLatest, this)) +{ + connect(m_web_socket, &QWebSocket::connected, this, &Web_socket_wrapper::m_on_connected); + connect(m_web_socket, &QWebSocket::disconnected, this, &Web_socket_wrapper::on_closed); + m_web_socket->open(url); +} + +Web_socket_wrapper::~Web_socket_wrapper() +{ + close(); +} + +void Web_socket_wrapper::send_command(Command command, QString id) +{ + json j; + switch (command) + { + case Command::get_UI_element: + j["command"]["type"] = magic_enum::enum_name(command).data(); + j["command"]["id"] = id.toStdString(); + m_web_socket->sendTextMessage(QString(j.dump().data())); + break; + case Command::get_UI_elements: + j["command"]["type"] = magic_enum::enum_name(command).data(); + m_web_socket->sendTextMessage(QString(j.dump().data())); + break; + case Command::get_active_simulator_name: + j["command"]["type"] = magic_enum::enum_name(command).data(); + m_web_socket->sendTextMessage(QString(j.dump().data())); + break; + case Command::get_simulators: + j["command"]["type"] = magic_enum::enum_name(command).data(); + m_web_socket->sendTextMessage(QString(j.dump().data())); + break; + case Command::switch_simulator: + j["command"]["type"] = magic_enum::enum_name(command).data(); + j["command"]["name"] = id.toStdString(); + m_web_socket->sendTextMessage(QString(j.dump().data())); + break; + default: + break; + } +} + +void Web_socket_wrapper::send_event(Event event, QString id) +{ + json j; + switch (event) + { + case Event::clicked: + j["event"]["type"] = magic_enum::enum_name(event).data(); + j["event"]["id"] = id.toStdString(); + m_web_socket->sendTextMessage(QString(j.dump().data())); + break; + default: + break; + } +} + +void Web_socket_wrapper::send_event(Event event, QString id, double val) +{ + json j; + switch (event) + { + case Event::value_changed: + j["event"]["type"] = magic_enum::enum_name(event).data(); + j["event"]["id"] = id.toStdString(); + j["event"]["value"] = val; + m_web_socket->sendTextMessage(QString(j.dump().data())); + break; + default: + break; + } +} + +void Web_socket_wrapper::send_event(Event event, QString id, QString val) +{ + json j; + switch (event) + { + case Event::text_changed: + j["event"]["type"] = magic_enum::enum_name(event).data(); + j["event"]["id"] = id.toStdString(); + j["event"]["text"] = val.toStdString(); + m_web_socket->sendTextMessage(QString(j.dump().data())); + break; + case Event::selected: + j["event"]["type"] = magic_enum::enum_name(event).data(); + j["event"]["id"] = id.toStdString(); + j["event"]["selected"] = val.toStdString(); + m_web_socket->sendTextMessage(QString(j.dump().data())); + break; + default: + break; + } +} + +void Web_socket_wrapper::close() +{ + if (m_connected) + m_web_socket->close(); +} + +void Web_socket_wrapper::m_on_connected() +{ + m_connected = true; + connect(m_web_socket, &QWebSocket::textMessageReceived, + this, &Web_socket_wrapper::m_on_received); + emit on_connected(); +} + +void Web_socket_wrapper::m_on_received(QString message) +{ + json j = json::parse(message.toStdString()); + if (j.contains("response")) + { + emit on_command_cb(j.at("response")); + return; + } + if (j.contains("event")) + { + emit on_event_cb(j.at("event")); + return; + } +} diff --git a/Qt/web_socket_wrapper.h b/Qt/web_socket_wrapper.h new file mode 100644 index 0000000..5c9c4d2 --- /dev/null +++ b/Qt/web_socket_wrapper.h @@ -0,0 +1,57 @@ +#ifndef WEB_SOCKET_WRAPPER_H +#define WEB_SOCKET_WRAPPER_H + +#include +#include +using json = nlohmann::json; + +class Web_socket_wrapper : public QObject +{ + Q_OBJECT + public: + enum class Command + { + get_UI_element, + get_UI_elements, + switch_simulator, + get_active_simulator_name, + get_simulators, + end, + begin = 0 + }; + + enum class Event + { + clicked, + value_changed, + text_changed, + selected, + ui_changed, + end, + begin = 0 + }; + public: + explicit Web_socket_wrapper(const QUrl &url, QObject *parent = nullptr); + ~Web_socket_wrapper(); + void send_command(Command command, QString id = QString()); + void send_event(Event event, QString id); + void send_event(Event event, QString id, double val); + void send_event(Event event, QString id, QString val); + void close(); + + Q_SIGNALS: + void on_connected(); + void on_closed(); + void on_command_cb(json& data); + void on_event_cb(json& data); + + private Q_SLOTS: + void m_on_connected(); + void m_on_received(QString message); + + private: + bool m_connected = false; + QWebSocket* m_web_socket; +}; + +#endif // WEB_SOCKET_WRAPPER_H