#include "pipe_operator.hpp" #include #if defined(BASALT_OS_WINDOWS) #include #else #include #include #include #endif namespace basalt::shared::pipe_operator { PipeOperator::PipeOperator(const char_types::BSStringView& 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