// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include #include ZEN_THIRD_PARTY_INCLUDES_START #include #if defined(ASIO_HAS_LOCAL_SOCKETS) # include #endif #if ZEN_USE_OPENSSL # include #endif ZEN_THIRD_PARTY_INCLUDES_END #include #include #include namespace zen { class HttpServer; } // namespace zen namespace zen::asio_http { /** * WebSocket connection over an ASIO stream socket * * Templated on SocketType to support both TCP and Unix domain sockets. * Owns the socket (moved from HttpServerConnection after the 101 handshake) * and runs an async read/write loop to exchange WebSocket frames. * * Lifetime is managed solely through intrusive reference counting (RefCounted). * The async read/write callbacks capture Ref<> to keep the connection alive * for the duration of the async operation. The service layer also holds a * Ref. */ template class WsAsioConnectionT : public WebSocketConnection { public: WsAsioConnectionT(std::unique_ptr Socket, IWebSocketHandler& Handler, HttpServer* Server); ~WsAsioConnectionT() override; /** * Start the async read loop. Must be called once after construction * and the 101 response has been sent. */ void Start(); // WebSocketConnection interface void SendText(std::string_view Text) override; void SendBinary(std::span Data) override; void Close(uint16_t Code, std::string_view Reason) override; bool IsOpen() const override; private: void EnqueueRead(); void OnDataReceived(const asio::error_code& Ec, std::size_t ByteCount); void ProcessReceivedData(); void EnqueueWrite(std::vector Frame); void FlushWriteQueue(); void OnWriteComplete(const asio::error_code& Ec, std::size_t ByteCount); void DoClose(uint16_t Code, std::string_view Reason); std::unique_ptr m_Socket; IWebSocketHandler& m_Handler; zen::HttpServer* m_HttpServer; asio::streambuf m_ReadBuffer; RwLock m_WriteLock; std::deque> m_WriteQueue; bool m_IsWriting = false; std::atomic m_IsOpen{true}; std::atomic m_CloseSent{false}; }; using WsAsioConnection = WsAsioConnectionT; #if defined(ASIO_HAS_LOCAL_SOCKETS) using WsAsioUnixConnection = WsAsioConnectionT; #endif #if ZEN_USE_OPENSSL using WsAsioSslConnection = WsAsioConnectionT>; #endif } // namespace zen::asio_http