#include "httplib.hpp" #include #include #include #include #include #include #include "PromtCtlDocument.hpp" #include "PromtFTManager.hpp" static inline std::string random_filename(int len = 65) { static const char ASCII_PRINTABLE[] = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; std::random_device random_device; std::mt19937 generator(random_device()); std::uniform_int_distribution distribution(0, static_cast(strlen(ASCII_PRINTABLE) - 1)); std::string random_string; for (std::size_t i = 0; i < len; ++i) random_string += ASCII_PRINTABLE[distribution(generator)]; return random_string; } static const char TMP_FOLDER[] = "C:\\tmpfs\\"; static const auto TMP_IN = TMP_FOLDER + random_filename(); static const auto TMP_OUT = TMP_FOLDER + random_filename(); static inline auto read_file(const std::string &filename) { char *in_buf = nullptr; { std::ifstream ifs(filename, std::ios::binary); ifs.seekg(0, ifs.end); size_t size = ifs.tellg(); ifs.seekg(0, ifs.beg); in_buf = new char[size + 1]; ifs.read(in_buf, size); in_buf[size] = 0; } int size = MultiByteToWideChar(1251, 0, in_buf, -1, NULL, 0); wchar_t *wstr = new wchar_t[size]; MultiByteToWideChar(1251, 0, in_buf, -1, wstr, size); delete[] in_buf; size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, 0, 0); std::string out; out.resize(size); WideCharToMultiByte(CP_UTF8, 0, wstr, -1, out.data(), size, 0, 0); delete[] wstr; return out; } class WebServer { private: PromtCtlDocument m_doc{}; PromtFTManager m_ftman{}; httplib::Server m_svr; std::mutex m_global_lock; private: int TranslateHtml(const std::string &text, httplib::Response &res) { const auto ft = PromtFTManager::FileType::kHTML; auto direction = m_doc.direction(); auto translator = m_ftman.Translator(ft, direction); { std::ofstream ofs(TMP_IN); ofs << text; } translator.Translate(TMP_IN, TMP_OUT); res.set_content(read_file(TMP_OUT), "text/html"); } void TranslateText(const std::string &text, httplib::Response &res) { res.set_content("Plain text translation not implemented", "text/plain"); res.status = 400; } bool SetDirection(const httplib::Headers &headers, httplib::Response &res) { const auto target_dir_it = headers.find("x-translation-direction"); if (target_dir_it != headers.end()) { auto target_dir = target_dir_it->second; if (target_dir == "en-ru") m_doc.direction(PromtCtlDocument::Direction::kEngRus); else if (target_dir == "ru-en") m_doc.direction(PromtCtlDocument::Direction::kRusEng); else { res.set_content("X-Translation-Direction must be one of: [\"en-ru\", \"ru-en\"]", "text/plain"); res.status = 400; return false; } } else m_doc.direction(PromtCtlDocument::Direction::kEngRus); return true; } void TranslateHandler(const httplib::Request &req, httplib::Response &res) { const std::lock_guard lock(m_global_lock); if (!SetDirection(req.headers, res)) return; const auto &body = req.body; if (body.empty()) { res.set_content("Request body must not be empty", "text/plain"); res.status = 400; return; } const auto content_type_it = req.headers.find("content-type"); if (content_type_it == req.headers.end()) { TranslateText(body, res); return; } auto content_type = content_type_it->second; if (content_type == "text/html") TranslateHtml(body, res); else TranslateText(body, res); } public: WebServer() { if (!std::filesystem::exists(TMP_FOLDER)) std::filesystem::create_directory(TMP_FOLDER); m_svr.Post("/translate", [this](const httplib::Request &req, httplib::Response &res) { TranslateHandler(req, res); }); } ~WebServer() { stop(); } void listen() { m_svr.listen("0.0.0.0", 80); } void stop() { m_svr.stop(); std::remove(TMP_IN.c_str()); std::remove(TMP_OUT.c_str()); } }; int main() { CoInitializeEx(NULL, COINIT_MULTITHREADED); CoInitializeSecurity(nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, nullptr, EOAC_NONE, nullptr); WebServer ws; ws.listen(); }