From 5e78c2728a83a63d215e00ce6443059302e0004c Mon Sep 17 00:00:00 2001 From: Syping Date: Fri, 12 Jan 2024 12:53:16 +0100 Subject: [PATCH] add submit_queue, translate other bots, few minor changes --- CMakeLists.txt | 2 ++ src/main.cpp | 24 +++++++++++++---- src/message_queue.cpp | 54 ++++++++++++++++++++++++------------- src/message_queue.h | 5 +++- src/settings.cpp | 37 ++++++++++++++++++------- src/settings.h | 4 ++- src/submit_queue.cpp | 63 +++++++++++++++++++++++++++++++++++++++++++ src/submit_queue.h | 46 +++++++++++++++++++++++++++++++ 8 files changed, 201 insertions(+), 34 deletions(-) create mode 100644 src/submit_queue.cpp create mode 100644 src/submit_queue.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f77034..f34f92b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,8 @@ add_executable(${PROJECT_NAME} src/message_queue.h src/settings.cpp src/settings.h + src/submit_queue.cpp + src/submit_queue.h ) set(THREADS_PREFER_PTHREAD_FLAG ON) diff --git a/src/main.cpp b/src/main.cpp index f8e0d93..1a25e0a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,14 +36,22 @@ int main(int argc, char* argv[]) { bot.on_log(dpp::utility::cout_logger()); + bot::submit_queue submit_queue; + std::thread submit_queue_loop(&bot::submit_queue::run, &submit_queue, &bot); + bot::message_queue message_queue; - std::thread message_queue_loop(&bot::message_queue::run, &message_queue, &bot, &settings); + std::thread message_queue_loop(&bot::message_queue::run, &message_queue, &settings, &submit_queue); bot.on_message_create([&bot, &message_queue, &settings](const dpp::message_create_t &event) { - if (event.msg.author.is_bot()) - return; + if (event.msg.webhook_id) { + const std::lock_guard guard(settings); - settings.lock(); + // We will not translate messages from our own bot + if (settings.is_translatebot(event.msg.webhook_id)) + return; + } + + const std::lock_guard guard(settings); bot::settings::channel *channel = settings.get_channel(event.msg.guild_id, event.msg.channel_id); if (channel) { bot::message message; @@ -55,10 +63,16 @@ int main(int argc, char* argv[]) { message.targets = channel->targets; message_queue.add(message); } - settings.unlock(); }); bot.start(dpp::st_wait); + // It's unneccessary, but we choose to exit clean anyway + message_queue.terminate(); + message_queue_loop.join(); + + submit_queue.terminate(); + submit_queue_loop.join(); + return 0; } diff --git a/src/message_queue.cpp b/src/message_queue.cpp index 1927c7a..f10cb89 100644 --- a/src/message_queue.cpp +++ b/src/message_queue.cpp @@ -16,12 +16,20 @@ * responsible for anything with use of the software, you are self responsible. *****************************************************************************/ -#include #include #include "message_queue.h" #include "settings.h" using namespace std::chrono_literals; +inline bot::translated_message make_translated_message(const bot::message &message, const std::string &translated_message, const std::string &webhook) +{ + bot::translated_message tr_message; + tr_message.author = message.author; + tr_message.message = translated_message; + tr_message.webhook = webhook; + return tr_message; +} + void bot::message_queue::add(const bot::message &message) { m_mutex.lock(); @@ -29,9 +37,10 @@ void bot::message_queue::add(const bot::message &message) m_mutex.unlock(); } -void bot::message_queue::run(dpp::cluster *bot, bot::settings::settings *settings) +void bot::message_queue::run(bot::settings::settings *settings, bot::submit_queue *submit_queue) { - while (true) { + m_running = true; + while (m_running) { m_mutex.lock(); if (!m_queue.empty()) { const bot::message message = m_queue.front(); @@ -62,25 +71,29 @@ void bot::message_queue::run(dpp::cluster *bot, bot::settings::settings *setting http_headers.emplace("Content-Type", "application/json"); std::string tr_message = message.message; - dpp::https_client http_request(tr_hostname, tr_port, tr_url, "POST", json_body.dump(), http_headers, !tr_tls); - if (http_request.get_status() == 200) { - dpp::json response = dpp::json::parse(http_request.get_content()); - if (response.is_object()) { - auto tr_text = response.find("translatedText"); - if (tr_text != response.end()) - tr_message = tr_text.value(); - } - } - - dpp::webhook webhook(target->webhook); - webhook.name = message.author; try { - bot->execute_webhook_sync(webhook, dpp::message(tr_message)); + dpp::https_client http_request(tr_hostname, tr_port, tr_url, "POST", json_body.dump(), http_headers, !tr_tls); + if (http_request.get_status() == 200) { + const dpp::json response = dpp::json::parse(http_request.get_content()); + if (response.is_object()) { + auto tr_text = response.find("translatedText"); + if (tr_text != response.end()) + tr_message = tr_text.value(); + } + } } - catch (const dpp::rest_exception &exception) { - std::cerr << "REST Error: " << exception.what() << std::endl; + catch (const dpp::json::exception &exception) { + std::cerr << "Exception thrown while parsing translated JSON: " << exception.what() << std::endl; } + catch (const std::exception &exception) { + std::cerr << "Exception thrown while translating: " << exception.what() << std::endl; + } + catch (...) { + std::cerr << "Exception thrown while translating: unknown" << std::endl; + } + + submit_queue->add(make_translated_message(message, tr_message, target->webhook)); } std::this_thread::yield(); @@ -91,3 +104,8 @@ void bot::message_queue::run(dpp::cluster *bot, bot::settings::settings *setting } } } + +void bot::message_queue::terminate() +{ + m_running = false; +} diff --git a/src/message_queue.h b/src/message_queue.h index 34a1712..a82186f 100644 --- a/src/message_queue.h +++ b/src/message_queue.h @@ -23,6 +23,7 @@ #include #include #include "settings.h" +#include "submit_queue.h" namespace bot { struct message { @@ -37,9 +38,11 @@ namespace bot { class message_queue { public: void add(const bot::message &message); - void run(dpp::cluster *bot, bot::settings::settings *settings); + void run(bot::settings::settings *settings, bot::submit_queue *submit_queue); + void terminate(); private: + bool m_running; std::mutex m_mutex; std::vector m_queue; }; diff --git a/src/settings.cpp b/src/settings.cpp index 3fb1151..a361aee 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -54,7 +54,7 @@ bot::settings::guild* bot::settings::settings::get_guild(uint64_t guild_id) bot::settings::translate* bot::settings::settings::get_translate() { - return &m_translate_settings; + return &m_translate; } const std::string bot::settings::settings::get_token() @@ -62,6 +62,15 @@ const std::string bot::settings::settings::get_token() return m_token; } +bool bot::settings::settings::is_translatebot(uint64_t webhook_id) +{ + for (auto id = m_webhookIds.begin(); id != m_webhookIds.end(); id++) { + if (*id == webhook_id) + return true; + } + return false; +} + void bot::settings::settings::lock() { m_mutex.lock(); @@ -79,7 +88,7 @@ bool bot::settings::settings::parse(const std::string &filename) ifs.close(); try { - dpp::json json = dpp::json::parse(sdata); + const dpp::json json = dpp::json::parse(sdata); if (!json.is_object()) { std::cerr << "JSON configuration file is corrupt" << std::endl; return false; @@ -110,33 +119,36 @@ bool bot::settings::settings::parse(const std::string &filename) std::cerr << "\"hostname\" can not be found in Translate settings" << std::endl; return false; } - m_translate_settings.hostname = json_translate_hostname.value(); + m_translate.hostname = json_translate_hostname.value(); auto json_translate_port = json_translate.value().find("port"); if (json_translate_port == json_translate.value().end()) { std::cerr << "\"port\" can not be found in Translate settings" << std::endl; return false; } - m_translate_settings.port = json_translate_port.value(); + m_translate.port = json_translate_port.value(); auto json_translate_url = json_translate.value().find("url"); if (json_translate_url == json_translate.value().end()) { std::cerr << "\"url\" can not be found in Translate settings" << std::endl; return false; } - m_translate_settings.url = json_translate_url.value(); + m_translate.url = json_translate_url.value(); auto json_translate_tls = json_translate.value().find("tls"); if (json_translate_tls != json_translate.value().end()) - m_translate_settings.tls = json_translate_tls.value(); + m_translate.tls = json_translate_tls.value(); else - m_translate_settings.tls = false; + m_translate.tls = false; auto json_translate_apiKey = json_translate.value().find("apiKey"); if (json_translate_apiKey != json_translate.value().end()) - m_translate_settings.apiKey = json_translate_apiKey.value(); + m_translate.apiKey = json_translate_apiKey.value(); else - m_translate_settings.apiKey.clear(); + m_translate.apiKey.clear(); + + m_guilds.clear(); + m_webhookIds.clear(); auto json_guilds = json.find("guilds"); if (json_guilds != json.end()) { @@ -183,6 +195,9 @@ bool bot::settings::settings::parse(const std::string &filename) target.target = json_channel_target.value(); target.webhook = json_channel->at("webhook"); channel.targets.push_back(target); + + const dpp::webhook webhook(target.webhook); + m_webhookIds.push_back(webhook.id); } else if (json_channel_target.value().is_object()) { for (auto json_target = json_channel_target.value().begin(); json_target != json_channel_target.value().end(); json_target++) { @@ -190,6 +205,9 @@ bool bot::settings::settings::parse(const std::string &filename) target.target = json_target.key(); target.webhook = json_target.value(); channel.targets.push_back(target); + + const dpp::webhook webhook(target.webhook); + m_webhookIds.push_back(webhook.id); } } } @@ -202,6 +220,7 @@ bool bot::settings::settings::parse(const std::string &filename) } } } + return true; } catch (const dpp::json::exception &exception) { diff --git a/src/settings.h b/src/settings.h index e359afc..f21d4ca 100644 --- a/src/settings.h +++ b/src/settings.h @@ -53,6 +53,7 @@ namespace bot { bot::settings::guild* get_guild(uint64_t guild_id); bot::settings::translate* get_translate(); const std::string get_token(); + bool is_translatebot(uint64_t webhook_id); void lock(); bool parse(const std::string &filename); void unlock(); @@ -60,8 +61,9 @@ namespace bot { private: std::recursive_mutex m_mutex; std::vector m_guilds; - bot::settings::translate m_translate_settings; + bot::settings::translate m_translate; std::string m_token; + std::vector m_webhookIds; }; } } diff --git a/src/submit_queue.cpp b/src/submit_queue.cpp new file mode 100644 index 0000000..ef2e8cf --- /dev/null +++ b/src/submit_queue.cpp @@ -0,0 +1,63 @@ +/***************************************************************************** +* dtranslatebot Discord Translate Bot +* Copyright (C) 2024 Syping +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* This software is provided as-is, no warranties are given to you, we are not +* responsible for anything with use of the software, you are self responsible. +*****************************************************************************/ + +#include +#include "submit_queue.h" +using namespace std::chrono_literals; + +void bot::submit_queue::add(const bot::translated_message &message) +{ + m_mutex.lock(); + m_queue.push_back(message); + m_mutex.unlock(); +} + +void bot::submit_queue::run(dpp::cluster *bot) +{ + m_running = true; + while (m_running) { + m_mutex.lock(); + if (!m_queue.empty()) { + const bot::translated_message message = m_queue.front(); + m_queue.erase(m_queue.begin()); + m_mutex.unlock(); + + dpp::webhook webhook(message.webhook); + webhook.name = message.author; + + try { + bot->execute_webhook_sync(webhook, dpp::message(message.message)); + } + catch (const dpp::rest_exception &exception) { + std::cerr << "REST Error: " << exception.what() << std::endl; + } + + std::this_thread::yield(); + } + else { + m_mutex.unlock(); + std::this_thread::sleep_for(100ms); + } + } +} + + +void bot::submit_queue::terminate() +{ + m_running = false; +} diff --git a/src/submit_queue.h b/src/submit_queue.h new file mode 100644 index 0000000..a1f2367 --- /dev/null +++ b/src/submit_queue.h @@ -0,0 +1,46 @@ +/***************************************************************************** +* dtranslatebot Discord Translate Bot +* Copyright (C) 2024 Syping +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* This software is provided as-is, no warranties are given to you, we are not +* responsible for anything with use of the software, you are self responsible. +*****************************************************************************/ + +#ifndef SUBMIT_QUEUE_H +#define SUBMIT_QUEUE_H +#include +#include +#include +#include + +namespace bot { + struct translated_message { + std::string author; + std::string message; + std::string webhook; + }; + + class submit_queue { + public: + void add(const bot::translated_message &message); + void run(dpp::cluster *bot); + void terminate(); + + private: + bool m_running; + std::mutex m_mutex; + std::vector m_queue; + }; +} + +#endif // SUBMIT_QUEUE_H