From 4cdc56a32d7a1e92a140f159ad16c23b14067ecc Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Tue, 6 Jan 2026 16:27:19 +0800 Subject: [PATCH] write shit --- .../Plugins/Deliver/PipeDeliver/main.cpp | 2 +- .../Plugins/Engine/DirectX11Engine/main.cpp | 12 +- BasaltPresenter/Presenter/dll_loader.cpp | 3 +- BasaltPresenter/Presenter/dll_loader.hpp | 2 +- BasaltPresenter/Presenter/main.cpp | 12 +- BasaltPresenter/README.md | 15 ++ BasaltPresenter/Shared/CMakeLists.txt | 16 +- .../char_types.hpp} | 1 + .../export_macro.hpp} | 0 BasaltPresenter/Shared/basalt/kernel.cpp | 65 ++++++ BasaltPresenter/Shared/basalt/kernel.hpp | 123 +++++++++++ BasaltPresenter/Shared/basalt/math.cpp | 5 + BasaltPresenter/Shared/basalt/math.hpp | 34 +++ .../Shared/{ => basalt}/pipe_operator.cpp | 0 .../Shared/{ => basalt}/pipe_operator.hpp | 2 +- BasaltPresenter/Shared/deliver.cpp | 9 - BasaltPresenter/Shared/deliver.hpp | 18 -- BasaltPresenter/Shared/engine.cpp | 30 --- BasaltPresenter/Shared/engine.hpp | 49 ----- BasaltTrainer/.gitignore | 3 + BasaltTrainer/pipe_operator.py | 203 ++++++++++++++++++ BasaltTrainer/pyproject.toml | 5 +- BasaltTrainer/uv.lock | 21 ++ Document/PROTOCOL.md | 17 +- 24 files changed, 512 insertions(+), 135 deletions(-) rename BasaltPresenter/Shared/{basalt_char.hpp => basalt/char_types.hpp} (96%) rename BasaltPresenter/Shared/{basalt_export.hpp => basalt/export_macro.hpp} (100%) create mode 100644 BasaltPresenter/Shared/basalt/kernel.cpp create mode 100644 BasaltPresenter/Shared/basalt/kernel.hpp create mode 100644 BasaltPresenter/Shared/basalt/math.cpp create mode 100644 BasaltPresenter/Shared/basalt/math.hpp rename BasaltPresenter/Shared/{ => basalt}/pipe_operator.cpp (100%) rename BasaltPresenter/Shared/{ => basalt}/pipe_operator.hpp (97%) delete mode 100644 BasaltPresenter/Shared/deliver.cpp delete mode 100644 BasaltPresenter/Shared/deliver.hpp delete mode 100644 BasaltPresenter/Shared/engine.cpp delete mode 100644 BasaltPresenter/Shared/engine.hpp create mode 100644 BasaltTrainer/pipe_operator.py diff --git a/BasaltPresenter/Plugins/Deliver/PipeDeliver/main.cpp b/BasaltPresenter/Plugins/Deliver/PipeDeliver/main.cpp index 734b6b9..ab428f5 100644 --- a/BasaltPresenter/Plugins/Deliver/PipeDeliver/main.cpp +++ b/BasaltPresenter/Plugins/Deliver/PipeDeliver/main.cpp @@ -1,4 +1,4 @@ -#include +#include BS_EXPORT void* BSCreateInstance() { return nullptr; diff --git a/BasaltPresenter/Plugins/Engine/DirectX11Engine/main.cpp b/BasaltPresenter/Plugins/Engine/DirectX11Engine/main.cpp index 970ab6f..cb548a7 100644 --- a/BasaltPresenter/Plugins/Engine/DirectX11Engine/main.cpp +++ b/BasaltPresenter/Plugins/Engine/DirectX11Engine/main.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include #include #include @@ -161,8 +161,8 @@ const char* g_PS = R"( } )"; -using ::Basalt::Shared::Engine::EngineConfig; -using ::Basalt::Shared::Engine::IEngine; +using ::Basalt::Shared::Kernel::EngineConfig; +using ::Basalt::Shared::Kernel::IEngine; class DirectX11Engine : public IEngine { public: @@ -383,9 +383,9 @@ public: }; BS_EXPORT void* BSCreateInstance() { - return new DirectX11Engine(); + return static_cast(new DirectX11Engine()); } BS_EXPORT void BSDestroyInstance(void* instance) { - delete reinterpret_cast(instance); + delete dynamic_cast(static_cast(instance)); } \ No newline at end of file diff --git a/BasaltPresenter/Presenter/dll_loader.cpp b/BasaltPresenter/Presenter/dll_loader.cpp index c68ef57..3a1b89c 100644 --- a/BasaltPresenter/Presenter/dll_loader.cpp +++ b/BasaltPresenter/Presenter/dll_loader.cpp @@ -54,8 +54,9 @@ namespace Basalt::Presenter { dll_path /= filename; #if defined(BASALT_OS_WINDOWS) dll_path.replace_extension(BSTEXT(".dll")); +#else + dll_path.replace_extension(BSTEXT(".so")); #endif - // Load DLL #if defined(BASALT_OS_WINDOWS) m_Handle = LoadLibraryW(dll_path.wstring().c_str()); diff --git a/BasaltPresenter/Presenter/dll_loader.hpp b/BasaltPresenter/Presenter/dll_loader.hpp index 01c893e..c09ac3e 100644 --- a/BasaltPresenter/Presenter/dll_loader.hpp +++ b/BasaltPresenter/Presenter/dll_loader.hpp @@ -1,4 +1,4 @@ -#include +#include #include #if defined(BASALT_OS_WINDOWS) diff --git a/BasaltPresenter/Presenter/main.cpp b/BasaltPresenter/Presenter/main.cpp index ac0ecca..81588b9 100644 --- a/BasaltPresenter/Presenter/main.cpp +++ b/BasaltPresenter/Presenter/main.cpp @@ -1,15 +1,17 @@ #include "dll_loader.hpp" -#include -#include +#include +#include namespace Presenter = ::Basalt::Presenter; -namespace Shared = ::Basalt::Shared; +namespace Kernel = ::Basalt::Shared::Kernel; int main(int argc, char* argv[]) { auto engine_dll = Presenter::DllLoader(Presenter::DllKind::Engine, BSTEXT("BasaltDirectX11Engine")); - auto* engine = engine_dll.CreateInstance(); + auto deliver_dll = Presenter::DllLoader(Presenter::DllKind::Deliver, BSTEXT("BasaltPipeDeliver")); + auto* engine = engine_dll.CreateInstance(); + auto* deliver = deliver_dll.CreateInstance(); - Shared::Engine::EngineConfig engine_config{.headless = false, .title = BSTEXT("Fuck You"), .width = 800, .height = 600}; + Kernel::EngineConfig engine_config{.headless = false, .title = BSTEXT("Fuck You"), .width = 800, .height = 600}; engine->Startup(std::move(engine_config)); while (true) { diff --git a/BasaltPresenter/README.md b/BasaltPresenter/README.md index e69de29..031bb2d 100644 --- a/BasaltPresenter/README.md +++ b/BasaltPresenter/README.md @@ -0,0 +1,15 @@ +# Basalt Presenter + +## Dependencies + +* [tinyobjloader](https://github.com/tinyobjloader/tinyobjloader) +* [cgltf](https://github.com/jkuhlmann/cgltf) + +## Warning + +This project was not written robustly. +So please confirm following conditions when running this program. + +- ASCII-only path. It would be better to have English-chars-only path. No space, tab or weird chars. +- Not too long path. It would be better that less than 200 chars. +- ASCII-only command line arguments. diff --git a/BasaltPresenter/Shared/CMakeLists.txt b/BasaltPresenter/Shared/CMakeLists.txt index e50810c..fb53207 100644 --- a/BasaltPresenter/Shared/CMakeLists.txt +++ b/BasaltPresenter/Shared/CMakeLists.txt @@ -2,9 +2,9 @@ add_library(BasaltShared STATIC "") target_sources(BasaltShared PRIVATE # Sources - pipe_operator.cpp - engine.cpp - deliver.cpp + basalt/pipe_operator.cpp + basalt/kernel.cpp + basalt/math.cpp ) target_sources(BasaltShared @@ -12,11 +12,11 @@ PUBLIC FILE_SET HEADERS FILES # Headers - basalt_char.hpp - basalt_export.hpp - pipe_operator.hpp - engine.hpp - deliver.hpp + basalt/char_types.hpp + basalt/export_macro.hpp + basalt/pipe_operator.hpp + basalt/kernel.hpp + basalt/math.hpp ) target_include_directories(BasaltShared PUBLIC diff --git a/BasaltPresenter/Shared/basalt_char.hpp b/BasaltPresenter/Shared/basalt/char_types.hpp similarity index 96% rename from BasaltPresenter/Shared/basalt_char.hpp rename to BasaltPresenter/Shared/basalt/char_types.hpp index bdb4d00..6fb445e 100644 --- a/BasaltPresenter/Shared/basalt_char.hpp +++ b/BasaltPresenter/Shared/basalt/char_types.hpp @@ -1,3 +1,4 @@ +#pragma once #include #include #include diff --git a/BasaltPresenter/Shared/basalt_export.hpp b/BasaltPresenter/Shared/basalt/export_macro.hpp similarity index 100% rename from BasaltPresenter/Shared/basalt_export.hpp rename to BasaltPresenter/Shared/basalt/export_macro.hpp diff --git a/BasaltPresenter/Shared/basalt/kernel.cpp b/BasaltPresenter/Shared/basalt/kernel.cpp new file mode 100644 index 0000000..ec99349 --- /dev/null +++ b/BasaltPresenter/Shared/basalt/kernel.cpp @@ -0,0 +1,65 @@ +#include "kernel.hpp" +#include + +namespace Basalt::Shared::Kernel { + +#pragma region Engine + + IEngine::IEngine() : config(), status(EngineStatus::Ready) {} + + IEngine::~IEngine() { + if (this->status != EngineStatus::Stop) { + this->Shutdown(); + } + } + + Guid IEngine::GetGuid() const { + throw std::logic_error("unimplemented function"); + } + + void IEngine::Startup(EngineConfig &&config) { + if (this->status != EngineStatus::Ready) throw std::runtime_error("unexpected engine status"); + this->config = std::move(config); + this->status = EngineStatus::Running; + } + + bool IEngine::Tick() { + if (this->status != EngineStatus::Running) throw std::runtime_error("unexpected engine status"); + return false; + } + + void IEngine::Shutdown() { + if (this->status != EngineStatus::Running) throw std::runtime_error("unexpected engine status"); + this->status = EngineStatus::Stop; + } + +#pragma endregion + +#pragma region Deliver + + IDeliver::IDeliver() {} + + IDeliver::~IDeliver() {} + + Guid IDeliver::GetGuid() const { + throw std::logic_error("unimplemented function"); + } + + void IDeliver::Startup(DeliverConfig &&config) { + if (this->status != DeliverStatus::Ready) throw std::runtime_error("unexpected deliver status"); + this->config = std::move(config); + this->status = DeliverStatus::Running; + } + + void IDeliver::Transmit() { + if (this->status != DeliverStatus::Running) throw std::runtime_error("unexpected deliver status"); + } + + void IDeliver::Shutdown() { + if (this->status != DeliverStatus::Running) throw std::runtime_error("unexpected deliver status"); + this->status = DeliverStatus::Stop; + } + +#pragma endregion + +} // namespace Basalt::Shared::Kernel diff --git a/BasaltPresenter/Shared/basalt/kernel.hpp b/BasaltPresenter/Shared/basalt/kernel.hpp new file mode 100644 index 0000000..21e893f --- /dev/null +++ b/BasaltPresenter/Shared/basalt/kernel.hpp @@ -0,0 +1,123 @@ +#pragma once +#include "char_types.hpp" +#include +#include + +namespace Basalt::Shared::Kernel { + +#pragma region Guid & Predefined Guid + + struct Guid { + std::uint32_t d1, d2; + + constexpr Guid(std::uint32_t gd1 = 0, std::uint32_t gd2 = 0) : d1(gd1), d2(gd2) {} + Guid(const Guid& rhs) : d1(rhs.d1), d2(rhs.d2) {} + Guid(Guid&& rhs) noexcept : d1(rhs.d1), d2(rhs.d2) {} + Guid& operator=(const Guid& rhs) { + this->d1 = rhs.d1; + this->d2 = rhs.d2; + return *this; + } + Guid& operator=(Guid&& rhs) noexcept { + this->d1 = rhs.d1; + this->d2 = rhs.d2; + return *this; + } + + auto operator<=>(const Guid& rhs) const { + if (auto cmp = this->d1 <=> rhs.d1; cmp != 0) return cmp; + return this->d2 <=> rhs.d2; + } + bool operator==(const Guid& rhs) const { return ((this->d1 == rhs.d1) && (this->d2 == rhs.d2)); } + }; + + constexpr Guid DIRECTX8_ENGINE{0x0, 0x1}; + constexpr Guid DIRECTX9_ENGINE{0x0, 0x2}; + constexpr Guid DIRECTX11_ENGINE{0x0, 0x3}; + constexpr Guid DIRECTX12_ENGINE{0x0, 0x4}; + constexpr Guid OPENGL_ENGINE{0x0, 0x5}; + constexpr Guid VULKAN_ENGINE{0x0, 0x6}; + + constexpr Guid CUDA_DELIVER{0x1, 0x1}; + constexpr Guid ROCM_DELIVER{0x1, 0x2}; + constexpr Guid PIPE_DELIVER{0x1, 0x3}; + constexpr Guid TCP_DELIVER{0x1, 0x4}; + constexpr Guid MMAP_DELIVER{0x1, 0x5}; + + constexpr Guid TINYOBJLOADER_OBJECT_LOADER{0x2, 0x1}; + constexpr Guid CGLTF_OBJECT_LOADER{0x2, 0x2}; + constexpr Guid ASSIMP_OBJECT_LOADER{0x2, 0x3}; + + constexpr Guid HOMEBREW_ANIME_LOADER{0x3, 0x1}; + +#pragma endregion + +#pragma region Engine + + struct EngineConfig { + bool headless; ///< Whether enable headless mode (No Window created). + std::basic_string title; ///< Window title. + std::uint32_t width; ///< Window width. + std::uint32_t height; ///< Window height. + Guid deliver; ///< The GUID of deliver. + }; + + enum class EngineStatus { + Ready, ///< Engine was allocated but not initialized. + Running, ///< Engine has been initialized and running. + Stop, ///< Engine is shutdown. + }; + + class IEngine { + public: + IEngine(); + virtual ~IEngine(); + + public: + virtual Guid GetGuid() const; + virtual void Startup(EngineConfig&& config); + /** + * @brief + * @return True for active exit. + */ + virtual bool Tick(); + virtual void Shutdown(); + + protected: + EngineConfig config; + EngineStatus status; + }; + +#pragma endregion + +#pragma region Deliver + + struct DeliverConfig { + Guid engine; ///< The GUID of render engine. + }; + + enum class DeliverStatus { + Ready, ///< Engine was allocated but not initialized. + Running, ///< Engine has been initialized and running. + Stop, ///< Engine is shutdown. + }; + + class IDeliver { + public: + IDeliver(); + virtual ~IDeliver(); + + public: + virtual Guid GetGuid() const; + virtual void Startup(DeliverConfig&& config); + virtual void Transmit(); + virtual void Shutdown(); + + protected: + DeliverConfig config; + DeliverStatus status; + }; + +#pragma endregion + +} // namespace Basalt::Shared::Kernel diff --git a/BasaltPresenter/Shared/basalt/math.cpp b/BasaltPresenter/Shared/basalt/math.cpp new file mode 100644 index 0000000..8b66f4b --- /dev/null +++ b/BasaltPresenter/Shared/basalt/math.cpp @@ -0,0 +1,5 @@ +#include "math.hpp" + +namespace Basalt::Shared::Math { + +} diff --git a/BasaltPresenter/Shared/basalt/math.hpp b/BasaltPresenter/Shared/basalt/math.hpp new file mode 100644 index 0000000..f5463bf --- /dev/null +++ b/BasaltPresenter/Shared/basalt/math.hpp @@ -0,0 +1,34 @@ +#pragma once +#include + +namespace Basalt::Shared::Math { + + using FloatPoint = float; + + struct Vector3 { + FloatPoint x, y, z; + }; + struct Vector4 { + FloatPoint x, y, z, w; + }; + struct Matrix4x4 { + Vector4 data[4]; + }; + + //template + // requires(std::integral || std::floating_point) + //struct Vector { + // TEle factor[VCnt]; + //}; + +#define NOT_IMPLEMENTED throw std::logic_error("not implemented function"); + + template + struct Vector3Traits {}; + + template + struct Matrix4x4Traits {}; + +#undef NOT_IMPLEMENTED + +} // namespace Basalt::Shared::Math diff --git a/BasaltPresenter/Shared/pipe_operator.cpp b/BasaltPresenter/Shared/basalt/pipe_operator.cpp similarity index 100% rename from BasaltPresenter/Shared/pipe_operator.cpp rename to BasaltPresenter/Shared/basalt/pipe_operator.cpp diff --git a/BasaltPresenter/Shared/pipe_operator.hpp b/BasaltPresenter/Shared/basalt/pipe_operator.hpp similarity index 97% rename from BasaltPresenter/Shared/pipe_operator.hpp rename to BasaltPresenter/Shared/basalt/pipe_operator.hpp index f574c1d..f2b51e7 100644 --- a/BasaltPresenter/Shared/pipe_operator.hpp +++ b/BasaltPresenter/Shared/basalt/pipe_operator.hpp @@ -1,4 +1,4 @@ -#include "basalt_char.hpp" +#include "char_types.hpp" #include #if defined(BASALT_OS_WINDOWS) diff --git a/BasaltPresenter/Shared/deliver.cpp b/BasaltPresenter/Shared/deliver.cpp deleted file mode 100644 index 90cfa94..0000000 --- a/BasaltPresenter/Shared/deliver.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "deliver.hpp" - -namespace Basalt::Shared::Deliver { - - IDeliver::IDeliver() {} - - IDeliver::~IDeliver() {} - -} // namespace Basalt::Shared::Deliver diff --git a/BasaltPresenter/Shared/deliver.hpp b/BasaltPresenter/Shared/deliver.hpp deleted file mode 100644 index dea56e3..0000000 --- a/BasaltPresenter/Shared/deliver.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -namespace Basalt::Shared::Deliver { - - struct DeliverConfig { - - }; - - class IDeliver { - public: - IDeliver(); - virtual ~IDeliver(); - - public: - virtual void Transmit() = 0; - }; - -} diff --git a/BasaltPresenter/Shared/engine.cpp b/BasaltPresenter/Shared/engine.cpp deleted file mode 100644 index 3d318ee..0000000 --- a/BasaltPresenter/Shared/engine.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "engine.hpp" -#include - -namespace Basalt::Shared::Engine { - - IEngine::IEngine() : config(), status(EngineStatus::Ready) {} - - IEngine::~IEngine() { - if (this->status != EngineStatus::Stop) { - this->Shutdown(); - } - } - - void IEngine::Startup(EngineConfig &&config) { - if (this->status != EngineStatus::Ready) throw std::runtime_error("unexpected engine status"); - this->config = std::move(config); - this->status = EngineStatus::Running; - } - - bool IEngine::Tick() { - if (this->status != EngineStatus::Running) throw std::runtime_error("unexpected engine status"); - return false; - } - - void IEngine::Shutdown() { - if (this->status != EngineStatus::Running) throw std::runtime_error("unexpected engine status"); - this->status = EngineStatus::Stop; - } - -} // namespace Basalt::Shared::Engine diff --git a/BasaltPresenter/Shared/engine.hpp b/BasaltPresenter/Shared/engine.hpp deleted file mode 100644 index 724f657..0000000 --- a/BasaltPresenter/Shared/engine.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -#include "basalt_char.hpp" -#include -#include - -namespace Basalt::Shared::Engine { - - enum class EngineKind { - DirectX8, - DirectX9, - DirectX11, - DirectX12, - OpenGL, - Vulkan, - }; - - struct EngineConfig { - bool headless; ///< Whether enable headless mode (No Window created). - std::basic_string title; ///< Window title. - std::uint32_t width; ///< Window width. - std::uint32_t height; ///< Window height. - }; - - enum class EngineStatus { - Ready, ///< Engine was allocated but not initialized. - Running, ///< Engine has been initialized and running. - Stop, ///< Engine is shutdown. - }; - - class IEngine { - public: - IEngine(); - virtual ~IEngine(); - - public: - virtual void Startup(EngineConfig&& config); - /** - * @brief - * @return True for active exit. - */ - virtual bool Tick(); - virtual void Shutdown(); - - protected: - EngineConfig config; - EngineStatus status; - }; - -} diff --git a/BasaltTrainer/.gitignore b/BasaltTrainer/.gitignore index 505a3b1..89a24af 100644 --- a/BasaltTrainer/.gitignore +++ b/BasaltTrainer/.gitignore @@ -1,3 +1,6 @@ +# VSCode +.vscode/ + # Python-generated files __pycache__/ *.py[oc] diff --git a/BasaltTrainer/pipe_operator.py b/BasaltTrainer/pipe_operator.py new file mode 100644 index 0000000..11dfcd1 --- /dev/null +++ b/BasaltTrainer/pipe_operator.py @@ -0,0 +1,203 @@ +import os +import sys +from typing import Optional, Any + +IS_WINDOWS: bool = sys.platform == "win32" + +if IS_WINDOWS: + import win32pipe + import win32file + import pywintypes +else: + import errno + + +class PipeOperator: + """ + A Python implementation of the pipe operator similar to the C++ version. + Uses win32pipe on Windows and os.mkfifo on POSIX systems. + """ + + pipe_handle: Optional[int] + pipe_name: str + + def __init__(self, name: str): + """ + Initialize the PipeOperator. + + :param name: Name of the pipe + :param is_server: True if this instance should create the pipe (server), False if connecting to existing pipe (client) + """ + self.pipe_handle = None + + if IS_WINDOWS: + self.pipe_name = f"\\\\.\\pipe\\{name}" + self.pipe_handle = win32pipe.CreateNamedPipe( + self.pipe_name, + win32pipe.PIPE_ACCESS_DUPLEX, + win32pipe.PIPE_TYPE_BYTE | win32pipe.PIPE_READMODE_BYTE + | win32pipe.PIPE_WAIT, + 1, # Number of pipe instances + 65536, # Output buffer size + 65536, # Input buffer size + 0, # Default timeout + None # Security attributes + ) + if self.pipe_handle == win32file.INVALID_HANDLE_VALUE: + raise RuntimeError("Failed to create named pipe.") + + # Wait for client to connect + win32pipe.ConnectNamedPipe(self.pipe_handle, None) + else: + # POSIX implementation + self.pipe_name = f"/tmp/{name}" + try: + os.mkfifo(self.pipe_name) + except OSError as e: + if e.errno != errno.EEXIST: + raise RuntimeError(f"Failed to create named pipe: {e}") + + # Open the FIFO for reading and writing (blocks until client connects) + self.pipe_handle = os.open(self.pipe_name, os.O_RDWR) + + def __del__(self): + """Cleanup resources when object is destroyed.""" + self.close() + + def close(self): + """Close the pipe handle.""" + if self.pipe_handle is not None: + if IS_WINDOWS: + win32file.CloseHandle(self.pipe_handle) + else: + os.close(self.pipe_handle) + # Remove the FIFO file if it is existing + if os.path.exists(self.pipe_name): + os.unlink(self.pipe_name) + + self.pipe_handle = None + + def read(self, size: int) -> bytes: + """ + Read data from the pipe. This is a blocking operation. + + :param size: Number of bytes to read + :return: Bytes read from the pipe + """ + if size <= 0: + return b"" + + if self.pipe_handle is None: + raise RuntimeError("Pipe is not open") + + if IS_WINDOWS: + try: + # The result is a tuple of (hr, string/PyOVERLAPPEDReadBuffer). + # You can convert this to a string (str(object)) [py2k] or (bytes(object)) [py3k] to obtain the data. + # I can't visit PyOVERLAPPEDReadBuffer so I simply set it to Any + data: Any + (hr, data) = win32file.ReadFile(self.pipe_handle, size) + if hr != 0: # Error occurred + raise RuntimeError( + f"Failed to read from pipe, error code: {hr}") + data = bytes(data) + if len(data) != size: + raise RuntimeError( + f"Incomplete read from pipe: expected {size} bytes, got {len(data)} bytes" + ) + return data + except pywintypes.error as e: + raise RuntimeError(f"Failed to read from named pipe: {e}") + else: + # POSIX implementation + data = b"" + while len(data) < size: + try: + chunk = os.read(self.pipe_handle, size - len(data)) + if not chunk: + raise RuntimeError("Named pipe closed during read") + data += chunk + except OSError as e: + raise RuntimeError(f"Failed to read from named pipe: {e}") + + if len(data) != size: + raise RuntimeError( + f"Incomplete read from pipe: expected {size} bytes, got {len(data)} bytes" + ) + + return data + + def write(self, data: bytes) -> None: + """ + Write data to the pipe. This is a blocking operation. + + :param data: Data to write to the pipe + """ + if len(data) == 0: + return + + if self.pipe_handle is None: + raise RuntimeError("Pipe is not open") + + if IS_WINDOWS: + try: + win32file.WriteFile(self.pipe_handle, data) + except pywintypes.error as e: + raise RuntimeError(f"Failed to write to named pipe: {e}") + else: + # POSIX implementation + total_written = 0 + while total_written < len(data): + try: + bytes_written = os.write(self.pipe_handle, + data[total_written:]) + total_written += bytes_written + except OSError as e: + raise RuntimeError(f"Failed to write to named pipe: {e}") + + +# class PipeServer: +# """ +# A convenience class for creating a pipe server that can handle connections in a separate thread. +# """ + +# def __init__(self, name: str): +# self._name = name +# self._pipe_operator: Optional[PipeOperator] = None +# self._server_thread: Optional[threading.Thread] = None +# self._stop_event = threading.Event() + +# def start_server(self, handler_func): +# """ +# Start the pipe server in a separate thread. + +# :param handler_func: Function to handle the connected pipe (takes PipeOperator as parameter) +# """ +# self._server_thread = threading.Thread(target=self._server_worker, +# args=(handler_func, )) +# self._server_thread.start() + +# def _server_worker(self, handler_func): +# """Internal method to handle server operations.""" +# try: +# # Create pipe server +# pipe_op = PipeOperator(self._name, is_server=True) +# self._pipe_operator = pipe_op + +# # Call the handler function with the connected pipe +# handler_func(pipe_op) +# except Exception as e: +# print(f"Error in pipe server: {e}") +# finally: +# if self._pipe_operator: +# self._pipe_operator.close() + +# def stop_server(self): +# """Stop the pipe server.""" +# self._stop_event.set() +# if self._server_thread: +# self._server_thread.join() + +# def get_pipe(self) -> Optional[PipeOperator]: +# """Get the connected pipe operator (only valid after client connects).""" +# return self._pipe_operator diff --git a/BasaltTrainer/pyproject.toml b/BasaltTrainer/pyproject.toml index 6ccb679..254ed41 100644 --- a/BasaltTrainer/pyproject.toml +++ b/BasaltTrainer/pyproject.toml @@ -8,8 +8,9 @@ dependencies = [ "datasets>=4.3.0", "matplotlib>=3.10.7", "numpy>=2.3.4", - "torch>=2.9.0", - "torchvision>=0.24.0", + "pywin32>=311 ; sys_platform == 'win32'", + "torch>=2.9.0", + "torchvision>=0.24.0", ] [tool.uv.sources] diff --git a/BasaltTrainer/uv.lock b/BasaltTrainer/uv.lock index 1919b4e..9dba3ea 100644 --- a/BasaltTrainer/uv.lock +++ b/BasaltTrainer/uv.lock @@ -165,6 +165,7 @@ dependencies = [ { name = "datasets" }, { name = "matplotlib" }, { name = "numpy" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, { name = "torch", version = "2.9.0", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'linux' and sys_platform != 'win32'" }, { name = "torch", version = "2.9.0+cu126", source = { registry = "https://download.pytorch.org/whl/cu126" }, marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "torchvision", version = "0.24.0", source = { registry = "https://download.pytorch.org/whl/cu126" }, marker = "platform_machine == 'aarch64' and sys_platform == 'linux'" }, @@ -177,6 +178,7 @@ requires-dist = [ { name = "datasets", specifier = ">=4.3.0" }, { name = "matplotlib", specifier = ">=3.10.7" }, { name = "numpy", specifier = ">=2.3.4" }, + { name = "pywin32", marker = "sys_platform == 'win32'", specifier = ">=311" }, { name = "torch", marker = "sys_platform != 'linux' and sys_platform != 'win32'", specifier = ">=2.9.0" }, { name = "torch", marker = "sys_platform == 'linux' or sys_platform == 'win32'", specifier = ">=2.9.0", index = "https://download.pytorch.org/whl/cu126" }, { name = "torchvision", marker = "sys_platform != 'linux' and sys_platform != 'win32'", specifier = ">=0.24.0" }, @@ -1648,6 +1650,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, ] +[[package]] +name = "pywin32" +version = "311" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151", size = 8697031, upload-time = "2025-07-14T20:13:13.266Z" }, + { url = "https://files.pythonhosted.org/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503", size = 9508308, upload-time = "2025-07-14T20:13:15.147Z" }, + { url = "https://files.pythonhosted.org/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2", size = 8703930, upload-time = "2025-07-14T20:13:16.945Z" }, + { url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" }, + { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" }, + { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, + { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, + { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, + { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, + { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, +] + [[package]] name = "pyyaml" version = "6.0.3" diff --git a/Document/PROTOCOL.md b/Document/PROTOCOL.md index 86fa785..b427529 100644 --- a/Document/PROTOCOL.md +++ b/Document/PROTOCOL.md @@ -4,18 +4,27 @@ This document introduce the protocol used between Basalt Presenter and Basalt Tr ## Command Protocol +Before introducing command protocol, it would be better to the priniciple, +that Presenter is the slave application, and Trainer is the master application. + |Code|Direction|Comment| |:---|:---|:---| +|`0x61`|Presenter<--Trainer|Handshake code (Are Presenter ready?)| +|`0x62`|Presenter-->Trainer|Handshake code (Presenter is ready).| |`0x01`|Presenter-->Trainer|Data was ready. Please Trainer receive it.| |`0x02`|Presenter<--Trainer|Data has been received. Please go into next loop.| -|`0x61`|Presenter<--Trainer|Handshake code (Are Presenter ready?)| -|`0x62`|Presenter-->Trainer|Handshake code (Presenter is ready)| +|`0x71`|Presenter-->Trainer|Actively Stop (Presenter request stop).| +|`0x71`|Presenter<--Trainer|Stop (Trainer agree the stop request, or trainer actively stop).| ### Handshake -At the beginning of execution, Trainer send handshake code to Presenter first and then Presenter send another handshake code to Trainer back. After this, both 2 applications start running. +At the beginning of execution, +Trainer send handshake code to Presenter first and then Presenter send another handshake code to Trainer back. +After this, both 2 applications start running. -When Presenter send handshake code back, Presenter should attach some values following it to indicate some essential properties of data which will be passed to Trainer in future. There is a table introduce these properties: +When Presenter send handshake code back, +Presenter should attach some values following it to indicate some essential properties of data which will be passed to Trainer in future. +There is a table introduce these properties: |Data Type|Comment| |:---|:---|