summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordelikesance <95828763+delikesance@users.noreply.github.com>2025-05-01 14:41:11 +0200
committerGitHub <noreply@github.com>2025-05-01 14:41:11 +0200
commit26207c990abdb9ce7f2cc8e9e371d63fcb439d46 (patch)
treebfe7ffb3281fb8e8cb0c52346b39e821cf2b43d2
parent39bfa6bca0b10a917258b87f722557339cf12e3d (diff)
parent5c50f36cca528c586e72d389c35774ecb64091be (diff)
Merge branch 'ketsuna-org:main' into main
-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) {