#pragma once #include #include #include class PipeClient { public: // Retries every 100 ms, up to 50 attempts (~5 s total). Returns true iff pipe is open. // Phase 16 VRCH-01 fix: default pipe is \\.\pipe\beyond_backglow_daemon, the // dedicated daemon pipe (inbound, multi-message, no response). The Phase 14 // CLI pipe \\.\pipe\beyond_proximity_ctl does FlushFileBuffers + DisconnectNamedPipe // on every message — fatal for the daemon's fire-and-forget 90 Hz stream. bool Connect(const char* pipeName = "\\\\.\\pipe\\beyond_backglow_daemon"); // Fire-and-forget message-mode write; 100 ms overlapped timeout; on failure closes handle. bool SendCommand(const char* line); bool IsConnected() const { return m_hPipe != INVALID_HANDLE_VALUE; } void Close(); ~PipeClient(); private: HANDLE m_hPipe{INVALID_HANDLE_VALUE}; // IN-05 (re-review): reuse a single manual-reset Event across all // overlapped writes rather than CreateEventW/CloseHandle on every // SendCommand. At 90 Hz the per-tick alloc pair was ~180 syscalls/s of // pure waste. Also eliminates the small race window between CancelIo and // CloseHandle(ov.hEvent) on the write-timeout path. Owned by Connect() / // Close(). HANDLE m_hEvent{NULL}; };