#pragma once #include #include #include #include #include #include #include namespace base::http { // TODO: maybe pimpl? struct WebSocketClient : public std::enable_shared_from_this { using RawStream = GenericStream; using StreamType = beast::websocket::stream; using EndpointType = typename GenericProtocol::endpoint; using Ptr = std::shared_ptr; using MessagePtr = std::shared_ptr; using ConstMessagePtr = std::shared_ptr; using MessageHandler = std::function(Ptr, ConstMessagePtr)>; using CloseHandler = std::function(Ptr)>; // TODO: close reason? struct Listener { virtual ~Listener() = default; virtual Awaitable OnClose() = 0; // TODO: close reason virtual Awaitable OnMessage(ConstMessagePtr message) = 0; // TODO: control frames }; WebSocketClient(RawStream&& stream, Request& req) : stream(std::move(stream)), sendCondition(stream.get_executor()), upgrade(req) {} //~WebSocketClient() { // logger.Info("~WebSocketClient"); //} void SetListener(Listener* listener) { this->listener = listener; } void Send(ConstMessagePtr message); Awaitable Handshake(); Awaitable Close(); Awaitable CloseWithReason(const std::string& reason); asio::ip::address Address(); Request& GetUpgradeRequest() { return upgrade; } private: StreamType stream; std::vector sendQueue; Listener* listener{nullptr}; AsyncConditionVariable sendCondition; bool sending { false }; bool closed = false; bool forceClosed { false }; Request upgrade; Logger logger { MakeChannelId(MessageSource::Http, MessageComponentSource::Http_WebSocketClient) }; constexpr static u32 MAX_MESSAGES_IN_QUEUE = 256; Awaitable WriteEnd(); Awaitable ReadEnd(); }; } // namespace base::http