From 72320b2eb0bfd3d84795a8a0ea5489dac59def58 Mon Sep 17 00:00:00 2001 From: OEOTYAN Date: Mon, 12 Aug 2024 04:32:04 +0800 Subject: [PATCH] feat: add StdoutRedirector --- src-client/ll/core/main.cpp | 1 + src/ll/api/io/StdoutRedirector.cpp | 79 ++++++++++++++++++++++++++++++ src/ll/api/io/StdoutRedirector.h | 24 +++++++++ src/ll/api/utils/RandomUtils.h | 3 +- 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 src/ll/api/io/StdoutRedirector.cpp create mode 100644 src/ll/api/io/StdoutRedirector.h diff --git a/src-client/ll/core/main.cpp b/src-client/ll/core/main.cpp index e69de29bb2..8b13789179 100644 --- a/src-client/ll/core/main.cpp +++ b/src-client/ll/core/main.cpp @@ -0,0 +1 @@ + diff --git a/src/ll/api/io/StdoutRedirector.cpp b/src/ll/api/io/StdoutRedirector.cpp new file mode 100644 index 0000000000..bfc3a8e3e8 --- /dev/null +++ b/src/ll/api/io/StdoutRedirector.cpp @@ -0,0 +1,79 @@ +#include "ll/api/io/StdoutRedirector.h" + +#include "ll/api/utils/RandomUtils.h" +#include "ll/api/utils/StringUtils.h" + +#include "Windows.h" + +#include "fcntl.h" +#include "io.h" + +namespace ll::io { + +static void createWinPipe(HANDLE& hRead, HANDLE& hWrite) { + std::wstring pipeName = LR"(\\.\pipe\stdoutredirector-levilamina-)"; + pipeName += string_utils::str2wstr(string_utils::intToHexStr(random_utils::rand())); + SECURITY_ATTRIBUTES attributes = {sizeof(SECURITY_ATTRIBUTES), 0, false}; + hRead = ::CreateNamedPipe( + pipeName.c_str(), + PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_WAIT, + 1, + 0, + 1024 * 1024, + 0, + &attributes + ); + SECURITY_ATTRIBUTES attributes2 = {sizeof(SECURITY_ATTRIBUTES), 0, true}; + hWrite = ::CreateFile(pipeName.c_str(), GENERIC_WRITE, 0, &attributes2, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + + ::ConnectNamedPipe(hRead, NULL); +} + +StdoutRedirector::StdoutRedirector(ProcessChannel channels) : m_channels(channels) { + createWinPipe(hRead, hWrite); + if (m_channels & StandardOutput) { + setvbuf(stdout, NULL, _IONBF, 0); + ::SetStdHandle(STD_OUTPUT_HANDLE, hWrite); + } + if (m_channels & StandardError) { + setvbuf(stderr, NULL, _IONBF, 0); + ::SetStdHandle(STD_ERROR_HANDLE, hWrite); + } + + int fd = _open_osfhandle((intptr_t)hWrite, _O_WRONLY | _O_U8TEXT); + if (m_channels & StandardOutput) _dup2(fd, 1); + if (m_channels & StandardError) _dup2(fd, 2); + _close(fd); +} + +StdoutRedirector::~StdoutRedirector() { + ::DisconnectNamedPipe(hRead); + if (m_channels & StandardOutput) { + FILE* s; + freopen_s(&s, "CONOUT$", "w+t", stdout); + } + if (m_channels & StandardError) { + FILE* s; + freopen_s(&s, "CONOUT$", "w+t", stderr); + } +} + +std::string StdoutRedirector::read() { + std::string result; + BOOL fSuccess; + do { + // Read from the pipe. + + char buf[4096]; + DWORD cbRead{0}; + + fSuccess = ReadFile(hRead, buf, sizeof(buf), &cbRead, NULL); + + result.append(buf, cbRead); + + if (!fSuccess && GetLastError() != ERROR_MORE_DATA) break; + } while (!fSuccess); // repeat loop if ERROR_MORE_DATA + return result; +} +} // namespace ll::io diff --git a/src/ll/api/io/StdoutRedirector.h b/src/ll/api/io/StdoutRedirector.h new file mode 100644 index 0000000000..23815f2852 --- /dev/null +++ b/src/ll/api/io/StdoutRedirector.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include "ll/api/base/Macro.h" + +namespace ll::io { + +class StdoutRedirector { +public: + enum ProcessChannel { StandardOutput = 1, StandardError = 2 }; + + LLNDAPI explicit StdoutRedirector(ProcessChannel channels = (ProcessChannel)(StandardOutput | StandardError)); + + LLAPI ~StdoutRedirector(); + + LLNDAPI std::string read(); + + ProcessChannel m_channels; + + void* hRead; + void* hWrite; +}; +} // namespace ll::io diff --git a/src/ll/api/utils/RandomUtils.h b/src/ll/api/utils/RandomUtils.h index 84d5fe0aa9..3b8d4f38aa 100644 --- a/src/ll/api/utils/RandomUtils.h +++ b/src/ll/api/utils/RandomUtils.h @@ -15,8 +15,7 @@ namespace ll::inline utils::random_utils { template inline T rand(T upBound = 0) { - static pcg_extras::seed_seq_from rd{}; - static pcg64 random{rd}; + static pcg64 random{pcg_extras::seed_seq_from{}}; constexpr auto digits = std::numeric_limits::digits; if (upBound != 0) {