diff options
| author | garder500 <jeremy27.clara22@gmail.com> | 2025-04-27 16:06:19 +0200 |
|---|---|---|
| committer | garder500 <jeremy27.clara22@gmail.com> | 2025-04-27 16:06:19 +0200 |
| commit | 7cbd16f1b3115d3335c61e7c82e349594a726f52 (patch) | |
| tree | 7a36ded6b73d924b6891ac052140f69bf73c33ac /bot/include/server.cpp | |
| parent | b3791125200154278d31514217c4f417d8961e84 (diff) | |
Ajout de la logique de connexion et de gestion des signaux pour le bot Discord, ainsi que des améliorations dans la gestion des chaînes JSON et des mises à jour des commandes.
Diffstat (limited to 'bot/include/server.cpp')
| -rw-r--r-- | bot/include/server.cpp | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/bot/include/server.cpp b/bot/include/server.cpp new file mode 100644 index 0000000..55e5df9 --- /dev/null +++ b/bot/include/server.cpp @@ -0,0 +1,182 @@ +#include <iostream> +#include <thread> +#include <mutex> +#include <vector> +#include <queue> +#include <functional> +#include <sys/socket.h> +#include <sys/un.h> +#include <poll.h> +#include <fcntl.h> +#include <unistd.h> +#include <cstring> + +#ifdef __APPLE__ +#define SOCKET_PATH_MAX 104 +#else +#define SOCKET_PATH_MAX 108 +#endif + +class UnixSocketServer { +public: + using MessageHandler = std::function<void(const std::string&)>; + + UnixSocketServer(const std::string& path) : + socket_path_(path.substr(0, SOCKET_PATH_MAX - 1)), + running_(false) {} + + ~UnixSocketServer() { stop(); } + + void start(MessageHandler handler) { + if (running_) return; + + server_fd_ = create_socket(); + setup_socket(); + + running_ = true; + server_thread_ = std::thread(&UnixSocketServer::event_loop, this, handler); + } + + void stop() { + running_ = false; + if (server_thread_.joinable()) { + server_thread_.join(); + } + cleanup(); + } + + void send(const std::string& message) { + std::lock_guard<std::mutex> lock(clients_mutex_); + for (auto& client : clients_) { + queue_message(client.fd, message); + } + } + +private: + struct Client { + int fd; + std::queue<std::string> write_queue; + }; + + int create_socket() { + int fd = ::socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) throw std::runtime_error("::socket() failed"); + return fd; + } + + void setup_socket() { + struct sockaddr_un addr = {}; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, socket_path_.c_str(), sizeof(addr.sun_path) - 1); + + unlink(socket_path_.c_str()); + + if (bind(server_fd_, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + close(server_fd_); + throw std::runtime_error("bind() failed"); + } + + if (listen(server_fd_, 5) == -1) { + close(server_fd_); + throw std::runtime_error("listen() failed"); + } + + set_nonblocking(server_fd_); + } + + void set_nonblocking(int fd) { + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + } + + void event_loop(MessageHandler handler) { + std::vector<struct pollfd> fds; + fds.push_back({server_fd_, POLLIN, 0}); + + while (running_) { + int ready = ::poll(fds.data(), fds.size(), 250); + if (ready == -1) break; + + for (size_t i = 0; i < fds.size(); ++i) { + if (fds[i].revents & POLLIN) { + if (fds[i].fd == server_fd_) { + accept_new_connection(fds); + } else { + handle_client_input(fds[i].fd, handler); + } + } + + if (fds[i].revents & POLLOUT) { + handle_client_output(fds[i].fd); + } + } + } + } + + void accept_new_connection(std::vector<struct pollfd>& fds) { + int client_fd = accept(server_fd_, nullptr, nullptr); + if (client_fd == -1) return; + + set_nonblocking(client_fd); + fds.push_back({client_fd, POLLIN | POLLOUT, 0}); + + std::lock_guard<std::mutex> lock(clients_mutex_); + clients_.push_back({client_fd, {}}); + } + + void handle_client_input(int fd, MessageHandler handler) { + char buffer[4096]; + ssize_t count = recv(fd, buffer, sizeof(buffer), 0); + + if (count > 0) { + handler(std::string(buffer, count)); + } else { + remove_client(fd); + } + } + + void handle_client_output(int fd) { + std::lock_guard<std::mutex> lock(clients_mutex_); + for (auto& client : clients_) { + if (client.fd == fd && !client.write_queue.empty()) { + const std::string& msg = client.write_queue.front(); + ssize_t sent = ::send(fd, msg.data(), msg.size(), 0); + if (sent > 0) { + client.write_queue.pop(); + } + } + } + } + + void queue_message(int fd, const std::string& message) { + std::lock_guard<std::mutex> lock(clients_mutex_); + for (auto& client : clients_) { + if (client.fd == fd) { + client.write_queue.push(message); + return; + } + } + } + + void remove_client(int fd) { + std::lock_guard<std::mutex> lock(clients_mutex_); + clients_.erase( + std::remove_if(clients_.begin(), clients_.end(), + [fd](const Client& c) { return c.fd == fd; }), + clients_.end() + ); + close(fd); + } + + void cleanup() { + close(server_fd_); + unlink(socket_path_.c_str()); + } + + std::string socket_path_; + int server_fd_ = -1; + std::atomic<bool> running_; + std::thread server_thread_; + std::mutex clients_mutex_; + std::vector<Client> clients_; +}; |
