### Install SimpleAmqpClient Library and Headers Source: https://github.com/alanxz/simpleamqpclient/blob/master/CMakeLists.txt This CMake code installs the SimpleAmqpClient library and its header files to the appropriate system directories. It handles runtime, archive, and library destinations for the target, and installs header files into the include directory. Dependencies include the SimpleAmqpClient target and standard CMake installation directories. ```cmake include(GNUInstallDirs) install(TARGETS SimpleAmqpClient RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) install(FILES src/SimpleAmqpClient/AmqpException.h src/SimpleAmqpClient/AmqpLibraryException.h src/SimpleAmqpClient/AmqpResponseLibraryException.h src/SimpleAmqpClient/BadUriException.h src/SimpleAmqpClient/BasicMessage.h src/SimpleAmqpClient/Channel.h src/SimpleAmqpClient/ConnectionClosedException.h src/SimpleAmqpClient/ConsumerCancelledException.h src/SimpleAmqpClient/ConsumerTagNotFoundException.h src/SimpleAmqpClient/Envelope.h src/SimpleAmqpClient/MessageReturnedException.h src/SimpleAmqpClient/MessageRejectedException.h src/SimpleAmqpClient/SimpleAmqpClient.h src/SimpleAmqpClient/Table.h src/SimpleAmqpClient/Util.h src/SimpleAmqpClient/Version.h DESTINATION include/SimpleAmqpClient ) ``` -------------------------------- ### Configure Package Information (pkg-config) Source: https://github.com/alanxz/simpleamqpclient/blob/master/CMakeLists.txt This CMake snippet configures the `libSimpleAmqpClient.pc` file, which is used by pkg-config to provide library information to other projects. It sets up installation paths for the pkg-config file. Dependencies include CMake's installation directory variables and the `libSimpleAmqpClient.pc.in` template. ```cmake configure_file(libSimpleAmqpClient.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libSimpleAmqpClient.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libSimpleAmqpClient.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) ``` -------------------------------- ### Exception Handling and Recovery Example Source: https://context7.com/alanxz/simpleamqpclient/llms.txt This C++ code demonstrates how to use SimpleAmqpClient and handle various exceptions, including soft errors like `PreconditionFailedException` and hard errors like `ConnectionForcedException`. It also shows a basic reconnection pattern. ```APIDOC ## Exception Handling and Recovery Example ### Description This example demonstrates how to connect to an AMQP server using SimpleAmqpClient and handle various exceptions that may occur during channel operations and connection establishment. It differentiates between soft errors (where the channel remains usable) and hard errors (which require reconnection). ### Method N/A (Illustrative C++ code) ### Endpoint N/A ### Parameters N/A ### Request Example N/A ### Response N/A ### Error Handling Details - **Soft Errors (Channel Exceptions):** `PreconditionFailedException`, `NotFoundException`, `AccessRefusedException`, `ChannelException`. These errors do not necessarily invalidate the channel, allowing for continued operations after handling. - **Hard Errors (Connection Exceptions):** `ConnectionForcedException`, `ConnectionException`. These errors indicate a fatal connection issue, requiring the channel to be reset and a reconnection attempt. - **Message Returned Exception:** `MessageReturnedException` is specific to messages that could not be routed when the `mandatory` flag was set. - **Reconnection Pattern:** A `while` loop with a `try-catch` block is shown to attempt reconnection after a specified delay if the initial connection fails. ### Code Example ```cpp #include #include #include // For sleep AmqpClient::Channel::ptr_t channel; try { AmqpClient::Channel::OpenOpts opts; opts.host = "localhost"; opts.port = 5672; opts.auth = AmqpClient::Channel::OpenOpts::BasicAuth("guest", "guest"); channel = AmqpClient::Channel::Open(opts); // Example: Try to declare a queue that might conflict channel->DeclareQueue("existing_queue", false, true, false, false); } catch (const AmqpClient::PreconditionFailedException& e) { // Soft error - queue exists with different parameters std::cerr << "Queue declaration failed: " << e.reply_text() << std::endl; std::cerr << "Reply code: " << e.reply_code() << std::endl; // Channel is still usable } catch (const AmqpClient::NotFoundException& e) { // Soft error - entity not found std::cerr << "Not found: " << e.reply_text() << std::endl; } catch (const AmqpClient::AccessRefusedException& e) { // Soft error - permission denied std::cerr << "Access refused: " << e.reply_text() << std::endl; } catch (const AmqpClient::ChannelException& e) { // General soft error std::cerr << "Channel error (recoverable): " << e.what() << std::endl; if (e.is_soft_error()) { // Continue using channel } } catch (const AmqpClient::ConnectionForcedException& e) { // Hard error - connection closed by operator std::cerr << "Connection forced closed: " << e.reply_text() << std::endl; channel.reset(); // Channel no longer usable } catch (const AmqpClient::ConnectionException& e) { // General hard error - must reconnect std::cerr << "Connection error (fatal): " << e.what() << std::endl; channel.reset(); } catch (const AmqpClient::MessageReturnedException& e) { // Message couldn't be routed (mandatory flag was set) std::cerr << "Message returned: " << e.reply_text() << std::endl; std::cerr << "Exchange: " << e.exchange() << std::endl; std::cerr << "Routing key: " << e.routing_key() << std::endl; // Handle message return (e.g., retry, log, save) } // Reconnection pattern example bool connected = false; AmqpClient::Channel::OpenOpts opts; opts.host = "localhost"; opts.port = 5672; opts.auth = AmqpClient::Channel::OpenOpts::BasicAuth("guest", "guest"); while (!connected) { try { channel = AmqpClient::Channel::Open(opts); connected = true; std::cout << "Successfully reconnected." << std::endl; } catch (const AmqpClient::AmqpException& e) { std::cerr << "Reconnection failed: " << e.what() << std::endl; sleep(5); // Wait 5 seconds before retrying } } ``` ``` -------------------------------- ### Install Boost Dependencies via NuGet Source: https://github.com/alanxz/simpleamqpclient/blob/master/README.md Commands to install required Boost libraries on Windows using the NuGet package manager. ```bash nuget install boost_chrono-vc142 -Version 1.77.0 nuget install boost_system-vc142 -Version 1.77.0 nuget install boost -Version 1.77.0 ``` -------------------------------- ### Synchronously Retrieve Messages with BasicGet Source: https://context7.com/alanxz/simpleamqpclient/llms.txt Shows how to perform synchronous, one-off message retrieval from a queue. This includes examples of auto-acknowledgment, manual acknowledgment with error handling, and polling a queue until it is empty. ```cpp #include AmqpClient::Channel::ptr_t channel = AmqpClient::Channel::Open(opts); channel->DeclareQueue("work_queue", false, true, false, false); // Get a message with auto-ack (no need to acknowledge) AmqpClient::Envelope::ptr_t envelope; bool got_message = channel->BasicGet(envelope, "work_queue", true); // no_ack = true if (got_message) { std::cout << "Message: " << envelope->Message()->Body() << std::endl; std::cout << "Delivery tag: " << envelope->DeliveryTag() << std::endl; } else { std::cout << "Queue is empty" << std::endl; } // Get message with manual acknowledgment AmqpClient::Envelope::ptr_t envelope2; if (channel->BasicGet(envelope2, "work_queue", false)) { // no_ack = false try { // Process message... std::cout << "Processing: " << envelope2->Message()->Body() << std::endl; // Acknowledge on success channel->BasicAck(envelope2); } catch (const std::exception& e) { // Reject and requeue on failure channel->BasicReject(envelope2, true, false); // requeue=true, multiple=false } } // Poll queue until empty while (channel->BasicGet(envelope, "work_queue", false)) { std::cout << "Got: " << envelope->Message()->Body() << std::endl; channel->BasicAck(envelope); } ``` -------------------------------- ### Initialize AMQP Channel Connection Source: https://github.com/alanxz/simpleamqpclient/blob/master/README.md Demonstrates how to include the library headers and establish a connection to an AMQP broker using the AmqpClient::Channel class. ```cpp #include AmqpClient::Channel::ptr_t connection = AmqpClient::Channel::Create("localhost"); ``` -------------------------------- ### Establish AMQP Broker Connection with Channel::Open Source: https://context7.com/alanxz/simpleamqpclient/llms.txt Demonstrates how to initialize a connection to an AMQP broker using OpenOpts. It covers basic authentication, URI-based connection strings, and secure TLS/SSL configurations. ```cpp #include // Basic connection with username/password AmqpClient::Channel::OpenOpts opts; opts.host = "localhost"; opts.port = 5672; opts.vhost = "/"; opts.auth = AmqpClient::Channel::OpenOpts::BasicAuth("guest", "guest"); opts.frame_max = 131072; AmqpClient::Channel::ptr_t channel = AmqpClient::Channel::Open(opts); // Create connection from URI AmqpClient::Channel::OpenOpts uri_opts = AmqpClient::Channel::OpenOpts::FromUri("amqp://guest:guest@localhost:5672/"); AmqpClient::Channel::ptr_t channel2 = AmqpClient::Channel::Open(uri_opts); // TLS/SSL connection AmqpClient::Channel::OpenOpts secure_opts; secure_opts.host = "secure.rabbitmq.example.com"; secure_opts.port = 5671; secure_opts.vhost = "/"; secure_opts.auth = AmqpClient::Channel::OpenOpts::BasicAuth("user", "password"); AmqpClient::Channel::OpenOpts::TLSParams tls; tls.client_key_path = "/path/to/client.key"; tls.client_cert_path = "/path/to/client.crt"; tls.ca_cert_path = "/path/to/ca.crt"; tls.verify_hostname = true; tls.verify_peer = true; secure_opts.tls_params = tls; AmqpClient::Channel::ptr_t secure_channel = AmqpClient::Channel::Open(secure_opts); ``` -------------------------------- ### Build SimpleAmqpClient with CMake Source: https://github.com/alanxz/simpleamqpclient/blob/master/README.md Standard procedure to configure and build the SimpleAmqpClient library using CMake in a dedicated build directory. ```bash mkdir simpleamqpclient-build cd simpleamqpclient-build cmake .. ``` -------------------------------- ### Create AMQP Messages with Properties using C++ Source: https://context7.com/alanxz/simpleamqpclient/llms.txt Demonstrates creating AMQP messages using `BasicMessage::Create`. Covers setting content type, encoding, delivery mode (persistent), priority, message ID, timestamp, app ID, correlation ID, reply-to, expiration, and custom headers. ```cpp #include #include #include // Create a simple message AmqpClient::BasicMessage::ptr_t message = AmqpClient::BasicMessage::Create("Hello, World!"); // Create a message with properties AmqpClient::BasicMessage::ptr_t json_message = AmqpClient::BasicMessage::Create( R"({\"user_id\": 123, \"action\": \"purchase\", \"amount\": 99.99})"); json_message->ContentType("application/json"); json_message->ContentEncoding("utf-8"); json_message->DeliveryMode(AmqpClient::BasicMessage::dm_persistent); // Survive broker restart json_message->Priority(5); json_message->MessageId("msg-001"); json_message->Timestamp(std::time(nullptr)); json_message->AppId("my-app"); // Create RPC-style message with correlation ID and reply-to AmqpClient::BasicMessage::ptr_t rpc_request = AmqpClient::BasicMessage::Create("get_user_data"); rpc_request->CorrelationId("request-12345"); rpc_request->ReplyTo("amq.rabbitmq.reply-to"); rpc_request->Expiration("60000"); // Message expires after 60 seconds // Add custom headers AmqpClient::Table headers; headers["x-custom-header"] = AmqpClient::TableValue("custom-value"); headers["x-request-id"] = AmqpClient::TableValue("req-xyz-789"); headers["x-priority-level"] = AmqpClient::TableValue(static_cast(1)); rpc_request->HeaderTable(headers); // Reading message properties std::cout << "Body: " << json_message->Body() << std::endl; std::cout << "Content-Type: " << json_message->ContentType() << std::endl; if (json_message->TimestampIsSet()) { std::cout << "Timestamp: " << json_message->Timestamp() << std::endl; } ``` -------------------------------- ### Consume Messages from a Queue Source: https://github.com/alanxz/simpleamqpclient/blob/master/README.md Shows how to set up a consumer, retrieve messages with optional timeouts, acknowledge receipt, and cancel the consumer. ```cpp std::string consumer_tag = channel->BasicConsume("my_queue", ""); Envelope::ptr_t envelope = channel->BasicConsumeMessage(consumer_tag); // Alternatively with timeout: Envelope::ptr_t envelope; channel->BasicConsumeMessage(consumer_tag, envelope, 10); // To ack: channel->BasicAck(envelope); // To cancel: channel->BasicCancel(consumer_tag); ``` -------------------------------- ### Consume Messages with SimpleAmqpClient Source: https://context7.com/alanxz/simpleamqpclient/llms.txt Demonstrates how to register a consumer on a queue, handle incoming messages with blocking or timeout-based retrieval, and manage multiple consumers. It also covers manual acknowledgment and consumer cancellation. ```cpp #include AmqpClient::Channel::ptr_t channel = AmqpClient::Channel::Open(opts); // Setup queue channel->DeclareQueue("task_queue", false, true, false, false); // Start consuming (no_ack=false means we must acknowledge messages) std::string consumer_tag = channel->BasicConsume( "task_queue", // queue name "", // consumer_tag (empty = broker generates) true, // no_local - don't receive own messages false, // no_ack - we will acknowledge manually false, // exclusive - allow other consumers 10); // prefetch_count - number of unacked messages std::cout << "Consumer started with tag: " << consumer_tag << std::endl; // Consume messages with blocking wait AmqpClient::Envelope::ptr_t envelope = channel->BasicConsumeMessage(consumer_tag); std::cout << "Received: " << envelope->Message()->Body() << std::endl; std::cout << "From exchange: " << envelope->Exchange() << std::endl; std::cout << "Routing key: " << envelope->RoutingKey() << std::endl; std::cout << "Redelivered: " << envelope->Redelivered() << std::endl; channel->BasicAck(envelope); // Acknowledge the message // Consume with timeout (non-blocking) AmqpClient::Envelope::ptr_t envelope2; bool received = channel->BasicConsumeMessage(consumer_tag, envelope2, 5000); // 5 second timeout if (received) { std::cout << "Got message: " << envelope2->Message()->Body() << std::endl; channel->BasicAck(envelope2); } else { std::cout << "Timeout - no message received" << std::endl; } // Consume from multiple consumers at once std::string tag1 = channel->BasicConsume("queue1", "", true, false, false, 10); std::string tag2 = channel->BasicConsume("queue2", "", true, false, false, 10); std::vector tags = {tag1, tag2}; AmqpClient::Envelope::ptr_t multi_envelope; if (channel->BasicConsumeMessage(tags, multi_envelope, 10000)) { std::cout << "Message from consumer: " << multi_envelope->ConsumerTag() << std::endl; channel->BasicAck(multi_envelope); } // Cancel consumer when done channel->BasicCancel(consumer_tag); ``` -------------------------------- ### Configure Consumer Prefetch with BasicQos in C++ Source: https://context7.com/alanxz/simpleamqpclient/llms.txt Explains how to use BasicQos to limit the number of unacknowledged messages delivered to a consumer. This is critical for load balancing and preventing consumer overload. ```cpp #include AmqpClient::Channel::ptr_t channel = AmqpClient::Channel::Open(opts); channel->DeclareQueue("heavy_tasks", false, true, false, false); std::string consumer = channel->BasicConsume("heavy_tasks", "", true, false, false, 1); // Set prefetch to 10 for higher throughput channel->BasicQos(consumer, 10); // Set prefetch to 1 for fair dispatch channel->BasicQos(consumer, 1); AmqpClient::Envelope::ptr_t envelope; while (channel->BasicConsumeMessage(consumer, envelope, -1)) { processTask(envelope->Message()->Body()); channel->BasicAck(envelope); } ``` -------------------------------- ### Managing AMQP TableValues and Headers in C++ Source: https://context7.com/alanxz/simpleamqpclient/llms.txt Demonstrates how to instantiate various AMQP data types using TableValue, construct arrays and nested tables, and apply them as headers to messages or configuration arguments for queues. ```cpp #include // Create table values of different types AmqpClient::TableValue void_val; // VT_void AmqpClient::TableValue bool_val(true); // VT_bool AmqpClient::TableValue int8_val(static_cast(-42)); // VT_int8 AmqpClient::TableValue int32_val(static_cast(12345)); // VT_int32 AmqpClient::TableValue int64_val(static_cast(9876543210LL)); // VT_int64 AmqpClient::TableValue float_val(3.14f); // VT_float AmqpClient::TableValue double_val(2.718281828); // VT_double AmqpClient::TableValue string_val("hello world"); // VT_string AmqpClient::TableValue timestamp_val = AmqpClient::TableValue::Timestamp(std::time(nullptr)); // VT_timestamp // Create an array value AmqpClient::Array arr; arr.push_back(AmqpClient::TableValue("item1")); arr.push_back(AmqpClient::TableValue("item2")); arr.push_back(AmqpClient::TableValue(static_cast(42))); AmqpClient::TableValue array_val(arr); // Create a nested table AmqpClient::Table nested; nested["key1"] = AmqpClient::TableValue("value1"); nested["key2"] = AmqpClient::TableValue(static_cast(100)); AmqpClient::TableValue table_val(nested); // Build a complete headers table AmqpClient::Table headers; headers["x-message-type"] = AmqpClient::TableValue("notification"); headers["x-priority"] = AmqpClient::TableValue(static_cast(5)); headers["x-tags"] = array_val; headers["x-metadata"] = table_val; // Apply headers to a message AmqpClient::BasicMessage::ptr_t msg = AmqpClient::BasicMessage::Create("data"); msg->HeaderTable(headers); // Read values from TableValue std::cout << "Type: " << string_val.GetType() << std::endl; std::cout << "String: " << string_val.GetString() << std::endl; std::cout << "Int64: " << int64_val.GetInt64() << std::endl; std::cout << "Integer (any): " << int32_val.GetInteger() << std::endl; // Use tables for queue arguments (e.g., dead-letter configuration) AmqpClient::Table queue_args; queue_args["x-dead-letter-exchange"] = AmqpClient::TableValue("dlx"); queue_args["x-dead-letter-routing-key"] = AmqpClient::TableValue("dead"); queue_args["x-message-ttl"] = AmqpClient::TableValue(static_cast(30000)); queue_args["x-max-length"] = AmqpClient::TableValue(static_cast(10000)); AmqpClient::Channel::ptr_t channel = AmqpClient::Channel::Open(opts); channel->DeclareQueue("my_queue", false, true, false, false, queue_args); ``` -------------------------------- ### Declare and Manage AMQP Queues in C++ Source: https://context7.com/alanxz/simpleamqpclient/llms.txt Demonstrates how to declare durable, exclusive, and temporary queues using SimpleAmqpClient. It also shows how to retrieve message counts, apply queue arguments like TTL, and perform maintenance tasks like purging or deleting queues. ```cpp #include AmqpClient::Channel::ptr_t channel = AmqpClient::Channel::Open(opts); // Declare a named durable queue std::string queue_name = channel->DeclareQueue("my_queue", false, // passive true, // durable false, // exclusive false); // auto_delete // Declare an exclusive auto-deleting queue (broker generates name) std::string temp_queue = channel->DeclareQueue("", // empty = broker-generated name false, // passive false, // durable true, // exclusive true); // auto_delete // Declare queue with message and consumer counts boost::uint32_t message_count, consumer_count; std::string queue = channel->DeclareQueueWithCounts("my_counted_queue", message_count, consumer_count, false, true, false, false); // Declare queue with arguments (e.g., message TTL) AmqpClient::Table queue_args; queue_args["x-message-ttl"] = AmqpClient::TableValue(60000); queue_args["x-max-length"] = AmqpClient::TableValue(1000); std::string ttl_queue = channel->DeclareQueue("my_ttl_queue", false, true, false, false, queue_args); // Check if queue exists bool queue_exists = channel->CheckQueueExists("my_queue"); // Delete and purge queues channel->PurgeQueue("my_queue"); channel->DeleteQueue("my_queue", false, false); ``` -------------------------------- ### Handle SimpleAmqpClient Exceptions in C++ Source: https://context7.com/alanxz/simpleamqpclient/llms.txt Demonstrates how to catch and handle various SimpleAmqpClient exceptions, including soft errors like PreconditionFailedException and hard errors like ConnectionForcedException. It shows how to differentiate between recoverable channel errors and fatal connection errors, and includes a basic reconnection loop. ```cpp #include AmqpClient::Channel::ptr_t channel; try { AmqpClient::Channel::OpenOpts opts; opts.host = "localhost"; opts.port = 5672; opts.auth = AmqpClient::Channel::OpenOpts::BasicAuth("guest", "guest"); channel = AmqpClient::Channel::Open(opts); // Try to declare a queue that conflicts with existing one channel->DeclareQueue("existing_queue", false, true, false, false); } catch (const AmqpClient::PreconditionFailedException& e) { // Soft error - queue exists with different parameters std::cerr << "Queue declaration failed: " << e.reply_text() << std::endl; std::cerr << "Reply code: " << e.reply_code() << std::endl; // Channel is still usable for other operations } catch (const AmqpClient::NotFoundException& e) { // Soft error - entity not found (e.g., passive declare failed) std::cerr << "Not found: " << e.reply_text() << std::endl; } catch (const AmqpClient::AccessRefusedException& e) { // Soft error - permission denied std::cerr << "Access refused: " << e.reply_text() << std::endl; } catch (const AmqpClient::ChannelException& e) { // Any soft error - channel still usable std::cerr << "Channel error (recoverable): " << e.what() << std::endl; if (e.is_soft_error()) { // Continue using channel } } catch (const AmqpClient::ConnectionForcedException& e) { // Hard error - connection closed by operator std::cerr << "Connection forced closed: " << e.reply_text() << std::endl; channel.reset(); // Channel no longer usable } catch (const AmqpClient::ConnectionException& e) { // Any hard error - must reconnect std::cerr << "Connection error (fatal): " << e.what() << std::endl; channel.reset(); } catch (const AmqpClient::MessageReturnedException& e) { // Message couldn't be routed (mandatory flag was set) std::cerr << "Message returned: " << e.reply_text() << std::endl; std::cerr << "Exchange: " << e.exchange() << std::endl; std::cerr << "Routing key: " << e.routing_key() << std::endl; // Can retry with different routing key or save for later } // Reconnection pattern bool connected = false; while (!connected) { try { channel = AmqpClient::Channel::Open(opts); connected = true; } catch (const AmqpClient::AmqpException& e) { std::cerr << "Reconnection failed: " << e.what() << std::endl; sleep(5); // Wait before retry } } ``` -------------------------------- ### Publish AMQP Messages to Exchange using C++ Source: https://context7.com/alanxz/simpleamqpclient/llms.txt Shows how to publish messages to an AMQP exchange using `BasicPublish`. Covers exchange declaration, queue declaration, binding, simple publishing, publishing with the mandatory flag, publishing to the default exchange, and publishing JSON payloads. ```cpp #include #include AmqpClient::Channel::ptr_t channel = AmqpClient::Channel::Open(opts); // Setup channel->DeclareExchange("events", AmqpClient::Channel::EXCHANGE_TYPE_TOPIC, false, true, false); channel->DeclareQueue("event_log", false, true, false, false); channel->BindQueue("event_log", "events", "event.#"); // Simple publish AmqpClient::BasicMessage::ptr_t message = AmqpClient::BasicMessage::Create("User logged in"); channel->BasicPublish("events", "event.user.login", message); // Publish with mandatory flag (throws if no queue receives message) try { AmqpClient::BasicMessage::ptr_t important_msg = AmqpClient::BasicMessage::Create("Critical alert"); important_msg->DeliveryMode(AmqpClient::BasicMessage::dm_persistent); channel->BasicPublish("events", "event.critical.alert", important_msg, true, // mandatory - must be routed to a queue false); // immediate - deprecated in RabbitMQ 3.0+ } catch (const AmqpClient::MessageReturnedException& e) { std::cerr << "Message could not be routed: " << e.reply_text() << std::endl; std::cerr << "Exchange: " << e.exchange() << ", Routing Key: " << e.routing_key() << std::endl; } // Publish to default exchange (direct to queue by name) channel->BasicPublish("", "my_queue", AmqpClient::BasicMessage::Create("Direct to queue")); // Publish JSON payload AmqpClient::BasicMessage::ptr_t json_msg = AmqpClient::BasicMessage::Create( R"({\"event\": \"order_placed\", \"order_id\": 12345})"); json_msg->ContentType("application/json"); json_msg->DeliveryMode(AmqpClient::BasicMessage::dm_persistent); channel->BasicPublish("events", "event.order.placed", json_msg); ``` -------------------------------- ### Define Library and Link Dependencies in CMake Source: https://github.com/alanxz/simpleamqpclient/blob/master/CMakeLists.txt This snippet defines the SimpleAmqpClient library using a list of source files and links it against required dependencies like rabbitmq-c, Boost, and system-specific socket libraries. ```cmake set(SAC_LIB_SRCS src/SimpleAmqpClient/SimpleAmqpClient.h src/Channel.cpp src/Table.cpp) add_library(SimpleAmqpClient ${SAC_LIB_SRCS}) target_link_libraries(SimpleAmqpClient ${Rabbitmqc_LIBRARY} ${SOCKET_LIBRARY} ${Boost_LIBRARIES} $<$:Boost::dynamic_linking>) ``` -------------------------------- ### Bind and Unbind Queues and Exchanges in C++ Source: https://context7.com/alanxz/simpleamqpclient/llms.txt Shows how to connect queues to exchanges using routing keys, including wildcard support for topic exchanges. It also demonstrates binding exchanges to other exchanges and cleaning up bindings with unbind operations. ```cpp #include AmqpClient::Channel::ptr_t channel = AmqpClient::Channel::Open(opts); // Setup exchanges and queues channel->DeclareExchange("orders", AmqpClient::Channel::EXCHANGE_TYPE_TOPIC, false, true, false); channel->DeclareQueue("all_orders", false, true, false, false); // Bind queues to exchange with routing keys channel->BindQueue("all_orders", "orders", "order.#"); channel->BindQueue("us_orders", "orders", "order.us.*"); // Bind with additional arguments AmqpClient::Table bind_args; bind_args["x-match"] = AmqpClient::TableValue("all"); channel->BindQueue("json_queue", "headers_exchange", "", bind_args); // Exchange-to-exchange binding channel->BindExchange("dest_exchange", "source_exchange", "important.#"); // Unbind when no longer needed channel->UnbindQueue("us_orders", "orders", "order.us.*"); channel->UnbindExchange("dest_exchange", "source_exchange", "important.#"); ``` -------------------------------- ### Configure Dependencies and Build Options in CMake Source: https://github.com/alanxz/simpleamqpclient/blob/master/CMakeLists.txt This snippet demonstrates how to locate the rabbitmq-c library using find_package, configure optional SSL support, and set default build types and compiler flags for the project. ```cmake find_package(rabbitmq-c CONFIG QUIET) if (rabbitmq-c_FOUND) if (BUILD_SHARED_LIBS) set(Rabbitmqc_LIBRARY rabbitmq::rabbitmq) else() set(Rabbitmqc_LIBRARY rabbitmq::rabbitmq-static) endif() get_target_property(Rabbitmqc_INCLUDE_DIRS ${Rabbitmqc_LIBRARY} INTERFACE_INCLUDE_DIRECTORIES) else() set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Modules) find_package(Rabbitmqc REQUIRED) INCLUDE_DIRECTORIES(SYSTEM ${Rabbitmqc_INCLUDE_DIRS}) endif() option(ENABLE_SSL_SUPPORT "Enable SSL support." ${Rabbitmqc_SSL_ENABLED}) if (ENABLE_SSL_SUPPORT) add_definitions(-DSAC_SSL_SUPPORT_ENABLED) endif() ``` -------------------------------- ### Manage Exchanges with DeclareExchange Source: https://context7.com/alanxz/simpleamqpclient/llms.txt Shows how to declare various types of exchanges (direct, fanout, topic) on an AMQP broker. It also demonstrates how to verify exchange existence and delete exchanges. ```cpp #include AmqpClient::Channel::ptr_t channel = AmqpClient::Channel::Open(opts); // Declare a direct exchange (default type) channel->DeclareExchange("my_direct_exchange", AmqpClient::Channel::EXCHANGE_TYPE_DIRECT, false, // passive - create if not exists true, // durable - survives broker restart false); // auto_delete - don't delete when unused // Declare a fanout exchange (broadcasts to all bound queues) channel->DeclareExchange("my_fanout_exchange", AmqpClient::Channel::EXCHANGE_TYPE_FANOUT, false, true, false); // Declare a topic exchange (pattern-based routing) channel->DeclareExchange("my_topic_exchange", AmqpClient::Channel::EXCHANGE_TYPE_TOPIC, false, true, false); // Declare exchange with additional arguments AmqpClient::Table args; args["alternate-exchange"] = AmqpClient::TableValue("my_alternate_exchange"); channel->DeclareExchange("my_exchange_with_args", AmqpClient::Channel::EXCHANGE_TYPE_DIRECT, false, true, false, args); // Check if exchange exists without creating bool exists = channel->CheckExchangeExists("my_direct_exchange"); // Delete an exchange channel->DeleteExchange("my_direct_exchange", false); // if_unused = false ``` -------------------------------- ### Perform Message Acknowledgment and Rejection in C++ Source: https://context7.com/alanxz/simpleamqpclient/llms.txt Demonstrates how to acknowledge successful message processing using BasicAck and handle failures using BasicReject. It includes options for requeueing messages and handling multiple acknowledgments. ```cpp #include AmqpClient::Channel::ptr_t channel = AmqpClient::Channel::Open(opts); channel->DeclareQueue("jobs", false, true, false, false); std::string consumer = channel->BasicConsume("jobs", "", true, false, false, 50); while (true) { AmqpClient::Envelope::ptr_t envelope; if (!channel->BasicConsumeMessage(consumer, envelope, 30000)) { continue; } try { std::string body = envelope->Message()->Body(); std::cout << "Processing job: " << body << std::endl; channel->BasicAck(envelope); } catch (const std::exception& e) { std::cerr << "Error processing message: " << e.what() << std::endl; channel->BasicReject(envelope, true, false); } } channel->BasicRecover(consumer); ``` -------------------------------- ### Configure Doxygen for API Documentation Source: https://github.com/alanxz/simpleamqpclient/blob/master/CMakeLists.txt This snippet configures Doxygen to build API documentation if the BUILD_API_DOCS option is enabled. It checks for Doxygen's presence and sets up the Doxyfile for documentation generation. Dependencies include Doxygen and the SimpleAmqpClient target. ```cmake find_package(Doxygen COMPONENTS dot) option(BUILD_API_DOCS "Build Doxygen API docs" ${DOXYGEN_FOUND}) if (BUILD_API_DOCS) if (NOT DOXYGEN_FOUND) message(FATAL_ERROR "Doxygen is required to build the API documentation") endif () configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/docs/Doxyfile @ONLY) add_custom_target(docs ALL COMMAND ${DOXYGEN_EXECUTABLE} VERBATIM WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/docs DEPENDS SimpleAmqpClient COMMENT "Generating API documentation" SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ) endif () ``` -------------------------------- ### Link Libraries for SimpleAmqpClient Source: https://github.com/alanxz/simpleamqpclient/blob/master/CMakeLists.txt This CMake code dynamically determines and sets the private or public library link paths and names for the SimpleAmqpClient. It iterates through provided libraries (like Boost and Windows-specific targets), extracts path and name components, and formats them for linking. It handles both target names and direct library paths. ```cmake # Propagate library dependencies set(libs_private "") set(libs_public "") if (BUILD_SHARED_LIBS) set(populate_libs "libs_private") else (BUILD_SHARED_LIBS) set(populate_libs "libs_public") set(extra_win32_targets "${Rabbitmqc_LIBRARY};${SOCKET_LIBRARY}") endif (BUILD_SHARED_LIBS) foreach(_lib ${Boost_LIBRARIES} ${extra_win32_targets}) # Check if FindBoost.cmake provided actual library paths or targets if(TARGET ${_lib}) get_target_property(_lib ${_lib} LOCATION) message(WARNING "Using target ${_lib} as a library") endif() get_filename_component(_LIBPATH ${_lib} PATH) if (NOT _LIBPATH STREQUAL _LASTLIBPATH AND NOT _LIBPATH STREQUAL "") set(${populate_libs} "${${populate_libs}} -L\"${_LIBPATH}\"" ) set(_LASTLIBPATH ${_LIBPATH}) endif() get_filename_component(_LIBNAME ${_lib} NAME_WLE) if (NOT _LIBNAME STREQUAL "debug" AND NOT _LIBNAME STREQUAL "optimized") if (NOT WIN32) string(REGEX REPLACE "^lib" "" _LIBNAME ${_LIBNAME}) endif () set(_LIBNAME "-l${_LIBNAME}") set(${populate_libs} "${${populate_libs}} ${_LIBNAME}") endif() endforeach() ``` -------------------------------- ### Configure Testing Environment in CMake Source: https://github.com/alanxz/simpleamqpclient/blob/master/CMakeLists.txt This snippet enables GoogleTest for the project, setting necessary build flags and adding the testing subdirectory if the ENABLE_TESTING option is set to ON. ```cmake option(ENABLE_TESTING "Enable smoke tests" OFF) if (ENABLE_TESTING) enable_testing() set(BUILD_GTEST ON CACHE BOOL "" FORCE) add_subdirectory(third-party/googletest) add_subdirectory(testing) endif (ENABLE_TESTING) ``` -------------------------------- ### DeclareQueue - Create or Verify a Queue Source: https://context7.com/alanxz/simpleamqpclient/llms.txt Methods to create, verify, and manage the lifecycle of AMQP queues, including support for durable, exclusive, and auto-delete configurations. ```APIDOC ## METHOD DeclareQueue ### Description Creates a queue on the AMQP broker if it does not already exist. Supports various configurations like durability, exclusivity, and auto-deletion. ### Method C++ Method Call ### Parameters #### Arguments - **queue_name** (string) - Required - Name of the queue. If empty, the broker generates a unique name. - **passive** (bool) - Required - If true, checks if queue exists without creating it. - **durable** (bool) - Required - If true, queue survives broker restart. - **exclusive** (bool) - Required - If true, queue is restricted to the current connection. - **auto_delete** (bool) - Required - If true, queue is deleted when the last consumer disconnects. - **arguments** (AmqpClient::Table) - Optional - Additional queue arguments like TTL or max length. ### Response - **string** - The name of the declared queue. ``` -------------------------------- ### Propagate Package Dependencies and Definitions Source: https://github.com/alanxz/simpleamqpclient/blob/master/CMakeLists.txt This CMake code manages the propagation of package dependencies and compile definitions for the SimpleAmqpClient library. It sets private and public requirements based on `BUILD_SHARED_LIBS` and collects interface compile definitions. Dependencies include CMake's target properties and conditional logic. ```cmake set(prefix ${CMAKE_INSTALL_PREFIX}) set(exec_prefix "\${prefix}") set(libdir "\${prefix}/${CMAKE_INSTALL_LIBDIR}") set(includedir "\${prefix}/include") if(WIN32) get_target_property(SIMPLEAMQPCLIENT_LIB SimpleAmqpClient OUTPUT_NAME) else(WIN32) set(SIMPLEAMQPCLIENT_LIB SimpleAmqpClient) endif(WIN32) # Propagate package dependencies if (BUILD_SHARED_LIBS) set(requires_private "librabbitmq") else (BUILD_SHARED_LIBS) set(requires_public "librabbitmq") endif (BUILD_SHARED_LIBS) # Propagate interface compile definitions set(SIMPLEAMQPCLIENT_DEFINITIONS "") get_target_property(propagated_definitions SimpleAmqpClient INTERFACE_COMPILE_DEFINITIONS) if (propagated_definitions) foreach(_def ${propagated_definitions}) set(SIMPLEAMQPCLIENT_DEFINITIONS "${SIMPLEAMQPCLIENT_DEFINITIONS} -D${_def}") endforeach() endif(propagated_definitions) ``` -------------------------------- ### BasicGet - Synchronously Retrieve a Single Message Source: https://context7.com/alanxz/simpleamqpclient/llms.txt Synchronously retrieves a single message from a queue without setting up a consumer. Useful for occasional message retrieval. ```APIDOC ## BasicGet - Synchronously Retrieve a Single Message ### Description The `BasicGet` method synchronously retrieves a single message from a queue without setting up a consumer. This is useful for occasional message retrieval but less efficient than consuming for continuous message processing. It returns immediately whether or not a message is available. ### Method `BasicGet` ### Endpoint N/A (This is a client-side library function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example (BasicGet with auto-ack) ```cpp AmqpClient::Channel::ptr_t channel = AmqpClient::Channel::Open(opts); channel->DeclareQueue("work_queue", false, true, false, false); AmqpClient::Envelope::ptr_t envelope; bool got_message = channel->BasicGet(envelope, "work_queue", true); // no_ack = true if (got_message) { std::cout << "Message: " << envelope->Message()->Body() << std::endl; } ``` ### Request Example (BasicGet with manual ack) ```cpp AmqpClient::Envelope::ptr_t envelope2; if (channel->BasicGet(envelope2, "work_queue", false)) { // no_ack = false try { // Process message... std::cout << "Processing: " << envelope2->Message()->Body() << std::endl; // Acknowledge on success channel->BasicAck(envelope2); } catch (const std::exception& e) { // Reject and requeue on failure channel->BasicReject(envelope2, true, false); // requeue=true, multiple=false } } ``` ### Request Example (Polling until queue is empty) ```cpp AmqpClient::Envelope::ptr_t envelope; while (channel->BasicGet(envelope, "work_queue", false)) { std::cout << "Got: " << envelope->Message()->Body() << std::endl; channel->BasicAck(envelope); } ``` ### Response #### Success Response (BasicGet) - **envelope** (AmqpClient::Envelope::ptr_t) - A pointer to the received message envelope if a message is available. - **got_message** (bool) - True if a message was retrieved, false otherwise. #### Response Example (if message is retrieved) ```json { "body": "message content", "delivery_tag": "12345", "redelivered": false } ``` ### Error Handling - `BasicGet` returns `false` if the queue is empty. - It can throw exceptions on connection errors. - Manual acknowledgment (`BasicAck`) or rejection (`BasicReject`) is required when `no_ack` is false. ```