summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgarder500 <jeremy27.clara22@gmail.com>2025-05-01 14:32:40 +0200
committergarder500 <jeremy27.clara22@gmail.com>2025-05-01 14:32:40 +0200
commit5c50f36cca528c586e72d389c35774ecb64091be (patch)
tree0c94147f2d9f94a7503269359103f7098a96bc35
parent23cba7cd6b32b7c5db98aa5a3f9206d4bce07902 (diff)
Refactor le serveur webhook HTTP pour améliorer la gestion des événements et des connexions, en ajoutant la prise en charge de l'architecture macOS et en optimisant la gestion des descripteurs de fichiers.
-rw-r--r--.gitignore1
-rw-r--r--.vscode/settings.json2
-rw-r--r--bot/include/http_webhook_server.hpp29
-rw-r--r--bot/src/http_webhook_server.cpp140
4 files changed, 137 insertions, 35 deletions
diff --git a/.gitignore b/.gitignore
index e123953..0deb2c8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,4 @@ devenv.local.nix
.pre-commit-config.yaml
build
discord-bot
+.cache/*
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 42e44f8..798eedd 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,5 @@
{
- "cmake.sourceDirectory": "/home/exa/perso/bot-creator-api/bot",
+ "cmake.sourceDirectory": "/Users/jeremy/Documents/bot-creator-api/bot",
"files.associations": {
"map": "cpp",
"__bit_reference": "cpp",
diff --git a/bot/include/http_webhook_server.hpp b/bot/include/http_webhook_server.hpp
index a42829f..8ba6841 100644
--- a/bot/include/http_webhook_server.hpp
+++ b/bot/include/http_webhook_server.hpp
@@ -1,12 +1,18 @@
#pragma once
-#include <sys/epoll.h>
-#include <netinet/in.h>
#include <functional>
#include <string>
#include <unordered_map>
#include <system_error>
#include <sstream>
+#include <string>
+#include <netinet/in.h>
+
+#ifdef __linux__
+ #include <sys/epoll.h>
+#elif defined(__APPLE__)
+ #include <sys/event.h>
+#endif
class HttpWebhookServer {
public:
@@ -27,7 +33,8 @@ public:
HttpWebhookServer(uint16_t port, Handler handler);
~HttpWebhookServer();
-
+ void setupEpoll();
+ void handleEvents();
void start();
void stop();
@@ -39,17 +46,29 @@ private:
};
void setupSocket();
- void setupEpoll();
- void handleEvent(struct epoll_event* event);
+ void setupEventLoop();
+ void handleEvent(int fd, uint32_t events);
void handleClient(int fd);
void closeClient(int fd);
+ void registerFdForRead(int fd);
+ void modifyFdToWrite(int fd);
+ void sendToClient(int fd);
void parseHttpRequest(ClientContext& ctx, HttpRequest& req);
void buildHttpResponse(const HttpResponse& res, std::string& output);
int server_fd = -1;
+ int event_fd = -1;
int epoll_fd = -1;
bool running = false;
uint16_t port;
Handler request_handler;
std::unordered_map<int, ClientContext> clients;
+
+#ifdef __linux__
+ static constexpr int MAX_EVENTS = 64;
+ struct epoll_event events[MAX_EVENTS];
+#elif defined(__APPLE__)
+ static constexpr int MAX_EVENTS = 64;
+ struct kevent events[MAX_EVENTS];
+#endif
};
diff --git a/bot/src/http_webhook_server.cpp b/bot/src/http_webhook_server.cpp
index a6daa63..fd01a1f 100644
--- a/bot/src/http_webhook_server.cpp
+++ b/bot/src/http_webhook_server.cpp
@@ -3,6 +3,15 @@
#include <unistd.h>
#include <cstring>
#include <algorithm>
+#include <sstream>
+#include <stdexcept>
+#include <system_error>
+
+#ifdef __linux__
+#include <sys/epoll.h>
+#elif defined(__APPLE__)
+#include <sys/event.h>
+#endif
HttpWebhookServer::HttpWebhookServer(uint16_t port, Handler handler)
: port(port), request_handler(handler) {
@@ -17,12 +26,16 @@ HttpWebhookServer::~HttpWebhookServer() {
}
void HttpWebhookServer::setupSocket() {
- server_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
- if (server_fd == -1) throw std::system_error(errno, std::generic_category());
+ server_fd = ::socket(AF_INET, SOCK_STREAM, 0);
+ if (server_fd == -1)
+ throw std::system_error(errno, std::generic_category());
int opt = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+ if (::fcntl(server_fd, F_SETFL, O_NONBLOCK) == -1)
+ throw std::system_error(errno, std::generic_category());
+
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
@@ -36,6 +49,7 @@ void HttpWebhookServer::setupSocket() {
}
void HttpWebhookServer::setupEpoll() {
+#ifdef __linux__
epoll_fd = ::epoll_create1(0);
if (epoll_fd == -1)
throw std::system_error(errno, std::generic_category());
@@ -46,33 +60,96 @@ void HttpWebhookServer::setupEpoll() {
if (::epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) == -1)
throw std::system_error(errno, std::generic_category());
+
+#elif defined(__APPLE__)
+ epoll_fd = ::kqueue();
+ if (epoll_fd == -1)
+ throw std::system_error(errno, std::generic_category());
+
+ struct kevent ev_set;
+ EV_SET(&ev_set, server_fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, nullptr);
+ if (kevent(epoll_fd, &ev_set, 1, nullptr, 0, nullptr) == -1)
+ throw std::system_error(errno, std::generic_category());
+#endif
+}
+
+void HttpWebhookServer::registerFdForRead(int fd) {
+#ifdef __linux__
+ epoll_event event{};
+ event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
+ event.data.fd = fd;
+ ::epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event);
+#elif defined(__APPLE__)
+ struct kevent ev_set;
+ EV_SET(&ev_set, fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, nullptr);
+ kevent(epoll_fd, &ev_set, 1, nullptr, 0, nullptr);
+#endif
+}
+
+void HttpWebhookServer::modifyFdToWrite(int fd) {
+#ifdef __linux__
+ epoll_event event{};
+ event.events = EPOLLOUT | EPOLLET | EPOLLRDHUP;
+ event.data.fd = fd;
+ ::epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &event);
+#elif defined(__APPLE__)
+ struct kevent ev_set[2];
+ EV_SET(&ev_set[0], fd, EVFILT_READ, EV_DELETE, 0, 0, nullptr);
+ EV_SET(&ev_set[1], fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, nullptr);
+ kevent(epoll_fd, ev_set, 2, nullptr, 0, nullptr);
+#endif
}
void HttpWebhookServer::start() {
running = true;
+
+#ifdef __linux__
epoll_event events[64];
+#elif defined(__APPLE__)
+ struct kevent events[64];
+#endif
while (running) {
+#ifdef __linux__
int nfds = ::epoll_wait(epoll_fd, events, 64, -1);
+#elif defined(__APPLE__)
+ int nfds = ::kevent(epoll_fd, nullptr, 0, events, 64, nullptr);
+#endif
if (nfds == -1 && errno != EINTR)
throw std::system_error(errno, std::generic_category());
for (int i = 0; i < nfds; ++i) {
- if (events[i].data.fd == server_fd) {
+#ifdef __linux__
+ int fd = events[i].data.fd;
+ bool isWritable = events[i].events & EPOLLOUT;
+#elif defined(__APPLE__)
+ int fd = static_cast<int>(events[i].ident);
+ bool isWritable = events[i].filter == EVFILT_WRITE;
+#endif
+
+ if (fd == server_fd) {
while (true) {
sockaddr_in client_addr{};
socklen_t client_len = sizeof(client_addr);
+
+#ifdef __linux__
int client_fd = ::accept4(server_fd, (sockaddr*)&client_addr, &client_len, SOCK_NONBLOCK);
+#elif defined(__APPLE__)
+ int client_fd = ::accept(server_fd, (sockaddr*)&client_addr, &client_len);
+ if (client_fd != -1) {
+ int flags = fcntl(client_fd, F_GETFL, 0);
+ fcntl(client_fd, F_SETFL, flags | O_NONBLOCK);
+ }
+#endif
if (client_fd == -1) break;
- epoll_event event{};
- event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
- event.data.fd = client_fd;
- ::epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event);
clients[client_fd] = ClientContext{};
+ registerFdForRead(client_fd);
}
+ } else if (isWritable) {
+ sendToClient(fd);
} else {
- handleClient(events[i].data.fd);
+ handleClient(fd);
}
}
}
@@ -83,11 +160,35 @@ void HttpWebhookServer::stop() {
}
void HttpWebhookServer::closeClient(int fd) {
+#ifdef __linux__
::epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, nullptr);
+#elif defined(__APPLE__)
+ struct kevent ev_del[2];
+ EV_SET(&ev_del[0], fd, EVFILT_READ, EV_DELETE, 0, 0, nullptr);
+ EV_SET(&ev_del[1], fd, EVFILT_WRITE, EV_DELETE, 0, 0, nullptr);
+ kevent(epoll_fd, ev_del, 2, nullptr, 0, nullptr);
+#endif
::close(fd);
clients.erase(fd);
}
+void HttpWebhookServer::sendToClient(int fd) {
+ if (!clients.count(fd)) return;
+
+ auto& ctx = clients[fd];
+ if (!ctx.output_buffer.empty()) {
+ ssize_t sent = ::send(fd,
+ ctx.output_buffer.data() + ctx.bytes_written,
+ ctx.output_buffer.size() - ctx.bytes_written,
+ MSG_DONTWAIT);
+
+ if (sent > 0) ctx.bytes_written += sent;
+ if (ctx.bytes_written == ctx.output_buffer.size()) {
+ closeClient(fd);
+ }
+ }
+}
+
void HttpWebhookServer::handleClient(int fd) {
char buffer[4096];
ssize_t count = ::recv(fd, buffer, sizeof(buffer), MSG_DONTWAIT);
@@ -103,31 +204,12 @@ void HttpWebhookServer::handleClient(int fd) {
HttpResponse res = request_handler(req);
buildHttpResponse(res, ctx.output_buffer);
- epoll_event event{};
- event.events = EPOLLOUT | EPOLLET | EPOLLRDHUP;
- event.data.fd = fd;
- ::epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &event);
+ modifyFdToWrite(fd);
}
- }
- else if (count == 0 || (count == -1 && errno != EAGAIN)) {
+ } else if (count == 0 || (count == -1 && errno != EAGAIN)) {
closeClient(fd);
return;
}
-
- if (!clients.count(fd)) return; // Client déjà fermé plus haut
-
- auto& ctx = clients[fd];
- if (!ctx.output_buffer.empty()) {
- ssize_t sent = ::send(fd,
- ctx.output_buffer.data() + ctx.bytes_written,
- ctx.output_buffer.size() - ctx.bytes_written,
- MSG_DONTWAIT);
-
- if (sent > 0) ctx.bytes_written += sent;
- if (ctx.bytes_written == ctx.output_buffer.size()) {
- closeClient(fd);
- }
- }
}
void HttpWebhookServer::parseHttpRequest(ClientContext& ctx, HttpRequest& req) {