mirror of
				https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka.git
				synced 2025-10-31 02:27:46 +00:00 
			
		
		
		
	Allow using generic message builders not tied to Buffer class
This commit is contained in:
		| @@ -25,14 +25,9 @@ else() | ||||
|     add_definitions("-DCPPKAFKA_STATIC=1") | ||||
| endif() | ||||
|  | ||||
| include_directories(${CMAKE_SOURCE_DIR}/include/cppkafka) | ||||
|  | ||||
| # Look for Boost (just need boost.optional headers here) | ||||
| find_package(Boost REQUIRED) | ||||
| include_directories(${Boost_INCLUDE_DIRS}) | ||||
|  | ||||
| find_package(RdKafka REQUIRED) | ||||
| include_directories(${RDKAFKA_INCLUDE_DIR}) | ||||
|  | ||||
| if (HAVE_OFFSETS_FOR_TIMES) | ||||
|     message(STATUS "Enabling support for KafkaHandleBase::get_offsets_for_times") | ||||
|   | ||||
| @@ -4,6 +4,7 @@ if (Boost_PROGRAM_OPTIONS_FOUND) | ||||
|     link_libraries(${Boost_LIBRARIES} cppkafka ${RDKAFKA_LIBRARY}) | ||||
|  | ||||
|     include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) | ||||
|     include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${RDKAFKA_INCLUDE_DIR}) | ||||
|  | ||||
|     add_executable(kafka_producer EXCLUDE_FROM_ALL kafka_producer.cpp) | ||||
|     add_executable(kafka_consumer EXCLUDE_FROM_ALL kafka_consumer.cpp) | ||||
|   | ||||
| @@ -38,6 +38,166 @@ | ||||
|  | ||||
| namespace cppkafka { | ||||
|  | ||||
| /** | ||||
|  * \brief Base template class for message construction | ||||
|  */ | ||||
| template <typename BufferType, typename Concrete> | ||||
| class CPPKAFKA_API BasicMessageBuilder { | ||||
| public: | ||||
|     /** | ||||
|      * Construct a BasicMessageBuilder | ||||
|      * | ||||
|      * \param topic The topic into which this message would be produced | ||||
|      */ | ||||
|     BasicMessageBuilder(const Topic& topic); | ||||
|  | ||||
|     /** | ||||
|      * Sets the partition into which this message will be produced | ||||
|      * | ||||
|      * \param value The partition to be used   | ||||
|      */ | ||||
|     Concrete& partition(Partition value); | ||||
|  | ||||
|     /** | ||||
|      * Sets the message's key | ||||
|      * | ||||
|      * \param value The key to be used | ||||
|      */ | ||||
|     Concrete& key(const BufferType& value); | ||||
|  | ||||
|     /** | ||||
|      * Sets the message's key | ||||
|      * | ||||
|      * \param value The key to be used | ||||
|      */ | ||||
|     Concrete& key(BufferType&& value); | ||||
|  | ||||
|     /** | ||||
|      * Sets the message's payload | ||||
|      * | ||||
|      * \param value The payload to be used | ||||
|      */ | ||||
|     Concrete& payload(const BufferType& value); | ||||
|  | ||||
|     /** | ||||
|      * Sets the message's payload | ||||
|      * | ||||
|      * \param value The payload to be used | ||||
|      */ | ||||
|     Concrete& payload(BufferType&& value); | ||||
|  | ||||
|     /** | ||||
|      * Sets the message's user data pointer | ||||
|      * | ||||
|      * \param value Pointer to the user data to be used on the produce call | ||||
|      */ | ||||
|     Concrete& user_data(void* value); | ||||
|  | ||||
|     /** | ||||
|      * Gets the topic this message will be produced into | ||||
|      */ | ||||
|     const Topic& topic() const; | ||||
|  | ||||
|     /** | ||||
|      * Gets the partition this message will be produced into | ||||
|      */ | ||||
|     const Partition& partition() const; | ||||
|  | ||||
|     /** | ||||
|      * Gets the message's key | ||||
|      */ | ||||
|     const BufferType& key() const; | ||||
|  | ||||
|     /** | ||||
|      * Gets the message's payload | ||||
|      */ | ||||
|     const BufferType& payload() const; | ||||
|  | ||||
|     /** | ||||
|      * Gets the message's user data pointer | ||||
|      */ | ||||
|     void* user_data() const; | ||||
| private: | ||||
|     void construct_buffer(BufferType& lhs, const BufferType& rhs); | ||||
|  | ||||
|     const Topic& topic_; | ||||
|     Partition partition_; | ||||
|     BufferType key_; | ||||
|     BufferType payload_; | ||||
|     void* user_data_; | ||||
| }; | ||||
|  | ||||
| template <typename T, typename C> | ||||
| BasicMessageBuilder<T, C>::BasicMessageBuilder(const Topic& topic) | ||||
| : topic_(topic) { | ||||
| } | ||||
|  | ||||
| template <typename T, typename C> | ||||
| C& BasicMessageBuilder<T, C>::partition(Partition value) { | ||||
|     partition_ = value; | ||||
|     return static_cast<C&>(*this); | ||||
| } | ||||
|  | ||||
| template <typename T, typename C> | ||||
| C& BasicMessageBuilder<T, C>::key(const T& value) { | ||||
|     static_cast<C&>(*this).construct_buffer(key_, value); | ||||
|     return static_cast<C&>(*this); | ||||
| } | ||||
|  | ||||
| template <typename T, typename C> | ||||
| C& BasicMessageBuilder<T, C>::key(T&& value) { | ||||
|     key_ = std::move(value); | ||||
|     return static_cast<C&>(*this); | ||||
| } | ||||
|  | ||||
| template <typename T, typename C> | ||||
| C& BasicMessageBuilder<T, C>::payload(const T& value) { | ||||
|     static_cast<C&>(*this).construct_buffer(payload_, value); | ||||
|     return static_cast<C&>(*this); | ||||
| } | ||||
|  | ||||
| template <typename T, typename C> | ||||
| C& BasicMessageBuilder<T, C>::payload(T&& value) { | ||||
|     payload_ = std::move(value); | ||||
|     return static_cast<C&>(*this); | ||||
| } | ||||
|  | ||||
| template <typename T, typename C> | ||||
| C& BasicMessageBuilder<T, C>::user_data(void* value) { | ||||
|     user_data_ = value; | ||||
|     return static_cast<C&>(*this); | ||||
| } | ||||
|  | ||||
| template <typename T, typename C> | ||||
| const Topic& BasicMessageBuilder<T, C>::topic() const { | ||||
|     return topic_; | ||||
| } | ||||
|  | ||||
| template <typename T, typename C> | ||||
| const Partition& BasicMessageBuilder<T, C>::partition() const { | ||||
|     return partition_; | ||||
| } | ||||
|  | ||||
| template <typename T, typename C> | ||||
| const T& BasicMessageBuilder<T, C>::key() const { | ||||
|     return key_; | ||||
| } | ||||
|  | ||||
| template <typename T, typename C> | ||||
| const T& BasicMessageBuilder<T, C>::payload() const { | ||||
|     return payload_; | ||||
| } | ||||
|  | ||||
| template <typename T, typename C> | ||||
| void* BasicMessageBuilder<T, C>::user_data() const { | ||||
|     return user_data_; | ||||
| } | ||||
|  | ||||
| template <typename T, typename C> | ||||
| void BasicMessageBuilder<T, C>::construct_buffer(T& lhs, const T& rhs) { | ||||
|     lhs = rhs; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \brief Message builder class | ||||
|  *  | ||||
| @@ -56,73 +216,22 @@ namespace cppkafka { | ||||
|  * producer.produce(MessageBuilder(topic).partition(5).payload(payload)); | ||||
|  * \endcode | ||||
|  */ | ||||
| class CPPKAFKA_API MessageBuilder { | ||||
| class MessageBuilder : public BasicMessageBuilder<Buffer, MessageBuilder> { | ||||
| public: | ||||
|     /** | ||||
|      * Construct a MessageBuilder | ||||
|      * | ||||
|      * \param topic The topic into which this message would be produced | ||||
|      */ | ||||
|     MessageBuilder(const Topic& topic); | ||||
|     using BasicMessageBuilder::BasicMessageBuilder; | ||||
|  | ||||
|     /** | ||||
|      * Sets the partition into which this message will be produced | ||||
|      * | ||||
|      * \param value The partition to be used   | ||||
|      */ | ||||
|     MessageBuilder& partition(Partition value); | ||||
|     void construct_buffer(Buffer& lhs, const Buffer& rhs) { | ||||
|         lhs = Buffer(rhs.get_data(), rhs.get_size()); | ||||
|     } | ||||
| }; | ||||
|  | ||||
|     /** | ||||
|      * Sets the message's key | ||||
|      * | ||||
|      * \param value The key to be used | ||||
|      */ | ||||
|     MessageBuilder& key(const Buffer& value); | ||||
|  | ||||
|     /** | ||||
|      * Sets the message's payload | ||||
|      * | ||||
|      * \param value The payload to be used | ||||
|      */ | ||||
|     MessageBuilder& payload(const Buffer& value); | ||||
|  | ||||
|     /** | ||||
|      * Sets the message's user data pointer | ||||
|      * | ||||
|      * \param value Pointer to the user data to be used on the produce call | ||||
|      */ | ||||
|     MessageBuilder& user_data(void* value); | ||||
|  | ||||
|     /** | ||||
|      * Gets the topic this message will be produced into | ||||
|      */ | ||||
|     const Topic& topic() const; | ||||
|  | ||||
|     /** | ||||
|      * Gets the partition this message will be produced into | ||||
|      */ | ||||
|     const Partition& partition() const; | ||||
|  | ||||
|     /** | ||||
|      * Gets the message's key | ||||
|      */ | ||||
|     const Buffer& key() const; | ||||
|  | ||||
|     /** | ||||
|      * Gets the message's payload | ||||
|      */ | ||||
|     const Buffer& payload() const; | ||||
|  | ||||
|     /** | ||||
|      * Gets the message's user data pointer | ||||
|      */ | ||||
|     void* user_data() const; | ||||
| private: | ||||
|     const Topic& topic_; | ||||
|     Partition partition_; | ||||
|     Buffer key_; | ||||
|     Buffer payload_; | ||||
|     void* user_data_; | ||||
| /** | ||||
|  * \brief Message builder class for a specific data type | ||||
|  */ | ||||
| template <typename T> | ||||
| class ConcreteMessageBuilder : public BasicMessageBuilder<T, ConcreteMessageBuilder<T>> { | ||||
| public: | ||||
|     using BasicMessageBuilder<T, ConcreteMessageBuilder<T>>::BasicMessageBuilder; | ||||
| }; | ||||
|  | ||||
| } // cppkafka | ||||
|   | ||||
| @@ -17,6 +17,11 @@ namespace cppkafka { | ||||
| template <typename BufferType> | ||||
| class BufferedProducer { | ||||
| public: | ||||
|     /** | ||||
|      * Concrete builder | ||||
|      */ | ||||
|     using Builder = ConcreteMessageBuilder<BufferType>; | ||||
|  | ||||
|     /** | ||||
|      * \brief Constructs a buffered producer using the provided configuration | ||||
|      * | ||||
| @@ -54,12 +59,12 @@ private: | ||||
|     using IndexType = std::conditional<sizeof(void*) == 8, uint64_t, uint32_t>::type; | ||||
|  | ||||
|     const Topic& get_topic(const std::string& topic); | ||||
|     void produce_message(IndexType index, MessageBuilder& message); | ||||
|     void produce_message(IndexType index, Builder& message); | ||||
|     Configuration prepare_configuration(Configuration config); | ||||
|     void on_delivery_report(const Message& message); | ||||
|  | ||||
|     Producer producer_; | ||||
|     std::map<IndexType, MessageBuilder> messages_; | ||||
|     std::map<IndexType, Builder> messages_; | ||||
|     std::vector<IndexType> failed_indexes_; | ||||
|     IndexType current_index_{0}; | ||||
|     std::vector<Topic> topics_; | ||||
| @@ -74,7 +79,7 @@ BufferedProducer<BufferType>::BufferedProducer(Configuration config) | ||||
|  | ||||
| template <typename BufferType> | ||||
| void BufferedProducer<BufferType>::add_message(const MessageBuilder& builder) { | ||||
|     MessageBuilder local_builder(get_topic(builder.topic().get_name())); | ||||
|     Builder local_builder(get_topic(builder.topic().get_name())); | ||||
|     local_builder.partition(builder.partition()); | ||||
|     local_builder.key(builder.key()); | ||||
|     local_builder.payload(builder.payload()); | ||||
| @@ -122,13 +127,16 @@ const Topic& BufferedProducer<BufferType>::get_topic(const std::string& topic) { | ||||
| } | ||||
|  | ||||
| template <typename BufferType> | ||||
| void BufferedProducer<BufferType>::produce_message(IndexType index, | ||||
|                                                    MessageBuilder& builder) { | ||||
| void BufferedProducer<BufferType>::produce_message(IndexType index, Builder& builder) { | ||||
|     bool sent = false; | ||||
|     builder.user_data(reinterpret_cast<void*>(index)); | ||||
|     MessageBuilder local_builder(builder.topic()); | ||||
|     local_builder.partition(builder.partition()) | ||||
|                  .key(builder.key()) | ||||
|                  .payload(builder.payload()) | ||||
|                  .user_data(reinterpret_cast<void*>(index)); | ||||
|     while (!sent) { | ||||
|         try { | ||||
|             producer_.produce(builder); | ||||
|             producer_.produce(local_builder); | ||||
|             sent = true; | ||||
|         } | ||||
|         catch (const HandleException& ex) { | ||||
|   | ||||
| @@ -11,13 +11,15 @@ set(SOURCES | ||||
|     topic_partition_list.cpp | ||||
|     metadata.cpp | ||||
|     error.cpp | ||||
|     message_builder.cpp | ||||
|  | ||||
|     kafka_handle_base.cpp | ||||
|     producer.cpp | ||||
|     consumer.cpp | ||||
| ) | ||||
|  | ||||
| include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include/cppkafka) | ||||
| include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${RDKAFKA_INCLUDE_DIR}) | ||||
|  | ||||
| add_library(cppkafka ${CPPKAFKA_LIBRARY_TYPE} ${SOURCES}) | ||||
| set_target_properties(cppkafka PROPERTIES VERSION ${CPPKAFKA_VERSION} | ||||
|                                           SOVERSION ${CPPKAFKA_VERSION}) | ||||
|   | ||||
| @@ -1,50 +0,0 @@ | ||||
| #include "message_builder.h" | ||||
| #include <boost/utility/typed_in_place_factory.hpp> | ||||
|  | ||||
| namespace cppkafka { | ||||
|  | ||||
| MessageBuilder::MessageBuilder(const Topic& topic) | ||||
| : topic_(topic) { | ||||
| } | ||||
|  | ||||
| MessageBuilder& MessageBuilder::partition(Partition value) { | ||||
|     partition_ = value; | ||||
|     return *this; | ||||
| } | ||||
|  | ||||
| MessageBuilder& MessageBuilder::key(const Buffer& value) { | ||||
|     key_ = Buffer(value.get_data(), value.get_size()); | ||||
|     return *this; | ||||
| } | ||||
|  | ||||
| MessageBuilder& MessageBuilder::payload(const Buffer& value) { | ||||
|     payload_ = Buffer(value.get_data(), value.get_size()); | ||||
|     return *this; | ||||
| } | ||||
|  | ||||
| MessageBuilder& MessageBuilder::user_data(void* value) { | ||||
|     user_data_ = value; | ||||
|     return *this; | ||||
| } | ||||
|  | ||||
| const Topic& MessageBuilder::topic() const { | ||||
|     return topic_; | ||||
| } | ||||
|  | ||||
| const Partition& MessageBuilder::partition() const { | ||||
|     return partition_; | ||||
| } | ||||
|  | ||||
| const Buffer& MessageBuilder::key() const { | ||||
|     return key_; | ||||
| } | ||||
|  | ||||
| const Buffer& MessageBuilder::payload() const { | ||||
|     return payload_; | ||||
| } | ||||
|  | ||||
| void* MessageBuilder::user_data() const { | ||||
|     return user_data_; | ||||
| } | ||||
|  | ||||
| } // cppkafka | ||||
| @@ -1,5 +1,6 @@ | ||||
| include_directories(${GOOGLETEST_INCLUDE}) | ||||
| include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include/) | ||||
| include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${RDKAFKA_INCLUDE_DIR}) | ||||
|  | ||||
| link_directories(${GOOGLETEST_LIBRARY}) | ||||
| link_libraries(cppkafka ${RDKAFKA_LIBRARY} gtest gtest_main pthread) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Matias Fontanini
					Matias Fontanini