// Copyright 2023 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source // License, and you may not use this file except in compliance with the Business Source License. // // As of the Change Date specified in that file, in accordance with // the Business Source License, use of this software will be governed // by the Apache License, Version 2.0, included in the file // licenses/APL.txt. #pragma once #include #include #include #include #include "communication/bolt/v1/codes.hpp" #include "communication/bolt/v1/encoder/base_encoder.hpp" namespace memgraph::communication::bolt { /** * Bolt Client Encoder. * Has public interfaces for writing Bolt specific request messages. * Supported messages are: Init, Run, DiscardAll, PullAll, AckFailure, Reset * * @tparam Buffer the output buffer that should be used */ template class ClientEncoder : private BaseEncoder { private: using BaseEncoder::WriteRAW; using BaseEncoder::WriteList; using BaseEncoder::WriteMap; using BaseEncoder::WriteString; using BaseEncoder::WriteNull; using BaseEncoder::buffer_; public: explicit ClientEncoder(Buffer &buffer) : BaseEncoder(buffer) {} using BaseEncoder::UpdateVersion; /** * Writes a Init message. * * From the Bolt v4.3 documentation: * HelloMess (signature=0x01) { * Map extra * } * * @param client_name the name of the connected client * @param auth_token a map with authentication data * @returns true if the data was successfully sent to the client * when flushing, false otherwise */ bool MessageInit(const std::map &extra) { WriteRAW(utils::UnderlyingCast(Marker::TinyStruct1)); WriteRAW(utils::UnderlyingCast(Signature::Init)); WriteMap(extra); // Try to flush all remaining data in the buffer, but tell it that we will // send more data (the end of message chunk). if (!buffer_.Flush(true)) return false; // Flush an empty chunk to indicate that the message is done. return buffer_.Flush(); } /** * Writes a Run message. * * From the Bolt v4.3 documentation: * RunMessage (signature=0x10) { * String statement * Map parameters * Map extra * } * * @param statement the statement that should be executed * @param parameters parameters that should be used to execute the statement * @returns true if the data was successfully sent to the client * when flushing, false otherwise */ bool MessageRun(const std::string &statement, const std::map ¶meters, const std::map &extra, bool have_more = true) { WriteRAW(utils::UnderlyingCast(Marker::TinyStruct3)); WriteRAW(utils::UnderlyingCast(Signature::Run)); WriteString(statement); WriteMap(parameters); WriteMap(extra); // Try to flush all remaining data in the buffer, but tell it that we will // send more data (the end of message chunk). if (!buffer_.Flush(true)) return false; // Flush an empty chunk to indicate that the message is done. Here we // forward the `have_more` flag to indicate if there is more data that will // be sent. return buffer_.Flush(have_more); } /** * Writes a Discard message. * * From the Bolt v4.3 documentation: * DiscardMessage (signature=0x2F) { * Map extra * } * * @returns true if the data was successfully sent to the client * when flushing, false otherwise */ bool MessageDiscard(const std::map &extra) { WriteRAW(utils::UnderlyingCast(Marker::TinyStruct1)); WriteRAW(utils::UnderlyingCast(Signature::Discard)); WriteMap(extra); // Try to flush all remaining data in the buffer, but tell it that we will // send more data (the end of message chunk). if (!buffer_.Flush(true)) return false; // Flush an empty chunk to indicate that the message is done. return buffer_.Flush(); } /** * Writes a PullAll message. * * From the Bolt v4.3 documentation: * PullMessage (signature=0x3F) { * Map extra * } * * @returns true if the data was successfully sent to the client * when flushing, false otherwise */ bool MessagePull(const std::map &extra) { WriteRAW(utils::UnderlyingCast(Marker::TinyStruct1)); WriteRAW(utils::UnderlyingCast(Signature::Pull)); WriteMap(extra); // Try to flush all remaining data in the buffer, but tell it that we will // send more data (the end of message chunk). if (!buffer_.Flush(true)) return false; // Flush an empty chunk to indicate that the message is done. return buffer_.Flush(); } /** * Writes a Reset message. * * From the Bolt v4.3 documentation: * ResetMessage (signature=0x0F) { * } * * @returns true if the data was successfully sent to the client * when flushing, false otherwise */ bool MessageReset() { WriteRAW(utils::UnderlyingCast(Marker::TinyStruct)); WriteRAW(utils::UnderlyingCast(Signature::Reset)); // Try to flush all remaining data in the buffer, but tell it that we will // send more data (the end of message chunk). if (!buffer_.Flush(true)) return false; // Flush an empty chunk to indicate that the message is done. return buffer_.Flush(); } /** * Writes a Route message. * * From the Bolt v4.3 documentation: * RouteMessage (signature=0x0F) { * Map routing * List bookmarks * String db * } * * @returns true if the data was successfully sent to the client * when flushing, false otherwise */ bool MessageRoute(const std::map &routing, const std::vector &bookmarks, const std::optional &db) { WriteRAW(utils::UnderlyingCast(Marker::TinyStruct3)); WriteRAW(utils::UnderlyingCast(Signature::Route)); WriteMap(routing); WriteList(bookmarks); if (db.has_value()) { WriteString(*db); } else { WriteNull(); } // Try to flush all remaining data in the buffer, but tell it that we will // send more data (the end of message chunk). if (!buffer_.Flush(true)) return false; // Flush an empty chunk to indicate that the message is done. return buffer_.Flush(); } }; } // namespace memgraph::communication::bolt