From 9af21b514ac9a42d549cea66ce47f07b23b0050d Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Thu, 27 Nov 2025 20:48:35 +0800 Subject: [PATCH] feat: finish pipe operator --- BasaltPresenter/Presenter/dll_loader.hpp | 18 ++- BasaltPresenter/Shared/CMakeLists.txt | 4 +- BasaltPresenter/Shared/pipe_operator.cpp | 167 +++++++++++++++++++++++ BasaltPresenter/Shared/pipe_operator.hpp | 37 +++++ BasaltPresenter/Shared/pipe_sender.cpp | 9 -- BasaltPresenter/Shared/pipe_sender.hpp | 19 --- 6 files changed, 223 insertions(+), 31 deletions(-) create mode 100644 BasaltPresenter/Shared/pipe_operator.cpp create mode 100644 BasaltPresenter/Shared/pipe_operator.hpp delete mode 100644 BasaltPresenter/Shared/pipe_sender.cpp delete mode 100644 BasaltPresenter/Shared/pipe_sender.hpp diff --git a/BasaltPresenter/Presenter/dll_loader.hpp b/BasaltPresenter/Presenter/dll_loader.hpp index e44adc1..b89212b 100644 --- a/BasaltPresenter/Presenter/dll_loader.hpp +++ b/BasaltPresenter/Presenter/dll_loader.hpp @@ -21,13 +21,29 @@ namespace Basalt::Presenter { #if defined(BASALT_OS_WINDOWS) using Handle = HMODULE; #else - using Handle = void *; + using Handle = void*; #endif public: DllLoader(DllKind kind, const std::basic_string_view filename); ~DllLoader(); + public: + template + T* CreateInstance() { + if (!m_Handle) return nullptr; + + using Fct = T* (*) (); + constexpr char EXPOSE_FUNC_NAME[] = "BSCreateInstance"; +#if defined(BASALT_OS_WINDOWS) + auto fct = (Fct) GetProcAddress(m_Handle, EXPOSE_FUNC_NAME); +#else + auto fct = (Fct) dlsym(m_Handle, EXPOSE_FUNC_NAME); +#endif + + return fct(); + } + private: Handle m_Handle; }; diff --git a/BasaltPresenter/Shared/CMakeLists.txt b/BasaltPresenter/Shared/CMakeLists.txt index 7480015..a69604f 100644 --- a/BasaltPresenter/Shared/CMakeLists.txt +++ b/BasaltPresenter/Shared/CMakeLists.txt @@ -1,7 +1,7 @@ add_library(BasaltShared STATIC "") target_sources(BasaltShared PRIVATE - pipe_sender.cpp + pipe_operator.cpp ) target_sources(BasaltShared PUBLIC @@ -9,7 +9,7 @@ FILE_SET HEADERS FILES # Headers basalt_char.hpp - pipe_sender.hpp + pipe_operator.hpp ) target_include_directories(BasaltShared PUBLIC diff --git a/BasaltPresenter/Shared/pipe_operator.cpp b/BasaltPresenter/Shared/pipe_operator.cpp new file mode 100644 index 0000000..3387ca9 --- /dev/null +++ b/BasaltPresenter/Shared/pipe_operator.cpp @@ -0,0 +1,167 @@ +#include "pipe_operator.hpp" +#include + +#if defined(BASALT_OS_WINDOWS) +#include +#else +#include +#include +#include +#endif + +namespace Basalt::Shared { + + PipeOperator::PipeOperator(const std::basic_string_view name) { +#if defined(BASALT_OS_WINDOWS) + // Create Windows pipe name from given name + auto fullname = std::format(BSTEXT("\\\\.\\pipe\\{}"), name); + + m_Handle = CreateFileW(fullname.c_str(), // 管道名称 + GENERIC_READ | GENERIC_WRITE, // 读写权限 + 0, // 不共享 + NULL, // 默认安全属性 + OPEN_EXISTING, // 打开已存在的管道 + 0, // 默认属性 + NULL // 无模板文件 + ); + + if (m_Handle == BAD_PIPE_HANDLE) { + throw std::runtime_error("Failed to open named pipe."); + } +#else + // Create Linux pipe name from given name + auto fullname = std::format(BSTEXT("/tmp/{}"), name); + + m_Handle = open(fullname.c_str(), O_RDWR); + if (m_Handle == BAD_PIPE_HANDLE) { + throw std::runtime_error("Failed to open named pipe."); + } +#endif + } + + PipeOperator::~PipeOperator() { +#if defined(BASALT_OS_WINDOWS) + if (m_Handle != BAD_PIPE_HANDLE) { + CloseHandle(m_Handle); + } +#else + if (m_Handle != BAD_PIPE_HANDLE) { + close(m_Handle); + } +#endif + } + + PipeOperator::PipeOperator(PipeOperator &&rhs) noexcept { +#if defined(BASALT_OS_WINDOWS) + m_Handle = rhs.m_Handle; + rhs.m_Handle = BAD_PIPE_HANDLE; +#else + m_Handle = rhs.m_Handle; + rhs.m_Handle = BAD_PIPE_HANDLE; +#endif + } + + PipeOperator &PipeOperator::operator=(PipeOperator &&rhs) noexcept { +#if defined(BASALT_OS_WINDOWS) + if (m_Handle != BAD_PIPE_HANDLE) { + CloseHandle(m_Handle); + } + m_Handle = rhs.m_Handle; + rhs.m_Handle = BAD_PIPE_HANDLE; +#else + if (m_Handle != BAD_PIPE_HANDLE) { + close(m_Handle); + } + m_Handle = rhs.m_Handle; + rhs.m_Handle = BAD_PIPE_HANDLE; +#endif + return *this; + } + + void PipeOperator::Read(void *buffer, size_t size) { + if (size == 0) { + return; // 读取0字节直接返回 + } + +#if defined(BASALT_OS_WINDOWS) + DWORD bytesRead = 0; + BOOL success = ReadFile(m_Handle, // 管道句柄 + buffer, // 缓冲区 + static_cast(size), // 缓冲区大小 + &bytesRead, // 实际读取的字节数 + NULL // 不使用重叠I/O + ); + + if (!success) { + throw std::runtime_error("Failed to read from named pipe."); + } + + if (bytesRead != static_cast(size)) { + throw std::runtime_error("Incomplete read from named pipe."); + } +#else + // Due to POSIX "write" may write bytes less than given, + // so we need use "while" syntax to implement it. + size_t totalRead = 0; + while (totalRead < size) { + ssize_t bytesRead = read(m_Handle, static_cast(buffer) + totalRead, size - totalRead); + + if (bytesRead == -1) { + throw std::runtime_error("Failed to read from named pipe"); + } + + if (bytesRead == 0) { + // 管道已关闭或到达末尾 + throw std::runtime_error("Named pipe closed during read."); + } + + totalRead += bytesRead; + } + + if (totalRead != size) { + throw std::runtime_error("Incomplete read from named pipe."); + } +#endif + } + + void PipeOperator::Write(const void *buffer, size_t size) { + if (size == 0) { + return; // 写入0字节直接返回 + } + +#if defined(BASALT_OS_WINDOWS) + DWORD bytesWritten = 0; + BOOL success = WriteFile(m_Handle, // 管道句柄 + buffer, // 数据缓冲区 + static_cast(size), // 数据大小 + &bytesWritten, // 实际写入的字节数 + NULL // 不使用重叠I/O + ); + + if (!success) { + throw std::runtime_error("Failed to write to named pipe."); + } + + if (bytesWritten != static_cast(size)) { + throw std::runtime_error("Incomplete write to named pipe."); + } +#else + // Due to the same reason, use "while" syntax. + size_t totalWritten = 0; + while (totalWritten < size) { + ssize_t bytesWritten = write(m_Handle, static_cast(buffer) + totalWritten, size - totalWritten); + + if (bytesWritten == -1) { + throw std::runtime_error("Failed to write to named pipe."); + } + + totalWritten += bytesWritten; + } + + if (totalWritten != size) { + throw std::runtime_error("Incomplete write to named pipe."); + } +#endif + } + +} // namespace Basalt::Shared diff --git a/BasaltPresenter/Shared/pipe_operator.hpp b/BasaltPresenter/Shared/pipe_operator.hpp new file mode 100644 index 0000000..f574c1d --- /dev/null +++ b/BasaltPresenter/Shared/pipe_operator.hpp @@ -0,0 +1,37 @@ +#include "basalt_char.hpp" +#include + +#if defined(BASALT_OS_WINDOWS) +#include +#else +#endif + +namespace Basalt::Shared { + + class PipeOperator { + public: +#if defined(BASALT_OS_WINDOWS) + using Handle = HANDLE; + static constexpr Handle BAD_PIPE_HANDLE = INVALID_HANDLE_VALUE; +#else + using Handle = int; + static constexpr Handle BAD_PIPE_HANDLE = -1; +#endif + + public: + PipeOperator(const std::basic_string_view name); + ~PipeOperator(); + // Delete copy ctor + PipeOperator(const PipeOperator&) = delete; + PipeOperator& operator=(const PipeOperator&) = delete; + // Implement move ctor + PipeOperator(PipeOperator&&) noexcept; + PipeOperator& operator=(PipeOperator&& other) noexcept; + + void Read(void* buffer, size_t size); + void Write(const void* buffer, size_t size); + + private: + Handle m_Handle; + }; +} // namespace Basalt::Shared diff --git a/BasaltPresenter/Shared/pipe_sender.cpp b/BasaltPresenter/Shared/pipe_sender.cpp deleted file mode 100644 index 4a08610..0000000 --- a/BasaltPresenter/Shared/pipe_sender.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "pipe_sender.hpp" - -namespace Basalt::Shared { - - PipeSender::PipeSender(PipeSenderKind kind) {} - - PipeSender::~PipeSender() {} - -} diff --git a/BasaltPresenter/Shared/pipe_sender.hpp b/BasaltPresenter/Shared/pipe_sender.hpp deleted file mode 100644 index d306cf8..0000000 --- a/BasaltPresenter/Shared/pipe_sender.hpp +++ /dev/null @@ -1,19 +0,0 @@ - - -namespace Basalt::Shared { - - enum class PipeSenderKind { - Data, - Command - }; - - class PipeSender { - public: - PipeSender(PipeSenderKind kind); - ~PipeSender(); - - private: - PipeSenderKind kind; - - }; -}