├── .gitignore ├── README.mkd ├── cmake └── Modules │ ├── FindRABBITMQ.cmake │ └── FindEvent.cmake ├── receive.cpp ├── send.cpp ├── worker.cpp ├── emit_log.cpp ├── rpc_server.cpp ├── receive_logs_topic.cpp ├── receive_logs_direct.cpp ├── emit_log_direct.cpp ├── receive_logs.cpp ├── emit_log_topic.cpp ├── new_task.cpp ├── conn_handler.h ├── rpc_client.cpp └── CMakeLists.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | build 4 | .idea 5 | -------------------------------------------------------------------------------- /README.mkd: -------------------------------------------------------------------------------- 1 | # C++ code for RabbitMQ tutorials 2 | 3 | Almost the same examples as in [AMQP-CPP](https://github.com/CopernicaMarketingSoftware/AMQP-CPP) 4 | project (see examples directory). With some minor changes. Based on 5 | [libevent](http://libevent.org). 6 | 7 | ## Code 8 | 9 | [Tutorial one: "Hello World!"](http://www.rabbitmq.com/tutorial-one-python.html): 10 | 11 | receive 12 | send 13 | 14 | 15 | [Tutorial two: Work Queues](http://www.rabbitmq.com/tutorial-two-python.html): 16 | 17 | new_task 18 | worker 19 | 20 | [Tutorial three: Publish/Subscribe](http://www.rabbitmq.com/tutorial-three-python.html): 21 | 22 | receive_logs 23 | emit_log 24 | 25 | [Tutorial four: Routing](http://www.rabbitmq.com/tutorial-four-python.html): 26 | 27 | receive_logs_direct 28 | emit_log_direct 29 | 30 | [Tutorial five: Topics](http://www.rabbitmq.com/tutorial-five-python.html): 31 | 32 | receive_logs_topic 33 | emit_log_topic 34 | 35 | [Tutorial six: RPC](http://www.rabbitmq.com/tutorial-six-python.html): 36 | 37 | rpc_server 38 | rpc_client 39 | 40 | -------------------------------------------------------------------------------- /cmake/Modules/FindRABBITMQ.cmake: -------------------------------------------------------------------------------- 1 | # Find RabbitMQ-C 2 | # Merder Kim 3 | # 4 | # input: 5 | # RABBITMQ_ROOT 6 | # 7 | # output: 8 | # RABBITMQ_FOUND 9 | # RABBOTMQ_INCLUDE_DIR 10 | # RABBITMQ_LIBRARIES 11 | # 12 | 13 | if(RABBITMQ_INCLUDE_DIR AND RABBITMQ_LIBRARIES) 14 | set(RABBITMQ_FIND_QUIETLY TRUE) # cached 15 | endif(RABBITMQ_INCLUDE_DIR AND RABBITMQ_LIBRARIES) 16 | 17 | if(NOT DEFINED RABBITMQ_ROOT) 18 | set (RABBITMQ_ROOT /usr /usr/local $ENV{RABBITMQ_ROOT} ) 19 | endif(NOT DEFINED RABBITMQ_ROOT) 20 | 21 | find_path(RABBITMQ_INCLUDE_DIR amqp.h 22 | PATHS ${RABBITMQ_ROOT} 23 | PATH_SUFFIXES amqp/include include 24 | ) 25 | 26 | find_library(RABBITMQ_LIBRARY 27 | NAMES rabbitmq 28 | PATHS ${RABBITMQ_ROOT} 29 | PATH_SUFFIXES lib 30 | ) 31 | 32 | set(RABBITMQ_LIBRARIES ${RABBITMQ_LIBRARY}) 33 | 34 | mark_as_advanced(RABBITMQ_INCLUDE_DIR RABBITMQ_LIBRARIES) 35 | 36 | include("${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake") 37 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(RABBITMQ DEFAULT_MSG RABBITMQ_INCLUDE_DIR RABBITMQ_LIBRARIES) 38 | 39 | -------------------------------------------------------------------------------- /cmake/Modules/FindEvent.cmake: -------------------------------------------------------------------------------- 1 | # Find Libevent 2 | # Merder Kim 3 | # 4 | # input: 5 | # Event_ROOT 6 | # 7 | # output: 8 | # Event_FOUND 9 | # Event_INCLUDE_DIR 10 | # Event_LIBRARIES 11 | # 12 | 13 | if(Event_INCLUDE_DIR AND Event_LIBRARIES) 14 | set(Event_FIND_QUIETLY TRUE) # cached 15 | endif(Event_INCLUDE_DIR AND Event_LIBRARIES) 16 | 17 | if(NOT DEFINED Event_ROOT) 18 | set (Event_ROOT /usr /usr/local $ENV{Event_ROOT} ) 19 | endif(NOT DEFINED Event_ROOT) 20 | 21 | find_path(Event_INCLUDE_DIR event.h 22 | PATHS ${Event_ROOT} 23 | PATH_SUFFIXES event/include include 24 | ) 25 | 26 | find_library(EventCore_LIBRARY 27 | NAMES event_core 28 | PATHS ${Event_ROOT} 29 | PATH_SUFFIXES lib "-2.0" 30 | ) 31 | 32 | find_library(Event2_LIBRARY 33 | NAMES event 34 | PATHS ${Event_ROOT} 35 | PATH_SUFFIXES lib "-2.0" 36 | ) 37 | 38 | set(Event_LIBRARIES ${Event2_LIBRARY}) 39 | 40 | add_definitions(-DLIBNET_LIL_ENDIAN) 41 | 42 | mark_as_advanced(Event_INCLUDE_DIR Event_LIBRARIES) 43 | 44 | include("${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake") 45 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Event DEFAULT_MSG Event_INCLUDE_DIR Event_LIBRARIES) 46 | 47 | -------------------------------------------------------------------------------- /receive.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "conn_handler.h" 4 | 5 | int 6 | main(void) 7 | { 8 | ConnHandler handler; 9 | AMQP::TcpConnection connection(handler, AMQP::Address("amqp://localhost/")); 10 | AMQP::TcpChannel channel(&connection); 11 | channel.onError([&handler](const char* message) 12 | { 13 | std::cout << "Channel error: " << message << std::endl; 14 | handler.Stop(); 15 | }); 16 | channel.declareQueue("hello", AMQP::autodelete) 17 | .onSuccess 18 | ( 19 | [&connection](const std::string &name, 20 | uint32_t messagecount, 21 | uint32_t consumercount) 22 | { 23 | std::cout << "Created queue: " << name << std::endl; 24 | } 25 | ); 26 | channel.consume("hello", AMQP::noack) 27 | .onReceived 28 | ( 29 | [](const AMQP::Message &msg, uint64_t tag, bool redelivered) 30 | { 31 | std::cout << "Received: " << msg.message() << std::endl; 32 | } 33 | ); 34 | handler.Start(); 35 | std::cout << "Closing connection." << std::endl; 36 | connection.close(); 37 | return 0; 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /send.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "conn_handler.h" 4 | 5 | int 6 | main(void) 7 | { 8 | auto evbase = event_base_new(); 9 | LibEventHandlerMyError hndl(evbase); 10 | 11 | AMQP::TcpConnection connection(&hndl, AMQP::Address("amqp://localhost/")); 12 | AMQP::TcpChannel channel(&connection); 13 | channel.onError([&evbase](const char* message) 14 | { 15 | std::cout << "Channel error: " << message << std::endl; 16 | event_base_loopbreak(evbase); 17 | }); 18 | channel.declareQueue("hello", AMQP::passive) 19 | .onSuccess 20 | ( 21 | [&connection](const std::string &name, 22 | uint32_t messagecount, 23 | uint32_t consumercount) 24 | { 25 | std::cout << "Queue: " << name << std::endl; 26 | } 27 | ) 28 | .onFinalize 29 | ( 30 | [&connection]() 31 | { 32 | std::cout << "Finalize." << std::endl; 33 | connection.close(); 34 | } 35 | ); 36 | channel.publish("", "hello", "Hello, world!"); 37 | 38 | event_base_dispatch(evbase); 39 | event_base_free(evbase); 40 | 41 | return 0; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /worker.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "conn_handler.h" 7 | 8 | int main(void) 9 | { 10 | ConnHandler handler; 11 | AMQP::TcpConnection connection(handler, 12 | AMQP::Address("localhost", 5672, 13 | AMQP::Login("guest", "guest"), "/")); 14 | AMQP::TcpChannel channel(&connection); 15 | channel.onError([&handler](const char* message) 16 | { 17 | std::cout << "Channel error: " << message << std::endl; 18 | handler.Stop(); 19 | }); 20 | 21 | channel.setQos(1); 22 | channel.declareQueue("task_queue", AMQP::durable); 23 | channel.consume("task_queue") 24 | .onReceived 25 | ( 26 | [&channel](const AMQP::Message msg, 27 | uint64_t tag, 28 | bool redelivered) 29 | { 30 | const auto body = msg.message(); 31 | std::cout << "Received: " << body << std::endl; 32 | size_t count = std::count(body.cbegin(), body.cend(), '.'); 33 | std::this_thread::sleep_for(std::chrono::seconds(count)); 34 | std::cout << "Done" << std::endl; 35 | channel.ack(tag); 36 | } 37 | ); 38 | handler.Start(); 39 | std::cout << "Closing connection." << std::endl; 40 | connection.close(); 41 | return 0; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /emit_log.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "conn_handler.h" 8 | 9 | template inline std::string 10 | join(InIter begin, InIter end, std::string delim) 11 | { 12 | std::stringstream ss; 13 | std::copy(begin, end, 14 | std::ostream_iterator(ss, delim.c_str())); 15 | return ss.str(); 16 | } 17 | 18 | int 19 | main(int argc, const char* argv[]) 20 | { 21 | const std::string msg = 22 | argc > 1 ? join(&argv[1], &argv[argc], " ") : "Hello World!"; 23 | 24 | auto evbase = event_base_new(); 25 | LibEventHandlerMyError handler(evbase); 26 | AMQP::TcpConnection connection(&handler, 27 | AMQP::Address("localhost", 5672, 28 | AMQP::Login("guest", "guest"), "/")); 29 | AMQP::TcpChannel channel(&connection); 30 | channel.onError([&evbase](const char* message) 31 | { 32 | std::cout << "Channel error: " << message << std::endl; 33 | event_base_loopbreak(evbase); 34 | }); 35 | channel.declareExchange("logs", AMQP::fanout) 36 | .onSuccess 37 | ( 38 | [&]() 39 | { 40 | channel.publish("logs", "", msg); 41 | std::cout << "Sent '" << msg << "'" << std::endl; 42 | event_base_loopbreak(evbase); 43 | } 44 | ); 45 | event_base_dispatch(evbase); 46 | event_base_free(evbase); 47 | return 0; 48 | } 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /rpc_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "conn_handler.h" 7 | 8 | int fib(int n) 9 | { 10 | switch (n) 11 | { 12 | case 0: 13 | return 0; 14 | case 1: 15 | return 1; 16 | default: 17 | return fib(n - 1) + fib(n - 2); 18 | } 19 | } 20 | 21 | int 22 | main(int argc, char* argv[]) 23 | { 24 | ConnHandler handler; 25 | AMQP::TcpConnection connection(handler, 26 | AMQP::Address("localhost", 5672, 27 | AMQP::Login("guest", "guest"), "/")); 28 | AMQP::TcpChannel channel(&connection); 29 | channel.onError([&handler](const char* message) 30 | { 31 | std::cout << "Channel error: " << message << std::endl; 32 | handler.Stop(); 33 | }); 34 | channel.setQos(1); 35 | channel.declareQueue("rpc_queue"); 36 | channel.consume("") 37 | .onReceived 38 | ( 39 | [&channel](const AMQP::Message& m, uint64_t tag, bool) 40 | { 41 | std::cout << "fib(" << m.message() << ")" << std::endl; 42 | 43 | AMQP::Envelope env(std::to_string(fib(std::stoi(m.message())))); 44 | env.setCorrelationID(m.correlationID()); 45 | 46 | channel.publish("", m.replyTo(), env); 47 | channel.ack(tag); 48 | } 49 | ); 50 | handler.Start(); 51 | std::cout << "Closing connection." << std::endl; 52 | connection.close(); 53 | return 0; 54 | } 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /receive_logs_topic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "conn_handler.h" 7 | 8 | int 9 | main(int argc, char* argv[]) 10 | { 11 | if (argc < 2) 12 | { 13 | std::cout << "Usage: ..." << std::endl; 14 | return 0; 15 | } 16 | ConnHandler handler; 17 | AMQP::TcpConnection connection(handler, 18 | AMQP::Address("localhost", 5672, 19 | AMQP::Login("guest", "guest"), "/")); 20 | AMQP::TcpChannel channel(&connection); 21 | channel.onError([&handler](const char* message) 22 | { 23 | std::cout << "Channel error: " << message << std::endl; 24 | handler.Stop(); 25 | }); 26 | channel.declareExchange("topic_logs", AMQP::topic); 27 | channel.declareQueue("logs", AMQP::exclusive); 28 | std::for_each (argv + 1, argv + argc, 29 | [&](const char* bind_key) 30 | { 31 | std::cout << bind_key << std::endl; 32 | channel.bindQueue("topic_logs", "logs", bind_key); 33 | channel.consume("logs", AMQP::noack) 34 | .onReceived 35 | ( 36 | [](const AMQP::Message& m, uint64_t, bool) 37 | { 38 | std::cout << m.routingKey() << ": " 39 | << m.message() << std::endl; 40 | } 41 | ); 42 | } 43 | ); 44 | handler.Start(); 45 | std::cout << "Closing connection." << std::endl; 46 | connection.close(); 47 | return 0; 48 | } 49 | 50 | 51 | -------------------------------------------------------------------------------- /receive_logs_direct.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "conn_handler.h" 7 | 8 | int 9 | main(int argc, char* argv[]) 10 | { 11 | if (argc < 2) 12 | { 13 | std::cout << "Usage: log_level..." << std::endl 14 | << "log level examples: info, warning, error" << std::endl; 15 | return 0; 16 | } 17 | ConnHandler handler; 18 | AMQP::TcpConnection connection(handler, 19 | AMQP::Address("localhost", 5672, 20 | AMQP::Login("guest", "guest"), "/")); 21 | AMQP::TcpChannel channel(&connection); 22 | channel.onError([&handler](const char* message) 23 | { 24 | std::cout << "Channel error: " << message << std::endl; 25 | handler.Stop(); 26 | }); 27 | channel.declareExchange("direct_logs", AMQP::direct); 28 | channel.declareQueue("logs", AMQP::exclusive); 29 | std::for_each (argv + 1, argv + argc, 30 | [&](const char* log_level) 31 | { 32 | channel.bindQueue("direct_logs", "", log_level); 33 | channel.consume("logs", AMQP::noack) 34 | .onReceived 35 | ( 36 | [](const AMQP::Message& m, uint64_t, bool) 37 | { 38 | std::cout << m.routingKey() << ": " 39 | << m.message() << std::endl; 40 | } 41 | ); 42 | } 43 | ); 44 | handler.Start(); 45 | std::cout << "Closing connection." << std::endl; 46 | connection.close(); 47 | return 0; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /emit_log_direct.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "conn_handler.h" 8 | 9 | template inline std::string 10 | join(InIter begin, InIter end, std::string delim) 11 | { 12 | std::stringstream ss; 13 | std::copy(begin, end, 14 | std::ostream_iterator(ss, delim.c_str())); 15 | return ss.str(); 16 | } 17 | 18 | int 19 | main(int argc, const char* argv[]) 20 | { 21 | const std::string log_level = argc > 2 ? argv[1] : "info"; 22 | const std::string msg = 23 | argc > 2 ? join(&argv[2], &argv[argc], " ") : "Hello World!"; 24 | 25 | auto evbase = event_base_new(); 26 | LibEventHandlerMyError handler(evbase); 27 | AMQP::TcpConnection connection(&handler, 28 | AMQP::Address("localhost", 5672, 29 | AMQP::Login("guest", "guest"), "/")); 30 | AMQP::TcpChannel channel(&connection); 31 | channel.onError([&evbase](const char* message) 32 | { 33 | std::cout << "Channel error: " << message << std::endl; 34 | event_base_loopbreak(evbase); 35 | }); 36 | channel.declareExchange("direct_logs", AMQP::direct) 37 | .onSuccess 38 | ( 39 | [&]() 40 | { 41 | channel.publish("direct_logs", log_level, msg); 42 | std::cout << "Sent " << log_level << ": '" 43 | << msg << "'" << std::endl; 44 | event_base_loopbreak(evbase); 45 | } 46 | ); 47 | event_base_dispatch(evbase); 48 | event_base_free(evbase); 49 | return 0; 50 | } 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /receive_logs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "conn_handler.h" 4 | 5 | int 6 | main(void) 7 | { 8 | ConnHandler handler; 9 | AMQP::TcpConnection connection(handler, 10 | AMQP::Address("localhost", 5672, 11 | AMQP::Login("guest", "guest"), "/")); 12 | AMQP::TcpChannel channel(&connection); 13 | channel.onError([&handler](const char* message) 14 | { 15 | std::cout << "Channel error: " << message << std::endl; 16 | handler.Stop(); 17 | }); 18 | 19 | auto printLog = [](const AMQP::Message &message, 20 | uint64_t deliveryTag, 21 | bool redelivered) 22 | { 23 | std::cout << "Log: " << message.message() << std::endl; 24 | }; 25 | 26 | channel.declareExchange("logs", AMQP::fanout) 27 | .onSuccess 28 | ( 29 | [&]() 30 | { 31 | std::cout << "Exchange created." << std::endl; 32 | channel.declareQueue(AMQP::exclusive) 33 | .onSuccess 34 | ( 35 | [&channel, printLog](const std::string &name, 36 | uint32_t messagecount, 37 | uint32_t consumercount) 38 | { 39 | std::cout << "Queue created." << std::endl; 40 | channel.bindQueue("logs", name,""); 41 | channel.consume(name, AMQP::noack).onReceived(printLog); 42 | } 43 | ); 44 | } 45 | ); 46 | handler.Start(); 47 | std::cout << "Closing connection." << std::endl; 48 | connection.close(); 49 | return 0; 50 | } 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /emit_log_topic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "conn_handler.h" 8 | 9 | template inline std::string 10 | join(InIter begin, InIter end, std::string delim) 11 | { 12 | std::stringstream ss; 13 | std::copy(begin, end, 14 | std::ostream_iterator(ss, delim.c_str())); 15 | return ss.str(); 16 | } 17 | 18 | int 19 | main(int argc, const char* argv[]) 20 | { 21 | const std::string routing_key = argc > 2 ? argv[1] : "anonymous.info"; 22 | const std::string msg = 23 | argc > 2 ? join(&argv[2], &argv[argc], " ") : "Hello World!"; 24 | 25 | auto evbase = event_base_new(); 26 | LibEventHandlerMyError handler(evbase); 27 | AMQP::TcpConnection connection(&handler, 28 | AMQP::Address("localhost", 5672, 29 | AMQP::Login("guest", "guest"), "/")); 30 | AMQP::TcpChannel channel(&connection); 31 | channel.onError([&evbase](const char* message) 32 | { 33 | std::cout << "Channel error: " << message << std::endl; 34 | event_base_loopbreak(evbase); 35 | }); 36 | channel.declareExchange("topic_logs", AMQP::topic) 37 | .onError([&](const char* msg) 38 | { 39 | std::cout << "ERROR: " << msg << std::endl; 40 | }) 41 | .onSuccess 42 | ( 43 | [&]() 44 | { 45 | channel.publish("topic_logs", routing_key, msg); 46 | std::cout << "Sent " << routing_key << ": '" 47 | << msg << "'" << std::endl; 48 | event_base_loopbreak(evbase); 49 | } 50 | ); 51 | event_base_dispatch(evbase); 52 | event_base_free(evbase); 53 | return 0; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /new_task.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "conn_handler.h" 8 | 9 | template inline std::string 10 | join(InIter begin, InIter end, std::string delim) 11 | { 12 | std::stringstream ss; 13 | std::copy(begin, end, 14 | std::ostream_iterator(ss, delim.c_str())); 15 | return ss.str(); 16 | } 17 | 18 | int 19 | main(int argc, const char* argv[]) 20 | { 21 | const std::string msg = 22 | argc > 1 ? join(&argv[1], &argv[argc], " ") : "Hello World!"; 23 | 24 | auto evbase = event_base_new(); 25 | LibEventHandlerMyError handler(evbase); 26 | AMQP::TcpConnection connection(&handler, 27 | AMQP::Address("localhost", 5672, 28 | AMQP::Login("guest", "guest"), "/")); 29 | AMQP::TcpChannel channel(&connection); 30 | channel.onError([&evbase](const char* message) 31 | { 32 | std::cout << "Channel error: " << message << std::endl; 33 | event_base_loopbreak(evbase); 34 | }); 35 | channel.declareQueue("task_queue", AMQP::passive | AMQP::durable) 36 | .onSuccess 37 | ( 38 | [msg, &channel, &evbase](const std::string &name, 39 | uint32_t messagecount, 40 | uint32_t consumercount) 41 | { 42 | AMQP::Envelope env(msg); 43 | env.setDeliveryMode(2); 44 | channel.publish("", "task_queue", env); 45 | std::cout << "Sent '" << msg << "'" << std::endl; 46 | event_base_loopbreak(evbase); 47 | } 48 | ); 49 | event_base_dispatch(evbase); 50 | event_base_free(evbase); 51 | return 0; 52 | } 53 | 54 | 55 | -------------------------------------------------------------------------------- /conn_handler.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | class LibEventHandlerMyError : public AMQP::LibEventHandler 7 | { 8 | public: 9 | LibEventHandlerMyError(struct event_base* evbase) : LibEventHandler(evbase), evbase_(evbase_) {} 10 | void onError(AMQP::TcpConnection *connection, const char *message) override 11 | { 12 | std::cout << "Error: " << message << std::endl; 13 | event_base_loopbreak(evbase_); 14 | } 15 | private: 16 | struct event_base* evbase_ {nullptr}; 17 | }; 18 | 19 | class ConnHandler 20 | { 21 | public: 22 | using EventBasePtrT = std::unique_ptr >; 23 | using EventPtrT = std::unique_ptr >; 24 | 25 | ConnHandler() 26 | : evbase_(event_base_new(), event_base_free) 27 | , stdin_event_(event_new(evbase_.get(), STDIN_FILENO, EV_READ, stop, 28 | evbase_.get()), event_free) 29 | , evhandler_(evbase_.get()) 30 | { 31 | event_add(stdin_event_.get(), nullptr); 32 | } 33 | 34 | void Start() 35 | { 36 | std::cout << "Waiting for messages. Press enter to exit." << std::endl; 37 | event_base_dispatch(evbase_.get()); 38 | } 39 | void Stop() 40 | { 41 | event_base_loopbreak(evbase_.get()); 42 | } 43 | 44 | operator AMQP::TcpHandler*() 45 | { 46 | return &evhandler_; 47 | } 48 | 49 | private: 50 | static void stop(evutil_socket_t fd, short what, void *evbase) 51 | { 52 | std::cout << "Safely braking event loop." << std::endl; 53 | event_base_loopbreak(reinterpret_cast(evbase)); 54 | } 55 | EventBasePtrT evbase_; 56 | EventPtrT stdin_event_; 57 | LibEventHandlerMyError evhandler_; 58 | }; 59 | 60 | -------------------------------------------------------------------------------- /rpc_client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "conn_handler.h" 8 | 9 | int 10 | main(int argc, char* argv[]) 11 | { 12 | std::stringstream ss; 13 | ss << std::chrono::duration_cast( 14 | std::chrono::high_resolution_clock::now().time_since_epoch()).count(); 15 | std::string correlation = ss.str(); 16 | ConnHandler handler; 17 | AMQP::TcpConnection connection(handler, 18 | AMQP::Address("localhost", 5672, 19 | AMQP::Login("guest", "guest"), "/")); 20 | AMQP::TcpChannel channel(&connection); 21 | channel.onError([&handler](const char* message) 22 | { 23 | std::cout << "Channel error: " << message << std::endl; 24 | handler.Stop(); 25 | }); 26 | channel.declareQueue(AMQP::exclusive) 27 | .onSuccess 28 | ( 29 | [&channel, correlation](const std::string& name, int, int) 30 | { 31 | AMQP::Envelope env("30"); 32 | env.setCorrelationID(correlation); 33 | env.setReplyTo(name); 34 | channel.publish("", "rpc_queue", env); 35 | std::cout << "Requesting fib(30)" << std::endl; 36 | } 37 | ); 38 | channel.consume("", AMQP::noack) 39 | .onReceived 40 | ( 41 | [correlation, &handler](const AMQP::Message& m, uint64_t, bool) 42 | { 43 | if (m.correlationID() != correlation) 44 | return; // just skip it 45 | std::cout << "Got " << m.message() << std::endl; 46 | handler.Stop(); 47 | } 48 | ); 49 | handler.Start(); 50 | std::cout << "Closing connection." << std::endl; 51 | connection.close(); 52 | return 0; 53 | } 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | option(WITH_SYSTEM_LIBEVENT "Don't build libevent, use installed" ON) 3 | 4 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/Modules") 5 | add_definitions("-std=c++11") 6 | 7 | ######################################################################## 8 | # RabbitMQ 9 | 10 | include(ExternalProject) 11 | set(AMQPCPP_ROOT "${CMAKE_CURRENT_BINARY_DIR}/amqpcpp") 12 | ExternalProject_Add(libamqpcpp 13 | URL "https://github.com/hoxnox/AMQP-CPP/archive/v2.5.1-nx2.tar.gz" 14 | URL_MD5 "fcfbd25c03eecde4e4b0dfa58598a426" 15 | CMAKE_ARGS -Wno-dev "-DCMAKE_INSTALL_PREFIX=" 16 | INSTALL_DIR ${AMQPCPP_ROOT} 17 | ) 18 | set(AMQPCPP_INCLUDE_DIR ${AMQPCPP_ROOT}/include) 19 | set(AMQPCPP_LIBRARIES ${AMQPCPP_ROOT}/lib/libamqp-cpp.a) 20 | message(STATUS "Found external dependency AMQP-CPP: " ${AMQPCPP_INCLUDE_DIR}) 21 | include_directories(${AMQPCPP_INCLUDE_DIR}) 22 | list(APPEND LIBRARIES ${AMQPCPP_LIBRARIES}) 23 | list(APPEND DEPENDENCIES libamqpcpp) 24 | 25 | ######################################################################## 26 | # libevent 27 | 28 | if (WITH_SYSTEM_LIBEVENT) 29 | find_package(Event REQUIRED) 30 | add_custom_target(libevent DEPENDS ${Event_INCLUDE_DIR}/event2/event.h) 31 | else() 32 | set(Event_ROOT "${CMAKE_CURRENT_BINARY_DIR}/libevent") 33 | ExternalProject_Add(libevent 34 | URL "https://github.com/libevent/libevent/archive/release-2.0.22-stable.tar.gz" 35 | URL_MD5 "8913ef56ec329f2c046007bd634c7201" 36 | PATCH_COMMAND /autogen.sh 37 | CONFIGURE_COMMAND /configure --disable-shared --enable-static 38 | --disable-openssl --disable-libevent-regress --prefix 39 | INSTALL_DIR ${Event_ROOT} 40 | ) 41 | set(Event_INCLUDE_DIR ${Event_ROOT}/include) 42 | set(Event_LIBRARIES ${Event_ROOT}/lib/libevent_core.a) 43 | message(STATUS "Found external dependency Event: " ${Event_INCLUDE_DIR}) 44 | endif() 45 | include_directories(${Event_INCLUDE_DIR}) 46 | list(APPEND LIBRARIES ${Event_LIBRARIES}) 47 | list(APPEND DEPENDENCIES libevent) 48 | 49 | ######################################################################## 50 | # threads 51 | 52 | find_package(Threads) 53 | list(APPEND LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) 54 | 55 | ######################################################################## 56 | 57 | add_executable(receive receive.cpp) 58 | target_link_libraries(receive ${LIBRARIES}) 59 | add_dependencies(receive ${DEPENDENCIES}) 60 | add_executable(send send.cpp) 61 | target_link_libraries(send ${LIBRARIES}) 62 | add_dependencies(send ${DEPENDENCIES}) 63 | 64 | add_executable(worker worker.cpp) 65 | target_link_libraries(worker ${LIBRARIES}) 66 | add_dependencies(worker ${DEPENDENCIES}) 67 | add_executable(new_task new_task.cpp) 68 | target_link_libraries(new_task ${LIBRARIES}) 69 | add_dependencies(new_task ${DEPENDENCIES}) 70 | 71 | add_executable(receive_logs receive_logs.cpp) 72 | target_link_libraries(receive_logs ${LIBRARIES}) 73 | add_dependencies(receive_logs ${DEPENDENCIES}) 74 | add_executable(emit_log emit_log.cpp) 75 | target_link_libraries(emit_log ${LIBRARIES}) 76 | add_dependencies(emit_log ${DEPENDENCIES}) 77 | 78 | add_executable(receive_logs_direct receive_logs_direct.cpp) 79 | target_link_libraries(receive_logs_direct ${LIBRARIES}) 80 | add_dependencies(receive_logs_direct ${DEPENDENCIES}) 81 | add_executable(emit_log_direct emit_log_direct.cpp) 82 | target_link_libraries(emit_log_direct ${LIBRARIES}) 83 | add_dependencies(emit_log_direct ${DEPENDENCIES}) 84 | 85 | add_executable(receive_logs_topic receive_logs_topic.cpp) 86 | target_link_libraries(receive_logs_topic ${LIBRARIES}) 87 | add_dependencies(receive_logs_topic ${DEPENDENCIES}) 88 | add_executable(emit_log_topic emit_log_topic.cpp) 89 | target_link_libraries(emit_log_topic ${LIBRARIES}) 90 | add_dependencies(emit_log_topic ${DEPENDENCIES}) 91 | 92 | add_executable(rpc_server rpc_server.cpp) 93 | target_link_libraries(rpc_server ${LIBRARIES}) 94 | add_dependencies(rpc_server ${DEPENDENCIES}) 95 | add_executable(rpc_client rpc_client.cpp) 96 | target_link_libraries(rpc_client ${LIBRARIES}) 97 | add_dependencies(rpc_client ${DEPENDENCIES}) 98 | --------------------------------------------------------------------------------