From 2578bce241bfbc8dbb8baf24def622b352225fb2 Mon Sep 17 00:00:00 2001 From: Chi Huu Huynh <73843190+Chi-EEE@users.noreply.github.com> Date: Tue, 5 Dec 2023 15:20:44 +0000 Subject: [PATCH] Frontend now shares WebSocket and code cleaner --- TODO.md | 7 +-- backend/src/controllers/WebSocketChat.hpp | 47 +++++++++------ frontend/src/lib/LidarStream.svelte | 2 +- frontend/src/routes/+page.svelte | 1 - frontend/src/routes/room/[slug]/+page.svelte | 15 +++-- raspberry_pi/include/global/Config.hpp | 5 +- raspberry_pi/settings/config.jsonc | 2 +- raspberry_pi/src/car_system/CarSystem.cpp | 15 ++--- raspberry_pi/src/car_system/CarSystem.h | 4 +- .../car_system/messaging/MessagingSystem.hpp | 60 +++++++++---------- raspberry_pi/src/main.cpp | 21 ++++--- 11 files changed, 98 insertions(+), 81 deletions(-) diff --git a/TODO.md b/TODO.md index 9b62b9d4..5e234dc7 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,6 @@ # TODO List: +- Wrap every endpoint with try-catch to prevent bad actors from crashing the server +- Pass commands from backend to raspberry pi +- Display Lidar data in Svelte -- Pass Lidar data from raspberry pi to backend -- Caleribate the compass - Authenication to rooms -- Pass commands from backend to raspberry pi -- Display Lidar data in Svelte \ No newline at end of file diff --git a/backend/src/controllers/WebSocketChat.hpp b/backend/src/controllers/WebSocketChat.hpp index a1b55d03..3d017b0a 100644 --- a/backend/src/controllers/WebSocketChat.hpp +++ b/backend/src/controllers/WebSocketChat.hpp @@ -147,26 +147,33 @@ void WebSocketChat::handleUserMessage(const drogon::WebSocketConnectionPtr& wsCo { auto& user = wsConnPtr->getContextRef(); spdlog::debug("Received a message from user: {} | WebSocketChat::handleUserMessage", wsConnPtr->peerAddr().toIp()); - json message_json = json::parse(message); - const std::string message_data = message_json["data"].get(); + try { + json message_json = json::parse(message); + const std::string message_data = message_json["data"].get(); - auto& room = RoomManager::instance()->getRoom(user.getChatRoomName()); + auto& room = RoomManager::instance()->getRoom(user.getChatRoomName()); - json out_json; - out_json["name"] = user.getName(); - bool is_command = message_data.rfind("/", 0); - if (is_command) { - this->handleUserCommand(out_json, split(message_data.c_str(), ' '), room); + json out_json; + out_json["name"] = user.getName(); + bool is_command = !message_data.rfind("/", 0); + if (is_command) { + this->handleUserCommand(out_json, split(message_data.c_str(), ' '), room); + } + else { + out_json["type"] = "message"; + out_json["data"] = message_data; + } + this->chat_rooms.publish(user.getChatRoomName(), out_json.dump()); } - else { - out_json["type"] = "message"; + catch (std::exception c) { + spdlog::error("Invalid JSON from {} | WebSocketChat::handleUserMessage", wsConnPtr->peerAddr().toIp()); } - this->chat_rooms.publish(user.getChatRoomName(), out_json.dump()); } void WebSocketChat::handleUserCommand(json& out_json, std::vector& split_string, std::shared_ptr& room) { out_json["type"] = "command"; std::string command_type = split_string[0]; + command_type.erase(0, 1); // Remove the slash if (command_type == "move") { out_json["command"] = "move"; if (split_string.size() == 2) { @@ -235,6 +242,12 @@ void WebSocketChat::handleNewConnection(const drogon::HttpRequestPtr& req, conn->forceClose(); } +/// +/// room_name +/// type +/// +/// +/// inline void WebSocketChat::handleCreateRequest(const drogon::HttpRequestPtr& req, const drogon::WebSocketConnectionPtr& conn) { std::string room_name = req->getParameter("room_name"); @@ -243,10 +256,6 @@ inline void WebSocketChat::handleCreateRequest(const drogon::HttpRequestPtr& req conn->forceClose(); return; } - UserType type = UserType::User; - if (req->getParameter("type") == "car") { - type = UserType::Car; - } spdlog::info("Creating room {} from {} | WebSocketChat::handleCreateRequest", room_name, req->peerAddr().toIp()); auto user = std::make_shared( this->chat_rooms.subscribe(room_name, @@ -257,7 +266,7 @@ inline void WebSocketChat::handleCreateRequest(const drogon::HttpRequestPtr& req }), conn, room_name, - type + UserType::User ); auto room = std::make_shared(user); RoomManager::instance()->addRoom(room_name, room); @@ -273,6 +282,10 @@ inline void WebSocketChat::handleJoinRequest(const drogon::HttpRequestPtr& req, return; } spdlog::info("Joining room {} from {} | WebSocketChat::handleJoinRequest", room_name, req->peerAddr().toIp()); + UserType type = UserType::User; + if (req->getParameter("type") == "car") { + type = UserType::Car; + } auto user = std::make_shared( this->chat_rooms.subscribe(room_name, [conn](const std::string& topic, @@ -282,7 +295,7 @@ inline void WebSocketChat::handleJoinRequest(const drogon::HttpRequestPtr& req, }), conn, room_name, - UserType::User + type ); auto room = RoomManager::instance()->getRoom(room_name); room->addUser(user); diff --git a/frontend/src/lib/LidarStream.svelte b/frontend/src/lib/LidarStream.svelte index fd68a7b3..76bed875 100644 --- a/frontend/src/lib/LidarStream.svelte +++ b/frontend/src/lib/LidarStream.svelte @@ -17,7 +17,7 @@ const websocket = get(websocket_store); - websocket.addEventListener("message", (event: MessageEvent) => { + websocket!!.addEventListener("message", (event: MessageEvent) => { const json_data = JSON.parse(event.data); if (json_data.type == "car") { points.length = 0; diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index 6648dbe2..006c7451 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -2,7 +2,6 @@ import { dev } from "$app/environment"; import { onMount } from "svelte"; - import LidarViewer from "$lib/LidarViewer.svelte";

