From e98bd9de6ca1e159938778719fd6a42c7c9fbc47 Mon Sep 17 00:00:00 2001 From: Syping Date: Sun, 29 Mar 2026 07:32:37 +0200 Subject: [PATCH] add http_header class and bot::http namespace --- CMakeLists.txt | 3 +- src/core/http_headers.cpp | 87 +++++++++++++++++++ src/core/http_headers.h | 53 +++++++++++ src/core/http_request.cpp | 43 ++------- src/core/http_request.h | 29 ++++--- src/core/http_response.h | 13 +-- src/translator/deepl/deepl.cpp | 9 +- src/translator/deepl/deepl.h | 1 - .../libretranslate/libretranslate.cpp | 10 +-- .../libretranslate/libretranslate.h | 1 - .../lingvatranslate/lingvatranslate.cpp | 3 +- .../lingvatranslate/lingvatranslate.h | 1 - src/translator/mozhi/mozhi.cpp | 3 +- src/translator/mozhi/mozhi.h | 1 - 14 files changed, 185 insertions(+), 72 deletions(-) create mode 100644 src/core/http_headers.cpp create mode 100644 src/core/http_headers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d32ddf5..43d4b60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,7 +119,8 @@ if (UNIX AND NOT APPLE) endif() # dtranslatebot Target + Installs -add_executable(dtranslatebot ${DTRANSLATEBOT_HEADERS} ${DTRANSLATEBOT_SOURCES} ${DTRANSLATEBOT_RESOURCES}) +add_executable(dtranslatebot ${DTRANSLATEBOT_HEADERS} ${DTRANSLATEBOT_SOURCES} ${DTRANSLATEBOT_RESOURCES} + src/core/http_headers.h src/core/http_headers.cpp) if (WITH_DPP_STATIC_BUNDLE) add_dependencies(dtranslatebot DPP) endif() diff --git a/src/core/http_headers.cpp b/src/core/http_headers.cpp new file mode 100644 index 0000000..632b518 --- /dev/null +++ b/src/core/http_headers.cpp @@ -0,0 +1,87 @@ +/***************************************************************************** +* dtranslatebot Discord Translate Bot +* Copyright (C) 2026 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 "http_headers.h" +using namespace bot::http; + +http_headers::http_headers() { + instance = nullptr; +} + +http_headers::http_headers(const std::string &field, const std::string &value) { + instance = nullptr; + add(field, value); +} + +http_headers::http_headers(const http_header &header) { + instance = nullptr; + add(header); +} + +http_headers::http_headers(const std::initializer_list &headers) { + instance = nullptr; + add(headers); +} + +http_headers::http_headers(const std::vector &headers) { + instance = nullptr; + add(headers); +} + +http_headers::~http_headers() { + curl_slist_free_all(instance); +} + +void http_headers::add(const std::string &field, const std::string &value) { + const std::string header = field + ": " + value; + curl_slist *headers = curl_slist_append(instance, header.c_str()); + if (!headers) + throw std::bad_alloc(); + instance = headers; +} + +void http_headers::add(const http_header &header) { + add(header.first, header.second); +} + +void http_headers::add(const std::initializer_list &headers) { + for (const auto &header : headers) + add(header); +} + +void http_headers::add(const std::vector &headers) { + for (const auto &header : headers) + add(header); +} + +void http_headers::remove(const std::string &field) { + const std::string header = field + ":"; + curl_slist *headers = curl_slist_append(instance, header.c_str()); + if (!headers) + throw std::bad_alloc(); + instance = headers; +} + +void http_headers::remove(const std::vector &fields) { + for (const auto &field : fields) + remove(field); +} + +const curl_slist* http_headers::data() const { + return instance; +} diff --git a/src/core/http_headers.h b/src/core/http_headers.h new file mode 100644 index 0000000..4547139 --- /dev/null +++ b/src/core/http_headers.h @@ -0,0 +1,53 @@ +/***************************************************************************** +* dtranslatebot Discord Translate Bot +* Copyright (C) 2026 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 HTTP_HEADERS_H +#define HTTP_HEADERS_H +#include +#include +#include +#include +#include + +namespace bot { + namespace http { + typedef std::pair http_header; + + class http_headers { + public: + http_headers(); + http_headers(const std::string &field, const std::string &value); + http_headers(const http_header &header); + http_headers(const std::initializer_list &headers); + http_headers(const std::vector &headers); + ~http_headers(); + void add(const std::string &field, const std::string &value); + void add(const http_header &header); + void add(const std::initializer_list &headers); + void add(const std::vector &headers); + void remove(const std::string &field); + void remove(const std::vector &fields); + const curl_slist* data() const; + + private: + curl_slist *instance; + }; + } +} + +#endif // HTTP_HEADERS_H diff --git a/src/core/http_request.cpp b/src/core/http_request.cpp index d9f6498..dde7872 100644 --- a/src/core/http_request.cpp +++ b/src/core/http_request.cpp @@ -17,6 +17,7 @@ *****************************************************************************/ #include "http_request.h" +using namespace bot::http; http_request::http_request() { instance = curl_easy_init(); @@ -24,56 +25,23 @@ http_request::http_request() { throw std::bad_alloc(); } -const http_response http_request::get(const std::string &url, const dpp::http_headers &headers) { +const http_response http_request::get(const std::string &url, const http_headers &headers) { http_response response; curl_easy_setopt(instance, CURLOPT_URL, url.c_str()); - curl_slist *header_slist = nullptr; - if (!headers.empty()) { - for (const auto &header : headers) { - curl_slist *new_header_slist = curl_slist_append(header_slist, std::string(header.first + ": " + header.second).c_str()); - if (!new_header_slist) { - curl_slist_free_all(header_slist); - throw std::bad_alloc(); - } - header_slist = new_header_slist; - } - } - if (header_slist) - curl_easy_setopt(instance, CURLOPT_HTTPHEADER, header_slist); + curl_easy_setopt(instance, CURLOPT_HTTPHEADER, headers.data()); curl_easy_setopt(instance, CURLOPT_WRITEDATA, &response.content); curl_easy_setopt(instance, CURLOPT_WRITEFUNCTION, &writer); CURLcode result = curl_easy_perform(instance); if (result == CURLE_OK) curl_easy_getinfo(instance, CURLINFO_RESPONSE_CODE, &response.status); curl_easy_reset(instance); - curl_slist_free_all(header_slist); return response; } -const http_response http_request::post(const std::string &url, const std::string &content, const std::string &content_type, const dpp::http_headers &headers) { +const http_response http_request::post(const std::string &url, const std::string &content, const http_headers &headers) { http_response response; curl_easy_setopt(instance, CURLOPT_URL, url.c_str()); - curl_slist *header_slist = nullptr; - if (!content_type.empty()) { - curl_slist *new_header_slist = curl_slist_append(header_slist, std::string("Content-Type: " + content_type).c_str()); - if (!new_header_slist) { - curl_slist_free_all(header_slist); - throw std::bad_alloc(); - } - header_slist = new_header_slist; - } - if (!headers.empty()) { - for (const auto &header : headers) { - curl_slist *new_header_slist = curl_slist_append(header_slist, std::string(header.first + ": " + header.second).c_str()); - if (!new_header_slist) { - curl_slist_free_all(header_slist); - throw std::bad_alloc(); - } - header_slist = new_header_slist; - } - } - if (header_slist) - curl_easy_setopt(instance, CURLOPT_HTTPHEADER, header_slist); + curl_easy_setopt(instance, CURLOPT_HTTPHEADER, headers.data()); curl_easy_setopt(instance, CURLOPT_POSTFIELDS, content.data()); curl_easy_setopt(instance, CURLOPT_POSTFIELDSIZE, content.size()); curl_easy_setopt(instance, CURLOPT_WRITEDATA, &response.content); @@ -82,7 +50,6 @@ const http_response http_request::post(const std::string &url, const std::string if (result == CURLE_OK) curl_easy_getinfo(instance, CURLINFO_RESPONSE_CODE, &response.status); curl_easy_reset(instance); - curl_slist_free_all(header_slist); return response; } diff --git a/src/core/http_request.h b/src/core/http_request.h index e9bb387..082c1c2 100644 --- a/src/core/http_request.h +++ b/src/core/http_request.h @@ -20,21 +20,24 @@ #define HTTP_REQUEST_H #include #include -#include +#include "http_headers.h" #include "http_response.h" -class http_request -{ -public: - http_request(); - ~http_request(); - const http_response get(const std::string &url, const dpp::http_headers &headers = {}); - const http_response post(const std::string &url, const std::string &content, const std::string &content_type, const dpp::http_headers &headers = {}); - static std::string legacy_url(const std::string &hostname, uint16_t port, const std::string &url, bool tls); +namespace bot { + namespace http { + class http_request { + public: + http_request(); + ~http_request(); + const http_response get(const std::string &url, const http_headers &headers = {}); + const http_response post(const std::string &url, const std::string &content, const http_headers &headers = {}); + static std::string legacy_url(const std::string &hostname, uint16_t port, const std::string &url, bool tls); -private: - static size_t writer(char *source, size_t size, size_t nmemb, std::string *target); - CURL *instance; -}; + private: + static size_t writer(char *source, size_t size, size_t nmemb, std::string *target); + CURL *instance; + }; + } +} #endif // HTTP_REQUEST_H diff --git a/src/core/http_response.h b/src/core/http_response.h index 2364e13..e4cc06a 100644 --- a/src/core/http_response.h +++ b/src/core/http_response.h @@ -20,10 +20,13 @@ #define HTTP_RESPONSE_H #include -struct http_response -{ - std::string content; - long status; -}; +namespace bot { + namespace http { + struct http_response { + std::string content; + long status; + }; + } +} #endif // HTTP_RESPONSE_H diff --git a/src/translator/deepl/deepl.cpp b/src/translator/deepl/deepl.cpp index ab509af..794c259 100644 --- a/src/translator/deepl/deepl.cpp +++ b/src/translator/deepl/deepl.cpp @@ -17,9 +17,10 @@ *****************************************************************************/ #include -#include +#include #include "../../core/http_request.h" #include "deepl.h" +using namespace bot::http; using namespace bot::translator; using namespace std::chrono_literals; @@ -43,7 +44,8 @@ const std::vector deepl::get_languages() try { http_request request; - http_response response = request.get(http_request::legacy_url(m_hostname, 443, "/v2/languages?type=target", true), { {"Authorization", "DeepL-Auth-Key " + m_apiKey} }); + http_response response = request.get(http_request::legacy_url(m_hostname, 443, "/v2/languages?type=target", true), + {{"Authorization", "DeepL-Auth-Key " + m_apiKey}}); if (response.status == 200) { const dpp::json json_response = dpp::json::parse(response.content); if (json_response.is_array()) { @@ -91,7 +93,8 @@ const std::string deepl::translate(const std::string &text, const std::string &s try { http_request request; - http_response response = request.post(http_request::legacy_url(m_hostname, 443, "/v2/translate", true), json_body.dump(), "application/json", { {"Authorization", "DeepL-Auth-Key " + m_apiKey} }); + http_response response = request.post(http_request::legacy_url(m_hostname, 443, "/v2/translate", true), json_body.dump(), + {{"Authorization", "DeepL-Auth-Key " + m_apiKey}, {"Content-Type", "application/json"}}); if (response.status == 200) { const dpp::json json_response = dpp::json::parse(response.content); if (json_response.is_object()) { diff --git a/src/translator/deepl/deepl.h b/src/translator/deepl/deepl.h index 6fd90f9..99ed5f8 100644 --- a/src/translator/deepl/deepl.h +++ b/src/translator/deepl/deepl.h @@ -19,7 +19,6 @@ #ifndef TRANSLATOR_DEEPL_H #define TRANSLATOR_DEEPL_H -#include #include "../../core/translator.h" namespace bot { diff --git a/src/translator/libretranslate/libretranslate.cpp b/src/translator/libretranslate/libretranslate.cpp index 41cb49b..0647a92 100644 --- a/src/translator/libretranslate/libretranslate.cpp +++ b/src/translator/libretranslate/libretranslate.cpp @@ -17,9 +17,10 @@ *****************************************************************************/ #include -#include +#include #include "../../core/http_request.h" #include "libretranslate.h" +using namespace bot::http; using namespace bot::translator; using namespace std::chrono_literals; @@ -77,10 +78,6 @@ const std::vector libretranslate::get_languages() const std::string libretranslate::translate(const std::string &text, const std::string &source, const std::string &target) { - const dpp::http_headers http_headers = { - {"Content-Type", "application/json"} - }; - dpp::json json_body = { {"q", text}, {"source", source.empty() ? "auto" : source}, @@ -93,7 +90,8 @@ const std::string libretranslate::translate(const std::string &text, const std:: try { http_request request; - http_response response = request.post(http_request::legacy_url(m_hostname, m_port, m_url + "translate", m_tls), json_body.dump(), "application/json"); + http_response response = request.post(http_request::legacy_url(m_hostname, m_port, m_url + "translate", m_tls), json_body.dump(), + {{"Content-Type", "application/json"}}); if (response.status == 200) { const dpp::json json_response = dpp::json::parse(response.content); if (json_response.is_object()) { diff --git a/src/translator/libretranslate/libretranslate.h b/src/translator/libretranslate/libretranslate.h index 04c0439..1af2f97 100644 --- a/src/translator/libretranslate/libretranslate.h +++ b/src/translator/libretranslate/libretranslate.h @@ -20,7 +20,6 @@ #define TRANSLATOR_LIBRETRANSLATE_H #include -#include #include "../../core/translator.h" namespace bot { diff --git a/src/translator/lingvatranslate/lingvatranslate.cpp b/src/translator/lingvatranslate/lingvatranslate.cpp index b1f82d6..74c84eb 100644 --- a/src/translator/lingvatranslate/lingvatranslate.cpp +++ b/src/translator/lingvatranslate/lingvatranslate.cpp @@ -17,10 +17,11 @@ *****************************************************************************/ #include -#include #include +#include #include "../../core/http_request.h" #include "lingvatranslate.h" +using namespace bot::http; using namespace bot::translator; using namespace std::chrono_literals; diff --git a/src/translator/lingvatranslate/lingvatranslate.h b/src/translator/lingvatranslate/lingvatranslate.h index cf65739..37cf604 100644 --- a/src/translator/lingvatranslate/lingvatranslate.h +++ b/src/translator/lingvatranslate/lingvatranslate.h @@ -20,7 +20,6 @@ #define TRANSLATOR_LINGVATRANSLATE_H #include -#include #include "../../core/translator.h" namespace bot { diff --git a/src/translator/mozhi/mozhi.cpp b/src/translator/mozhi/mozhi.cpp index dced526..2a3e1fb 100644 --- a/src/translator/mozhi/mozhi.cpp +++ b/src/translator/mozhi/mozhi.cpp @@ -17,10 +17,11 @@ *****************************************************************************/ #include -#include #include +#include #include "../../core/http_request.h" #include "mozhi.h" +using namespace bot::http; using namespace bot::translator; using namespace std::chrono_literals; diff --git a/src/translator/mozhi/mozhi.h b/src/translator/mozhi/mozhi.h index 1602096..ac3aba6 100644 --- a/src/translator/mozhi/mozhi.h +++ b/src/translator/mozhi/mozhi.h @@ -20,7 +20,6 @@ #define TRANSLATOR_MOZHI_H #include -#include #include "../../core/translator.h" namespace bot {