2015-11-17 16:33:28 +08:00
|
|
|
/**
|
|
|
|
|
* LibEV.cpp
|
|
|
|
|
*
|
|
|
|
|
* Test program to check AMQP functionality based on LibEV
|
|
|
|
|
*
|
|
|
|
|
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
|
2022-11-24 05:09:15 +08:00
|
|
|
* @copyright 2015 - 2022 Copernica BV
|
2015-11-17 16:33:28 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Dependencies
|
|
|
|
|
*/
|
|
|
|
|
#include <ev.h>
|
|
|
|
|
#include <amqpcpp.h>
|
|
|
|
|
#include <amqpcpp/libev.h>
|
2018-03-07 01:07:34 +08:00
|
|
|
#include <openssl/ssl.h>
|
2018-03-08 20:36:56 +08:00
|
|
|
#include <openssl/opensslv.h>
|
2015-11-17 16:33:28 +08:00
|
|
|
|
2017-11-17 19:18:04 +08:00
|
|
|
/**
|
|
|
|
|
* Custom handler
|
|
|
|
|
*/
|
|
|
|
|
class MyHandler : public AMQP::LibEvHandler
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
/**
|
|
|
|
|
* Method that is called when a connection error occurs
|
|
|
|
|
* @param connection
|
|
|
|
|
* @param message
|
|
|
|
|
*/
|
|
|
|
|
virtual void onError(AMQP::TcpConnection *connection, const char *message) override
|
|
|
|
|
{
|
|
|
|
|
std::cout << "error: " << message << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Method that is called when the TCP connection ends up in a connected state
|
|
|
|
|
* @param connection The TCP connection
|
|
|
|
|
*/
|
|
|
|
|
virtual void onConnected(AMQP::TcpConnection *connection) override
|
|
|
|
|
{
|
|
|
|
|
std::cout << "connected" << std::endl;
|
|
|
|
|
}
|
2018-11-08 00:34:35 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Method that is called when the TCP connection ends up in a ready
|
|
|
|
|
* @param connection The TCP connection
|
|
|
|
|
*/
|
|
|
|
|
virtual void onReady(AMQP::TcpConnection *connection) override
|
|
|
|
|
{
|
|
|
|
|
std::cout << "ready" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Method that is called when the TCP connection is closed
|
|
|
|
|
* @param connection The TCP connection
|
|
|
|
|
*/
|
|
|
|
|
virtual void onClosed(AMQP::TcpConnection *connection) override
|
|
|
|
|
{
|
|
|
|
|
std::cout << "closed" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Method that is called when the TCP connection is detached
|
|
|
|
|
* @param connection The TCP connection
|
|
|
|
|
*/
|
|
|
|
|
virtual void onDetached(AMQP::TcpConnection *connection) override
|
|
|
|
|
{
|
|
|
|
|
std::cout << "detached" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-17 19:18:04 +08:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* Constructor
|
|
|
|
|
* @param ev_loop
|
|
|
|
|
*/
|
|
|
|
|
MyHandler(struct ev_loop *loop) : AMQP::LibEvHandler(loop) {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Destructor
|
|
|
|
|
*/
|
|
|
|
|
virtual ~MyHandler() = default;
|
|
|
|
|
};
|
|
|
|
|
|
2018-04-13 15:45:57 +08:00
|
|
|
/**
|
|
|
|
|
* Class that runs a timer
|
|
|
|
|
*/
|
|
|
|
|
class MyTimer
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
/**
|
|
|
|
|
* The actual watcher structure
|
|
|
|
|
* @var struct ev_io
|
|
|
|
|
*/
|
|
|
|
|
struct ev_timer _timer;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Pointer towards the AMQP channel
|
|
|
|
|
* @var AMQP::TcpChannel
|
|
|
|
|
*/
|
|
|
|
|
AMQP::TcpChannel *_channel;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Name of the queue
|
|
|
|
|
* @var std::string
|
|
|
|
|
*/
|
|
|
|
|
std::string _queue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Callback method that is called by libev when the timer expires
|
|
|
|
|
* @param loop The loop in which the event was triggered
|
|
|
|
|
* @param timer Internal timer object
|
|
|
|
|
* @param revents The events that triggered this call
|
|
|
|
|
*/
|
|
|
|
|
static void callback(struct ev_loop *loop, struct ev_timer *timer, int revents)
|
|
|
|
|
{
|
|
|
|
|
// retrieve the this pointer
|
|
|
|
|
MyTimer *self = static_cast<MyTimer*>(timer->data);
|
|
|
|
|
|
|
|
|
|
// publish a message
|
|
|
|
|
self->_channel->publish("", self->_queue, "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* Constructor
|
|
|
|
|
* @param loop
|
|
|
|
|
* @param channel
|
|
|
|
|
* @param queue
|
|
|
|
|
*/
|
|
|
|
|
MyTimer(struct ev_loop *loop, AMQP::TcpChannel *channel, std::string queue) :
|
|
|
|
|
_channel(channel), _queue(std::move(queue))
|
|
|
|
|
{
|
|
|
|
|
// initialize the libev structure
|
2018-11-08 00:34:35 +08:00
|
|
|
ev_timer_init(&_timer, callback, 0.005, 1.005);
|
2018-04-13 15:45:57 +08:00
|
|
|
|
|
|
|
|
// this object is the data
|
|
|
|
|
_timer.data = this;
|
|
|
|
|
|
|
|
|
|
// and start it
|
|
|
|
|
ev_timer_start(loop, &_timer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Destructor
|
|
|
|
|
*/
|
|
|
|
|
virtual ~MyTimer()
|
|
|
|
|
{
|
|
|
|
|
// @todo to be implemented
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2015-11-17 16:33:28 +08:00
|
|
|
/**
|
|
|
|
|
* Main program
|
|
|
|
|
* @return int
|
|
|
|
|
*/
|
|
|
|
|
int main()
|
|
|
|
|
{
|
|
|
|
|
// access to the event loop
|
|
|
|
|
auto *loop = EV_DEFAULT;
|
|
|
|
|
|
|
|
|
|
// handler for libev
|
2017-11-17 19:18:04 +08:00
|
|
|
MyHandler handler(loop);
|
2018-03-06 02:53:53 +08:00
|
|
|
|
|
|
|
|
// init the SSL library
|
2018-03-08 20:36:56 +08:00
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
|
|
|
SSL_library_init();
|
|
|
|
|
#else
|
|
|
|
|
OPENSSL_init_ssl(0, NULL);
|
|
|
|
|
#endif
|
2018-03-06 02:53:53 +08:00
|
|
|
|
2015-11-17 16:33:28 +08:00
|
|
|
// make a connection
|
2018-03-08 21:02:15 +08:00
|
|
|
AMQP::Address address("amqp://guest:guest@localhost/");
|
2018-03-09 20:55:49 +08:00
|
|
|
// AMQP::Address address("amqps://guest:guest@localhost/");
|
2018-03-02 19:54:09 +08:00
|
|
|
AMQP::TcpConnection connection(&handler, address);
|
2018-03-02 23:56:35 +08:00
|
|
|
|
2015-11-17 16:33:28 +08:00
|
|
|
// we need a channel too
|
|
|
|
|
AMQP::TcpChannel channel(&connection);
|
2018-03-02 23:56:35 +08:00
|
|
|
|
2015-11-17 16:33:28 +08:00
|
|
|
// create a temporary queue
|
2022-11-24 05:09:15 +08:00
|
|
|
channel.declareQueue(AMQP::exclusive).onSuccess([&connection, &channel, loop](const std::string &queuename, uint32_t messagecount, uint32_t consumercount) {
|
2015-11-17 16:33:28 +08:00
|
|
|
|
|
|
|
|
// report the name of the temporary queue
|
2022-11-24 05:09:15 +08:00
|
|
|
std::cout << "declared queue " << queuename << std::endl;
|
2018-03-08 17:44:42 +08:00
|
|
|
|
|
|
|
|
// close the channel
|
2018-04-13 15:45:57 +08:00
|
|
|
//channel.close().onSuccess([&connection, &channel]() {
|
|
|
|
|
//
|
|
|
|
|
// // report that channel was closed
|
|
|
|
|
// std::cout << "channel closed" << std::endl;
|
|
|
|
|
//
|
|
|
|
|
// // close the connection
|
|
|
|
|
// connection.close();
|
|
|
|
|
//});
|
|
|
|
|
|
|
|
|
|
// construct a timer that is going to publish stuff
|
2022-11-24 05:09:15 +08:00
|
|
|
auto *timer = new MyTimer(loop, &channel, queuename);
|
|
|
|
|
|
|
|
|
|
// start a consumer
|
|
|
|
|
channel.consume(queuename).onSuccess([](const std::string &tag) {
|
|
|
|
|
|
|
|
|
|
// the consumer is ready
|
|
|
|
|
std::cout << "started consuming with tag " << tag << std::endl;
|
|
|
|
|
|
|
|
|
|
}).onCancelled([](const std::string &tag) {
|
|
|
|
|
|
|
|
|
|
// the consumer was cancelled by the server
|
|
|
|
|
std::cout << "consumer " << tag << " was cancelled" << std::endl;
|
|
|
|
|
|
|
|
|
|
}).onReceived([&channel, queuename](const AMQP::Message &message, uint64_t deliveryTag, bool redelivered) {
|
|
|
|
|
|
|
|
|
|
std::cout << "received " << deliveryTag << std::endl;
|
|
|
|
|
|
|
|
|
|
// we remove the queue -- to see if this indeed causes the onCancelled method to be called
|
|
|
|
|
if (deliveryTag > 3) channel.removeQueue(queuename);
|
|
|
|
|
|
|
|
|
|
// ack the message
|
|
|
|
|
channel.ack(deliveryTag);
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
2018-11-08 00:34:35 +08:00
|
|
|
|
|
|
|
|
//connection.close();
|
2015-11-17 16:33:28 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// run the loop
|
|
|
|
|
ev_run(loop, 0);
|
|
|
|
|
|
|
|
|
|
// done
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|