Skip to content

Commit 439d329

Browse files
authored
Merge pull request #90 from G-Epitech/rtp-104-mnt
RTP-104 - Monitor
2 parents 955c619 + 503394c commit 439d329

38 files changed

+11175
-45
lines changed

libs/abra/dependencies.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# External dependencies
2-
find_package(Boost REQUIRED COMPONENTS system mysql)
2+
find_package(Boost REQUIRED COMPONENTS system mysql json beast)
33

44
IF(Boost_FOUND)
55
include_directories(${Boost_INCLUDE_DIRS})
66
link_directories(${Boost_LIBRARY_DIRS})
77
ENDIF(Boost_FOUND)
88

9-
target_link_libraries(abra PUBLIC Boost::system Boost::mysql)
9+
target_link_libraries(abra PUBLIC Boost::system Boost::mysql Boost::json Boost::beast)

libs/abra/includes/network.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@
1111
#include "libs/abra/src/client/udp/client_udp.hpp"
1212
#include "libs/abra/src/server/tcp/server_tcp.hpp"
1313
#include "libs/abra/src/server/tcp/session/session_tcp.hpp"
14+
#include "libs/abra/src/server/websocket/server_websocket.hpp"
15+
#include "libs/abra/src/server/websocket/session/session_websocket.hpp"
1416
#include "libs/abra/src/server/udp/server_udp.hpp"
1517
#include "libs/abra/src/tools/logger/logger.hpp"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
add_subdirectory(tcp)
22
add_subdirectory(udp)
3+
add_subdirectory(websocket)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
target_sources(abra PRIVATE
2+
server_websocket.cpp
3+
server_websocket.hpp
4+
)
5+
6+
add_subdirectory(session)
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
** EPITECH PROJECT, 2024
3+
** server_tcp.cpp
4+
** File description:
5+
** ServerTCP class
6+
*/
7+
8+
#include "./server_websocket.hpp"
9+
10+
#include <iostream>
11+
12+
using namespace abra::server;
13+
using namespace boost::asio;
14+
15+
ServerWebsocket::ServerWebsocket(
16+
const int &port,
17+
const std::function<void(std::pair<std::uint64_t, const boost::json::object &>)> &handler)
18+
: acceptor_(ioc_, ip::tcp::endpoint(ip::tcp::v4(), port)),
19+
lastClientId_(0),
20+
handler_(handler),
21+
logger_("websocket") {}
22+
23+
ServerWebsocket::~ServerWebsocket() {
24+
this->Close();
25+
}
26+
27+
void ServerWebsocket::Start() {
28+
AcceptNewConnection();
29+
30+
logger_.Info("Websocket started on port " + std::to_string(acceptor_.local_endpoint().port()));
31+
ioc_.run();
32+
}
33+
34+
void ServerWebsocket::AcceptNewConnection() {
35+
acceptor_.async_accept([this](boost::system::error_code error, ip::tcp::socket socket) {
36+
if (!error) {
37+
std::uint64_t clientId = lastClientId_;
38+
lastClientId_++;
39+
40+
logger_.Info("New connection accepted");
41+
auto clientSession = std::make_shared<SessionWebsocket>(
42+
std::move(socket), clientId, handler_,
43+
[this](std::uint64_t clientId) { this->OnSessionClose(clientId); });
44+
45+
clientSession->Start();
46+
logger_.Info("Session started with clientID " + std::to_string(clientId));
47+
48+
RegisterNewClient(clientSession, clientId);
49+
} else {
50+
logger_.Error("Error while accepting new connection: " + error.message());
51+
}
52+
53+
AcceptNewConnection();
54+
});
55+
}
56+
57+
void ServerWebsocket::RegisterNewClient(std::shared_ptr<SessionWebsocket> client,
58+
const std::uint64_t &clientId) {
59+
clients_[clientId] = std::move(client);
60+
}
61+
62+
void ServerWebsocket::Close() {
63+
if (!acceptor_.is_open() || ioc_.stopped()) {
64+
return;
65+
}
66+
67+
this->logger_.Info("Closing session");
68+
69+
for (auto &client : clients_) {
70+
client.second->Close();
71+
}
72+
ioc_.stop();
73+
74+
this->logger_.Info("Session closed");
75+
}
76+
77+
void ServerWebsocket::SendToClient(const std::uint64_t &clientId,
78+
const boost::json::object &message) {
79+
if (clients_.find(clientId) == clients_.end() || !clients_[clientId]) {
80+
logger_.Error("Client not found");
81+
return;
82+
}
83+
84+
clients_[clientId]->Send(message);
85+
}
86+
87+
void ServerWebsocket::OnSessionClose(const std::uint64_t &clientId) {
88+
if (clients_.find(clientId) == clients_.end()) {
89+
logger_.Error("Client not found");
90+
return;
91+
}
92+
93+
clients_.erase(clientId);
94+
logger_.Info("Client " + std::to_string(clientId) + " disconnected");
95+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
** EPITECH PROJECT, 2024
3+
** server_tcp.hpp
4+
** File description:
5+
** ServerTCP class
6+
*/
7+
8+
#pragma once
9+
10+
#include <boost/asio.hpp>
11+
#include <boost/json.hpp>
12+
#include <cstdint>
13+
#include <map>
14+
#include <queue>
15+
16+
#include "./session/session_websocket.hpp"
17+
#include "libs/abra/src/core.hpp"
18+
#include "libs/abra/src/tools/logger/logger.hpp"
19+
20+
namespace abra::server {
21+
class EXPORT_NETWORK_SDK_API ServerWebsocket;
22+
}
23+
24+
class abra::server::ServerWebsocket {
25+
public:
26+
/**
27+
* @brief Construct a new ServerTCP instance
28+
* @param port The TCP port
29+
* @param middleware The middleware to catch messages from listeners
30+
*/
31+
ServerWebsocket(
32+
const int &port,
33+
const std::function<void(std::pair<std::uint64_t, const boost::json::object &>)> &handler);
34+
35+
~ServerWebsocket();
36+
37+
/**
38+
* @brief Start the server
39+
*/
40+
void Start();
41+
42+
/**
43+
* @brief Send a message to a client
44+
* @param clientId The client id
45+
* @param message The message to send
46+
*/
47+
void SendToClient(const std::uint64_t &clientId, const boost::json::object &message);
48+
49+
/**
50+
* @brief Close the server
51+
*/
52+
void Close();
53+
54+
private:
55+
/**
56+
* @brief Accept a new connection
57+
*/
58+
void AcceptNewConnection();
59+
60+
/**
61+
* @brief Register a new client
62+
* @param client
63+
*/
64+
void RegisterNewClient(std::shared_ptr<SessionWebsocket> client, const std::uint64_t &clientId);
65+
66+
/**
67+
* @brief Handle the session close
68+
* @param clientId The client id
69+
*/
70+
void OnSessionClose(const std::uint64_t &clientId);
71+
72+
/// @brief Input Output Context
73+
boost::asio::io_context ioc_;
74+
75+
/// @brief Acceptor of sockets (TCP protocol)
76+
boost::asio::ip::tcp::acceptor acceptor_;
77+
78+
/// @brief Clients map
79+
std::map<std::uint64_t, std::shared_ptr<SessionWebsocket>> clients_;
80+
81+
/// @brief Last client id
82+
std::uint64_t lastClientId_;
83+
84+
/// @brief Handler of websocket messages
85+
std::function<void(std::pair<std::uint64_t, const boost::json::object &>)> handler_;
86+
87+
/// @brief Logger
88+
tools::Logger logger_;
89+
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
target_sources(abra PRIVATE
2+
session_websocket.cpp
3+
session_websocket.hpp
4+
)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
** EPITECH PROJECT, 2024
3+
** session_tcp.cpp
4+
** File description:
5+
** SessionTCP class
6+
*/
7+
8+
#include "./session_websocket.hpp"
9+
10+
#include <utility>
11+
12+
#include "libs/abra/src/tools/packet/packet_utils.hpp"
13+
14+
using namespace abra::server;
15+
using namespace boost;
16+
17+
SessionWebsocket::SessionWebsocket(
18+
boost::asio::ip::tcp::socket socket, std::uint64_t clientId,
19+
const std::function<void(std::pair<std::uint64_t, const boost::json::object &>)> &handler,
20+
const std::function<void(std::uint64_t)> &onClose)
21+
: ws_(std::move(socket)),
22+
buffer_(),
23+
clientId_(clientId),
24+
handler_(handler),
25+
onClose_(onClose),
26+
logger_("session_websocket_" + std::to_string(clientId)) {}
27+
28+
SessionWebsocket::~SessionWebsocket() {
29+
this->Close();
30+
}
31+
32+
void SessionWebsocket::Start() {
33+
auto self(shared_from_this());
34+
35+
ws_.async_accept([self](beast::error_code ec) {
36+
if (!ec) {
37+
self->ListenNewRequest();
38+
} else {
39+
return;
40+
}
41+
});
42+
}
43+
44+
void SessionWebsocket::ListenNewRequest() {
45+
auto self(shared_from_this());
46+
47+
ws_.async_read(buffer_, [self](beast::error_code ec, std::size_t bytes_transferred) {
48+
boost::ignore_unused(bytes_transferred);
49+
50+
if (!ec) {
51+
auto message = beast::buffers_to_string(self->buffer_.data());
52+
self->HandleRequest(message);
53+
self->buffer_.consume(self->buffer_.size());
54+
self->ListenNewRequest();
55+
} else {
56+
self->onClose_(self->clientId_);
57+
return;
58+
}
59+
});
60+
}
61+
62+
void SessionWebsocket::HandleRequest(const std::string &message) {
63+
logger_.Info("Received message: " + std::to_string(message.size()));
64+
65+
auto json = boost::json::parse(message);
66+
handler_(std::make_pair(this->clientId_, json.as_object()));
67+
}
68+
69+
void SessionWebsocket::Close() {
70+
if (!this->ws_.is_open()) {
71+
return;
72+
}
73+
74+
this->logger_.Info("Closing session");
75+
this->ws_.close(beast::websocket::close_code::normal);
76+
this->logger_.Info("Session closed");
77+
}
78+
79+
void SessionWebsocket::Send(const boost::json::object &message) {
80+
auto json = boost::json::serialize(message);
81+
82+
ws_.write(boost::asio::buffer(json));
83+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
** EPITECH PROJECT, 2024
3+
** session_tcp.hpp
4+
** File description:
5+
** SessionTCP class
6+
*/
7+
8+
#pragma once
9+
10+
#include <boost/array.hpp>
11+
#include <boost/asio.hpp>
12+
#include <boost/beast.hpp>
13+
#include <boost/json.hpp>
14+
#include <memory>
15+
#include <queue>
16+
17+
#include "libs/abra/src/core.hpp"
18+
#include "libs/abra/src/server/tcp/props/message.hpp"
19+
#include "libs/abra/src/tools/logger/logger.hpp"
20+
#include "libs/abra/src/tools/message/message.hpp"
21+
#include "libs/abra/src/tools/packet/packet.hpp"
22+
#include "libs/abra/src/tools/packet/props/props.hpp"
23+
24+
namespace abra::server {
25+
class EXPORT_NETWORK_SDK_API SessionWebsocket;
26+
} // namespace abra::server
27+
28+
class abra::server::SessionWebsocket : public std::enable_shared_from_this<SessionWebsocket> {
29+
public:
30+
/**
31+
* @brief Construct a new SessionTCP. This session will handle incoming data
32+
* @param socket Client socket
33+
*/
34+
SessionWebsocket(
35+
boost::asio::ip::tcp::socket socket, std::uint64_t clientId,
36+
const std::function<void(std::pair<std::uint64_t, const boost::json::object &>)> &handler_,
37+
const std::function<void(std::uint64_t)> &onClose);
38+
39+
/**
40+
* @brief Destroy the SessionTCP object
41+
*/
42+
~SessionWebsocket();
43+
44+
/**
45+
* @brief Start the client session
46+
*/
47+
void Start();
48+
49+
/**
50+
* @brief Close the connection
51+
*/
52+
void Close();
53+
54+
/**
55+
* @brief Send a message to the client
56+
* @param message The message to send
57+
*/
58+
void Send(const boost::json::object &message);
59+
60+
private:
61+
/**
62+
* @brief Listen the new request of the client
63+
*/
64+
void ListenNewRequest();
65+
66+
/**
67+
* @brief Handle the request of the client
68+
* @param message The message received
69+
*/
70+
void HandleRequest(const std::string &message);
71+
72+
/// @brief The socket of the client
73+
boost::beast::websocket::stream<boost::asio::ip::tcp::socket> ws_;
74+
75+
/// @brief The buffer of the client
76+
boost::beast::flat_buffer buffer_;
77+
78+
/// @brief Client id
79+
std::uint64_t clientId_;
80+
81+
/// @brief Handler
82+
std::function<void(std::pair<std::uint64_t, const boost::json::object &>)> handler_;
83+
84+
/// @brief On close callback
85+
std::function<void(std::uint64_t)> onClose_;
86+
87+
/// @brief Logger
88+
tools::Logger logger_;
89+
};

0 commit comments

Comments
 (0)