From 08fd5407c30e0d0f3a99442fbcd7cd19b0572706 Mon Sep 17 00:00:00 2001 From: Sander Speetjens Date: Tue, 19 May 2026 11:10:34 +0200 Subject: [PATCH] server update websocket updated to use protobuf not quite finished with the Websocket message parser --- server/CMakeLists.txt | 1 + server/message_parser.cpp | 223 ++++++++++++++++++------------------- server/simulator_base.cpp | 12 +- server/simulator_base.hpp | 32 ++---- server/simulators.cpp | 91 +++++++-------- server/simulators.hpp | 33 +++--- server/simulators/test.cpp | 12 +- server/websocket.cpp | 26 ++++- server/websocket.hpp | 10 +- 9 files changed, 220 insertions(+), 220 deletions(-) diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 644151e..3a54ab4 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -57,6 +57,7 @@ target_sources(server_common target_link_libraries(server_common PUBLIC UI + proto-ui spdlog cpp_templates ${GPIOD_LIB} diff --git a/server/message_parser.cpp b/server/message_parser.cpp index 6b4196a..6f6520b 100644 --- a/server/message_parser.cpp +++ b/server/message_parser.cpp @@ -3,131 +3,126 @@ #include #include -QString Simulators::message_parser(QString message) +// TODO: Fix parsing messages +QByteArray Simulators::message_parser(QByteArray message) { - json j = json::parse(message.toStdString()); - if (j.contains("command")) + Event_m event_m; + bool event = m_serializer.deserialize(&event_m, message); + // if (j.contains("command")) + // { + // return QString::fromStdString(command_parser(j["command"]).dump()); + // } + /*else*/ if (event) { - return QString::fromStdString(command_parser(j["command"]).dump()); + event_handler(event_m); } - else if (j.contains("event")) - { - event_handler(j["event"]); - } - return "{}"; + return QByteArray(); } -json Simulators::command_parser(json command) +// QByteArray Simulators::command_parser(json command) +// { +// json j = "{}"_json; +// try +// { +// std::string type = command.at("type"); +// Command cmd = magic_enum::enum_cast(type).value_or(Command::end); +// switch (cmd) +// { +// case Command::get_UI_element: +// SPDLOG_INFO("Command {}: {}", type, (size_t)command.at("id")); +// if (is_not_active()) +// { +// SPDLOG_ERROR("Command got called but there is no active simulator"); +// return j; +// } +// j["response"]["type"] = type; +// j["response"]["UI_item"] = +// invoke_active_simulator()->get_UI_item(command.at("id"))->to_json(command.at("id")); +// break; +// case Command::get_UI_elements: +// SPDLOG_INFO("Command {}", type); +// if (is_not_active()) +// { +// SPDLOG_ERROR("Command got called but there is no active simulator"); +// return j; +// } +// j["response"]["type"] = type; +// j["response"]["UI_items"] = invoke_active_simulator()->get_UI_items()["UI_items"]; +// break; +// case Command::switch_simulator: +// SPDLOG_INFO("Command {} to {}", type, std::string(command.at("name"))); +// switch_simulator(command.at("name")); +// j["response"]["type"] = type; +// break; +// case Command::get_active_simulator_name: +// SPDLOG_INFO("Command {}", type); +// j["response"]["type"] = type; +// j["response"]["name"] = active_simulator_name(); +// break; +// case Command::get_simulators: +// SPDLOG_INFO("Command {}", type); +// j["response"]["type"] = type; +// j["response"]["simulators"] = list_simulators(); +// break; +// default: +// break; +// } +// } +// catch (const json::exception &e) +// { +// SPDLOG_ERROR("{} {}", __FUNCTION__, e.what()); +// } + +// return j; +// } + +void Simulators::event_handler(Event_m event) { - json j = "{}"_json; - try + if (invoke_active_simulator() == nullptr) { - std::string type = command.at("type"); - Command cmd = magic_enum::enum_cast(type).value_or(Command::end); - switch (cmd) - { - case Command::get_UI_element: - SPDLOG_INFO("Command {}: {}", type, (size_t)command.at("id")); - if (is_not_active()) - { - SPDLOG_ERROR("Command got called but there is no active simulator"); - return j; - } - j["response"]["type"] = type; - j["response"]["UI_item"] = - invoke_active_simulator()->get_UI_item(command.at("id"))->to_json(command.at("id")); - break; - case Command::get_UI_elements: - SPDLOG_INFO("Command {}", type); - if (is_not_active()) - { - SPDLOG_ERROR("Command got called but there is no active simulator"); - return j; - } - j["response"]["type"] = type; - j["response"]["UI_items"] = invoke_active_simulator()->get_UI_items()["UI_items"]; - break; - case Command::switch_simulator: - SPDLOG_INFO("Command {} to {}", type, std::string(command.at("name"))); - switch_simulator(command.at("name")); - j["response"]["type"] = type; - break; - case Command::get_active_simulator_name: - SPDLOG_INFO("Command {}", type); - j["response"]["type"] = type; - j["response"]["name"] = active_simulator_name(); - break; - case Command::get_simulators: - SPDLOG_INFO("Command {}", type); - j["response"]["type"] = type; - j["response"]["simulators"] = list_simulators(); - break; - default: - break; - } - } - catch (const json::exception &e) - { - SPDLOG_ERROR("{} {}", __FUNCTION__, e.what()); + SPDLOG_ERROR("Event got called but there is no active simulator"); + return; } - return j; -} + QString type; // = QString::fromStdString(magic_enum::enum_cast(event.kindField()).value_or(Event_m::KindFields::UninitializedField)); -void Simulators::event_handler(json event) -{ - try + switch (event.kindField()) { - std::string type = event.at("type"); - Event e = magic_enum::enum_cast(type).value_or(Event::end); - if (invoke_active_simulator() == nullptr) - { - SPDLOG_ERROR("Event got called but there is no active simulator"); - return; - } - - switch (e) - { - case Event::clicked: { - SPDLOG_DEBUG("Event {}: {}", type, (size_t)event.at("id")); - invoke_active_simulator()->get_UI_item(event.at("id"))->click(); - break; - } - case Event::value_changed: { - SPDLOG_DEBUG("Event {}: {} {}", type, (size_t)event.at("id"), (double)(event["value"])); - invoke_active_simulator()->get_UI_item(event.at("id"))->set_value((double)event.at("value")); - break; - } - case Event::text_changed: { - SPDLOG_DEBUG("Event {}: {} {}", type, (size_t)event.at("id"), std::string(event.at("text"))); - invoke_active_simulator()->get_UI_item(event.at("id"))->set_text(std::string(event.at("text"))); - break; - } - case Event::selected: { - SPDLOG_DEBUG("Event {}: {} {}", type, (size_t)event.at("id"), std::to_string((size_t)event.at("selected"))); - invoke_active_simulator()->get_UI_item(event.at("id"))->set_selected(event.at("selected")); - break; - } - case Event::can_send: { - SPDLOG_DEBUG("Event {}: {}", type, (size_t)event.at("id")); - invoke_active_simulator() - ->get_UI_item(event.at("id")) - ->can_send((uint32_t)event.at("sid"), (uint8_t)event.at("dlc"), - (std::array)event.at("payload")); - break; - } - case Event::clear: { - SPDLOG_DEBUG("Event {}: {}", type, (size_t)event.at("id")); - invoke_active_simulator()->get_UI_item(event.at("id"))->clear(); - break; - } - default: { - break; - } - } + case Event_m::KindFields::Clicked: { + SPDLOG_DEBUG("Event {}: {}", type, (size_t)event.id_proto()); + invoke_active_simulator()->get_UI_item(event.id_proto())->click(); + break; + } + case Event_m::KindFields::ValueChanged: { + SPDLOG_DEBUG("Event {}: {} {}", type, event.id_proto(), event.valueChanged().value()); + invoke_active_simulator()->get_UI_item(event.id_proto())->set_value(event.valueChanged().value()); + break; + } + case Event_m::KindFields::TextChanged: { + SPDLOG_DEBUG("Event {}: {} {}", type, event.id_proto(), event.textChanged().text()); + invoke_active_simulator()->get_UI_item(event.id_proto())->set_text(event.textChanged().text()); + break; + } + case Event_m::KindFields::Selected: { + SPDLOG_DEBUG("Event {}: {} {}", type, event.id_proto(), std::to_string(event.selected().selected())); + invoke_active_simulator()->get_UI_item(event.id_proto())->set_selected(event.selected().selected()); + break; + } + case Event_m::KindFields::CanSend: { + SPDLOG_DEBUG("Event {}: {}", type, event.id_proto()); + invoke_active_simulator() + ->get_UI_item(event.id_proto()) + ->can_send(event.canSend().frame().sid(), event.canSend().frame().dlc(), + event.canSend().frame().payload()); + break; + } + case Event_m::KindFields::Clear: { + SPDLOG_DEBUG("Event {}: {}", type, event.id_proto()); + invoke_active_simulator()->get_UI_item(event.id_proto())->clear(); + break; + } + default: { + break; } - catch (const json::exception &e) - { - SPDLOG_ERROR("{} {}", __FUNCTION__, e.what()); } } diff --git a/server/simulator_base.cpp b/server/simulator_base.cpp index dfbba6d..d0e28f0 100644 --- a/server/simulator_base.cpp +++ b/server/simulator_base.cpp @@ -2,7 +2,7 @@ #include "simulator_base.hpp" #include "ui_item.hpp" -Simulator_base::Simulator_base(std::string name, Communication *com, std::chrono::milliseconds interval, +Simulator_base::Simulator_base(QString name, Communication *com, std::chrono::milliseconds interval, QObject *parent) : QObject(parent), m_name(name), m_timer(new QTimer(this)), m_interval(interval), m_com(com) { @@ -10,7 +10,7 @@ Simulator_base::Simulator_base(std::string name, Communication *com, std::chrono m_UI_items.reserve(50); } -std::string Simulator_base::name() const +QString Simulator_base::name() const { // Get the name of the simulator return m_name; @@ -20,17 +20,17 @@ void Simulator_base::push_ui_item(UI_item *item) { // Add a UI item to the simulator connect(item, &UI_item::ui_changed, this, [this] { emit sim_changed(); }); + item->set_id(m_UI_items.size()); m_UI_items.push_back(item); } -json Simulator_base::get_UI_items() const +QList Simulator_base::get_UI_items() const { // Get the UI items - json items; - items["name"] = m_name; + QList items; for (size_t i = 0; i < m_UI_items.size(); i++) { - items["UI_items"].push_back(m_UI_items[i]->to_json(i)); + items.push_back(m_UI_items[i]->to_proto()); } return items; diff --git a/server/simulator_base.hpp b/server/simulator_base.hpp index d7f7b4e..e3cd8b0 100644 --- a/server/simulator_base.hpp +++ b/server/simulator_base.hpp @@ -7,11 +7,8 @@ #ifndef INTERNAL #include "ui.hpp" #else -#include - -using json = nlohmann::json; - Q_FORWARD_DECLARE_OBJC_CLASS(UI_item); +Q_FORWARD_DECLARE_OBJC_CLASS(UI_item_m); #endif #define PUSH_UI_ITEM(item) push_ui_item(&item) @@ -75,15 +72,15 @@ class Simulator_base : public QObject * @param interval The interval of the timer (default is 100ms) * @param parent The parent QObject */ - Simulator_base(std::string name, Communication *comms, + Simulator_base(QString name, Communication *comms, std::chrono::milliseconds interval = std::chrono::milliseconds(100), QObject *parent = nullptr); /** * @brief Returns the name of the simulator * - * @return std::string The name of the simulator + * @return QString The name of the simulator */ - std::string name() const; + QString name() const; /** * @brief This function adds a UI item to the simulator @@ -98,7 +95,7 @@ class Simulator_base : public QObject * * @return json The UI items in json format */ - json get_UI_items() const; + QList get_UI_items() const; /** * @brief Get the UI item object by id @@ -112,20 +109,11 @@ class Simulator_base : public QObject * @brief Get the id of a UI item by pointer * * @param ptr A pointer to the UI item - * @return size_t The id of the UI item, or -1 if not found + * @return qsizetype The id of the UI item, or -1 if not found */ - size_t ptr_to_id(UI_item *ptr) const + qsizetype ptr_to_id(UI_item *ptr) const { - size_t id = 0; - while (id < m_UI_items.size()) - { - if (m_UI_items[id] == ptr) - { - return id; - } - id++; - } - return (size_t)-1; + return m_UI_items.indexOf(ptr); } /** @@ -196,12 +184,12 @@ class Simulator_base : public QObject * @brief The name of the simulator * */ - std::string m_name; + QString m_name; /** * @brief The UI items of the simulator * */ - std::vector m_UI_items; + QList m_UI_items; /** * @brief The timer for the simulator * diff --git a/server/simulators.cpp b/server/simulators.cpp index d30a0d0..aa467c4 100644 --- a/server/simulators.cpp +++ b/server/simulators.cpp @@ -7,7 +7,6 @@ #include #include #include -#include typedef Simulator_base *(*Get_Sim)(Communication *, QObject *); @@ -71,17 +70,17 @@ Simulators::Simulators(uint16_t port, QStringList can_devs, QStringList uart_dev lib.unload(); continue; } - m_simulators.insert(std::make_pair(widget->name(), widget)); + m_simulators.insert(widget->name(), widget); } // Insert Debug sims here // INSERT_SIMULATOR(TEST_SIM); - connect(m_server, &Websocket::on_message, this, [this](QWebSocket *conn, QString message) { - QString response = message_parser(message); - if (response == "{}") + connect(m_server, &Websocket::on_binary_message, this, [this](QWebSocket *conn, QByteArray message) { + QByteArray response = message_parser(message); + if (response.isEmpty()) return; - m_server->send(conn, response); + m_server->send_binary(conn, response); }); } @@ -89,7 +88,7 @@ Simulators::~Simulators() { } -std::string Simulators::active_simulator_name() const +QString Simulators::active_simulator_name() const { return this->m_current_simulator; } @@ -101,14 +100,14 @@ void Simulators::start() SPDLOG_WARN("No simulators found"); return; } - if (this->m_current_simulator.empty()) + if (this->m_current_simulator.isEmpty()) { SPDLOG_WARN("No active simulator"); return; } - m_before = this->m_simulators.at(m_current_simulator)->get_UI_items(); - this->m_simulators.at(m_current_simulator)->start(); + m_before = this->m_simulators.value(m_current_simulator)->get_UI_items(); + this->m_simulators.value(m_current_simulator)->start(); } void Simulators::stop() @@ -118,16 +117,16 @@ void Simulators::stop() SPDLOG_WARN("No simulators found"); return; } - if (this->m_current_simulator.empty()) + if (this->m_current_simulator.isEmpty()) { SPDLOG_WARN("No active simulator"); return; } - this->m_simulators.at(m_current_simulator)->stop(); + this->m_simulators.value(m_current_simulator)->stop(); } -void Simulators::switch_simulator(std::string name) +void Simulators::switch_simulator(QString name) { if (this->m_simulators.empty()) { @@ -136,29 +135,31 @@ void Simulators::switch_simulator(std::string name) } if (this->m_simulators.find(name) == this->m_simulators.end()) { - SPDLOG_WARN("Simulator {} not found", name); + SPDLOG_WARN("Simulator {} not found", name.toStdString()); return; } - if (!this->m_current_simulator.empty()) + if (!this->m_current_simulator.isEmpty()) { - SPDLOG_INFO("Stopping current simulator {} and switching to {}", m_current_simulator, name); - this->m_simulators.at(m_current_simulator)->stop(); - disconnect(m_simulators.at(m_current_simulator).get()); + SPDLOG_INFO("Stopping current simulator {} and switching to {}", m_current_simulator.toStdString(), name.toStdString()); + this->m_simulators.value(m_current_simulator)->stop(); + disconnect(m_simulators.value(m_current_simulator)); } this->m_current_simulator = name; connect( - m_simulators.at(m_current_simulator).get(), &Simulator_base::sim_changed, this, + m_simulators.value(m_current_simulator), &Simulator_base::sim_changed, this, [this] { - auto json = changed_UI_items(); - if (!json.empty()) + auto changed = changed_UI_items(); + UI_items_m items; + items.setItem(changed); + if (!changed.isEmpty()) { - m_server->broadcast(QString::fromStdString(json.dump())); + m_server->broadcast_binary(m_serializer.serialize(&items)); } }, Qt::QueuedConnection); - connect(m_simulators.at(m_current_simulator).get(), &Simulator_base::log_signal, this, + connect(m_simulators.value(m_current_simulator), &Simulator_base::log_signal, this, [](const char *filename_in, int line_in, const char *funcname_in, int level, QString msg) { if (spdlog::default_logger_raw()->should_log((spdlog::level::level_enum)level)) spdlog::default_logger_raw()->log(spdlog::source_loc{filename_in, line_in, funcname_in}, @@ -167,19 +168,14 @@ void Simulators::switch_simulator(std::string name) this->start(); } -std::vector Simulators::list_simulators() const +QList Simulators::list_simulators() const { - std::vector names; - for (const auto &simulator : this->m_simulators) - { - names.push_back(simulator.first); - } - return names; + return this->m_simulators.keys(); } bool Simulators::is_not_active() const { - return this->m_current_simulator.empty(); + return this->m_current_simulator.isEmpty(); } Simulator_base *Simulators::invoke_active_simulator() @@ -189,45 +185,40 @@ Simulator_base *Simulators::invoke_active_simulator() { return nullptr; } - if (this->m_current_simulator.empty()) + if (this->m_current_simulator.isEmpty()) { return nullptr; } - m_before = this->m_simulators.at(m_current_simulator)->get_UI_items(); + m_before = this->m_simulators.value(m_current_simulator)->get_UI_items(); - return this->m_simulators.at(m_current_simulator).get(); + return this->m_simulators.value(m_current_simulator); } -json Simulators::changed_UI_items() +QList Simulators::changed_UI_items() { std::lock_guard lock(m_mutex); + QList ret; - if (this->m_simulators.empty() || this->m_current_simulator.empty()) - return "{}"_json; + if (this->m_simulators.empty() || this->m_current_simulator.isEmpty()) + return ret; - json after = this->m_simulators.at(m_current_simulator)->get_UI_items(); + auto after = this->m_simulators.value(m_current_simulator)->get_UI_items(); // Fast path: nothing at all changed if (after == m_before) - return "{}"_json; + return ret; - json changed; - changed["event"]["type"] = "ui_changed"; - - const auto &ui_items = after["UI_items"]; - const auto &prev_ui_items = m_before["UI_items"]; // may be null on first call - - const size_t count = ui_items.size(); - for (size_t i = 0; i < count; ++i) + const qsizetype count = after.size(); + for (qsizetype i = 0; i < count; ++i) { // If item is new or any field changed -> send full current item - if (i >= prev_ui_items.size() || ui_items[i] != prev_ui_items[i]) + if (i >= m_before.size() || after[i] != m_before[i]) { - changed["event"]["UI_items"].push_back(ui_items[i]); + ret.push_back(after[i]); } } m_before = std::move(after); - return changed; + return ret; } \ No newline at end of file diff --git a/server/simulators.hpp b/server/simulators.hpp index 2cd4936..65d06ce 100644 --- a/server/simulators.hpp +++ b/server/simulators.hpp @@ -1,9 +1,10 @@ #pragma once #include -#include +#include #include #include -#include +#include +#include #define INSERT_SIMULATOR(type) \ m_simulators.insert(std::make_pair(type(&m_com).name(), std::make_unique(&m_com, this))); @@ -14,8 +15,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(CAN_Wrapper); Q_FORWARD_DECLARE_OBJC_CLASS(QSerialPort); Q_FORWARD_DECLARE_OBJC_CLASS(Simulator_base); Q_FORWARD_DECLARE_OBJC_CLASS(Communication); - -using json = nlohmann::json; +Q_FORWARD_DECLARE_OBJC_CLASS(UI_item_m); /** * @brief Class managing all simulators @@ -75,9 +75,9 @@ class Simulators : public QObject /** * @brief Get the name of the active simulator * - * @return std::string The name of the active simulator + * @return QString The name of the active simulator */ - std::string active_simulator_name() const; + QString active_simulator_name() const; /** * @brief Start the active simulator * @@ -93,13 +93,13 @@ class Simulators : public QObject * * @param name The name of the simulator to switch to */ - void switch_simulator(std::string name); + void switch_simulator(QString name); /** * @brief List all available simulators * - * @return std::vector A list of simulator names + * @return std::vector A list of simulator names */ - std::vector list_simulators() const; + QList list_simulators() const; /** * @brief Check if no simulator is active * @@ -120,7 +120,7 @@ class Simulators : public QObject * * @return json The changed UI items */ - json changed_UI_items(); + QList changed_UI_items(); // Functions in message_parser.cpp /** @@ -129,27 +129,28 @@ class Simulators : public QObject * @param message The message to parse * @return QString The parsed message */ - QString message_parser(QString message); + QByteArray message_parser(QByteArray message); /** * @brief Parse a command in json format * * @param command The command to parse * @return json The parsed command */ - json command_parser(json command); + //json command_parser(json command); /** * @brief Handle an event in json format * * @param event The event to handle */ - void event_handler(json event); + void event_handler(Event_m event); private: QThread *m_server_thread; Websocket *m_server; Communication *m_com; - std::map> m_simulators; - std::string m_current_simulator = ""; + QMap m_simulators; + QString m_current_simulator = ""; std::mutex m_mutex; - json m_before; + QList m_before; + QProtobufSerializer m_serializer; }; diff --git a/server/simulators/test.cpp b/server/simulators/test.cpp index 199b076..78e7d74 100644 --- a/server/simulators/test.cpp +++ b/server/simulators/test.cpp @@ -5,10 +5,10 @@ EXPORT_SIM(Test_Sim); Test_Sim::Test_Sim(Communication *com, QObject *parent) : Simulator_base("Test Sim", com, std::chrono::milliseconds(1000), parent), m_button("Off", Color::White, Color::Red), - m_combobox(Color::White, Color::Black, {"Option 1", "Option 2", "Option 3"}, 0), + m_combobox({"Option 1", "Option 2", "Option 3"}, 0), m_label("Label", Color::White, Color::Black), m_checkbox("Option 1", Color::Default, Color::Default), - m_slider("Slider", Color::White, Color::Black, 0, 100, 0), m_dial("Dial", Color::White, Color::Black, 0, 100, 0), - m_thermo("Thermo", "%", Color::White, Color::Black, 0, 100, 0), m_led("Led", Color::White, Color::Red), + m_slider("Slider", 0, 100, 0), m_dial("Dial", 0, 100, 0), + m_thermo("Thermo", "%", 0, 100, 0), m_led("Led", Color::White, Color::Red), m_table(4, 4, {"Row 1", "Row 2", "Row 3", "Row 4"}, {"Column 1", "Column 2", "Column 3", "Column 4"}), m_spinbox(0, 255, 0), m_double_spinbox(0, 255, 0), m_hex_spinbox(0, 255, 0), m_tab_widget({"Tab 1", "Tab 2", "Tab 3"}, 0), m_stacked_widget(3, 0), m_status_bar() @@ -39,7 +39,7 @@ Test_Sim::Test_Sim(Communication *com, QObject *parent) for (size_t i = 0; i < m_table.capacity(); i++) { - m_table.insert_item(i / 4, i % 4, QString("%0 %1").arg(i / 4).arg(i % 4).toStdString()); + m_table.insert_item(i / 4, i % 4, QString("%0 %1").arg(i / 4).arg(i % 4)); } QObject::connect(&m_button, &UI_button::clicked, this, [=, this] { button_clicked(&m_button); }); @@ -87,14 +87,14 @@ void Test_Sim::slider_changed(UI_slider *id, double value) if (id == &m_slider) { LOG_INFO(QString("Test slider changed to %0").arg(value)); - m_label.set_text(std::to_string(value)); + m_label.set_text(QString::number(value)); m_dial.set_value(value); m_thermo.set_value(value); m_plot.add_value(value); m_spinbox.set_value(value); m_double_spinbox.set_value(value); m_hex_spinbox.set_value(value); - m_status_bar.show_message("Test slider changed to " + std::to_string(value)); + m_status_bar.show_message("Test slider changed to " + QString::number(value)); return; } } diff --git a/server/websocket.cpp b/server/websocket.cpp index 747b959..f0eee34 100644 --- a/server/websocket.cpp +++ b/server/websocket.cpp @@ -60,7 +60,15 @@ Websocket::~Websocket() qDeleteAll(m_clients.begin(), m_clients.end()); } -void Websocket::broadcast(QString message) +void Websocket::broadcast_binary(QByteArray message) +{ + foreach (QWebSocket *conn, m_clients) + { + conn->sendBinaryMessage(message); + } +} + +void Websocket::broadcast_text(QString message) { foreach (QWebSocket *conn, m_clients) { @@ -68,7 +76,12 @@ void Websocket::broadcast(QString message) } } -void Websocket::send(QWebSocket *conn, QString message) +void Websocket::send_binary(QWebSocket *conn, QByteArray message) +{ + conn->sendBinaryMessage(message); +} + +void Websocket::send_text(QWebSocket *conn, QString message) { conn->sendTextMessage(message); } @@ -77,16 +90,23 @@ void Websocket::onNewConnection() { QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection(); + connect(pSocket, &QWebSocket::binaryMessageReceived, this, &Websocket::processBinaryMessage); connect(pSocket, &QWebSocket::textMessageReceived, this, &Websocket::processTextMessage); connect(pSocket, &QWebSocket::disconnected, this, &Websocket::socketDisconnected); m_clients << pSocket; } +void Websocket::processBinaryMessage(QByteArray message) +{ + QWebSocket *pClient = qobject_cast(sender()); + emit on_binary_message(pClient, message); +} + void Websocket::processTextMessage(QString message) { QWebSocket *pClient = qobject_cast(sender()); - emit on_message(pClient, message); + emit on_text_message(pClient, message); } void Websocket::socketDisconnected() diff --git a/server/websocket.hpp b/server/websocket.hpp index e07022e..5d022ac 100644 --- a/server/websocket.hpp +++ b/server/websocket.hpp @@ -41,14 +41,16 @@ class Websocket : public QObject * * @param message The message to send */ - void broadcast(QString message); + void broadcast_binary(QByteArray message); + void broadcast_text(QString message); /** * @brief Send a message to a specific client * * @param conn The client connection * @param message The message to send */ - void send(QWebSocket *conn, QString message); + void send_binary(QWebSocket *conn, QByteArray message); + void send_text(QWebSocket *conn, QString message); signals: /** * @brief Signal emitted when a message is received from a client @@ -56,7 +58,8 @@ class Websocket : public QObject * @param conn The client connection * @param message The received message */ - void on_message(QWebSocket *conn, QString message); + void on_binary_message(QWebSocket *conn, QByteArray message); + void on_text_message(QWebSocket *conn, QString message); /** * @brief Signal emitted when the server is closed * @@ -74,6 +77,7 @@ class Websocket : public QObject * * @param message The received message */ + void processBinaryMessage(QByteArray message); void processTextMessage(QString message); /** * @brief Private Slot called when a client disconnects