summaryrefslogtreecommitdiff
path: root/bot/include
diff options
context:
space:
mode:
Diffstat (limited to 'bot/include')
-rw-r--r--bot/include/server.cpp182
-rw-r--r--bot/include/utils.cpp38
-rw-r--r--bot/include/utils.hpp22
3 files changed, 234 insertions, 8 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_;
+};
diff --git a/bot/include/utils.cpp b/bot/include/utils.cpp
index 6a47d42..081fd4e 100644
--- a/bot/include/utils.cpp
+++ b/bot/include/utils.cpp
@@ -20,7 +20,7 @@ namespace app
return g.get_icon_url(1024, i_webp);
}
- std::string update_string(const std::string &initial, const std::map<std::string, std::string> &updates)
+ std::string update_string(const std::string &initial, const std::unordered_map<std::string, std::string> &updates)
{
static const std::regex placeholderRegex(R"(\(\((.*?)\)\))", std::regex::icase);
@@ -62,12 +62,12 @@ namespace app
return result;
}
// Forward declaration
- void process_interaction_option(const slashcommand_t &event, const command_data_option &option, std::map<std::string, std::string> &kv);
+ void process_interaction_option(const slashcommand_t &event, const command_data_option &option, std::unordered_map<std::string, std::string> &kv);
// Génère la map clé/valeur
- std::map<std::string, std::string> generate_key_values(const slashcommand_t &event)
+ std::unordered_map<std::string, std::string> generate_key_values(const slashcommand_t &event)
{
- std::map<std::string, std::string> key_values;
+ std::unordered_map<std::string, std::string> key_values;
const guild *g = event.command.is_guild_interaction() ? &event.command.get_guild() : nullptr;
const channel &c = event.command.get_channel();
const user &u = event.command.get_issuing_user();
@@ -98,7 +98,7 @@ namespace app
}
// Traite une option d'interaction récursivement
- void process_interaction_option(const slashcommand_t &event, const command_data_option &option, std::map<std::string, std::string> &kv)
+ void process_interaction_option(const slashcommand_t &event, const command_data_option &option, std::unordered_map<std::string, std::string> &kv)
{
switch (option.type)
{
@@ -184,4 +184,32 @@ namespace app
break;
}
}
+
+ nlohmann::json json_from_string(const std::string &str)
+ {
+ nlohmann::json j;
+ try
+ {
+ j = nlohmann::json::parse(str);
+ }
+ catch (const nlohmann::json::parse_error &e)
+ {
+ std::cerr << "JSON parse error: " << e.what() << std::endl;
+ }
+ return j;
+ }
+
+ std::string string_from_json(const nlohmann::json &j)
+ {
+ std::string str;
+ try
+ {
+ str = j.dump();
+ }
+ catch (const nlohmann::json::exception &e)
+ {
+ std::cerr << "JSON exception: " << e.what() << std::endl;
+ }
+ return str;
+ }
}
diff --git a/bot/include/utils.hpp b/bot/include/utils.hpp
index 19c834c..57f4005 100644
--- a/bot/include/utils.hpp
+++ b/bot/include/utils.hpp
@@ -37,7 +37,7 @@ namespace app
* @param updates A map of key-value pairs to replace placeholders
* @return std::string The updated string with placeholders replaced
*/
- std::string update_string(const std::string &initial, const std::map<std::string, std::string> &updates);
+ std::string update_string(const std::string &initial, const std::unordered_map<std::string, std::string> &updates);
/**
* @brief Processes a command option recursively and adds values to the key-value map
@@ -46,7 +46,7 @@ namespace app
* @param option The command option to process
* @param kv The key-value map to update
*/
- void process_interaction_option(const slashcommand_t &event, const command_data_option &option, std::map<std::string, std::string> &kv);
+ void process_interaction_option(const slashcommand_t &event, const command_data_option &option, std::unordered_map<std::string, std::string> &kv);
/**
* @brief Generates a map of key-value pairs from a slash command event
@@ -54,7 +54,23 @@ namespace app
* @param event The slash command event
* @return std::map<std::string, std::string> A map containing information about the command, user, guild, and options
*/
- std::map<std::string, std::string> generate_key_values(const slashcommand_t &event);
+ std::unordered_map<std::string, std::string> generate_key_values(const slashcommand_t &event);
+
+ /**
+ * @brief Parses a JSON string into a JSON object
+ *
+ * @param str The JSON string to parse
+ * @return nlohmann::json The parsed JSON object
+ */
+ nlohmann::json json_from_string(const std::string &str);
+
+ /**
+ * @brief Converts a JSON object into a string
+ *
+ * @param j The JSON object to convert
+ * @return std::string The string representation of the JSON object
+ */
+ std::string string_from_json(const nlohmann::json &j);
} // namespace dpp