Welcome to SvelteKit

diff --git a/frontend/src/routes/room/[slug]/+page.svelte b/frontend/src/routes/room/[slug]/+page.svelte index 69d34ffe..beb6eb50 100644 --- a/frontend/src/routes/room/[slug]/+page.svelte +++ b/frontend/src/routes/room/[slug]/+page.svelte @@ -13,12 +13,12 @@ websocket_url_store.set( `ws://${location.host}/ws/room?request=create&room_name=${room_name}`, ); - websocket_store.subscribe((websocket: WebSocket) => { - websocket.addEventListener("open", (event) => { + websocket_store.subscribe((websocket) => { + websocket!!.addEventListener("open", (event) => { console.log("Websocket opened"); }); - websocket.addEventListener("message", (event: MessageEvent) => { + websocket!!.addEventListener("message", (event: MessageEvent) => { const json_data = JSON.parse(event.data); console.log(json_data); }); @@ -26,8 +26,8 @@ let message = ""; function sendMessage() { - const websocket: WebSocket = get(websocket_store); - websocket.send(JSON.stringify({ data: message })); + const websocket = get(websocket_store); + websocket!!.send(JSON.stringify({ data: message })); } let data: { @@ -45,7 +45,10 @@

This is the Room page

Title: {data.room_name}

- + { + if (key.key === "Enter") + sendMessage() + }} bind:value={message} />

Hello {data.room_name}!

diff --git a/raspberry_pi/include/global/Config.hpp b/raspberry_pi/include/global/Config.hpp index ee38efa5..8b7efab2 100644 --- a/raspberry_pi/include/global/Config.hpp +++ b/raspberry_pi/include/global/Config.hpp @@ -36,8 +36,7 @@ namespace global std::optional port; std::string name; - - std::string code; + std::string room; private: Config() { @@ -61,7 +60,7 @@ namespace global this->name = config_json["name"].get(); - this->code = config_json["code"].get(); + this->room = config_json["room"].get(); } catch (const std::exception& e) { diff --git a/raspberry_pi/settings/config.jsonc b/raspberry_pi/settings/config.jsonc index 3e8bdafc..80a2802b 100644 --- a/raspberry_pi/settings/config.jsonc +++ b/raspberry_pi/settings/config.jsonc @@ -2,5 +2,5 @@ "host": "localhost", "port": 8848, "name": "RaspberryPi", - "code": "1" + "room": "1" } \ No newline at end of file diff --git a/raspberry_pi/src/car_system/CarSystem.cpp b/raspberry_pi/src/car_system/CarSystem.cpp index 100e61cc..37269da1 100644 --- a/raspberry_pi/src/car_system/CarSystem.cpp +++ b/raspberry_pi/src/car_system/CarSystem.cpp @@ -3,7 +3,7 @@ namespace car_system { CarSystem::CarSystem(const std::string& websocket_url, std::unique_ptr lidar_device, std::unique_ptr messaging_system) : lidar_device(std::move(lidar_device)), messaging_system(std::move(messaging_system)) { - this->initialize(websocket_url); + this->initalize(); } CarSystem::~CarSystem() @@ -11,9 +11,15 @@ namespace car_system { this->terminate(); } + void CarSystem::initalize() + { + this->messaging_system->initalize(); + } + void CarSystem::run() { spdlog::info("Running Car"); + this->messaging_system->start(); this->lidar_device->start(); while (true) { @@ -29,15 +35,10 @@ namespace car_system { } ); } - this->messaging_system->send(output_json.dump()); + this->messaging_system->sendMessage(output_json.dump()); } } - void CarSystem::initialize(const std::string& websocket_url) - { - - } - void CarSystem::terminate() { this->lidar_device->terminate(); diff --git a/raspberry_pi/src/car_system/CarSystem.h b/raspberry_pi/src/car_system/CarSystem.h index 065fca99..7d2eb694 100644 --- a/raspberry_pi/src/car_system/CarSystem.h +++ b/raspberry_pi/src/car_system/CarSystem.h @@ -23,6 +23,8 @@ namespace car_system { CarSystem(const std::string& websocket_url, std::unique_ptr lidar_device, std::unique_ptr messaging_system); ~CarSystem(); + void initalize(); + void run(); void terminate(); @@ -30,8 +32,6 @@ namespace car_system { void move(float distance); private: - void initialize(const std::string& websocket_url); - std::unique_ptr lidar_device; std::unique_ptr messaging_system; }; diff --git a/raspberry_pi/src/car_system/messaging/MessagingSystem.hpp b/raspberry_pi/src/car_system/messaging/MessagingSystem.hpp index 8f07d93e..cc9c2e40 100644 --- a/raspberry_pi/src/car_system/messaging/MessagingSystem.hpp +++ b/raspberry_pi/src/car_system/messaging/MessagingSystem.hpp @@ -27,32 +27,11 @@ namespace car_system::messaging { { public: MessagingSystem(const std::string& websocket_url) : websocket_url(websocket_url) { - this->websocket.start(); - bool open = false; - for (int i = 0; i < 3; i++) { - if (this->websocket.getReadyState() == ix::ReadyState::Open) { - open = true; - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(i * 3000)); - } - if (!open) { - spdlog::error("Could not connect to websocket"); - return; - } - else - { - spdlog::info("Connected to websocket"); - } - { - json first_message = { {"type", "car"} }; - spdlog::info("Sending first message: {}", first_message.dump()); - this->websocket.ping(first_message.dump()); - } - }; - void initalize() { + }; + void initalize() + { ix::initNetSystem(); this->websocket.setUrl(websocket_url); this->websocket.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) @@ -63,20 +42,20 @@ namespace car_system::messaging { if (message_json["type"] == "command") { if (message_json["command"] == "turn") { float angle = message_json["angle"].get(); - this->turn_command_signal( + /*this->turn_command_signal( TurnCommand{ angle } - ); + );*/ spdlog::info("Turning by {} angle", angle); } else if (message_json["command"] == "move") { int speed = message_json["speed"].get(); - this->move_command_signal( + /* this->move_command_signal( MoveCommand{ speed } - ); + );*/ spdlog::info("Moving with {} speed", speed); } } @@ -101,6 +80,27 @@ namespace car_system::messaging { ); } + void start() + { + this->websocket.start(); + bool open = false; + for (int i = 0; i < 3; i++) { + if (this->websocket.getReadyState() == ix::ReadyState::Open) { + open = true; + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(i * 3000)); + } + if (!open) { + spdlog::error("Could not connect to websocket"); + return; + } + else + { + spdlog::info("Connected to websocket"); + } + } + void terminate() { this->websocket.stop(); ix::uninitNetSystem(); @@ -118,8 +118,8 @@ namespace car_system::messaging { ix::WebSocket websocket; std::string websocket_url; - nod::signal move_command_signal; - nod::signal turn_command_signal; + /*nod::signal move_command_signal; + nod::signal turn_command_signal;*/ }; }; diff --git a/raspberry_pi/src/main.cpp b/raspberry_pi/src/main.cpp index 4313982d..237c720f 100644 --- a/raspberry_pi/src/main.cpp +++ b/raspberry_pi/src/main.cpp @@ -30,19 +30,19 @@ std::string getWebsocketUrl() std::optional maybe_port = GET_CONFIG_VALUE(port); if (maybe_port.has_value()) { - return "ws://" + GET_CONFIG_VALUE(host) + ":" + std::to_string(maybe_port.value()) + "/ws/room?room_name=" + GET_CONFIG_VALUE(code); + return fmt::format("ws://{}:{}/ws/room?request=join&type=car&room_name={}", GET_CONFIG_VALUE(host), maybe_port.value(), GET_CONFIG_VALUE(room)); } - return "ws://" + GET_CONFIG_VALUE(host) + "/ws/room?room_name=" + GET_CONFIG_VALUE(code); + return fmt::format("ws://{}/ws/room?request=join&type=&room_name={}", GET_CONFIG_VALUE(host), GET_CONFIG_VALUE(room)); } // Car is a global variable so that car.terminate() can be called on exit std::unique_ptr car_system_obj; -void terminate() { - car_system_obj->terminate(); - spdlog::info("Terminated"); - system("pause"); -} +//void terminate() { +// car_system_obj->terminate(); +// spdlog::info("Terminated"); +// system("pause"); +//} int main() { @@ -53,8 +53,11 @@ int main() std::unique_ptr scanner = std::make_unique(); // std::unique_ptr scanner = std::make_unique("COM3"); - car_system_obj = std::make_unique(websocket_url, std::move(scanner)); - std::atexit(terminate); + std::unique_ptr messaging_system = std::make_unique(websocket_url); + + car_system_obj = std::make_unique(websocket_url, std::move(scanner), std::move(messaging_system)); + //std::atexit(terminate); + car_system_obj->run(); return 0;