900 lines
28 KiB
C++
900 lines
28 KiB
C++
#include <copernica/amqp.h>
|
|
#include <copernica/network.h>
|
|
#include <iomanip>
|
|
#include "amqpbasicframe.h"
|
|
|
|
// namespaces to use
|
|
using namespace std;
|
|
using namespace Copernica;
|
|
|
|
/**
|
|
* Our own socket handler
|
|
*/
|
|
class SocketHandler : public Network::TcpHandler
|
|
{
|
|
private:
|
|
/**
|
|
* Status of the connection, and substatuses
|
|
* @var int
|
|
*/
|
|
int _status;
|
|
int _connectionStatus;
|
|
int _channelStatus;
|
|
int _exchangeStatus;
|
|
int _qosStatus;
|
|
int _queueStatus;
|
|
int _basicStatus;
|
|
int _deleteStatus;
|
|
int _restStatus;
|
|
|
|
AMQP::AMQPBasic _basic;
|
|
|
|
/**
|
|
* Channel we're working on
|
|
* @var int
|
|
*/
|
|
uint16_t _channel;
|
|
|
|
std::string _exchangeName;
|
|
std::string _queueName;
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
SocketHandler() : _status(0), _connectionStatus(0), _channelStatus(0), _qosStatus(0), _exchangeStatus(0), _queueStatus(0), _basicStatus(0), _deleteStatus(0), _restStatus(0), _basic(), _channel(0), _exchangeName("testexchange"), _queueName("testqueue") {}
|
|
|
|
/**
|
|
* Virtual destructor
|
|
*/
|
|
virtual ~SocketHandler() {}
|
|
|
|
/**
|
|
* Method that is called when the connection failed
|
|
* @param socket Pointer to the socket
|
|
*/
|
|
virtual void onFailure(Network::TcpSocket *socket)
|
|
{
|
|
cout << "connection failure" << endl;
|
|
}
|
|
|
|
/**
|
|
* Method that is called when the connection timed out (which also is a failure
|
|
* @param socket Pointer to the socket
|
|
*/
|
|
virtual void onTimeout(Network::TcpSocket *socket)
|
|
{
|
|
cout << "connection timeout" << endl;
|
|
}
|
|
|
|
/**
|
|
* Method that is called when the connection succeeded
|
|
* @param socket Pointer to the socket
|
|
*/
|
|
virtual void onConnected(Network::TcpSocket *socket)
|
|
{
|
|
if(_status == 0){ // send protocol header frame
|
|
AMQP::ProtocolHeaderFrame frame;
|
|
socket->write(frame.buffer(), frame.size());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method that is called when the socket is closed (as a result of a TcpSocket::close() call)
|
|
* @param socket Pointer to the socket
|
|
*/
|
|
virtual void onClosed(Network::TcpSocket *socket)
|
|
{
|
|
cout << "connection closed" << endl;
|
|
}
|
|
|
|
/**
|
|
* Method that is called when the peer closed the connection
|
|
* @param socket Pointer to the socket
|
|
*/
|
|
virtual void onLost(Network::TcpSocket *socket)
|
|
{
|
|
cout << "connection lost" << endl;
|
|
}
|
|
|
|
/**
|
|
* Method that is called when data is received on the socket
|
|
* @param socket Pointer to the socket
|
|
* @param buffer Pointer to the filled input buffer
|
|
*/
|
|
virtual void onData(Network::TcpSocket *socket, Network::Buffer *buffer)
|
|
{
|
|
// try getting a frame
|
|
auto frame = AMQP::Frame::decode(buffer->data(), buffer->length());
|
|
if(frame == nullptr)
|
|
{
|
|
std::cout << "error decoding received frame" << std::endl;
|
|
|
|
return;
|
|
}
|
|
if(_status != 5) buffer->shrink(frame->totalSize());
|
|
if(_status == 0)
|
|
{
|
|
// the connection hasn't been set up, do this now.
|
|
setupConnection(*socket, *buffer, frame);
|
|
}
|
|
if(_status == 1)
|
|
{
|
|
// time to setup the channel
|
|
setupChannel(*socket, *buffer, frame);
|
|
}
|
|
if(_status == 2)
|
|
{
|
|
// time to do the QOS stuff
|
|
setupQOS(*socket, *buffer, frame);
|
|
}
|
|
if(_status == 3)
|
|
{
|
|
// setup the exchange
|
|
setupExchange(*socket, *buffer, frame);
|
|
}
|
|
if(_status == 4)
|
|
{
|
|
// setup the queue
|
|
setupQueue(*socket, *buffer, frame);
|
|
}
|
|
if(_status == 5)
|
|
{
|
|
// publish testing etc
|
|
testBasicFunctionalities(*socket, *buffer, frame);
|
|
}
|
|
if(_status == 6)
|
|
{
|
|
testRestStuff(*socket, *buffer, frame);
|
|
}
|
|
if(_status == 7)
|
|
{
|
|
// start deleting everything.
|
|
deleteAMQP(*socket, *buffer, frame);
|
|
}
|
|
if(_status == 8)
|
|
{
|
|
socket->close();
|
|
}
|
|
}
|
|
|
|
|
|
void testRestStuff(Network::TcpSocket &socket, Network::Buffer &buffer, std::shared_ptr<AMQP::Frame> &frame)
|
|
{
|
|
if(_restStatus == 0)
|
|
{
|
|
std::cout << "rest testing";
|
|
std::string consumertag = "";
|
|
auto *sendframe = new AMQP::BasicCancelFrame(_channel, consumertag, false);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_restStatus++;
|
|
delete sendframe;
|
|
return; // wait for response
|
|
}
|
|
if(_restStatus == 1)
|
|
{
|
|
auto f = std::dynamic_pointer_cast<AMQP::BasicCancelOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to BasicCancelOKFrame, should work"<<std::endl; return; }
|
|
_restStatus = 5;
|
|
}
|
|
if(_restStatus == 2)
|
|
{
|
|
auto *sendframe = new AMQP::BasicRecoverFrame(_channel, true);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_restStatus++;
|
|
delete sendframe;
|
|
return; // wait for response
|
|
}
|
|
if(_restStatus == 3)
|
|
{
|
|
auto f = std::dynamic_pointer_cast<AMQP::BasicRecoverOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to BasicRecoverOKFrame, should work"<<std::endl; return; }
|
|
_restStatus++;
|
|
}
|
|
if(_restStatus == 4)
|
|
{
|
|
auto *sendframe = new AMQP::BasicRecoverAsyncFrame(_channel, true);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_restStatus++;
|
|
delete sendframe;
|
|
// recover async does not wait for response.
|
|
}
|
|
if(_restStatus == 5)
|
|
{
|
|
declareQueue(socket, buffer);
|
|
_restStatus++;
|
|
return; //wait
|
|
}
|
|
if(_restStatus == 6)
|
|
{
|
|
waitDeclareQueueOK(buffer, frame);
|
|
_restStatus = 20;
|
|
}
|
|
|
|
if(_restStatus == 20)
|
|
{
|
|
purgeQueue(socket, buffer);
|
|
_restStatus++;
|
|
return;
|
|
}
|
|
|
|
if(_restStatus == 21)
|
|
{
|
|
waitPurgeQueueOK(buffer, frame);
|
|
_restStatus = 7;
|
|
}
|
|
|
|
|
|
if(_restStatus == 7)
|
|
{
|
|
auto *sendframe = new AMQP::TransactionSelectFrame(_channel);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_restStatus++;
|
|
delete sendframe;
|
|
return; // wait for response
|
|
}
|
|
if(_restStatus == 8)
|
|
{
|
|
auto f = std::dynamic_pointer_cast<AMQP::TransactionSelectOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to TransactionSelectOKFrame, should work"<<std::endl; return; }
|
|
_restStatus++;
|
|
}
|
|
if(_restStatus == 9)
|
|
{
|
|
auto *sendframe = new AMQP::TransactionCommitFrame(_channel);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_restStatus++;
|
|
delete sendframe;
|
|
return; // wait for response
|
|
}
|
|
if(_restStatus == 10)
|
|
{
|
|
auto f = std::dynamic_pointer_cast<AMQP::TransactionCommitOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to TransactionCommitOKFrame, should work"<<std::endl; return; }
|
|
_restStatus++;
|
|
}
|
|
if(_restStatus == 11)
|
|
{
|
|
auto *sendframe = new AMQP::TransactionRollbackFrame(_channel);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_restStatus++;
|
|
delete sendframe;
|
|
return; // wait for response
|
|
}
|
|
if(_restStatus == 12)
|
|
{
|
|
auto f = std::dynamic_pointer_cast<AMQP::TransactionRollbackOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to TransactionRollbackOKFrame, should work"<<std::endl; return; }
|
|
_restStatus++;
|
|
}
|
|
|
|
|
|
|
|
std::cout << " ... DONE" << std::endl;
|
|
_status++;
|
|
}
|
|
|
|
|
|
int deliverHeaderBody(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr<AMQP::Frame> &frame)
|
|
{
|
|
int lastDeliveryTag = 0;
|
|
while(buffer.length() > 0)
|
|
{
|
|
if(_basicStatus != 20)
|
|
{
|
|
frame = AMQP::Frame::decode(buffer.data(), buffer.length());
|
|
buffer.shrink(frame->totalSize());
|
|
}
|
|
auto f = std::dynamic_pointer_cast<AMQP::BasicDeliverFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to BasicDeliverFrame, should work"<<std::endl; return 0; }
|
|
|
|
|
|
lastDeliveryTag = f->deliveryTag();
|
|
|
|
frame = AMQP::Frame::decode(buffer.data(), buffer.length());
|
|
auto f2 = std::dynamic_pointer_cast<AMQP::BasicHeaderFrame>(frame);
|
|
if(f2 == nullptr){ std::cout<<"Error casting to BasicHeaderFrame, should work"<<std::endl; return 0; }
|
|
buffer.shrink(f2->totalSize());
|
|
|
|
int bytesRead = f2->bodySize();
|
|
|
|
while(bytesRead > 0)
|
|
{
|
|
frame = AMQP::Frame::decode(buffer.data(), buffer.length());
|
|
auto f3 = std::dynamic_pointer_cast<AMQP::BodyFrame>(frame);
|
|
if(f3 == nullptr){ std::cout<<"Error casting to BodyFrame, should work"<<std::endl; return 0; }
|
|
buffer.shrink(f3->totalSize());
|
|
|
|
auto payload = f3->payload();
|
|
bytesRead -= payload.size();
|
|
}
|
|
}
|
|
return lastDeliveryTag;
|
|
}
|
|
|
|
|
|
|
|
void testBasicFunctionalities(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr<AMQP::Frame> &frame)
|
|
{
|
|
int lastDeliveryTag = 0;
|
|
if(_basicStatus == 0)
|
|
{ // basic publish
|
|
std::cout << "basic testing";
|
|
_basic.sendPublish(socket);
|
|
_basicStatus++;
|
|
}
|
|
|
|
if(_basicStatus == 1)
|
|
{ // content header
|
|
_basic.sendHeader(socket);
|
|
_basicStatus++;
|
|
|
|
}
|
|
if(_basicStatus == 2)
|
|
{ // content body
|
|
for(int i = 0 ; i < 10; i++) { _basic.sendBody(socket); }
|
|
_basicStatus++;
|
|
|
|
}
|
|
if(_basicStatus == 3)
|
|
{ // basic consume frame
|
|
_basic.sendConsume(socket);
|
|
_basicStatus++;
|
|
return;
|
|
}
|
|
|
|
|
|
if(_basicStatus == 4)
|
|
{
|
|
_basic.waitConsumeOK(buffer);
|
|
_basicStatus++;
|
|
}
|
|
|
|
if(_basicStatus == 5)
|
|
{ // received consumeok frame, let's work on those basic deliver, content header, content body frames.
|
|
_basic.waitDeliver(buffer);
|
|
_basic.waitHeader(buffer);
|
|
_basic.waitBody(buffer);
|
|
_basicStatus++;
|
|
}
|
|
|
|
// done reading all incoming messages, ack them.
|
|
if(_basicStatus == 6)
|
|
{
|
|
_basic.sendAck(socket);
|
|
_basicStatus+=2;
|
|
}
|
|
|
|
if(_basicStatus == 8)
|
|
{ // send a basic get frame
|
|
_basic.sendGet(socket);
|
|
_basicStatus++;
|
|
return; // wait for response
|
|
}
|
|
|
|
|
|
if(_basicStatus == 9)
|
|
{ // expect a basic-get-empty frame (at 5 & 6 we've cleared the queue)
|
|
|
|
_basic.waitGetEmpty(buffer);
|
|
_basicStatus ++;
|
|
}
|
|
|
|
|
|
if(_basicStatus == 10)
|
|
{ // send some more data to the queue, to test basicgetok
|
|
for(int i = 0; i < 5; i++){
|
|
_basic.sendPublish(socket);
|
|
_basic.sendHeader(socket);
|
|
for(int i = 0; i < 10; i++) { _basic.sendBody(socket); }
|
|
}
|
|
_basicStatus++;
|
|
}
|
|
|
|
|
|
if(_basicStatus == 11)
|
|
{ // send a basic get frame
|
|
_basic.sendGet(socket);
|
|
_basicStatus++;
|
|
return; // wait for response
|
|
}
|
|
|
|
|
|
|
|
if(_basicStatus == 12)
|
|
{ // expect a basic-get-empty frame (at 5 & 6 we've cleared the queue)
|
|
_basic.waitGetOK(buffer);
|
|
_basic.waitHeader(buffer);
|
|
_basic.waitBody(buffer);
|
|
_basicStatus++;
|
|
}
|
|
|
|
if(_basicStatus == 13)
|
|
{ // received consumeok frame, let's work on those basic deliver, content header, content body frames.
|
|
while(buffer.length() > 0)
|
|
{
|
|
_basic.waitDeliver(buffer);
|
|
_basic.waitHeader(buffer);
|
|
_basic.waitBody(buffer);
|
|
}
|
|
_basicStatus++;
|
|
}
|
|
|
|
if(_basicStatus == 14)
|
|
{
|
|
// add some more messages to the queue
|
|
_basic.sendPublish(socket);
|
|
_basic.sendHeader(socket, 9);
|
|
_basic.sendBody(socket);
|
|
_basicStatus++;
|
|
}
|
|
|
|
if(_basicStatus == 15)
|
|
{
|
|
// channel flow frame
|
|
auto *sendframe2 = new AMQP::ChannelFlowFrame(_channel, true);
|
|
socket.write(sendframe2->buffer(), sendframe2->totalSize());
|
|
_basicStatus++;
|
|
delete sendframe2;
|
|
return; // wait for response
|
|
}
|
|
|
|
|
|
if(_basicStatus == 16)
|
|
{
|
|
// check if we've received a channelflowokframe
|
|
auto f = std::dynamic_pointer_cast<AMQP::ChannelFlowOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to channelflowokframe, should work"<<std::endl; return; }
|
|
buffer.shrink(frame->totalSize());
|
|
_basicStatus++;
|
|
}
|
|
|
|
if(_basicStatus == 17)
|
|
{
|
|
_status++;
|
|
std::cout << " ... DONE" << std::endl;
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
void purgeQueue(Network::TcpSocket& socket, Network::Buffer& buffer)
|
|
{
|
|
auto *sendframe = new AMQP::QueuePurgeFrame(_channel, _queueName);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
delete sendframe;
|
|
}
|
|
|
|
void waitPurgeQueueOK( Network::Buffer& buffer, std::shared_ptr<AMQP::Frame> &frame)
|
|
{
|
|
auto f = std::dynamic_pointer_cast<AMQP::QueuePurgeOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to QueuePurgeOKFrame, should work"<<std::endl; return; }
|
|
buffer.shrink(frame->totalSize());
|
|
}
|
|
|
|
void deleteAMQP(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr<AMQP::Frame> &frame)
|
|
{
|
|
// queue deletion stuff
|
|
|
|
// for purge testing, let's add a message to the queue (in case it is empty)
|
|
if(_deleteStatus == 0)
|
|
{ // nothing deleted so far
|
|
// queue purge
|
|
auto *sendframe = new AMQP::QueuePurgeFrame(_channel, _queueName);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_deleteStatus++;
|
|
delete sendframe;
|
|
return; // wait for response
|
|
}
|
|
if(_deleteStatus == 1)
|
|
{ // nothing deleted so far
|
|
// queue purge ok
|
|
auto f = std::dynamic_pointer_cast<AMQP::QueuePurgeOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to QueuePurgeOKFrame, should work"<<std::endl; return; }
|
|
buffer.shrink(frame->totalSize());
|
|
|
|
_deleteStatus++;
|
|
}
|
|
|
|
if(_deleteStatus == 2)
|
|
{ // nothing deleted so far
|
|
std::cout << "cleanup";
|
|
// unbind queue
|
|
auto *sendframe = new AMQP::QueueUnbindFrame(_channel, _queueName, _exchangeName);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_deleteStatus++;
|
|
delete sendframe;
|
|
return; // wait for response
|
|
}
|
|
if(_deleteStatus == 3)
|
|
{ // nothing deleted so far
|
|
// unbind queue ok
|
|
auto f = std::dynamic_pointer_cast<AMQP::QueueUnbindOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to QueueUnbindOKFrame, should work"<<std::endl; return; }
|
|
buffer.shrink(frame->totalSize());
|
|
|
|
_deleteStatus++;
|
|
}
|
|
if(_deleteStatus == 4)
|
|
{ // nothing deleted so far
|
|
// queue delete
|
|
auto *sendframe = new AMQP::QueueDeleteFrame(_channel, _queueName);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_deleteStatus++;
|
|
delete sendframe;
|
|
return; // wait for response
|
|
}
|
|
if(_deleteStatus == 5)
|
|
{ // nothing deleted so far
|
|
//// queue delete ok
|
|
auto f = std::dynamic_pointer_cast<AMQP::QueueDeleteOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to QueueDeleteOKFrame, should work"<<std::endl; return; }
|
|
buffer.shrink(frame->totalSize());
|
|
|
|
_deleteStatus++;
|
|
}
|
|
|
|
//exchange deletion
|
|
if(_deleteStatus == 6)
|
|
{ // send exchange delete
|
|
auto *sendframe = new AMQP::ExchangeDeleteFrame(_channel, _exchangeName);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_deleteStatus++;
|
|
delete sendframe;
|
|
return; // wait for response
|
|
}
|
|
if(_deleteStatus == 7)
|
|
{ // expect exchangedeleteok
|
|
auto f = std::dynamic_pointer_cast<AMQP::ExchangeDeleteOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to ExchangeDeleteOKFrame, should work"<<std::endl; return; }
|
|
buffer.shrink(frame->totalSize());
|
|
|
|
_deleteStatus++;
|
|
}
|
|
|
|
// channel close
|
|
if(_deleteStatus == 8)
|
|
{ // send channel close
|
|
std::string replyText = "200";
|
|
auto *sendframe = new AMQP::ChannelCloseFrame(_channel, 200, replyText);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_deleteStatus++;
|
|
|
|
delete sendframe;
|
|
return; // wait for response
|
|
}
|
|
if(_deleteStatus == 9)
|
|
{ // expect channelcloseok
|
|
auto f = std::dynamic_pointer_cast<AMQP::ChannelCloseOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to ChannelCloseOKFrame, should work"<<std::endl; return; }
|
|
buffer.shrink(frame->totalSize());
|
|
|
|
_deleteStatus++;
|
|
}
|
|
|
|
// connection close
|
|
if(_deleteStatus == 10)
|
|
{ // send exchange delete
|
|
std::string replyText = "200";
|
|
auto *sendframe = new AMQP::ConnectionCloseFrame(0, 200, replyText);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_deleteStatus++;
|
|
|
|
delete sendframe;
|
|
return; // wait for response
|
|
}
|
|
|
|
if(_deleteStatus == 11)
|
|
{ // expect exchangedeleteok
|
|
auto f = std::dynamic_pointer_cast<AMQP::ConnectionCloseOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to ConnectionCloseOKFrame, should work"<<std::endl; return; }
|
|
buffer.shrink(frame->totalSize());
|
|
|
|
_deleteStatus++;
|
|
_status++;
|
|
|
|
std::cout << " ... DONE" << std::endl;
|
|
}
|
|
}
|
|
|
|
|
|
void declareQueue(Network::TcpSocket& socket, Network::Buffer& buffer)
|
|
{
|
|
auto *sendframe = new AMQP::QueueDeclareFrame(_channel, _queueName, false, true, false, false, false);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_queueStatus++;
|
|
delete sendframe;
|
|
}
|
|
|
|
void waitDeclareQueueOK(Network::Buffer& buffer, std::shared_ptr<AMQP::Frame> &frame)
|
|
{
|
|
auto f = std::dynamic_pointer_cast<AMQP::QueueDeclareOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to QueueDeclareOKFrame, should work"<<std::endl; return; }
|
|
buffer.shrink(frame->totalSize());
|
|
_queueStatus++;
|
|
}
|
|
|
|
void setupQueue(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr<AMQP::Frame> &frame)
|
|
{
|
|
if(_queueStatus == 0)
|
|
{ // nothing has been done in the queue world
|
|
std::cout << "set up queue " << _queueName;
|
|
// send a queue declare frame
|
|
declareQueue(socket, buffer);
|
|
return; //wait for response
|
|
}
|
|
if(_queueStatus == 1)
|
|
{
|
|
waitDeclareQueueOK(buffer, frame);
|
|
}
|
|
if(_queueStatus == 2)
|
|
{
|
|
auto *sendframe = new AMQP::QueueBindFrame(_channel, _queueName, _exchangeName);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_queueStatus++;
|
|
delete sendframe;
|
|
return; // wait for response
|
|
}
|
|
if(_queueStatus == 3)
|
|
{
|
|
auto f = std::dynamic_pointer_cast<AMQP::QueueBindOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to QueueBindOKFrame, should work"<<std::endl; return; }
|
|
buffer.shrink(frame->totalSize());
|
|
|
|
_queueStatus++;
|
|
_status++;
|
|
std::cout << " ... DONE" << std::endl;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void setupQOS(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr<AMQP::Frame> &frame)
|
|
{
|
|
if(_qosStatus == 0)
|
|
{ // nothing has been done in the qos world
|
|
std::cout << "set up qos";
|
|
// send the basic qos packet
|
|
auto *sendframe = new AMQP::BasicQosFrame(_channel, 0, 3, false);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_qosStatus++;
|
|
delete sendframe;
|
|
return; // we wait for a response
|
|
}
|
|
if(_qosStatus == 1)
|
|
{
|
|
auto f = std::dynamic_pointer_cast<AMQP::BasicQosOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to basicqosokframe, should work"<<std::endl; return; }
|
|
buffer.shrink(frame->totalSize());
|
|
_status++;
|
|
std::cout << " ... DONE" << std::endl;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void setupChannel(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr<AMQP::Frame> &frame)
|
|
{
|
|
if(_channelStatus == 0)
|
|
{ // nothing has been done in the channel world.
|
|
std::cout << "set up channel";
|
|
// we send the channel open frame
|
|
_channel = 1;
|
|
auto *sendframe = new AMQP::ChannelOpenFrame(_channel);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_channelStatus++;
|
|
|
|
delete sendframe;
|
|
return; // we wait for the response
|
|
}
|
|
if(_channelStatus == 1)
|
|
{
|
|
// check if we've received a channel open ok response
|
|
auto f = std::dynamic_pointer_cast<AMQP::ChannelOpenOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to channelopenokframe, should work"<<std::endl; return; }
|
|
buffer.shrink(frame->totalSize());
|
|
|
|
_channelStatus++;
|
|
// received a response, send a new frame
|
|
}
|
|
if(_channelStatus == 2)
|
|
{
|
|
// channel flow frame
|
|
auto *sendframe2 = new AMQP::ChannelFlowFrame(_channel, true);
|
|
socket.write(sendframe2->buffer(), sendframe2->totalSize());
|
|
_channelStatus++;
|
|
delete sendframe2;
|
|
return; // wait for response
|
|
}
|
|
if(_channelStatus == 3)
|
|
{
|
|
// check if we've received a channelflowokframe
|
|
auto f = std::dynamic_pointer_cast<AMQP::ChannelFlowOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to channelflowokframe, should work"<<std::endl; return; }
|
|
buffer.shrink(frame->totalSize());
|
|
_status++;
|
|
_channelStatus++;
|
|
|
|
std::cout << " ... DONE" << std::endl;
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void setupExchange(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr<AMQP::Frame> &frame)
|
|
{
|
|
if(_exchangeStatus == 0)
|
|
{ // nothing has been done in the exchange world.
|
|
std::cout << "set up exchange";
|
|
// create an exchange declare frame
|
|
const AMQP::Table *t = new AMQP::Table();
|
|
std::string type = "direct";
|
|
auto *sendframe = new AMQP::ExchangeDeclareFrame(_channel, _exchangeName, type, false, true, false, *t);
|
|
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
_exchangeStatus++;
|
|
|
|
delete t;
|
|
delete sendframe;
|
|
return; // await response
|
|
}
|
|
if(_exchangeStatus == 1)
|
|
{ // expect an exchangedeclareokframe
|
|
auto f = std::dynamic_pointer_cast<AMQP::ExchangeDeclareOKFrame>(frame);
|
|
if(f == nullptr){ std::cout<<"Error casting to exchangedeclareokframe, should work"<<std::endl; return; }
|
|
buffer.shrink(frame->totalSize());
|
|
_status++;
|
|
_exchangeStatus++;
|
|
std::cout << " ... DONE" << std::endl;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void setupConnection(Network::TcpSocket& socket, Network::Buffer& buffer, std::shared_ptr<AMQP::Frame> &frame)
|
|
{
|
|
// received connectionStart frame, send connectionStartOK frame
|
|
if(_connectionStatus == 0)
|
|
{
|
|
std::cout << "set up connection";
|
|
auto f = std::dynamic_pointer_cast<AMQP::ConnectionStartFrame>(frame);
|
|
if(f == nullptr)
|
|
{
|
|
std::cout << "error casting to connectionstartframe, should work??" << std::endl;
|
|
return;
|
|
}
|
|
buffer.shrink(frame->totalSize());
|
|
AMQP::Table *properties = new AMQP::Table();
|
|
|
|
std::string mechanism = "PLAIN";
|
|
std::string *response = new std::string("\0micha\0micha", 12);
|
|
std::string locales = "en_US";
|
|
auto *sendframe = new AMQP::ConnectionStartOKFrame(_channel, *properties, mechanism, *response, locales);
|
|
socket.write(sendframe->buffer(), sendframe->totalSize());
|
|
|
|
delete response;
|
|
delete sendframe;
|
|
delete properties;
|
|
_connectionStatus++;
|
|
return; // we wait for a response
|
|
}
|
|
|
|
// received connectionTuneFrame, probably
|
|
if(_connectionStatus == 1)
|
|
{
|
|
auto f = std::dynamic_pointer_cast<AMQP::ConnectionTuneFrame>(frame);
|
|
if(f == nullptr)
|
|
{
|
|
std::cout << "error casting to connectiontuneframe, should work??" << std::endl;
|
|
return;
|
|
}
|
|
uint16_t channelMax = 10;
|
|
uint32_t frameMax = 131072;
|
|
uint16_t heartbeat = 0;
|
|
auto *conopframe = new AMQP::ConnectionTuneOKFrame(_channel, channelMax, frameMax, heartbeat);
|
|
socket.write(conopframe->buffer(), conopframe->totalSize());
|
|
_connectionStatus++;
|
|
|
|
delete conopframe;
|
|
|
|
// we respond to the server, now send a new frame
|
|
}
|
|
if(_connectionStatus == 2)
|
|
{
|
|
// after sending the tuneok frame, send the connection open frame
|
|
std::string vhost = "/";
|
|
// rest of the fields are deprecated, the constructor handles that for us
|
|
|
|
auto *conopframe = new AMQP::ConnectionOpenFrame(_channel, vhost);
|
|
socket.write(conopframe->buffer(), conopframe->totalSize());
|
|
_connectionStatus++;
|
|
|
|
delete conopframe;
|
|
return; // we await a response
|
|
}
|
|
if(_connectionStatus == 3)
|
|
{
|
|
// we probably received the connection open ok frame
|
|
buffer.shrink(frame->totalSize());
|
|
_status++;
|
|
std::cout << " ... DONE" << std::endl;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method that is called when the internal buffers are emptied and the socket
|
|
* is in a writable state again. It is also called after a call to TcpSocket::wait()
|
|
*/
|
|
virtual void onWritable(Network::TcpSocket *socket)
|
|
{
|
|
|
|
cout << "socket writable" << endl;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Main procedure
|
|
* @param argc
|
|
* @param argv
|
|
* @return int
|
|
*/
|
|
int main(int argc, const char *argv[])
|
|
{
|
|
// our own handler
|
|
SocketHandler tcphandler;
|
|
|
|
// create a socket
|
|
Network::TcpSocket socket(Event::MainLoop::instance(), &tcphandler);
|
|
|
|
// connect to the socket
|
|
socket.connect(Network::Ipv4Address("127.0.0.1"), 5672);
|
|
|
|
std::cout << "start main loop" << std::endl;
|
|
|
|
// run the main event loop
|
|
Event::MainLoop::instance()->run();
|
|
|
|
std::cout << "exited main loop" << std::endl;
|
|
|
|
// done
|
|
return 0;
|
|
}
|