/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once #include "cmConfigure.h" // IWYU pragma: keep #include "cmUVHandlePtr.h" #include "cm_uv.h" #include #include #include class cmServerBase; /*** * Given a sequence of bytes with any kind of buffering, instances of this * class arrange logical chunks according to whatever the use case is for * the connection. */ class cmConnectionBufferStrategy { public: virtual ~cmConnectionBufferStrategy(); /*** * Called whenever with an active raw buffer. If a logical chunk * becomes available, that chunk is returned and that portion is * removed from the rawBuffer * * @param rawBuffer in/out parameter. Receive buffer; the buffer strategy is * free to manipulate this buffer anyway it needs to. * * @return Next chunk from the stream. Returns the empty string if a chunk * isn't ready yet. Users of this interface should repeatedly call this * function until an empty string is returned since its entirely possible * multiple chunks come in a single raw buffer. */ virtual std::string BufferMessage(std::string& rawBuffer) = 0; /*** * Called to properly buffer an outgoing message. * * @param rawBuffer Message to format in the correct way * * @return Formatted message */ virtual std::string BufferOutMessage(const std::string& rawBuffer) const { return rawBuffer; }; /*** * Resets the internal state of the buffering */ virtual void clear(); // TODO: There should be a callback / flag set for errors }; class cmConnection { public: cmConnection() = default; cmConnection(cmConnection const&) = delete; cmConnection& operator=(cmConnection const&) = delete; virtual void WriteData(const std::string& data) = 0; virtual ~cmConnection(); virtual bool OnConnectionShuttingDown(); virtual bool IsOpen() const = 0; virtual void SetServer(cmServerBase* s); virtual void ProcessRequest(const std::string& request); virtual bool OnServeStart(std::string* pString); protected: cmServerBase* Server = nullptr; }; /*** * Abstraction of a connection; ties in event callbacks from libuv and notifies * the server when appropriate */ class cmEventBasedConnection : public cmConnection { public: /*** * @param bufferStrategy If no strategy is given, it will process the raw * chunks as they come in. The connection * owns the pointer given. */ cmEventBasedConnection(cmConnectionBufferStrategy* bufferStrategy = nullptr); virtual void Connect(uv_stream_t* server); virtual void ReadData(const std::string& data); bool IsOpen() const override; void WriteData(const std::string& data) override; bool OnConnectionShuttingDown() override; virtual void OnDisconnect(int errorCode); static void on_close(uv_handle_t* handle); template static void on_close_delete(uv_handle_t* handle) { delete reinterpret_cast(handle); } protected: cm::uv_stream_ptr WriteStream; std::string RawReadBuffer; std::unique_ptr BufferStrategy; static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); static void on_write(uv_write_t* req, int status); static void on_new_connection(uv_stream_t* stream, int status); static void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf); };