From b1329aa961efaaa33a3d2ca5bc9ef01521b35426 Mon Sep 17 00:00:00 2001 From: Syping Date: Mon, 25 Mar 2024 10:52:01 +0100 Subject: [PATCH] cache available languages and make translator shared --- src/core/settings.cpp | 41 ++++++++----------- src/core/settings.h | 4 +- src/core/settings_types.h | 7 +--- src/core/translator.h | 6 +++ src/translator/deepl/deepl.cpp | 34 ++++++++++----- src/translator/deepl/deepl.h | 1 + .../libretranslate/libretranslate.cpp | 26 ++++++++---- .../libretranslate/libretranslate.h | 2 + 8 files changed, 69 insertions(+), 52 deletions(-) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index ee0cbd9..37e6f59 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -220,23 +220,24 @@ void process_url(const std::string &url, translator &translator) } } -bool process_translator_settings(const dpp::json &json, translator &translator) +bool process_translator_settings(const dpp::json &json, std::shared_ptr &translator_instance) { if (!json.is_object()) { std::cerr << "[Error] Value translator needs to be a object" << std::endl; return false; } - std::string translator_type = "libretranslate"; + bot::settings::translator translator; auto json_translator_type = json.find("type"); if (json_translator_type != json.end()) { - translator_type = *json_translator_type; - std::transform(translator_type.begin(), translator_type.end(), translator_type.begin(), ::tolower); + translator.type = *json_translator_type; + std::transform(translator.type.begin(), translator.type.end(), translator.type.begin(), ::tolower); + } + else { + translator.type = "libretranslate"; } - if (translator_type == "deepl") { - translator.type = TRANSLATOR_DEEPL; - + if (translator.type == "deepl") { auto json_deepl_hostname = json.find("hostname"); if (json_deepl_hostname != json.end()) translator.hostname = *json_deepl_hostname; @@ -249,10 +250,10 @@ bool process_translator_settings(const dpp::json &json, translator &translator) return false; } translator.apiKey = *json_deepl_apiKey; - } - else if (translator_type == "libretranslate") { - translator.type = TRANSLATOR_LIBRETRANSLATE; + translator_instance = std::make_shared(translator.hostname, translator.apiKey); + } + else if (translator.type == "libretranslate") { auto json_lt_hostname = json.find("hostname"); if (json_lt_hostname != json.end()) translator.hostname = *json_lt_hostname; @@ -288,9 +289,11 @@ bool process_translator_settings(const dpp::json &json, translator &translator) translator.apiKey = *json_lt_apiKey; else translator.apiKey.clear(); + + translator_instance = std::make_shared(translator.hostname, translator.port, translator.url, translator.tls, translator.apiKey); } - else if (translator_type == "stub") { - translator.type = TRANSLATOR_STUB; + else if (translator.type == "stub") { + translator_instance = std::make_shared(); } else { std::cerr << "[Error] Translator " << translator.type << " is unknown" << std::endl; @@ -471,20 +474,10 @@ std::shared_ptr settings::get_database() const return m_database; } -std::unique_ptr settings::get_translator() const +std::shared_ptr settings::get_translator() const { const std::lock_guard guard(m_mutex); - - switch (m_translator.type) { - case TRANSLATOR_DEEPL: - return std::make_unique(m_translator.hostname, m_translator.apiKey); - case TRANSLATOR_LIBRETRANSLATE: - return std::make_unique(m_translator.hostname, m_translator.port, m_translator.url, m_translator.tls, m_translator.apiKey); - case TRANSLATOR_STUB: - return std::make_unique(); - default: - return std::make_unique(); - } + return m_translator; } const std::string settings::token() const diff --git a/src/core/settings.h b/src/core/settings.h index fe6b219..f71f812 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -47,7 +47,7 @@ namespace bot { static const target* get_target(const channel *channel, const std::string &target); const std::vector preferred_languages() const; std::shared_ptr get_database() const; - std::unique_ptr get_translator() const; + std::shared_ptr get_translator() const; const std::string token() const; /* is functions */ @@ -73,7 +73,7 @@ namespace bot { std::shared_ptr m_database; std::vector m_guilds; std::vector m_prefLangs; - bot::settings::translator m_translator; + std::shared_ptr m_translator; std::string m_token; std::vector m_webhookIds; }; diff --git a/src/core/settings_types.h b/src/core/settings_types.h index 3eed401..96d9017 100644 --- a/src/core/settings_types.h +++ b/src/core/settings_types.h @@ -40,13 +40,8 @@ namespace bot { dpp::snowflake id; std::vector channel; }; - enum translator_type { - TRANSLATOR_DEEPL, - TRANSLATOR_LIBRETRANSLATE, - TRANSLATOR_STUB - }; struct translator { - translator_type type; + std::string type; std::string hostname; uint16_t port; std::string url; diff --git a/src/core/translator.h b/src/core/translator.h index c230abd..91502d9 100644 --- a/src/core/translator.h +++ b/src/core/translator.h @@ -19,6 +19,7 @@ #ifndef TRANSLATOR_H #define TRANSLATOR_H +#include #include #include @@ -29,6 +30,11 @@ namespace bot { std::string name; }; + struct supported_languages { + std::vector languages; + std::chrono::system_clock::time_point query_time; + }; + class translator { public: explicit translator() = default; diff --git a/src/translator/deepl/deepl.cpp b/src/translator/deepl/deepl.cpp index 43d9c76..94a7dff 100644 --- a/src/translator/deepl/deepl.cpp +++ b/src/translator/deepl/deepl.cpp @@ -20,6 +20,7 @@ #include #include "deepl.h" using namespace bot::translator; +using namespace std::chrono_literals; using namespace std::string_literals; deepl::deepl(const std::string &hostname, const std::string apiKey) : @@ -33,31 +34,41 @@ deepl::~deepl() const std::vector deepl::get_languages() { - std::vector languages; + if (!m_languages.languages.empty()) { + auto current_time = std::chrono::system_clock::now(); + auto threshold_time = m_languages.query_time + 24h; + if (current_time <= threshold_time) + return m_languages.languages; + } try { dpp::https_client http_request(m_hostname, 443, "/v2/languages?type=target", "GET", {}, { {"Authorization"s, "DeepL-Auth-Key " + m_apiKey} }, false); if (http_request.get_status() == 200) { const dpp::json response = dpp::json::parse(http_request.get_content()); if (response.is_array()) { - for (const auto &json_language : response) { - if (json_language.is_object()) { + m_languages.languages.clear(); + for (auto json_language = response.begin(); json_language != response.end(); json_language++) { + if (json_language->is_object()) { language language; - auto json_lang_code = json_language.find("language"); - if (json_lang_code != json_language.end()) + auto json_lang_code = json_language->find("language"); + if (json_lang_code != json_language->end()) language.code = *json_lang_code; - std::transform(language.code.begin(), language.code.end(), language.code.begin(), ::tolower); + if (language.code.size() > 2) + std::transform(language.code.begin(), language.code.begin() + 2, language.code.begin(), ::tolower); + else + std::transform(language.code.begin(), language.code.end(), language.code.begin(), ::tolower); - auto json_lang_name = json_language.find("name"); - if (json_lang_name != json_language.end()) + auto json_lang_name = json_language->find("name"); + if (json_lang_name != json_language->end()) language.name = *json_lang_name; if (!language.code.empty() && !language.name.empty()) - languages.push_back(std::move(language)); + m_languages.languages.push_back(std::move(language)); } } + m_languages.query_time = std::chrono::system_clock::now(); } } } @@ -65,18 +76,19 @@ const std::vector deepl::get_languages() std::cerr << "[Exception] " << exception.what() << std::endl; } - return languages; + return m_languages.languages; } const std::string deepl::translate(const std::string &text, const std::string &source, const std::string &target) { const dpp::http_headers http_headers = { - {"Authorization"s, "DeepL-Auth-Key "s + m_apiKey}, + {"Authorization"s, "DeepL-Auth-Key " + m_apiKey}, {"Content-Type"s, "application/json"s} }; dpp::json json_body = { {"text"s, { text } }, + {"source_lang"s, source}, {"target_lang"s, target}, }; diff --git a/src/translator/deepl/deepl.h b/src/translator/deepl/deepl.h index a33031e..f1b6aa0 100644 --- a/src/translator/deepl/deepl.h +++ b/src/translator/deepl/deepl.h @@ -33,6 +33,7 @@ namespace bot { private: std::string m_apiKey; std::string m_hostname; + supported_languages m_languages; }; } } diff --git a/src/translator/libretranslate/libretranslate.cpp b/src/translator/libretranslate/libretranslate.cpp index 7e5e9e7..909dbb3 100644 --- a/src/translator/libretranslate/libretranslate.cpp +++ b/src/translator/libretranslate/libretranslate.cpp @@ -20,6 +20,7 @@ #include #include "libretranslate.h" using namespace bot::translator; +using namespace std::chrono_literals; using namespace std::string_literals; libretranslate::libretranslate(const std::string &hostname, uint16_t port, const std::string &url, bool tls, const std::string apiKey) : @@ -33,29 +34,36 @@ libretranslate::~libretranslate() const std::vector libretranslate::get_languages() { - std::vector languages; + if (!m_languages.languages.empty()) { + auto current_time = std::chrono::system_clock::now(); + auto threshold_time = m_languages.query_time + 24h; + if (current_time <= threshold_time) + return m_languages.languages; + } try { dpp::https_client http_request(m_hostname, m_port, m_url + "languages", "GET", {}, {}, !m_tls); if (http_request.get_status() == 200) { const dpp::json response = dpp::json::parse(http_request.get_content()); if (response.is_array()) { - for (const auto &json_language : response) { - if (json_language.is_object()) { + m_languages.languages.clear(); + for (auto json_language = response.begin(); json_language != response.end(); json_language++) { + if (json_language->is_object()) { language language; - auto json_lang_code = json_language.find("code"); - if (json_lang_code != json_language.end()) + auto json_lang_code = json_language->find("code"); + if (json_lang_code != json_language->end()) language.code = *json_lang_code; - auto json_lang_name = json_language.find("name"); - if (json_lang_name != json_language.end()) + auto json_lang_name = json_language->find("name"); + if (json_lang_name != json_language->end()) language.name = *json_lang_name; if (!language.code.empty() && !language.name.empty()) - languages.push_back(std::move(language)); + m_languages.languages.push_back(std::move(language)); } } + m_languages.query_time = std::chrono::system_clock::now(); } } } @@ -63,7 +71,7 @@ const std::vector libretranslate::get_languages() std::cerr << "[Exception] " << exception.what() << std::endl; } - return languages; + return m_languages.languages; } const std::string libretranslate::translate(const std::string &text, const std::string &source, const std::string &target) diff --git a/src/translator/libretranslate/libretranslate.h b/src/translator/libretranslate/libretranslate.h index 235a253..1af2f97 100644 --- a/src/translator/libretranslate/libretranslate.h +++ b/src/translator/libretranslate/libretranslate.h @@ -25,6 +25,7 @@ namespace bot { namespace translator { class libretranslate : public translator { + public: explicit libretranslate(const std::string &hostname, uint16_t port, const std::string &url, bool tls, const std::string apiKey = {}); ~libretranslate() override; @@ -34,6 +35,7 @@ namespace bot { private: std::string m_apiKey; std::string m_hostname; + supported_languages m_languages; uint16_t m_port; std::string m_url; bool m_tls;