From 7d86400665a1e1c204f93a2372e2bd7b6f8b3f31 Mon Sep 17 00:00:00 2001 From: DrSocalkwe3n Date: Wed, 12 Nov 2025 02:08:51 +0600 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B2=D1=8B=D0=B9=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=BC=D0=B8=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + CMakeLists.txt | 29 ++ Src/TOSAsync.hpp | 96 +++++ Src/TOSLib.cpp | 1000 ++++++++++++++++++++++++++++++++++++++++++++++ Src/TOSLib.hpp | 591 +++++++++++++++++++++++++++ 5 files changed, 1719 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 Src/TOSAsync.hpp create mode 100644 Src/TOSLib.cpp create mode 100644 Src/TOSLib.hpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..502c7b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/build/ +/.cache/ +/.vscode/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..fa6954c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.17) + +project(TOSLib + VERSION 1.0 + DESCRIPTION "TOSLib") + +add_library(${PROJECT_NAME} STATIC) +target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23) + + +include(FetchContent) + +find_package(ICU REQUIRED COMPONENTS i18n uc) +target_include_directories(${PROJECT_NAME} PUBLIC ${ICU_INCLUDE_DIR}) +target_link_libraries(${PROJECT_NAME} PUBLIC ${ICU_LIBRARIES}) + +# OpenSSL +find_package(OpenSSL REQUIRED) +target_link_libraries(${PROJECT_NAME} PUBLIC OpenSSL::SSL OpenSSL::Crypto) + +# Boost +find_package(Boost CONFIG 1.89 REQUIRED COMPONENTS headers) +target_link_libraries(${PROJECT_NAME} PUBLIC Boost::headers) + +# Исходники +file(GLOB_RECURSE SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "Src/*.cpp") +target_sources(${PROJECT_NAME} PRIVATE ${SOURCES}) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/Src) + diff --git a/Src/TOSAsync.hpp b/Src/TOSAsync.hpp new file mode 100644 index 0000000..1530374 --- /dev/null +++ b/Src/TOSAsync.hpp @@ -0,0 +1,96 @@ +#pragma once + +#include "boost/asio/awaitable.hpp" +#include "boost/asio/co_spawn.hpp" +#include "boost/asio/deadline_timer.hpp" +#include "boost/asio/detached.hpp" +#include "boost/asio/io_context.hpp" +#include "boost/asio/use_awaitable.hpp" +#include +#include +#include + +namespace TOS { + +using namespace boost::asio::experimental::awaitable_operators; +template +using coro = boost::asio::awaitable; + +class AsyncSemaphore +{ + boost::asio::deadline_timer Deadline; + std::atomic Lock = 0; + +public: + AsyncSemaphore( + boost::asio::io_context& ioc) + : Deadline(ioc, boost::posix_time::ptime(boost::posix_time::pos_infin)) + {} + + boost::asio::awaitable async_wait() { + try { + co_await Deadline.async_wait(boost::asio::use_awaitable); + } catch(boost::system::system_error code) { + if(code.code() != boost::system::errc::operation_canceled) + throw; + } + + co_await boost::asio::this_coro::throw_if_cancelled(); + } + + boost::asio::awaitable async_wait(std::function predicate) { + while(!predicate()) + co_await async_wait(); + } + + void notify_one() { + Deadline.cancel_one(); + } + + void notify_all() { + Deadline.cancel(); + } +}; + +class IAsyncDestructible : public std::enable_shared_from_this { +protected: + boost::asio::any_io_executor IOC; + boost::asio::deadline_timer DestructLine; + + virtual coro<> asyncDestructor() { DestructLine.cancel(); co_return; } + +public: + IAsyncDestructible(boost::asio::any_io_executor ioc) + : IOC(ioc), DestructLine(ioc, boost::posix_time::ptime(boost::posix_time::pos_infin)) + {} + + virtual ~IAsyncDestructible() {} + + coro> cancelable(coro<> &&c) { return std::move(c) || DestructLine.async_wait(boost::asio::use_awaitable); } + + template> + static std::shared_ptr createShared(boost::asio::any_io_executor ioc, T *ptr) + { + return std::shared_ptr(ptr, [ioc = std::move(ioc)](IAsyncDestructible *ptr) { + boost::asio::co_spawn(ioc, [](IAsyncDestructible *ptr) -> coro<> { + try { co_await ptr->asyncDestructor(); } catch(...) { } + delete ptr; + co_return; + } (ptr), boost::asio::detached); + }); + } + + template> + static std::shared_ptr makeShared(boost::asio::any_io_executor ioc, Args&& ... args) + { + std::shared_ptr(new T(ioc, std::forward(args)..., [ioc = std::move(ioc)](IAsyncDestructible *ptr) { + boost::asio::co_spawn(ioc, [](IAsyncDestructible *ptr) -> coro<> { + try { co_await ptr->asyncDestructor(); } catch(...) { } + delete ptr; + co_return; + } (ptr), boost::asio::detached); + })); + } +}; + +} \ No newline at end of file diff --git a/Src/TOSLib.cpp b/Src/TOSLib.cpp new file mode 100644 index 0000000..2c2ca8f --- /dev/null +++ b/Src/TOSLib.cpp @@ -0,0 +1,1000 @@ +/* + * TOSLib.cpp + * + * Created on: 22 янв. 2023 г. + * Author: mr_s + */ + +#include "TOSLib.hpp" +#include "boost/regex/v5/icu.hpp" +#include "boost/regex/v5/regex.hpp" +#include "boost/date_time/posix_time/posix_time.hpp" +#include +#include +#include +#include +#include +#include +#include +#define DBOOST_STACKTRACE_USE_ADDR2LINE +#include +#include +#include +#include +#include +#include +#include +#include + +namespace TOS { + +namespace Str { + +std::vector split(const std::string &in, const std::string &delimeter, bool useRegex) { + if (useRegex) { + if (maxUnicode(in) != 1) { + std::u32string u32in = toUStr(in), u32delimeter = toUStr(delimeter); + + std::vector out; + size_t prev = 0, next = 0; + + for (boost::u32regex_iterator begin(in.begin(), in.end(), boost::make_u32regex(toUStr(delimeter))), end; begin != end; ++begin) { + out.push_back(std::string(in.data() + prev, begin->position() - prev)); + prev = begin->position() + begin->length(0); + } + + out.push_back(std::string(in.data() + prev)); + + return out; + } else { + boost::regex pattern(delimeter.begin(), delimeter.end()); + std::vector out; + size_t prev = 0; + + for (boost::cregex_iterator begin(in.data(), in.data() + in.size(), pattern), end; begin != end; ++begin) { + if (prev < begin->position()) + out.push_back(std::string(in.data() + prev, begin->position() - prev)); + + prev = begin->position() + begin->length(0); + } + + if (prev < in.size()) + out.push_back(std::string(in.data() + prev, in.size() - prev)); + + return out; + } + } else { + size_t prev = 0, next, count = 0; + + while ((next = in.find(delimeter, prev)) != std::string::npos) { + count++; + prev = next + delimeter.size(); + } + + std::vector out(count + 1); + prev = next = count = 0; + + while ((next = in.find(delimeter, prev)) != std::string::npos) { + out[count++] = {in.data() + prev, next - prev}; + prev = next + delimeter.size(); + } + + out[count] = {in.data() + prev, in.size() - prev}; + + return out; + } +} + +std::string replace(const std::string &in, const std::string &pattern, const std::string &to, bool useRegex) +{ + std::vector views = split(in, pattern, useRegex); + std::string out; + + { + size_t size = views.size() * to.size(); + for(auto &view : views) + size += view.size(); + + out.reserve(size); + } + + for(size_t iter = 0; iter < views.size(); iter++) + { + out.append(views[iter]); + if(iter < views.size()-1) + out.append(to); + } + + return out; +} + +bool contains(const std::string &in, const std::string &pattern, bool useRegex) +{ + if(useRegex) + return boost::cregex_iterator(in.data(), in.data()+in.size(), boost::regex(pattern.begin(), pattern.end())) != boost::cregex_iterator(); + else + return in.find(pattern) != std::string::npos; +} + +size_t count(const std::string &in, const std::string &pattern) +{ + return split(in, pattern, false).size(); +} + +std::optional>> match(const std::string &in, const std::string &pattern) +{ + boost::smatch xResults; + bool matched; + + if(maxUnicode(in) != 1) + { + matched = boost::u32regex_match(in, xResults, boost::make_u32regex(toUStr(pattern))); + } else { + matched = boost::regex_match(in, xResults, boost::regex(pattern.begin(), pattern.end())); + } + + if(!matched) + return {}; + + std::vector> data(xResults.size()); + + for(size_t index = 0; index= view.size()) + out += L'?'; + else if((view[ret+1] & 0x80) == 0x80) + out += (view[ret+1] & 0x3F) | ((view[ret] & 0x1F) << 6); + else + { + out += L'?'; + ret--; + } + + ret++; + } else if((c & 0xE0) == 0xE0) + { + if(ret+2 >= view.size()) + out += L'?'; + else if((view[ret+1] & 0x80) == 0x80 && (view[ret+2] & 0x80) == 0x80) + out += (view[ret+2] & 0x3F) + ((view[ret+1] & 0x3F) << 6) | ((view[ret] & 0xF) << 12); + else + { + out += L'?'; + ret -= 2; + } + + ret += 2; + } else if((c & 0xF0) == 0xF0) + { + if(ret+3 >= view.size()) + out += L'?'; + else if((view[ret+1] & 0x80) == 0x80 && (view[ret+2] & 0x80) == 0x80 && (view[ret+3] & 0x80) == 0x80) + out += (view[ret+3] & 0x3F) | ((view[ret+2] & 0x3F) << 6) | ((view[ret+1] & 0x3F) << 12) | ((view[ret] & 0xF) << 18); + else + { + out += L'?'; + ret -= 3; + } + + ret += 3; + } + } + + out.shrink_to_fit(); + + return out; +} + +std::string toStr(const std::wstring &view) +{ + int size = 0; + + for(wchar_t sym : view) + { + if(sym & (~0x7F)) + { + if(sym & (~0x7FF)) + size += 3; + else + size += 2; + } else + size++; + } + + std::string out; + out.reserve(size); + + for(wchar_t sym : view) + { + if(sym & (~0x7F)) + { + if(sym & (~0x7FF)) + { + out += 0xE0 | ((sym >> 12) & 0x0F); + out += 0x80 | ((sym >> 6) & 0x3F); + out += 0x80 | (sym & 0x3F); + } else { + out += 0xC0 | ((sym >> 6) & 0x1F); + out += 0x80 | (sym & 0x3F); + } + } else + out += sym; + } + + return out; +} + +std::u32string toUStr(const std::string &view) +{ + std::u32string out; + out.reserve(view.size()); + + for(size_t ret = 0; ret < view.size(); ret++) + { + char c = view[ret]; + if((c & 0x80) == 0) + out += c; + else if((c & 0xC0) == 0xC0) + { + if(ret+1 >= view.size()) + out += L'?'; + else if((view[ret+1] & 0x80) == 0x80) + out += (view[ret+1] & 0x3F) | ((view[ret] & 0x1F) << 6); + else + { + out += L'?'; + ret--; + } + + ret++; + } else if((c & 0xE0) == 0xE0) + { + if(ret+2 >= view.size()) + out += L'?'; + else if((view[ret+1] & 0x80) == 0x80 && (view[ret+2] & 0x80) == 0x80) + out += (view[ret+2] & 0x3F) | ((view[ret+1] & 0x3F) << 6) | ((view[ret] & 0xF) << 12); + else + { + out += L'?'; + ret-=2; + } + + ret += 2; + } else if((c & 0xF0) == 0xF0) + { + if(ret+3 >= view.size()) + out += L'?'; + else if((view[ret+1] & 0x80) == 0x80 && (view[ret+2] & 0x80) == 0x80 && (view[ret+3] & 0x80) == 0x80) + out += (view[ret+3] & 0x3F) | ((view[ret+2] & 0x3F) << 6) | ((view[ret+1] & 0x3F) << 12) | ((view[ret] & 0xF) << 18); + else + { + out += L'?'; + ret -= 3; + } + + ret += 3; + } + } + + out.shrink_to_fit(); + + return out; +} + +std::string toStr(const std::u32string &view) +{ + int size = 0; + + for(wchar_t sym : view) + { + if(sym & (~0x7F)) + { + if(sym & (~0x7FF)) + size += 4; + else + size += 2; + } else + size++; + } + + std::string out; + out.reserve(size); + + for(char32_t sym : view) + { + if(sym & (~0x7F)) + { + if(sym & (~0x7FF)) + { + out += 0xF0; + out += 0x80 | ((sym >> 12) & 0x3F); + out += 0x80 | ((sym >> 6) & 0x3F); + out += 0x80 | (sym & 0x3F); + } else { + out += 0xC0 | ((sym >> 6) & 0x1F); + out += 0x80 | (sym & 0x3F); + } + } else + out += sym; + } + + return out; +} + +int maxUnicode(const std::string &view) +{ + int max = 1; + char sym; + + for(size_t iter = 0; iter < view.size(); iter++) + { + char c = view[iter]; + if((c & 0xC0) == 0xC0) + { + if(2 > max) + max = 2; + + iter++; + } else if((c & 0xE0) == 0xE0) + { + if(3 > max) + max = 3; + + iter += 2; + } else if((c & 0xF0) == 0xF0) + { + if(4 > max) + max = 4; + + iter += 3; + } + } + + return max; +} + +std::string toLowerCase(const std::string &view) +{ + std::u32string out = toUStr(view); + + for(char32_t &sym : out) + { + sym = std::tolower(sym); + if(sym >= L'А' && sym <= L'Я') + sym += 32; + } + + return toStr(out); +} + +std::string toUpperCase(const std::string &view) +{ + std::u32string out = toUStr(view); + + for(char32_t &sym : out) + { + sym = std::toupper(sym); + if(sym >= L'а' && sym <= L'я') + sym -= 32; + } + + return toStr(out); +} + +float compareRelative(const std::string &left, const std::string &right) +{ + size_t equals = 0, minSize = std::min(left.size(), right.size()); + for(size_t iter = 0; iter < minSize; iter++) + if(left[iter] == right[iter]) + equals++; + + if(!minSize) + return left.size() == right.size(); + + return float(equals) / float(std::max(left.size(), right.size())); +} + +} + + +namespace Enc { + +std::string toHex(const uint8_t *begin, size_t size) +{ + std::string out(size, ' '); + char *data = out.data(); + + for(const uint8_t *end = begin + size; begin != end; begin++) + { + *(data++) = "0123456789abcdf"[*begin & 0xf]; + *(data++) = "0123456789abcdf"[(*begin >> 4) & 0xf]; + } + + return out; +} + +void fromHex(const std::string &in, uint8_t *data) +{ + const char *begin = in.data(), *end = begin + in.size(); + for(; begin != end;) + { + *data = 0; + if(*begin >= 'a') + *data |= *begin - 'a' + 10; + else + *data |= *begin - '0'; + + begin++; + + if(*begin >= 'a') + *data |= (*begin - 'a' + 10) << 4; + else + *data |= (*begin - '0') << 4; + + begin++; + data++; + } +} + +std::string toBase64(const uint8_t *data, size_t size) +{ + using namespace boost::archive::iterators; + using It = base64_from_binary>; + auto tmp = std::string(It((const char*) data), It((const char*) data+size)); + return std::string(tmp.append((3 - size % 3) % 3, '=')); //.replace("/", "_").replace("+", "-"); +} + +ByteBuffer fromBase64(const std::string &view) +{ + //std::string val = view.replace("_", "/").replace("-", "+").toStr(); + using namespace boost::archive::iterators; + using It = transform_width, 8, 6>; + std::string out(It(view.begin()), It(view.end())); + return {out.size(), (const uint8_t*) out.data()}; +} + +void base64UrlConvert(std::string &in) +{ + for(char &sym : in) + { + if(sym == '_') + sym = '/'; + else if(sym == '-') + sym = '+'; + else if(sym == '/') + sym = '_'; + else if(sym == '+') + sym = '-'; + } +} + +std::string md5(const uint8_t *data, size_t size) +{ + boost::uuids::detail::md5 md5; + md5.process_bytes((const char*) data, size); + unsigned hash[4] = {0}; + md5.get_digest((boost::uuids::detail::md5::digest_type&)hash); + + char buf[33] = {0}; + + for (int i = 0; i < 4; i++) + std::sprintf(buf + (i << 3), "%08x", hash[i]); + + return Str::toLowerCase(buf); +} + +std::string sha1(const uint8_t *data, size_t size) +{ + boost::uuids::detail::sha1 sha1; + sha1.process_bytes((const char*) data, size); + unsigned hash[5] = {0}; + sha1.get_digest((boost::uuids::detail::sha1::digest_type&)hash); + + char buf[41] = {0}; + + for (int i = 0; i < 5; i++) + std::sprintf(buf + (i << 3), "%08x", hash[i]); + + return Str::toLowerCase(buf); +} + +} + + +namespace Time { + +std::string getDateAsString() +{ + auto time = boost::posix_time::second_clock::local_time().date(); + std::stringstream out; + out << std::to_string(time.year()); + std::string temp = std::to_string(time.month()); + + out << '.'; + if(temp.size() == 1) + out << '0'; + out << temp; + + temp = std::to_string(time.day()); + out << '.'; + if(temp.size() == 1) + out << '0'; + out << temp; + + return out.str(); +} + +std::string getTimeAsString() +{ + auto day = boost::posix_time::second_clock::local_time().time_of_day(); + std::stringstream out; + std::string temp = std::to_string(day.hours()); + + if(temp.size() == 1) + out << '0'; + out << temp; + + out << ':'; + temp = std::to_string(day.minutes()); + if(temp.size() == 1) + out << '0'; + out << temp; + + out << ':'; + temp = std::to_string(day.seconds()); + if(temp.size() == 1) + out << '0'; + out << temp; + + return out.str(); +} + +} + +std::string makeStacktrace(int stack_up) +{ + std::vector spl = Str::split(boost::stacktrace::to_string(boost::stacktrace::stacktrace()), "\n"); + std::string out; + for(size_t i = 1+stack_up; i 128) + line << spl[i].substr(0, 128); + else + line << spl[i]; + + if(Str::contains(line.str(), "boost::asio::asio_handler_invoke")) + break; + else + out += line.str(); + } + + return out; +} + +void DynamicLibrary::symbolOut() +{ + throw std::runtime_error("Символ не привязан"); +} + +bool DynamicLibrary::IsOverWine = DynamicLibrary::checkWine(); +bool DynamicLibrary::checkWine() +{ + try { + DynamicLibrary ntdll("ntdll.dll"); + void *sym = ntdll.getSymbol("wine_get_version"); + return sym; + } catch(...) {} + + return false; +} + +DynamicLibrary::DynamicLibrary(const std::string &name) + : Name(name) +{ +#ifdef _WIN32 + FD = (uint64_t) LoadLibrary(name.toWStr().c_str()); + if (!FD) + { + uint64_t err = (uint64_t) GetLastError(); + MAKE_ERROR << "Не удалось загрузить разделяемую библиотеку " << name << ", код ошибки " << err; + } + + wchar_t name2[256]; + GetModuleFileName((HMODULE) FD, name2, 256); + Name = std::wstring(name2); +#else + const char* error_msg; + FD = uint64_t(dlopen(name.data(), RTLD_NOW | RTLD_GLOBAL)); + if(!FD) + { + error_msg = dlerror(); + + std::stringstream info; + info << "Библиотека " << name << " не найдена"; + if(error_msg) + info << ": " << error_msg; + + throw std::runtime_error(info.str()); + } + + try { + std::ifstream r("/proc/self/maps"); + std::string str; + char path[256] = ""; + + while (std::getline(r, str)) { + if (sscanf(str.c_str(), "%*llx-%*llx %*s %*s %*s %*s %s", path) == 1) { + if(Str::contains(path, name)) + { + Path = path; + break; + } + } + } + + } catch(...) { + Path = name; + } + + if(Path.empty()) + Path = name; + + +// if(!FD && (!error_msg || String(error_msg).contains("No such file or directory"))) +// { + +// auto lock = LD_LIBRARY_PATH.lockRead(); +// for(int id = 0; id<3 && !FD; id++) +// for(const File &str : *lock) +// { +// if(str.isExist() && str.isDir()) +// for(File f : str.getSubFiles()) +// { +// if(f.isDir() || !f.isReal()) +// continue; + +// if((id == 0 && f.getFilename().starts_with("lib" << name << ".so")) +// || (id == 1 && TOS::REGEX::match("^lib" << name << ".*" << "\\.so", f.getFilename())) +// || (id == 2 && f.getFilename().starts_with(name) && f.getFilename().contains(".so")) +// ) +// { +// FD = uint64_t(dlopen(f.getFullPathFile().getPath().toCStr(), RTLD_LAZY | RTLD_GLOBAL)); + +// if(FD) +// { +// loaded = f; +// Path = f.getFullPathFile().getPath(); +// break; +// } else { +// error_msg = dlerror(); +// MAKE_ERROR << "Не удалось загрузить разделяемую библиотеку " << name << ", ошибка: " << error_msg; +// } +// } +// } +// if(FD) +// break; +// } +// } + +// if(!FD) +// MAKE_ERROR << "Не удалось загрузить разделяемую библиотеку " << name << ", ошибка: " << error_msg; + +// Dl_info info; +// if(!Path.size()) +// { +// if(dladdr((void*) FD, &info) && info.dli_fname && (!*info.dli_fname || *info.dli_fname == '/')) +// Path = info.dli_fname; +// else +// Path = File(name).getPath(); +// } + +// LOGGER.debug() << "Запрос " << name << "; найдено " << Path; + +#endif +} + +DynamicLibrary::~DynamicLibrary() +{ + if(!FD) + return; + +#ifdef _WIN32 + FreeLibrary((HMODULE) FD); +#else + dlclose((void*) FD); +#endif +} + +void* DynamicLibrary::getSymbol(const std::string &name) const +{ +#ifdef _WIN32 + void *sym = (void*) GetProcAddress((HMODULE) FD, name.toCStr()); + if(!sym) + { + uint64_t error = (uint64_t) GetLastError(); + MAKE_ERROR("Ошибка загрузки символа " << name << " в библиотеке " << Name << ", код ошибки " << error); + } + return sym; +#else + void *sym = dlsym((void*) FD, name.data()); + if(!sym) + { + const char* str = dlerror(); + MAKE_ERROR("Ошибка загрузки символа " << name << " в библиотеке " << Name << ", ошибка: " << str); + } + return sym; +#endif +} + +void* DynamicLibrary::takeSymbol(const std::string &name) const +{ +#ifdef _WIN32 + void *sym = (void*) GetProcAddress((HMODULE) FD, name.toCStr()); + if(!sym) + sym = (void*) &symbolOut; + return sym; +#else + void *sym = dlsym((void*) FD, name.data()); + if(!sym) + sym = (void*) &symbolOut; + return sym; +#endif +} + +void* DynamicLibrary::getDynamicSymbol(const std::string &name) +{ +#ifdef _WIN32 + void *sym = (void*) GetProcAddress(GetModuleHandle(nullptr), name.toCStr()); + if(!sym) + { + uint64_t error = (uint64_t) GetLastError(); + MAKE_ERROR("Ошибка загрузки символа " << name << " в общем пространстве символов, код ошибки " << error); + } + return sym; +#else + void *sym = dlsym((void*) RTLD_DEFAULT, name.data()); + if(!sym) + { + const char* str = dlerror(); + MAKE_ERROR("Ошибка загрузки символа " << name << " в общем пространстве символов, ошибка: " << str); + } + return sym; +#endif +} + +void* DynamicLibrary::takeDynamicSymbol(const std::string &name) +{ +#ifdef _WIN32 + void *sym = (void*) GetProcAddress(GetModuleHandle(nullptr), name.toCStr()); + if(!sym) + sym = (void*) &symbolOut; + return sym; +#else + void *sym = dlsym((void*) RTLD_DEFAULT, name.data()); + if(!sym) + sym = (void*) &symbolOut; + return sym; +#endif +} + +void* DynamicLibrary::hasDynamicSymbol(const std::string &name) +{ +#ifdef _WIN32 + return (void*) GetProcAddress(GetModuleHandle(nullptr), name.toCStr()); +#else + return dlsym((void*) RTLD_DEFAULT, name.data()); +#endif +} + +void DynamicLibrary::needGlobalLibraryTemplate(const std::string &name) +{ +} + + +std::vector DynamicLibrary::getLdPaths() +{ + std::vector paths; +#ifdef _WIN32 +#else + const char *str = getenv("PATH"); + + if(str) + for(auto &iter : Str::split(str, ":")) + paths.push_back(iter); + + str = getenv("LD_LIBRARY_PATH"); + + if(str) + for(auto &iter : Str::split(str, ":")) + paths.push_back(iter); +#endif + + return paths; +} + +struct LogFile { + boost::u32regex RegexForPath; + boost::nowide::ofstream Write; + EnumLogType Levels; + uint32_t LastLoggedDay = 0; + + LogFile(const std::string ®ex_for_path, EnumLogType levels, const std::filesystem::path &path) + : RegexForPath(boost::make_u32regex(Str::toUStr(regex_for_path))), + Levels(levels), + Write(path, std::ios::out | std::ios::binary | std::ios::app) + {} + + LogFile(const LogFile&) = delete; + LogFile(LogFile&&) = default; + LogFile& operator=(const LogFile&) = delete; + LogFile& operator=(LogFile&&) = default; +}; + +struct LogCmd { + boost::u32regex RegexForPath; + EnumLogType Levels; + + LogCmd(const std::string &view, EnumLogType levels) + : RegexForPath(boost::make_u32regex(Str::toUStr(view))), + Levels(levels) + {} + + LogCmd(const LogCmd&) = delete; + LogCmd(LogCmd&&) = default; + LogCmd& operator=(const LogCmd&) = delete; + LogCmd& operator=(LogCmd&&) = default; +}; + +static std::mutex LogFilesMtx; +static std::vector LogFiles; +static std::vector LogRegexs; +static uint32_t LogCmdLastDay = Time::getDay(); + +LogSession::LogSession(const std::string &path, EnumLogType type) + : Path(path) +{ + { + std::lock_guard lock(LogFilesMtx); + + for(auto &iter : LogRegexs) + if(int(type) & int(iter.Levels) && boost::u32regex_match(path.data(), iter.RegexForPath)) + { + NeedC = true; + break; + } + + for(auto &iter : LogFiles) + if(int(type) & int(iter.Levels) && boost::u32regex_match(path.data(), iter.RegexForPath)) + { + NeedF = true; + break; + } + + if(!NeedF && !NeedC) + { + return; + } + } + + *this << char(27) << '['; + switch(type) { + case EnumLogType::Debug: *this << "37"; break; + case EnumLogType::Info: *this << "36"; break; + case EnumLogType::Warn: *this << "33"; break; + case EnumLogType::Error: *this << "31"; break; + case EnumLogType::All: *this << "35"; break; + default: break; + } + + *this << "m[" << Time::getTimeAsString() << ' ' << path << '-'; + switch(type) { + case EnumLogType::Debug: *this << 'D'; break; + case EnumLogType::Info: *this << 'I'; break; + case EnumLogType::Warn: *this << 'W'; break; + case EnumLogType::Error: *this << 'E'; break; + case EnumLogType::All: *this << '%'; break; + default: break; + } + + *this << "]: " << char(27) << "[0m"; +} + +LogSession::~LogSession() +{ + if(!NeedF && !NeedC) + return; + + std::lock_guard lock(LogFilesMtx); + + if(NeedF) + { + for(auto &iter : LogFiles) + if(boost::u32regex_match(Path.data(), iter.RegexForPath)) + { + uint32_t day = Time::getDay(); + if(iter.LastLoggedDay != day) + { + iter.LastLoggedDay = day; + std::stringstream date; + date << " -*[ " << Time::getDateAsString() << " ]*-\n"; + iter.Write << date.str() << std::endl; + } + + iter.Write << Str::replace(str(), "\n", "\n\t") << std::endl; + iter.Write.flush(); + } + } + + if(NeedC) + { + uint32_t day = Time::getDay(); + if(LogCmdLastDay != day) + { + LogCmdLastDay = day; + std::stringstream date; + date << " -*[ " << Time::getDateAsString() << " ]*-\n"; + std::cout << date.str() << std::endl; + } + + std::cout << Str::replace(str(), "\n", "\n\t") << std::endl; + std::cout.flush(); + } +} + +void Logger::addLogFile(const std::string ®ex_for_path, EnumLogType levels, const std::filesystem::path &file, bool rewrite) +{ + if(rewrite && std::filesystem::exists(file)) + std::filesystem::remove(file); + + std::lock_guard lock(LogFilesMtx); + LogFiles.emplace_back(regex_for_path, levels, file); +} + +void Logger::addLogOutput(const std::string ®ex_for_path, EnumLogType levels) +{ + std::lock_guard lock(LogFilesMtx); + LogRegexs.emplace_back(regex_for_path, levels); +} + +static bool exec = [](){ + std::cout.sync_with_stdio(false); + return false; +}(); + +namespace TIME { + +size_t getSeconds() +{ + static size_t val1 = 0, val2 = 0; + size_t time = boost::posix_time::second_clock::local_time().time_of_day().total_seconds(); + if(time < val1) + val2++; + val1 = time; + return val2*86400+time; +} + +} + +} /* namespace TOS */ diff --git a/Src/TOSLib.hpp b/Src/TOSLib.hpp new file mode 100644 index 0000000..691f698 --- /dev/null +++ b/Src/TOSLib.hpp @@ -0,0 +1,591 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#define _USE_MATH_DEFINES +#include +#include + +namespace TOS { + + +#if __BYTE_ORDER == __LITTLE_ENDIAN + template + static inline T swapEndian(const T &u) { return u; } +#else + template + static inline T swapEndian(const T &u) + { + union { + T u; + byte u8[sizeof(T)]; + } source, dest; + + source.u = u; + + for (size_t k = 0; k < sizeof(T); k++) + dest.u8[k] = source.u8[sizeof(T) - k - 1]; + + return dest.u; + } + + template<> inline uint8_t swapEndian(const uint8_t &value) { return value; } + template<> inline int8_t swapEndian(const int8_t &value) { return swapEndian(*(uint8_t*) &value); } + template<> inline uint16_t swapEndian(const uint16_t &value) { return __bswap_16(value); } + template<> inline int16_t swapEndian(const int16_t &value) { return swapEndian(*(uint16_t*) &value); } + template<> inline uint32_t swapEndian(const uint32_t &value) { return __bswap_32(value); } + template<> inline int32_t swapEndian(const int32_t &value) { return swapEndian(*(uint32_t*) &value); } + template<> inline uint64_t swapEndian(const uint64_t &value) { return __bswap_64(value); } + template<> inline int64_t swapEndian(const int64_t &value) { return swapEndian(*(uint64_t*) &value); } +#endif + + +class ByteBuffer : public std::vector { + protected: + typedef std::vector base; + + public: + class Reader; + class Writer; + + public: + ByteBuffer() = default; + template>> + ByteBuffer(Args&& ... args) + : base(std::forward(args)...) + {} + + ByteBuffer(std::istream &&stream) + { + size_t gs = stream.tellg(); + stream.seekg(0, std::ios::end); + resize(std::min(size_t(stream.tellg()) - gs, 1024*1024)); + + stream.seekg(gs, std::ios::beg); + + char buff[4096]; + + size_t offset = 0; + + while((gs = stream.readsome(buff, 4096))) + { + if(offset+gs > size()) + resize(offset+gs); + + std::copy(buff, buff+gs, data() + offset); + offset += gs; + } + + resize(offset); + shrink_to_fit(); + } + + + ByteBuffer(size_t size, const uint8_t *ptr = nullptr) + : base(size) + { + if(ptr) + std::copy(ptr, ptr+size, data()); + } + + ~ByteBuffer() = default; + + ByteBuffer(const ByteBuffer&) = default; + ByteBuffer(ByteBuffer&&) = default; + ByteBuffer& operator=(const ByteBuffer&) = default; + ByteBuffer& operator=(ByteBuffer&&) = default; + + Reader reader() const; + static Writer writer(); + }; + + class ByteBuffer::Reader { + const ByteBuffer *Obj; + size_t Index = 0; + + template inline T readOffset() { + if(Index + sizeof(T) > Obj->size()) + throw std::runtime_error("Вышли за пределы буфера"); + + const uint8_t *ptr = Obj->data()+Index; + Index += sizeof(T); + return swapEndian(*(const T*) ptr); + } + + public: + Reader(const ByteBuffer &buff) + : Obj(&buff) + {} + + Reader(const Reader&) = delete; + Reader(Reader&&) = default; + Reader& operator=(const Reader&) = delete; + Reader& operator=(Reader&&) = default; + + inline Reader& operator>>(int8_t &value) { value = readOffset(); return *this; } + inline Reader& operator>>(uint8_t &value) { value = readOffset(); return *this; } + inline Reader& operator>>(int16_t &value) { value = readOffset(); return *this; } + inline Reader& operator>>(uint16_t &value) { value = readOffset(); return *this; } + inline Reader& operator>>(int32_t &value) { value = readOffset(); return *this; } + inline Reader& operator>>(uint32_t &value) { value = readOffset(); return *this; } + inline Reader& operator>>(int64_t &value) { value = readOffset(); return *this; } + inline Reader& operator>>(uint64_t &value) { value = readOffset(); return *this; } + inline Reader& operator>>(bool &value) { value = readOffset(); return *this; } + inline Reader& operator>>(float &value) { return operator>>(*(uint32_t*) &value); } + inline Reader& operator>>(double &value) { return operator>>(*(uint64_t*) &value); } + + inline int8_t readInt8() { int8_t value; this->operator>>(value); return value; } + inline uint8_t readUInt8() { uint8_t value; this->operator>>(value); return value; } + inline int16_t readInt16() { int16_t value; this->operator>>(value); return value; } + inline uint16_t readUInt16() { uint16_t value; this->operator>>(value); return value; } + inline int32_t readInt32() { int32_t value; this->operator>>(value); return value; } + inline uint32_t readUInt32() { uint32_t value; this->operator>>(value); return value; } + inline int64_t readInt64() { int64_t value; this->operator>>(value); return value; } + inline uint64_t readUInt64() { uint64_t value; this->operator>>(value); return value; } + inline bool readBool() { bool value; this->operator>>(value); return value; } + inline float readFloat() { float value; this->operator>>(value); return value; } + inline double readDouble() { double value; this->operator>>(value); return value; } + + inline void readSize(size_t &size) + { + uint8_t bytes[6]; + int readed = 0; + do { + *this >> bytes[readed++]; + } while(((bytes[readed-1] >> 7) & 1) && readed < 6); + + size = 0; + for(int iter = 0; iter < readed; iter++) + if(iter != 4) + size |= size_t(bytes[iter] & 0x7f) << (iter*7); + else + size |= size_t(bytes[iter] & 0xf) << (iter*7); + } + + inline void readBuffer(ByteBuffer &buff) + { + size_t size; + readSize(size); + + if(Index + size > Obj->size()) + throw std::runtime_error("Вышли за пределы буфера"); + + const uint8_t *ptr = Obj->data() + Index; + Index += size; + buff.resize(size); + std::copy(ptr, ptr+size, buff.data()); + } + + inline void readString(std::string &str) + { + size_t size; + readSize(size); + + if(Index + size > Obj->size()) + throw std::runtime_error("Вышли за пределы буфера"); + + const uint8_t *ptr = Obj->data() + Index; + Index += size; + str.resize(size); + std::copy(ptr, ptr+size, str.data()); + } + + inline size_t readSize() { size_t size; readSize(size); return size; } + inline ByteBuffer readBuffer() { ByteBuffer buff; readBuffer(buff); return buff; } + inline std::string readString() { std::string str; readString(str); return str; } + + Reader& operator>>(ByteBuffer &buff) { readBuffer(buff); return *this; } + Reader& operator>>(std::string &str) { readString(str); return *this; } + + void setPos(size_t pos) { Index = pos; } + void offset(ssize_t offset) { setPos(Index+size_t(offset)); } + + bool checkBorder() const { return Index >= Obj->size(); } + + ByteBuffer cutToBuffer() + { + ByteBuffer out(Obj->size()-Index); + + std::copy(Obj->data() + Index, Obj->data() + Obj->size(), out.data()); + Index += out.size(); + + return out; + } + }; + + class ByteBuffer::Writer { + ByteBuffer Obj; + size_t Index = 0; + uint16_t BlockSize = 256; + + + inline uint8_t* checkBorder(size_t count) + { + if(Index+count >= Obj.capacity()) + Obj.reserve(size_t(BlockSize)*(std::ceil(float(Index+count)/float(BlockSize))+1)); + Obj.resize(Index+count); + + uint8_t *ptr = Obj.data()+Index; + Index += count; + return ptr; + } + + public: + Writer() = default; + + Writer(const Writer&) = default; + Writer(Writer&&) = default; + Writer& operator=(const Writer&) = default; + Writer& operator=(Writer&&) = default; + + inline Writer& operator<<(const int8_t &value) { *(int8_t*) checkBorder(sizeof(value)) = value; return *this; } + inline Writer& operator<<(const uint8_t &value) { *(uint8_t*) checkBorder(sizeof(value)) = value; return *this; } + inline Writer& operator<<(const int16_t &value) { *(int16_t*) checkBorder(sizeof(value)) = swapEndian(value); return *this; } + inline Writer& operator<<(const uint16_t &value) { *(uint16_t*) checkBorder(sizeof(value)) = swapEndian(value); return *this; } + inline Writer& operator<<(const int32_t &value) { *(int32_t*) checkBorder(sizeof(value)) = swapEndian(value); return *this; } + inline Writer& operator<<(const uint32_t &value) { *(uint32_t*) checkBorder(sizeof(value)) = swapEndian(value); return *this; } + inline Writer& operator<<(const int64_t &value) { *(int64_t*) checkBorder(sizeof(value)) = swapEndian(value); return *this; } + inline Writer& operator<<(const uint64_t &value) { *(uint64_t*) checkBorder(sizeof(value)) = swapEndian(value); return *this; } + inline Writer& operator<<(const bool &value) { *(uint8_t*) checkBorder(sizeof(value)) = uint8_t(value ? 1 : 0); return *this; } + inline Writer& operator<<(const float &value) { *(uint32_t*) checkBorder(sizeof(value)) = swapEndian(*(uint32_t*) &value); return *this; } + inline Writer& operator<<(const double &value) { *(uint64_t*) checkBorder(sizeof(value)) = swapEndian(*(uint64_t*) &value); return *this; } + + inline void writeInt8(const int8_t &value) { this->operator<<(value); } + inline void writeUInt8(const uint8_t &value) { this->operator<<(value); } + inline void writeInt16(const int16_t &value) { this->operator<<(value); } + inline void writeUInt16(const uint16_t &value) { this->operator<<(value); } + inline void writeInt32(const int32_t &value) { this->operator<<(value); } + inline void writeUInt32(const uint32_t &value) { this->operator<<(value); } + inline void writeInt64(const int64_t &value) { this->operator<<(value); } + inline void writeUInt64(const uint64_t &value) { this->operator<<(value); } + inline void writeBool(const bool &value) { this->operator<<(value); } + inline void writeFloat(const float &value) { this->operator<<(value); } + inline void writeDouble(const double &value) { this->operator<<(value); } + + inline void writeSize(size_t size) + { + size_t temp = size; + int count = 1; + for(; count < 6; count++) + { + temp >>= 7; + if(!temp) + break; + } + + temp = size; + for(int iter = 0; iter < count; iter++) + { + if(iter != count-1) + writeUInt8((temp & 0x3f) | (0b1 << 7)); + else + writeUInt8((temp & 0x3f)); + + temp >>= 7; + } + } + + inline void writeBuffer(const ByteBuffer &buff) + { + writeSize(buff.size()); + uint8_t *ptr = checkBorder(buff.size()); + std::copy(buff.data(), buff.data()+buff.size(), ptr); + } + + inline void writeString(const std::string &str) + { + writeSize(str.size()); + uint8_t *ptr = checkBorder(str.size()); + std::copy(str.data(), str.data()+str.size(), ptr); + } + + inline void putBuffer(const ByteBuffer &buff) + { + uint8_t *ptr = checkBorder(buff.size()); + std::copy(buff.data(), buff.data()+buff.size(), ptr); + } + + inline Writer& operator<<(const ByteBuffer &buff) { writeBuffer(buff); return *this; } + inline Writer& operator<<(const std::string &str) { writeString(str); return *this; } + inline Writer& operator<<(const char *str) { writeString(std::string(str)); return *this; } + + ByteBuffer complite() { Obj.shrink_to_fit(); return std::move(Obj); Index = 0; } + }; + + inline ByteBuffer::Reader ByteBuffer::reader() const { return *this; } + inline ByteBuffer::Writer ByteBuffer::writer() { return {}; } + + +namespace Str { + + std::vector split(const std::string &in, const std::string &delimeter, bool useRegex = false); + + std::string replace(const std::string &in, const std::string &pattern, const std::string &to, bool useRegex = false); + bool contains(const std::string &in, const std::string &pattern, bool useRegex = false); + size_t count(const std::string &in, const std::string &pattern); + std::optional>> match(const std::string &in, const std::string &pattern); + + std::wstring toWStr(const std::string &view); + std::string toStr(const std::wstring &view); + std::u32string toUStr(const std::string &view); + std::string toStr(const std::u32string &view); + int maxUnicode(const std::string &view); + + std::string toLowerCase(const std::string &view); + std::string toUpperCase(const std::string &view); + + float compareRelative(const std::string &left, const std::string &right); + + template::value>::type> + inline T toVal(const std::string &view) + { + std::string str; + + if constexpr(std::is_same::value) + return std::stoi(view.data()); + else if constexpr(std::is_same::value) + return std::stoul(view.data()); + else if constexpr(std::is_same::value) + return std::stol(view.data()); + else if constexpr(std::is_same::value) + return std::stoll(view.data()); + else if constexpr(std::is_same::value) + return std::stoull(view.data()); + else if constexpr(std::is_same::value) + return std::stold(view.data()); + else if constexpr(std::is_same::value) + return std::stof(view.data()); + else if constexpr(std::is_same::value) + return std::stod(view.data()); + + return 0; + } + + template::value>::type> + inline T toValOrDef(const std::string &view, T def = 0, bool *ok = nullptr) + { + if(ok) + *ok = true; + + try { + if constexpr(std::is_same::value) + return std::stoi(view.data()); + else if constexpr(std::is_same::value) + return std::stoul(view.data()); + else if constexpr(std::is_same::value) + return std::stol(view.data()); + else if constexpr(std::is_same::value) + return std::stoll(view.data()); + else if constexpr(std::is_same::value) + return std::stoull(view.data()); + else if constexpr(std::is_same::value) + return std::stold(view.data()); + else if constexpr(std::is_same::value) + return std::stof(view.data()); + else if constexpr(std::is_same::value) + return std::stod(view.data()); + } catch(...) { + if(ok) + *ok = false; + } + + return def; + } +} + +namespace Enc { + + template + >::type> + std::string toHex(T value) + { + std::stringstream stream; + stream << std::setfill('0') << std::setw(sizeof(T)*2) + << std::hex << uint64_t(value); + return stream.str(); + }; + + std::string toHex(const uint8_t *data, size_t size); + void fromHex(const std::string &in, uint8_t *data); + + std::string toBase64(const uint8_t *data, size_t size); + ByteBuffer fromBase64(const std::string &view); + void base64UrlConvert(std::string &in); + + // LowerCase + std::string md5(const uint8_t *data, size_t size); + inline std::string md5(const std::string &str) { return md5((const uint8_t*) str.data(), str.size()); } + std::string sha1(const uint8_t *data, size_t size); + inline std::string sha1(const std::string &str) { return sha1((const uint8_t*) str.data(), str.size()); } +} + +using namespace std::chrono; + +namespace Time { + template + inline void sleep(T val) { std::this_thread::sleep_for(val); } + inline void sleep3(uint64_t mls) { std::this_thread::sleep_for(std::chrono::milliseconds { mls }); } + inline void sleep6(uint64_t mcs) { std::this_thread::sleep_for(std::chrono::microseconds { mcs }); } + inline void sleep9(uint64_t nas) { std::this_thread::sleep_for(std::chrono::nanoseconds { nas }); } + + // Системное время, может изменяться в обратку + inline uint64_t nowSystem() { return std::chrono::system_clock::now().time_since_epoch().count(); } + // Время с запуска хоста, только растёт + inline uint64_t nowSteady() { return std::chrono::steady_clock::now().time_since_epoch().count(); } + // Максимально точное время + inline uint64_t nowHigh() { return std::chrono::high_resolution_clock::now().time_since_epoch().count(); } + + inline std::time_t getTime() { return std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); } + // Количество секунд с начала эпохи на часах системы + inline uint64_t getSeconds() { return std::chrono::system_clock::now().time_since_epoch().count() / 1000000000ull; } + + inline uint32_t getDay() { return getSeconds() / 86400; } + + // yyyy.mm.dd + std::string getDateAsString(); + // hh:mm:ss + std::string getTimeAsString(); +} + +//[0.0,1.0) +inline double genRand(double min = 1, double max = 0) +{ + double res; +#ifdef _WIN32 + res = std::clamp(rand() / double(RAND_MAX), 0., 0.9999999); +#else + res = drand48(); +#endif + return res*(max-min)+min; +} + +std::string makeStackTrace(int stack_up = 1); + +struct Timer +{ + boost::timer::cpu_timer Obj; + + /* Возвращает прошедшее время в наносекундах 1/1'000'000'000 */ + uint64_t timePastNan() + { + auto time = Obj.elapsed(); + return time.wall; + } + /* Возвращает прошедшее время в милисекундах 1/1'000 */ + uint32_t timePastMil() { return timePastNan()/1000000; } + + /* Возвращает затраченное процессорное время в наносекундах 1/1'000'000'000 */ + uint64_t timeUsedNan() + { + auto time = Obj.elapsed(); + return time.system+time.user; + } + /* Возвращает затраченное процессорное время в милисекундах 1/1'000 */ + uint32_t timeUsedMil() { return timeUsedNan()/1000000; } + + /* Обнуляет счетчик таймера и запускает его */ + void start() { Obj.start(); } + /* Запускает таймер */ + void resume() { Obj.resume(); } + /* Останавливает таймер */ + void stop() { Obj.stop(); } + bool isStopped() { return Obj.is_stopped(); } +}; + +class DynamicLibrary { + std::string Name, Path; + uint64_t FD; + static bool IsOverWine; + + static void symbolOut(); + static bool checkWine(); + +public: + DynamicLibrary(const std::string &name_or_path); + DynamicLibrary(const char *name_or_path) : DynamicLibrary(std::string(name_or_path)) {} + ~DynamicLibrary(); + + DynamicLibrary(const DynamicLibrary&) = delete; + DynamicLibrary(DynamicLibrary&&); + DynamicLibrary& operator=(const DynamicLibrary&) = delete; + DynamicLibrary& operator=(DynamicLibrary&&); + + std::string getName() const { return Name; } + std::string getPath() const { return Path; } + uint64_t getHandler() const { return FD; } + + // Запрашивает адрес символа из библиотеки, иначе генерирует ошибку + void* getSymbol(const std::string &name) const; + template + inline void getSymbol(Result (*&to)(Args...), const std::string &name) const { to = (Result (*)(Args...)) getSymbol(name); } + // Запрашивает адрес символа из библиотеки, если отсутствует ссылает на &symbolOut + void* takeSymbol(const std::string &name) const; + template + inline void takeSymbol(Result (*&to)(Args...), const std::string &name) const { to = (Result (*)(Args...)) takeSymbol(name); } + + // Запрашивает адрес из глобального пространства, если нет, то ошибка + static void* getDynamicSymbol(const std::string &name); + // Вместо ошибки даёт symbolOut + static void* takeDynamicSymbol(const std::string &name); + // + static void* hasDynamicSymbol(const std::string &name); + // Проверяет наличие или загружает библиотеку с глобальной линковкой функций + static void needGlobalLibraryTemplate(const std::string &name); + static std::vector getLdPaths(); + static bool isOverWine() { return IsOverWine; } +}; + +enum struct EnumLogType : int { + Debug = 1, Info = 2, Warn = 4, Error = 8, All = 15 +}; + + +class LogSession : public std::stringstream { + bool NeedF = false, NeedC = false; + std::string Path; + +public: + LogSession(const std::string &name, EnumLogType type); + ~LogSession(); + + LogSession(const LogSession&) = delete; + LogSession(LogSession&&) = delete; + LogSession& operator=(const LogSession&) = delete; + LogSession& operator=(LogSession&&) = delete; +}; + +class Logger { + std::string Path; + +public: + Logger(const std::string &path) : Path(path) {} + Logger(const char *path) : Path(path) {} + ~Logger() = default; + + inline LogSession print(EnumLogType type) const { return LogSession(Path, type); } + inline LogSession debug() const { return print(EnumLogType::Debug); } + inline LogSession info() const { return print(EnumLogType::Info); } + inline LogSession warn() const { return print(EnumLogType::Warn); } + inline LogSession error() const { return print(EnumLogType::Error); } + + void setName(const std::string &path) { Path = path; } + + static LogSession print(const std::string &path) { return LogSession(path, EnumLogType::All); } + static void addLogFile(const std::string ®ex_for_path, EnumLogType levels, const std::filesystem::path &file, bool rewrite = false); + static void addLogOutput(const std::string ®ex_for_path, EnumLogType levels); +}; + +} + +#define MAKE_ERROR(arg) throw std::runtime_error((std::stringstream() << arg).str())