├── .gitignore ├── .travis.yml ├── Doxyfile ├── LICENSE ├── README.md ├── qamqp.pri ├── qamqp.pro ├── src ├── .gitignore ├── qamqpInterface.pri ├── qamqpauthenticator.cpp ├── qamqpauthenticator.h ├── qamqpchannel.cpp ├── qamqpchannel.h ├── qamqpchannel_p.h ├── qamqpchannelhash.cpp ├── qamqpchannelhash_p.h ├── qamqpclient.cpp ├── qamqpclient.h ├── qamqpclient_p.h ├── qamqpexchange.cpp ├── qamqpexchange.h ├── qamqpexchange_p.h ├── qamqpframe.cpp ├── qamqpframe_p.h ├── qamqpglobal.h ├── qamqpmessage.cpp ├── qamqpmessage.h ├── qamqpmessage_p.h ├── qamqpqueue.cpp ├── qamqpqueue.h ├── qamqpqueue_p.h ├── qamqptable.cpp ├── qamqptable.h └── src.pro ├── tests ├── auto │ ├── auto.pro │ ├── qamqpchannel │ │ ├── qamqpchannel.pro │ │ └── tst_qamqpchannel.cpp │ ├── qamqpclient │ │ ├── certs.qrc │ │ ├── qamqpclient.pro │ │ └── tst_qamqpclient.cpp │ ├── qamqpexchange │ │ ├── qamqpexchange.pro │ │ └── tst_qamqpexchange.cpp │ └── qamqpqueue │ │ ├── qamqpqueue.pro │ │ └── tst_qamqpqueue.cpp ├── common │ ├── qamqptestcase.h │ └── signalspy.h ├── files │ ├── certs │ │ ├── client │ │ │ ├── cert.pem │ │ │ ├── key.pem │ │ │ ├── keycert.p12 │ │ │ └── req.pem │ │ ├── server │ │ │ ├── cert.pem │ │ │ ├── key.pem │ │ │ ├── keycert.p12 │ │ │ └── req.pem │ │ └── testca │ │ │ ├── cacert.cer │ │ │ ├── cacert.pem │ │ │ ├── certs │ │ │ ├── 01.pem │ │ │ └── 02.pem │ │ │ ├── index.txt │ │ │ ├── index.txt.attr │ │ │ ├── index.txt.attr.old │ │ │ ├── index.txt.old │ │ │ ├── openssl.cnf │ │ │ ├── private │ │ │ └── cakey.pem │ │ │ ├── serial │ │ │ └── serial.old │ └── travis │ │ ├── rabbitmq-setup.sh │ │ └── test-deps.sh ├── gen-coverage.sh ├── tests.pri └── tests.pro └── tutorials ├── helloworld ├── helloworld.pro ├── receive │ ├── main.cpp │ └── receive.pro └── send │ ├── main.cpp │ └── send.pro ├── pubsub ├── emit_log │ ├── emit_log.pro │ └── main.cpp ├── pubsub.pro └── receive_logs │ ├── main.cpp │ └── receive_logs.pro ├── routing ├── emit_log_direct │ ├── emit_log_direct.pro │ └── main.cpp ├── receive_logs_direct │ ├── main.cpp │ └── receive_logs_direct.pro └── routing.pro ├── rpc ├── rpc.pro ├── rpc_client │ ├── fibonaccirpcclient.cpp │ ├── fibonaccirpcclient.h │ ├── main.cpp │ └── rpc_client.pro └── rpc_server │ ├── main.cpp │ ├── rpc_server.pro │ ├── server.cpp │ └── server.h ├── topics ├── emit_log_topic │ ├── emit_log_topic.pro │ └── main.cpp ├── receive_logs_topic │ ├── main.cpp │ └── receive_logs_topic.pro └── topics.pro ├── tutorials.pro └── workqueues ├── new_task ├── main.cpp └── new_task.pro ├── worker ├── main.cpp └── worker.pro └── workqueues.pro /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | *.ncb 3 | *.suo 4 | /Debug 5 | /GeneratedFiles 6 | build -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | cache: apt 3 | env: 4 | - QT_SELECT=qt4 5 | - QT_SELECT=qt5 6 | services: 7 | - rabbitmq 8 | before_install: 9 | - sudo pip install cpp-coveralls 10 | install: 11 | - tests/files/travis/test-deps.sh 12 | script: 13 | - qmake -config gcov 14 | - make 15 | - make check 16 | after_success: 17 | - coveralls -e tutorials -e tests -E ".moc_*.cpp" -E ".*.moc*" -E ".rcc*" --gcov-options '\-lp' 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/mbroadst/qamqp.svg?branch=master)](https://travis-ci.org/mbroadst/qamqp) 2 | [![Coverage Status](https://img.shields.io/coveralls/mbroadst/qamqp.svg)](https://coveralls.io/r/mbroadst/qamqp?branch=master) 3 | 4 | QAMQP 5 | ============= 6 | A Qt4/Qt5 implementation of AMQP 0.9.1, focusing primarily on RabbitMQ support. 7 | 8 | Usage 9 | ------------ 10 | * [hello world](https://github.com/mbroadst/qamqp/tree/master/tutorials/helloworld) 11 | * [pubsub](https://github.com/mbroadst/qamqp/tree/master/tutorials/pubsub) 12 | * [routing](https://github.com/mbroadst/qamqp/tree/master/tutorials/routing) 13 | * [rpc](https://github.com/mbroadst/qamqp/tree/master/tutorials/rpc) 14 | * [topics](https://github.com/mbroadst/qamqp/tree/master/tutorials/topics) 15 | * [work queues](https://github.com/mbroadst/qamqp/tree/master/tutorials/workqueues) 16 | 17 | Documentation 18 | ------------ 19 | Coming soon! 20 | 21 | 22 | AMQP Support 23 | ------------ 24 | 25 | #### connection 26 | | method | supported | 27 | | --- | --- | 28 | | connection.start | ✓ | 29 | | connection.start-ok | ✓ | 30 | | connection.secure | ✓ | 31 | | connection.secure-ok | ✓ | 32 | | connection.tune | ✓ | 33 | | connection.tune-ok | ✓ | 34 | | connection.open | ✓ | 35 | | connection.open-ok | ✓ | 36 | | connection.close | ✓ | 37 | | connection.close-ok | ✓ | 38 | 39 | #### channel 40 | | method | supported | 41 | | ------ | --------- | 42 | | channel.open | ✓ | 43 | | channel.open-ok | ✓ | 44 | | channel.flow | ✓ | 45 | | channel.flow-ok | ✓ | 46 | | channel.close | ✓ | 47 | | channel.close-ok | ✓ | 48 | 49 | #### exchange 50 | | method | supported | 51 | | ------ | --------- | 52 | | exchange.declare | ✓ | 53 | | exchange.declare-ok | ✓ | 54 | | exchange.delete | ✓ | 55 | | exchange.delete-ok | ✓ | 56 | 57 | #### queue 58 | | method | supported | 59 | | ------ | --------- | 60 | | queue.declare | ✓ | 61 | | queue.declare-ok | ✓ | 62 | | queue.bind | ✓ | 63 | | queue.bind-ok | ✓ | 64 | | queue.unbind | ✓ | 65 | | queue.unbind-ok | ✓ | 66 | | queue.purge | ✓ | 67 | | queue.purge-ok | ✓ | 68 | | queue.delete | ✓ | 69 | | queue.delete-ok | ✓ | 70 | 71 | #### basic 72 | | method | supported | 73 | | ------ | --------- | 74 | | basic.qos | ✓ | 75 | | basic.consume | ✓ | 76 | | basic.consume-ok | ✓ | 77 | | basic.cancel | ✓ | 78 | | basic.cancel-ok | ✓ | 79 | | basic.publish | ✓ | 80 | | basic.return | ✓ | 81 | | basic.deliver | ✓ | 82 | | basic.get | ✓ | 83 | | basic.get-ok | ✓ | 84 | | basic.get-empty | ✓ | 85 | | basic.ack | ✓ | 86 | | basic.reject | ✓ | 87 | | basic.recover | ✓ | 88 | 89 | #### tx 90 | | method | supported | 91 | | ------ | --------- | 92 | | tx.select | X | 93 | | tx.select-ok | X | 94 | | tx.commit | X | 95 | | tx.commit-ok | X | 96 | | tx.rollback | X | 97 | | tx.rollback-ok | X | 98 | 99 | #### confirm 100 | | method | supported | 101 | | ------ | --------- | 102 | | confirm.select | ✓ | 103 | | confirm.select-ok | ✓ | 104 | 105 | Credits 106 | ------------ 107 | * Thank you to [@fuCtor](https://github.com/fuCtor) for the original implementation work. 108 | -------------------------------------------------------------------------------- /qamqp.pri: -------------------------------------------------------------------------------- 1 | QAMQP_VERSION = 0.5.0 2 | 3 | isEmpty(QAMQP_LIBRARY_TYPE) { 4 | QAMQP_LIBRARY_TYPE = shared 5 | } 6 | 7 | QT += network 8 | QAMQP_INCLUDEPATH = $${PWD}/src 9 | QAMQP_LIBS = -lqamqp 10 | CONFIG(debug, debug|release){ 11 | QAMQP_LIBS = -lqamqpd 12 | } 13 | contains(QAMQP_LIBRARY_TYPE, staticlib) { 14 | DEFINES += QAMQP_STATIC 15 | } else { 16 | DEFINES += QAMQP_SHARED 17 | win32:QAMQP_LIBS = -lqamqp0 18 | } 19 | 20 | isEmpty(PREFIX) { 21 | unix { 22 | PREFIX = /usr 23 | } else { 24 | PREFIX = $$[QT_INSTALL_PREFIX] 25 | } 26 | } 27 | isEmpty(LIBDIR) { 28 | LIBDIR = lib 29 | } 30 | 31 | -------------------------------------------------------------------------------- /qamqp.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS += src \ 3 | tests \ 4 | tutorials 5 | CONFIG += ordered 6 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | debug/* 2 | release/* 3 | *.lib 4 | *.dll 5 | *.so 6 | *.a 7 | *.prl 8 | *.pdb 9 | Makefile* 10 | -------------------------------------------------------------------------------- /src/qamqpInterface.pri: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += $${PWD} 2 | 3 | CONFIG(debug, debug|release){ 4 | LIBS += -L$$PWD -lqamqpd 5 | } else { 6 | LIBS += -L$$PWD -lqamqp 7 | } 8 | -------------------------------------------------------------------------------- /src/qamqpauthenticator.cpp: -------------------------------------------------------------------------------- 1 | #include "qamqptable.h" 2 | #include "qamqpframe_p.h" 3 | #include "qamqpauthenticator.h" 4 | 5 | QAmqpPlainAuthenticator::QAmqpPlainAuthenticator(const QString &l, const QString &p) 6 | : login_(l), 7 | password_(p) 8 | { 9 | } 10 | 11 | QAmqpPlainAuthenticator::~QAmqpPlainAuthenticator() 12 | { 13 | } 14 | 15 | QString QAmqpPlainAuthenticator::login() const 16 | { 17 | return login_; 18 | } 19 | 20 | QString QAmqpPlainAuthenticator::password() const 21 | { 22 | return password_; 23 | } 24 | 25 | QString QAmqpPlainAuthenticator::type() const 26 | { 27 | return "AMQPLAIN"; 28 | } 29 | 30 | void QAmqpPlainAuthenticator::setLogin(const QString &l) 31 | { 32 | login_ = l; 33 | } 34 | 35 | void QAmqpPlainAuthenticator::setPassword(const QString &p) 36 | { 37 | password_ = p; 38 | } 39 | 40 | void QAmqpPlainAuthenticator::write(QDataStream &out) 41 | { 42 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, type()); 43 | QAmqpTable response; 44 | response["LOGIN"] = login_; 45 | response["PASSWORD"] = password_; 46 | out << response; 47 | } 48 | -------------------------------------------------------------------------------- /src/qamqpauthenticator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2014 Alexey Shcherbakov 3 | * Copyright (C) 2014-2015 Matt Broadstone 4 | * Contact: https://github.com/mbroadst/qamqp 5 | * 6 | * This file is part of the QAMQP Library. 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | */ 18 | #ifndef QAMQPAUTHENTICATOR_H 19 | #define QAMQPAUTHENTICATOR_H 20 | 21 | #include 22 | #include 23 | 24 | #include "qamqpglobal.h" 25 | 26 | class QAMQP_EXPORT QAmqpAuthenticator 27 | { 28 | public: 29 | virtual ~QAmqpAuthenticator() {} 30 | virtual QString type() const = 0; 31 | virtual void write(QDataStream &out) = 0; 32 | }; 33 | 34 | class QAMQP_EXPORT QAmqpPlainAuthenticator : public QAmqpAuthenticator 35 | { 36 | public: 37 | QAmqpPlainAuthenticator(const QString &login = QString(), const QString &password = QString()); 38 | virtual ~QAmqpPlainAuthenticator(); 39 | 40 | QString login() const; 41 | void setLogin(const QString &l); 42 | 43 | QString password() const; 44 | void setPassword(const QString &p); 45 | 46 | virtual QString type() const; 47 | virtual void write(QDataStream &out); 48 | 49 | private: 50 | QString login_; 51 | QString password_; 52 | 53 | }; 54 | 55 | #endif // QAMQPAUTHENTICATOR_H 56 | -------------------------------------------------------------------------------- /src/qamqpchannel.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "qamqpchannel.h" 5 | #include "qamqpchannel_p.h" 6 | #include "qamqpclient.h" 7 | #include "qamqpclient_p.h" 8 | 9 | quint16 QAmqpChannelPrivate::nextChannelNumber = 0; 10 | QAmqpChannelPrivate::QAmqpChannelPrivate(QAmqpChannel *q) 11 | : channelNumber(0), 12 | opened(false), 13 | needOpen(true), 14 | prefetchSize(0), 15 | requestedPrefetchSize(0), 16 | prefetchCount(0), 17 | requestedPrefetchCount(0), 18 | error(QAMQP::NoError), 19 | q_ptr(q) 20 | { 21 | } 22 | 23 | QAmqpChannelPrivate::~QAmqpChannelPrivate() 24 | { 25 | if (!client.isNull()) { 26 | QAmqpClientPrivate *priv = client->d_func(); 27 | priv->methodHandlersByChannel[channelNumber].removeAll(this); 28 | } 29 | } 30 | 31 | void QAmqpChannelPrivate::init(int channel, QAmqpClient *c) 32 | { 33 | client = c; 34 | needOpen = (channel <= nextChannelNumber && channel != -1) ? false : true; 35 | channelNumber = channel == -1 ? ++nextChannelNumber : channel; 36 | nextChannelNumber = qMax(channelNumber, nextChannelNumber); 37 | } 38 | 39 | bool QAmqpChannelPrivate::_q_method(const QAmqpMethodFrame &frame) 40 | { 41 | Q_ASSERT(frame.channel() == channelNumber); 42 | if (frame.channel() != channelNumber) 43 | return true; 44 | 45 | if (frame.methodClass() == QAmqpFrame::Basic) { 46 | if (frame.id() == bmQosOk) { 47 | qosOk(frame); 48 | return true; 49 | } 50 | 51 | return false; 52 | } 53 | 54 | if (frame.methodClass() != QAmqpFrame::Channel) 55 | return false; 56 | 57 | switch (frame.id()) { 58 | case miOpenOk: 59 | openOk(frame); 60 | break; 61 | case miFlow: 62 | flow(frame); 63 | break; 64 | case miFlowOk: 65 | flowOk(frame); 66 | break; 67 | case miClose: 68 | close(frame); 69 | break; 70 | case miCloseOk: 71 | closeOk(frame); 72 | break; 73 | } 74 | 75 | return true; 76 | } 77 | 78 | void QAmqpChannelPrivate::_q_open() 79 | { 80 | open(); 81 | } 82 | 83 | void QAmqpChannelPrivate::sendFrame(const QAmqpFrame &frame) 84 | { 85 | if (!client) { 86 | qAmqpDebug() << Q_FUNC_INFO << "invalid client"; 87 | return; 88 | } 89 | 90 | client->d_func()->sendFrame(frame); 91 | } 92 | 93 | void QAmqpChannelPrivate::resetInternalState() 94 | { 95 | if (!opened) return; 96 | opened = false; 97 | needOpen = true; 98 | } 99 | 100 | void QAmqpChannelPrivate::open() 101 | { 102 | if (!needOpen || opened) 103 | return; 104 | 105 | if (!client->isConnected()) 106 | return; 107 | 108 | qAmqpDebug("<- channel#open( channel=%d, name=%s )", channelNumber, qPrintable(name)); 109 | QAmqpMethodFrame frame(QAmqpFrame::Channel, miOpen); 110 | frame.setChannel(channelNumber); 111 | 112 | QByteArray arguments; 113 | arguments.resize(1); 114 | arguments[0] = 0; 115 | 116 | frame.setArguments(arguments); 117 | sendFrame(frame); 118 | } 119 | 120 | void QAmqpChannelPrivate::flow(bool active) 121 | { 122 | QByteArray arguments; 123 | QDataStream stream(&arguments, QIODevice::WriteOnly); 124 | QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortShortUint, (active ? 1 : 0)); 125 | 126 | QAmqpMethodFrame frame(QAmqpFrame::Channel, miFlow); 127 | frame.setChannel(channelNumber); 128 | frame.setArguments(arguments); 129 | sendFrame(frame); 130 | } 131 | 132 | // NOTE: not implemented until I can figure out a good way to force the server 133 | // to pause the channel in a test. It seems like RabbitMQ just doesn't 134 | // care about flow control, preferring rather to use basic.qos 135 | void QAmqpChannelPrivate::flow(const QAmqpMethodFrame &frame) 136 | { 137 | Q_UNUSED(frame); 138 | qAmqpDebug("-> channel#flow( channel=%d, name=%s )", channelNumber, qPrintable(name)); 139 | } 140 | 141 | void QAmqpChannelPrivate::flowOk() 142 | { 143 | qAmqpDebug("<- channel#flowOk( channel=%d, name=%s )", channelNumber, qPrintable(name)); 144 | } 145 | 146 | void QAmqpChannelPrivate::flowOk(const QAmqpMethodFrame &frame) 147 | { 148 | Q_Q(QAmqpChannel); 149 | qAmqpDebug("-> channel#flowOk( channel=%d, name=%s )", channelNumber, qPrintable(name)); 150 | 151 | QByteArray data = frame.arguments(); 152 | QDataStream stream(&data, QIODevice::ReadOnly); 153 | bool active = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::Boolean).toBool(); 154 | if (active) 155 | Q_EMIT q->resumed(); 156 | else 157 | Q_EMIT q->paused(); 158 | } 159 | 160 | void QAmqpChannelPrivate::close(int code, const QString &text, int classId, int methodId) 161 | { 162 | qAmqpDebug("<- channel#close( channel=%d, name=%s, reply-code=%d, text=%s class-id=%d, method-id:%d, )", 163 | channelNumber, qPrintable(name), code, qPrintable(text), classId, methodId); 164 | 165 | QByteArray arguments; 166 | QDataStream stream(&arguments, QIODevice::WriteOnly); 167 | 168 | if (!code) code = 200; 169 | QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortUint, code); 170 | if (!text.isEmpty()) { 171 | QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortString, text); 172 | } else { 173 | QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortString, QLatin1String("OK")); 174 | } 175 | 176 | QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortUint, classId); 177 | QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortUint, methodId); 178 | 179 | QAmqpMethodFrame frame(QAmqpFrame::Channel, miClose); 180 | frame.setChannel(channelNumber); 181 | frame.setArguments(arguments); 182 | sendFrame(frame); 183 | } 184 | 185 | void QAmqpChannelPrivate::close(const QAmqpMethodFrame &frame) 186 | { 187 | Q_Q(QAmqpChannel); 188 | QByteArray data = frame.arguments(); 189 | QDataStream stream(&data, QIODevice::ReadOnly); 190 | qint16 code = 0, classId, methodId; 191 | stream >> code; 192 | QString text = 193 | QAmqpFrame::readAmqpField(stream, QAmqpMetaType::ShortString).toString(); 194 | 195 | stream >> classId; 196 | stream >> methodId; 197 | 198 | QAMQP::Error checkError = static_cast(code); 199 | if (checkError != QAMQP::NoError) { 200 | error = checkError; 201 | errorString = qPrintable(text); 202 | Q_EMIT q->error(error); 203 | } 204 | 205 | qAmqpDebug("-> channel#close( channel=%d, name=%s, reply-code=%d, reply-text=%s, class-id=%d, method-id=%d, )", 206 | channelNumber, qPrintable(name), code, qPrintable(text), classId, methodId); 207 | 208 | // complete handshake 209 | QAmqpMethodFrame closeOkFrame(QAmqpFrame::Channel, miCloseOk); 210 | closeOkFrame.setChannel(channelNumber); 211 | sendFrame(closeOkFrame); 212 | 213 | // notify everyone that the channel was closed on us. 214 | notifyClosed(); 215 | } 216 | 217 | void QAmqpChannelPrivate::closeOk(const QAmqpMethodFrame &) 218 | { 219 | qAmqpDebug("-> channel#closeOk( channel=%d, name=%s )", channelNumber, qPrintable(name)); 220 | notifyClosed(); 221 | } 222 | 223 | void QAmqpChannelPrivate::notifyClosed() 224 | { 225 | Q_Q(QAmqpChannel); 226 | Q_EMIT q->closed(); 227 | q->channelClosed(); 228 | opened = false; 229 | } 230 | 231 | void QAmqpChannelPrivate::openOk(const QAmqpMethodFrame &) 232 | { 233 | Q_Q(QAmqpChannel); 234 | qAmqpDebug("-> channel#openOk( channel=%d, name=%s )", channelNumber, qPrintable(name)); 235 | opened = true; 236 | Q_EMIT q->opened(); 237 | q->channelOpened(); 238 | } 239 | 240 | void QAmqpChannelPrivate::_q_disconnected() 241 | { 242 | nextChannelNumber = 0; 243 | opened = false; 244 | } 245 | 246 | void QAmqpChannelPrivate::qosOk(const QAmqpMethodFrame &frame) 247 | { 248 | Q_Q(QAmqpChannel); 249 | Q_UNUSED(frame) 250 | qAmqpDebug("-> basic#qosOk( channel=%d, name=%s )", channelNumber, qPrintable(name)); 251 | 252 | prefetchCount = requestedPrefetchCount; 253 | prefetchSize = requestedPrefetchSize; 254 | Q_EMIT q->qosDefined(); 255 | } 256 | 257 | ////////////////////////////////////////////////////////////////////////// 258 | 259 | QAmqpChannel::QAmqpChannel(QAmqpChannelPrivate *dd, QAmqpClient *parent) 260 | : QObject(parent), 261 | d_ptr(dd) 262 | { 263 | } 264 | 265 | QAmqpChannel::~QAmqpChannel() 266 | { 267 | } 268 | 269 | void QAmqpChannel::close() 270 | { 271 | Q_D(QAmqpChannel); 272 | d->needOpen = true; 273 | if (d->opened) 274 | d->close(0, QString(), 0,0); 275 | } 276 | 277 | void QAmqpChannel::reopen() 278 | { 279 | Q_D(QAmqpChannel); 280 | if (d->opened) 281 | close(); 282 | d->open(); 283 | } 284 | 285 | QString QAmqpChannel::name() const 286 | { 287 | Q_D(const QAmqpChannel); 288 | return d->name; 289 | } 290 | 291 | int QAmqpChannel::channelNumber() const 292 | { 293 | Q_D(const QAmqpChannel); 294 | return d->channelNumber; 295 | } 296 | 297 | void QAmqpChannel::setName(const QString &name) 298 | { 299 | Q_D(QAmqpChannel); 300 | d->name = name; 301 | } 302 | 303 | bool QAmqpChannel::isOpen() const 304 | { 305 | Q_D(const QAmqpChannel); 306 | return d->opened; 307 | } 308 | 309 | void QAmqpChannel::qos(qint16 prefetchCount, qint32 prefetchSize) 310 | { 311 | Q_D(QAmqpChannel); 312 | QAmqpMethodFrame frame(QAmqpFrame::Basic, QAmqpChannelPrivate::bmQos); 313 | frame.setChannel(d->channelNumber); 314 | 315 | QByteArray arguments; 316 | QDataStream stream(&arguments, QIODevice::WriteOnly); 317 | 318 | d->requestedPrefetchSize = prefetchSize; 319 | d->requestedPrefetchCount = prefetchCount; 320 | 321 | stream << qint32(prefetchSize); 322 | stream << qint16(prefetchCount); 323 | stream << qint8(0x0); // global 324 | 325 | qAmqpDebug("<- basic#qos( channel=%d, name=%s, prefetch-size=%d, prefetch-count=%d, global=%d )", 326 | d->channelNumber, qPrintable(d->name), prefetchSize, prefetchCount, 0); 327 | 328 | frame.setArguments(arguments); 329 | d->sendFrame(frame); 330 | } 331 | 332 | qint32 QAmqpChannel::prefetchSize() const 333 | { 334 | Q_D(const QAmqpChannel); 335 | return d->prefetchSize; 336 | } 337 | 338 | qint16 QAmqpChannel::prefetchCount() const 339 | { 340 | Q_D(const QAmqpChannel); 341 | return d->prefetchCount; 342 | } 343 | 344 | void QAmqpChannel::reset() 345 | { 346 | Q_D(QAmqpChannel); 347 | d->resetInternalState(); 348 | } 349 | 350 | QAMQP::Error QAmqpChannel::error() const 351 | { 352 | Q_D(const QAmqpChannel); 353 | return d->error; 354 | } 355 | 356 | QString QAmqpChannel::errorString() const 357 | { 358 | Q_D(const QAmqpChannel); 359 | return d->errorString; 360 | } 361 | 362 | void QAmqpChannel::resume() 363 | { 364 | Q_D(QAmqpChannel); 365 | d->flow(true); 366 | } 367 | 368 | #include "moc_qamqpchannel.cpp" 369 | -------------------------------------------------------------------------------- /src/qamqpchannel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2014 Alexey Shcherbakov 3 | * Copyright (C) 2014-2015 Matt Broadstone 4 | * Contact: https://github.com/mbroadst/qamqp 5 | * 6 | * This file is part of the QAMQP Library. 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | */ 18 | #ifndef QAMQPCHANNEL_H 19 | #define QAMQPCHANNEL_H 20 | 21 | #include 22 | #include "qamqpglobal.h" 23 | 24 | class QAmqpClient; 25 | class QAmqpChannelPrivate; 26 | class QAMQP_EXPORT QAmqpChannel : public QObject 27 | { 28 | Q_OBJECT 29 | Q_PROPERTY(int number READ channelNumber CONSTANT) 30 | Q_PROPERTY(bool open READ isOpen CONSTANT) 31 | Q_PROPERTY(QString name READ name WRITE setName) 32 | public: 33 | virtual ~QAmqpChannel(); 34 | 35 | int channelNumber() const; 36 | bool isOpen() const; 37 | 38 | QString name() const; 39 | void setName(const QString &name); 40 | 41 | QAMQP::Error error() const; 42 | QString errorString() const; 43 | 44 | qint32 prefetchSize() const; 45 | qint16 prefetchCount() const; 46 | 47 | void reset(); 48 | 49 | // AMQP Basic 50 | void qos(qint16 prefetchCount, qint32 prefetchSize = 0); 51 | 52 | public Q_SLOTS: 53 | void close(); 54 | void reopen(); 55 | void resume(); 56 | 57 | Q_SIGNALS: 58 | void opened(); 59 | void closed(); 60 | void resumed(); 61 | void paused(); 62 | void error(QAMQP::Error error); 63 | void qosDefined(); 64 | 65 | protected: 66 | virtual void channelOpened() = 0; 67 | virtual void channelClosed() = 0; 68 | 69 | protected: 70 | explicit QAmqpChannel(QAmqpChannelPrivate *dd, QAmqpClient *client); 71 | 72 | Q_DISABLE_COPY(QAmqpChannel) 73 | Q_DECLARE_PRIVATE(QAmqpChannel) 74 | QScopedPointer d_ptr; 75 | 76 | Q_PRIVATE_SLOT(d_func(), void _q_open()) 77 | Q_PRIVATE_SLOT(d_func(), void _q_disconnected()) 78 | 79 | friend class QAmqpClientPrivate; 80 | friend class QAmqpExchangePrivate; 81 | }; 82 | 83 | #endif // QAMQPCHANNEL_H 84 | -------------------------------------------------------------------------------- /src/qamqpchannel_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QAMQPCHANNEL_P_H 2 | #define QAMQPCHANNEL_P_H 3 | 4 | #include 5 | #include "qamqpframe_p.h" 6 | #include "qamqptable.h" 7 | 8 | #define METHOD_ID_ENUM(name, id) name = id, name ## Ok 9 | 10 | class QAmqpChannel; 11 | class QAmqpClient; 12 | class QAmqpClientPrivate; 13 | class QAmqpChannelPrivate : public QAmqpMethodFrameHandler 14 | { 15 | public: 16 | enum MethodId { 17 | METHOD_ID_ENUM(miOpen, 10), 18 | METHOD_ID_ENUM(miFlow, 20), 19 | METHOD_ID_ENUM(miClose, 40) 20 | }; 21 | 22 | enum BasicMethod { 23 | METHOD_ID_ENUM(bmQos, 10), 24 | METHOD_ID_ENUM(bmConsume, 20), 25 | METHOD_ID_ENUM(bmCancel, 30), 26 | bmPublish = 40, 27 | bmReturn = 50, 28 | bmDeliver = 60, 29 | METHOD_ID_ENUM(bmGet, 70), 30 | bmGetEmpty = 72, 31 | bmAck = 80, 32 | bmReject = 90, 33 | bmRecoverAsync = 100, 34 | METHOD_ID_ENUM(bmRecover, 110), 35 | bmNack = 120 36 | }; 37 | 38 | QAmqpChannelPrivate(QAmqpChannel *q); 39 | virtual ~QAmqpChannelPrivate(); 40 | 41 | void init(int channel, QAmqpClient *client); 42 | void sendFrame(const QAmqpFrame &frame); 43 | virtual void resetInternalState(); 44 | 45 | void open(); 46 | void flow(bool active); 47 | void flowOk(); 48 | void close(int code, const QString &text, int classId, int methodId); 49 | void notifyClosed(); 50 | 51 | // reimp MethodHandler 52 | virtual bool _q_method(const QAmqpMethodFrame &frame); 53 | void openOk(const QAmqpMethodFrame &frame); 54 | void flow(const QAmqpMethodFrame &frame); 55 | void flowOk(const QAmqpMethodFrame &frame); 56 | void close(const QAmqpMethodFrame &frame); 57 | void closeOk(const QAmqpMethodFrame &frame); 58 | void qosOk(const QAmqpMethodFrame &frame); 59 | 60 | // private slots 61 | virtual void _q_disconnected(); 62 | void _q_open(); 63 | 64 | QPointer client; 65 | QString name; 66 | quint16 channelNumber; 67 | static quint16 nextChannelNumber; 68 | bool opened; 69 | bool needOpen; 70 | 71 | qint32 prefetchSize; 72 | qint32 requestedPrefetchSize; 73 | qint16 prefetchCount; 74 | qint16 requestedPrefetchCount; 75 | 76 | QAMQP::Error error; 77 | QString errorString; 78 | 79 | Q_DECLARE_PUBLIC(QAmqpChannel) 80 | QAmqpChannel * const q_ptr; 81 | QAmqpTable arguments; 82 | }; 83 | 84 | #endif // QAMQPCHANNEL_P_H 85 | -------------------------------------------------------------------------------- /src/qamqpchannelhash.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2014 Alexey Shcherbakov 3 | * Copyright (C) 2014-2015 Matt Broadstone 4 | * Contact: https://github.com/mbroadst/qamqp 5 | * 6 | * This file is part of the QAMQP Library. 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | */ 18 | #include "qamqpqueue.h" 19 | #include "qamqpexchange.h" 20 | #include "qamqpchannelhash_p.h" 21 | 22 | /*! 23 | * Retrieve a pointer to the named channel. 24 | * 25 | * A NULL string is assumed to be equivalent to "" for the purpose 26 | * of retrieving the nameless (default) exchange. 27 | * 28 | * \param[in] name The name of the channel to retrieve. 29 | * \retval NULL Channel does not exist. 30 | */ 31 | QAmqpChannel* QAmqpChannelHash::get(const QString& name) const 32 | { 33 | if (name.isEmpty()) 34 | return m_channels.value(QString()); 35 | return m_channels.value(name); 36 | } 37 | 38 | QStringList QAmqpChannelHash::channels() const 39 | { 40 | return m_channels.keys(); 41 | } 42 | 43 | /*! 44 | * Return true if the named channel exists. 45 | */ 46 | bool QAmqpChannelHash::contains(const QString& name) const 47 | { 48 | if (name.isEmpty()) 49 | return m_channels.contains(QString()); 50 | return m_channels.contains(name); 51 | } 52 | 53 | /*! 54 | * Store an exchange in the hash. The nameless exchange is stored under 55 | * the name "". 56 | */ 57 | void QAmqpChannelHash::put(QAmqpExchange* exchange) 58 | { 59 | if (exchange->name().isEmpty()) 60 | put(QString(), exchange); 61 | else 62 | put(exchange->name(), exchange); 63 | } 64 | 65 | /*! 66 | * Store a queue in the hash. If the queue is nameless, we hook its 67 | * declared signal and store it when the queue receives a name from the 68 | * broker, otherwise we store it under the name given. 69 | */ 70 | void QAmqpChannelHash::put(QAmqpQueue* queue) 71 | { 72 | if (queue->name().isEmpty()) 73 | connect(queue, SIGNAL(declared()), this, SLOT(queueDeclared())); 74 | else 75 | put(queue->name(), queue); 76 | } 77 | 78 | /*! 79 | * Handle destruction of a channel. Do a full garbage collection run. 80 | */ 81 | void QAmqpChannelHash::channelDestroyed(QObject* object) 82 | { 83 | QList names(m_channels.keys()); 84 | QList::iterator it; 85 | for (it = names.begin(); it != names.end(); it++) { 86 | if (m_channels.value(*it) == object) 87 | m_channels.remove(*it); 88 | } 89 | } 90 | 91 | /*! 92 | * Handle a queue that has just been declared and given a new name. The 93 | * caller is assumed to be a QAmqpQueue instance. 94 | */ 95 | void QAmqpChannelHash::queueDeclared() 96 | { 97 | QAmqpQueue *queue = qobject_cast(sender()); 98 | if (queue) 99 | put(queue); 100 | } 101 | 102 | /*! 103 | * Store a channel in the hash. The channel is assumed 104 | * to be named at the time of storage. This hooks the 'destroyed' signal 105 | * so the channel can be removed from our list. 106 | */ 107 | void QAmqpChannelHash::put(const QString& name, QAmqpChannel* channel) 108 | { 109 | connect(channel, SIGNAL(destroyed(QObject*)), this, SLOT(channelDestroyed(QObject*))); 110 | m_channels[name] = channel; 111 | } 112 | 113 | /* vim: set ts=4 sw=4 et */ 114 | -------------------------------------------------------------------------------- /src/qamqpchannelhash_p.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2014 Alexey Shcherbakov 3 | * Copyright (C) 2014-2015 Matt Broadstone 4 | * Contact: https://github.com/mbroadst/qamqp 5 | * 6 | * This file is part of the QAMQP Library. 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | */ 18 | #ifndef QAMQPCHANNELHASH_P_H 19 | #define QAMQPCHANNELHASH_P_H 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | /* Forward declarations */ 27 | class QAmqpChannel; 28 | class QAmqpQueue; 29 | class QAmqpExchange; 30 | 31 | /*! 32 | * QAmqpChannelHash is a container for storing queues and exchanges for later 33 | * retrieval. When the objects are destroyed, they are automatically removed 34 | * from the container. 35 | */ 36 | class QAmqpChannelHash : public QObject 37 | { 38 | Q_OBJECT 39 | public: 40 | /*! 41 | * Retrieve a pointer to the named channel. 42 | * 43 | * A NULL string is assumed to be equivalent to "" for the purpose 44 | * of retrieving the nameless (default) exchange. 45 | * 46 | * \param[in] name The name of the channel to retrieve. 47 | * \retval NULL Channel does not exist. 48 | */ 49 | QAmqpChannel* get(const QString& name) const; 50 | 51 | /*! 52 | * Return true if the named channel exists. 53 | */ 54 | bool contains(const QString& name) const; 55 | 56 | /** 57 | * Returns a list of channels tracked by this hash 58 | */ 59 | QStringList channels() const; 60 | 61 | /*! 62 | * Store an exchange in the hash. The nameless exchange is stored under 63 | * the name "". 64 | */ 65 | void put(QAmqpExchange* exchange); 66 | 67 | /*! 68 | * Store a queue in the hash. If the queue is nameless, we hook its 69 | * declared signal and store it when the queue receives a name from the 70 | * broker, otherwise we store it under the name given. 71 | */ 72 | void put(QAmqpQueue* queue); 73 | 74 | private Q_SLOTS: 75 | /*! 76 | * Handle destruction of a channel. Do a full garbage collection run. 77 | */ 78 | void channelDestroyed(QObject* object); 79 | 80 | /*! 81 | * Handle a queue that has just been declared and given a new name. The 82 | * caller is assumed to be a QAmqpQueue instance. 83 | */ 84 | void queueDeclared(); 85 | 86 | private: 87 | /*! 88 | * Store a channel in the hash. This hooks the 'destroyed' signal 89 | * so the channel can be removed from our list. 90 | */ 91 | void put(const QString& name, QAmqpChannel* channel); 92 | 93 | /*! A collection of channels. Key is the channel's "name". */ 94 | QHash m_channels; 95 | }; 96 | 97 | /* vim: set ts=4 sw=4 et */ 98 | #endif 99 | -------------------------------------------------------------------------------- /src/qamqpclient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2014 Alexey Shcherbakov 3 | * Copyright (C) 2014-2015 Matt Broadstone 4 | * Contact: https://github.com/mbroadst/qamqp 5 | * 6 | * This file is part of the QAMQP Library. 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | */ 18 | #ifndef QAMQPCLIENT_H 19 | #define QAMQPCLIENT_H 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "qamqpglobal.h" 28 | 29 | class QAmqpExchange; 30 | class QAmqpQueue; 31 | class QAmqpAuthenticator; 32 | class QAmqpClientPrivate; 33 | class QAMQP_EXPORT QAmqpClient : public QObject 34 | { 35 | Q_OBJECT 36 | Q_PROPERTY(quint32 port READ port WRITE setPort) 37 | Q_PROPERTY(QString host READ host WRITE setHost) 38 | Q_PROPERTY(QString virtualHost READ virtualHost WRITE setVirtualHost) 39 | Q_PROPERTY(QString user READ username WRITE setUsername) 40 | Q_PROPERTY(QString password READ password WRITE setPassword) 41 | Q_PROPERTY(bool autoReconnect READ autoReconnect WRITE setAutoReconnect) 42 | Q_PROPERTY(qint16 channelMax READ channelMax WRITE setChannelMax) 43 | Q_PROPERTY(qint32 frameMax READ frameMax WRITE setFrameMax) 44 | Q_PROPERTY(qint16 heartbeatDelay READ heartbeatDelay() WRITE setHeartbeatDelay) 45 | 46 | public: 47 | explicit QAmqpClient(QObject *parent = 0); 48 | ~QAmqpClient(); 49 | 50 | // properties 51 | quint16 port() const; 52 | void setPort(quint16 port); 53 | 54 | QString host() const; 55 | void setHost(const QString &host); 56 | 57 | QString virtualHost() const; 58 | void setVirtualHost(const QString &virtualHost); 59 | 60 | QString username() const; 61 | void setUsername(const QString &username); 62 | 63 | QString password() const; 64 | void setPassword(const QString &password); 65 | 66 | void setAuth(QAmqpAuthenticator *auth); 67 | QAmqpAuthenticator *auth() const; 68 | 69 | bool autoReconnect() const; 70 | void setAutoReconnect(bool value, int timeout = 0); 71 | 72 | bool isConnected() const; 73 | 74 | qint16 channelMax() const; 75 | void setChannelMax(qint16 channelMax); 76 | 77 | qint32 frameMax() const; 78 | void setFrameMax(qint32 frameMax); 79 | 80 | qint16 heartbeatDelay() const; 81 | void setHeartbeatDelay(qint16 delay); 82 | 83 | int writeTimeout() const; 84 | void setWriteTimeout(int msecs); 85 | 86 | void addCustomProperty(const QString &name, const QString &value); 87 | QString customProperty(const QString &name) const; 88 | 89 | QAbstractSocket::SocketError socketError() const; 90 | QAbstractSocket::SocketState socketState() const; 91 | 92 | QAMQP::Error error() const; 93 | QString errorString() const; 94 | 95 | QSslConfiguration sslConfiguration() const; 96 | void setSslConfiguration(const QSslConfiguration &config); 97 | 98 | static QString gitVersion(); 99 | 100 | // channels 101 | QAmqpExchange *createExchange(int channelNumber = -1); 102 | QAmqpExchange *createExchange(const QString &name, int channelNumber = -1); 103 | 104 | QAmqpQueue *createQueue(int channelNumber = -1); 105 | QAmqpQueue *createQueue(const QString &name, int channelNumber = -1); 106 | 107 | // methods 108 | void connectToHost(const QString &uri = QString()); 109 | void connectToHost(const QHostAddress &address, quint16 port = AMQP_PORT); 110 | void disconnectFromHost(); 111 | void abort(); 112 | 113 | Q_SIGNALS: 114 | void connected(); 115 | void disconnected(); 116 | void heartbeat(); 117 | void error(QAMQP::Error error); 118 | void socketError(QAbstractSocket::SocketError error); 119 | void socketStateChanged(QAbstractSocket::SocketState state); 120 | void sslErrors(const QList &errors); 121 | 122 | public Q_SLOTS: 123 | void ignoreSslErrors(const QList &errors); 124 | 125 | protected: 126 | QAmqpClient(QAmqpClientPrivate *dd, QObject *parent = 0); 127 | 128 | Q_DISABLE_COPY(QAmqpClient) 129 | Q_DECLARE_PRIVATE(QAmqpClient) 130 | QScopedPointer d_ptr; 131 | 132 | private: 133 | Q_PRIVATE_SLOT(d_func(), void _q_socketConnected()) 134 | Q_PRIVATE_SLOT(d_func(), void _q_socketDisconnected()) 135 | Q_PRIVATE_SLOT(d_func(), void _q_readyRead()) 136 | Q_PRIVATE_SLOT(d_func(), void _q_socketError(QAbstractSocket::SocketError error)) 137 | Q_PRIVATE_SLOT(d_func(), void _q_heartbeat()) 138 | Q_PRIVATE_SLOT(d_func(), void _q_connect()) 139 | Q_PRIVATE_SLOT(d_func(), void _q_disconnect()) 140 | 141 | friend class QAmqpChannelPrivate; 142 | friend class QAmqpQueuePrivate; 143 | 144 | }; 145 | 146 | #endif // QAMQPCLIENT_H 147 | -------------------------------------------------------------------------------- /src/qamqpclient_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QAMQPCLIENT_P_H 2 | #define QAMQPCLIENT_P_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "qamqpchannelhash_p.h" 11 | #include "qamqpglobal.h" 12 | #include "qamqpauthenticator.h" 13 | #include "qamqptable.h" 14 | #include "qamqpframe_p.h" 15 | 16 | #define METHOD_ID_ENUM(name, id) name = id, name ## Ok 17 | 18 | class QTimer; 19 | class QSslSocket; 20 | class QAmqpClient; 21 | class QAmqpQueue; 22 | class QAmqpExchange; 23 | class QAmqpConnection; 24 | class QAmqpAuthenticator; 25 | class QAMQP_EXPORT QAmqpClientPrivate : public QAmqpMethodFrameHandler 26 | { 27 | public: 28 | enum MethodId { 29 | METHOD_ID_ENUM(miStart, 10), 30 | METHOD_ID_ENUM(miSecure, 20), 31 | METHOD_ID_ENUM(miTune, 30), 32 | METHOD_ID_ENUM(miOpen, 40), 33 | METHOD_ID_ENUM(miClose, 50) 34 | }; 35 | 36 | QAmqpClientPrivate(QAmqpClient *q); 37 | virtual ~QAmqpClientPrivate(); 38 | 39 | virtual void init(); 40 | virtual void initSocket(); 41 | void resetChannelState(); 42 | void setUsername(const QString &username); 43 | void setPassword(const QString &password); 44 | void parseConnectionString(const QString &uri); 45 | void sendFrame(const QAmqpFrame &frame); 46 | 47 | void closeConnection(); 48 | 49 | // private slots 50 | void _q_socketConnected(); 51 | void _q_socketDisconnected(); 52 | void _q_readyRead(); 53 | void _q_socketError(QAbstractSocket::SocketError error); 54 | void _q_heartbeat(); 55 | virtual void _q_connect(); 56 | void _q_disconnect(); 57 | 58 | virtual bool _q_method(const QAmqpMethodFrame &frame); 59 | 60 | // method handlers, FROM server 61 | void start(const QAmqpMethodFrame &frame); 62 | void secure(const QAmqpMethodFrame &frame); 63 | void tune(const QAmqpMethodFrame &frame); 64 | void openOk(const QAmqpMethodFrame &frame); 65 | void closeOk(const QAmqpMethodFrame &frame); 66 | 67 | // method handlers, TO server 68 | void startOk(); 69 | void secureOk(); 70 | void tuneOk(); 71 | void open(); 72 | 73 | // method handlers, BOTH ways 74 | void close(int code, const QString &text, int classId = 0, int methodId = 0); 75 | void close(const QAmqpMethodFrame &frame); 76 | 77 | quint16 port; 78 | QString host; 79 | QString virtualHost; 80 | 81 | QSharedPointer authenticator; 82 | 83 | // Network 84 | QByteArray buffer; 85 | bool autoReconnect; 86 | bool reconnectFixedTimeout; 87 | int timeout; 88 | bool connecting; 89 | bool useSsl; 90 | 91 | QSslSocket *socket; 92 | QHash > methodHandlersByChannel; 93 | QHash > contentHandlerByChannel; 94 | QHash > bodyHandlersByChannel; 95 | 96 | // Connection 97 | bool closed; 98 | bool connected; 99 | QPointer heartbeatTimer; 100 | QPointer reconnectTimer; 101 | QAmqpTable customProperties; 102 | qint16 channelMax; 103 | qint16 heartbeatDelay; 104 | qint32 frameMax; 105 | 106 | QAMQP::Error error; 107 | QString errorString; 108 | 109 | /*! Exchange objects */ 110 | QAmqpChannelHash exchanges; 111 | 112 | /*! Named queue objects */ 113 | QAmqpChannelHash queues; 114 | 115 | QAmqpClient * const q_ptr; 116 | Q_DECLARE_PUBLIC(QAmqpClient) 117 | 118 | }; 119 | 120 | #endif // QAMQPCLIENT_P_H 121 | -------------------------------------------------------------------------------- /src/qamqpexchange.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "qamqpexchange.h" 7 | #include "qamqpexchange_p.h" 8 | #include "qamqpqueue.h" 9 | #include "qamqpglobal.h" 10 | #include "qamqpclient.h" 11 | 12 | QString QAmqpExchangePrivate::typeToString(QAmqpExchange::ExchangeType type) 13 | { 14 | switch (type) { 15 | case QAmqpExchange::Direct: return QLatin1String("direct"); 16 | case QAmqpExchange::FanOut: return QLatin1String("fanout"); 17 | case QAmqpExchange::Topic: return QLatin1String("topic"); 18 | case QAmqpExchange::Headers: return QLatin1String("headers"); 19 | } 20 | 21 | return QLatin1String("direct"); 22 | } 23 | 24 | QAmqpExchangePrivate::QAmqpExchangePrivate(QAmqpExchange *q) 25 | : QAmqpChannelPrivate(q), 26 | delayedDeclare(false), 27 | declared(false), 28 | nextDeliveryTag(0) 29 | { 30 | } 31 | 32 | void QAmqpExchangePrivate::resetInternalState() 33 | { 34 | QAmqpChannelPrivate::resetInternalState(); 35 | delayedDeclare = false; 36 | declared = false; 37 | nextDeliveryTag = 0; 38 | } 39 | 40 | void QAmqpExchangePrivate::declare() 41 | { 42 | if (!opened) { 43 | delayedDeclare = true; 44 | return; 45 | } 46 | 47 | if (name.isEmpty()) { 48 | qAmqpDebug() << Q_FUNC_INFO << "attempting to declare an unnamed exchange, aborting..."; 49 | return; 50 | } 51 | 52 | QAmqpMethodFrame frame(QAmqpFrame::Exchange, QAmqpExchangePrivate::miDeclare); 53 | frame.setChannel(channelNumber); 54 | 55 | QByteArray args; 56 | QDataStream stream(&args, QIODevice::WriteOnly); 57 | 58 | stream << qint16(0); //reserved 1 59 | QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortString, name); 60 | QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortString, type); 61 | 62 | stream << qint8(options); 63 | QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::Hash, arguments); 64 | 65 | qAmqpDebug("<- exchange#declare( name=%s, type=%s, passive=%d, durable=%d, no-wait=%d )", 66 | qPrintable(name), qPrintable(type), 67 | options.testFlag(QAmqpExchange::Passive), options.testFlag(QAmqpExchange::Durable), 68 | options.testFlag(QAmqpExchange::NoWait)); 69 | 70 | frame.setArguments(args); 71 | sendFrame(frame); 72 | delayedDeclare = false; 73 | } 74 | 75 | bool QAmqpExchangePrivate::_q_method(const QAmqpMethodFrame &frame) 76 | { 77 | Q_Q(QAmqpExchange); 78 | if (QAmqpChannelPrivate::_q_method(frame)) 79 | return true; 80 | 81 | if (frame.methodClass() == QAmqpFrame::Basic) { 82 | switch (frame.id()) { 83 | case bmAck: 84 | case bmNack: 85 | handleAckOrNack(frame); 86 | break; 87 | case bmReturn: basicReturn(frame); break; 88 | 89 | default: 90 | break; 91 | } 92 | 93 | return true; 94 | } 95 | 96 | if (frame.methodClass() == QAmqpFrame::Confirm) { 97 | if (frame.id() == cmConfirmOk) { 98 | Q_EMIT q->confirmsEnabled(); 99 | return true; 100 | } 101 | } 102 | 103 | if (frame.methodClass() == QAmqpFrame::Exchange) { 104 | switch (frame.id()) { 105 | case miDeclareOk: declareOk(frame); break; 106 | case miDeleteOk: deleteOk(frame); break; 107 | 108 | default: 109 | break; 110 | } 111 | 112 | return true; 113 | } 114 | 115 | return false; 116 | } 117 | 118 | void QAmqpExchangePrivate::declareOk(const QAmqpMethodFrame &frame) 119 | { 120 | Q_UNUSED(frame) 121 | Q_Q(QAmqpExchange); 122 | qAmqpDebug("-> exchange[ %s ]#declareOk()", qPrintable(name)); 123 | declared = true; 124 | Q_EMIT q->declared(); 125 | } 126 | 127 | void QAmqpExchangePrivate::deleteOk(const QAmqpMethodFrame &frame) 128 | { 129 | Q_UNUSED(frame) 130 | Q_Q(QAmqpExchange); 131 | qAmqpDebug("-> exchange#deleteOk[ %s ]()", qPrintable(name)); 132 | declared = false; 133 | Q_EMIT q->removed(); 134 | } 135 | 136 | void QAmqpExchangePrivate::_q_disconnected() 137 | { 138 | QAmqpChannelPrivate::_q_disconnected(); 139 | qAmqpDebug() << "exchange disconnected: " << name; 140 | delayedDeclare = false; 141 | declared = false; 142 | unconfirmedDeliveryTags.clear(); 143 | } 144 | 145 | void QAmqpExchangePrivate::basicReturn(const QAmqpMethodFrame &frame) 146 | { 147 | Q_Q(QAmqpExchange); 148 | QByteArray data = frame.arguments(); 149 | QDataStream stream(&data, QIODevice::ReadOnly); 150 | 151 | quint16 replyCode; 152 | stream >> replyCode; 153 | QString replyText = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::ShortString).toString(); 154 | QString exchangeName = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::ShortString).toString(); 155 | QString routingKey = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::ShortString).toString(); 156 | 157 | QAMQP::Error checkError = static_cast(replyCode); 158 | if (checkError != QAMQP::NoError) { 159 | error = checkError; 160 | errorString = qPrintable(replyText); 161 | Q_EMIT q->error(error); 162 | } 163 | 164 | qAmqpDebug("-> basic#return( reply-code=%d, reply-text=%s, exchange=%s, routing-key=%s )", 165 | replyCode, qPrintable(replyText), qPrintable(exchangeName), qPrintable(routingKey)); 166 | } 167 | 168 | void QAmqpExchangePrivate::handleAckOrNack(const QAmqpMethodFrame &frame) 169 | { 170 | Q_Q(QAmqpExchange); 171 | QByteArray data = frame.arguments(); 172 | QDataStream stream(&data, QIODevice::ReadOnly); 173 | 174 | qlonglong deliveryTag = 175 | QAmqpFrame::readAmqpField(stream, QAmqpMetaType::LongLongUint).toLongLong(); 176 | bool multiple = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::Boolean).toBool(); 177 | if (frame.id() == QAmqpExchangePrivate::bmAck) { 178 | if (deliveryTag == 0) { 179 | unconfirmedDeliveryTags.clear(); 180 | } else { 181 | int idx = unconfirmedDeliveryTags.indexOf(deliveryTag); 182 | if (idx == -1) { 183 | return; 184 | } 185 | 186 | if (multiple) { 187 | unconfirmedDeliveryTags.remove(0, idx + 1); 188 | } else { 189 | unconfirmedDeliveryTags.remove(idx); 190 | } 191 | } 192 | 193 | if (unconfirmedDeliveryTags.isEmpty()) 194 | Q_EMIT q->allMessagesDelivered(); 195 | 196 | } else { 197 | qAmqpDebug() << "nacked(" << deliveryTag << "), multiple=" << multiple; 198 | } 199 | } 200 | 201 | ////////////////////////////////////////////////////////////////////////// 202 | 203 | QAmqpExchange::QAmqpExchange(int channelNumber, QAmqpClient *parent) 204 | : QAmqpChannel(new QAmqpExchangePrivate(this), parent) 205 | { 206 | Q_D(QAmqpExchange); 207 | d->init(channelNumber, parent); 208 | } 209 | 210 | QAmqpExchange::~QAmqpExchange() 211 | { 212 | } 213 | 214 | void QAmqpExchange::channelOpened() 215 | { 216 | Q_D(QAmqpExchange); 217 | if (d->delayedDeclare) 218 | d->declare(); 219 | } 220 | 221 | void QAmqpExchange::channelClosed() 222 | { 223 | } 224 | 225 | QAmqpExchange::ExchangeOptions QAmqpExchange::options() const 226 | { 227 | Q_D(const QAmqpExchange); 228 | return d->options; 229 | } 230 | 231 | QString QAmqpExchange::type() const 232 | { 233 | Q_D(const QAmqpExchange); 234 | return d->type; 235 | } 236 | 237 | bool QAmqpExchange::isDeclared() const 238 | { 239 | Q_D(const QAmqpExchange); 240 | return d->declared; 241 | } 242 | 243 | void QAmqpExchange::declare(ExchangeType type, ExchangeOptions options, const QAmqpTable &args) 244 | { 245 | declare(QAmqpExchangePrivate::typeToString(type), options, args); 246 | } 247 | 248 | void QAmqpExchange::declare(const QString &type, ExchangeOptions options, const QAmqpTable &args) 249 | { 250 | Q_D(QAmqpExchange); 251 | d->type = type; 252 | d->options = options; 253 | d->arguments = args; 254 | d->declare(); 255 | } 256 | 257 | void QAmqpExchange::remove(int options) 258 | { 259 | Q_D(QAmqpExchange); 260 | QAmqpMethodFrame frame(QAmqpFrame::Exchange, QAmqpExchangePrivate::miDelete); 261 | frame.setChannel(d->channelNumber); 262 | 263 | QByteArray arguments; 264 | QDataStream stream(&arguments, QIODevice::WriteOnly); 265 | 266 | stream << qint16(0); //reserved 1 267 | QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortString, d->name); 268 | stream << qint8(options); 269 | 270 | qAmqpDebug("<- exchange#delete( exchange=%s, if-unused=%d, no-wait=%d )", 271 | qPrintable(d->name), options & QAmqpExchange::roIfUnused, options & QAmqpExchange::roNoWait); 272 | 273 | frame.setArguments(arguments); 274 | d->sendFrame(frame); 275 | } 276 | 277 | void QAmqpExchange::publish(const QString &message, const QString &routingKey, 278 | const QAmqpMessage::PropertyHash &properties, int publishOptions) 279 | { 280 | publish(message.toUtf8(), routingKey, QLatin1String("text.plain"), 281 | QAmqpTable(), properties, publishOptions); 282 | } 283 | 284 | void QAmqpExchange::publish(const QByteArray &message, const QString &routingKey, 285 | const QString &mimeType, const QAmqpMessage::PropertyHash &properties, 286 | int publishOptions) 287 | { 288 | publish(message, routingKey, mimeType, QAmqpTable(), properties, publishOptions); 289 | } 290 | 291 | void QAmqpExchange::publish(const QByteArray &message, const QString &routingKey, 292 | const QString &mimeType, const QAmqpTable &headers, 293 | const QAmqpMessage::PropertyHash &properties, int publishOptions) 294 | { 295 | Q_D(QAmqpExchange); 296 | if (d->nextDeliveryTag > 0) { 297 | d->unconfirmedDeliveryTags.append(d->nextDeliveryTag); 298 | d->nextDeliveryTag++; 299 | } 300 | 301 | QAmqpMethodFrame frame(QAmqpFrame::Basic, QAmqpExchangePrivate::bmPublish); 302 | frame.setChannel(d->channelNumber); 303 | 304 | QByteArray arguments; 305 | QDataStream out(&arguments, QIODevice::WriteOnly); 306 | 307 | out << qint16(0); //reserved 1 308 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->name); 309 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, routingKey); 310 | out << qint8(publishOptions); 311 | 312 | qAmqpDebug("<- basic#publish( exchange=%s, routing-key=%s, mandatory=%d, immediate=%d )", 313 | qPrintable(d->name), qPrintable(routingKey), 314 | publishOptions & QAmqpExchange::poMandatory, publishOptions & QAmqpExchange::poImmediate); 315 | 316 | frame.setArguments(arguments); 317 | d->sendFrame(frame); 318 | 319 | QAmqpContentFrame content(QAmqpFrame::Basic); 320 | content.setChannel(d->channelNumber); 321 | content.setProperty(QAmqpMessage::ContentType, mimeType); 322 | content.setProperty(QAmqpMessage::ContentEncoding, "utf-8"); 323 | content.setProperty(QAmqpMessage::Headers, headers); 324 | 325 | QAmqpMessage::PropertyHash::ConstIterator it; 326 | QAmqpMessage::PropertyHash::ConstIterator itEnd = properties.constEnd(); 327 | for (it = properties.constBegin(); it != itEnd; ++it) 328 | content.setProperty(it.key(), it.value()); 329 | content.setBodySize(message.size()); 330 | d->sendFrame(content); 331 | 332 | int fullSize = message.size(); 333 | for (int sent = 0; sent < fullSize; sent += (d->client->frameMax() - 7)) { 334 | QAmqpContentBodyFrame body; 335 | QByteArray partition = message.mid(sent, (d->client->frameMax() - 7)); 336 | body.setChannel(d->channelNumber); 337 | body.setBody(partition); 338 | d->sendFrame(body); 339 | } 340 | } 341 | 342 | void QAmqpExchange::enableConfirms(bool noWait) 343 | { 344 | Q_D(QAmqpExchange); 345 | QAmqpMethodFrame frame(QAmqpFrame::Confirm, QAmqpExchangePrivate::cmConfirm); 346 | frame.setChannel(d->channelNumber); 347 | 348 | QByteArray arguments; 349 | QDataStream stream(&arguments, QIODevice::WriteOnly); 350 | stream << qint8(noWait ? 1 : 0); 351 | 352 | frame.setArguments(arguments); 353 | d->sendFrame(frame); 354 | 355 | // for tracking acks and nacks 356 | if (d->nextDeliveryTag == 0) d->nextDeliveryTag = 1; 357 | } 358 | 359 | bool QAmqpExchange::waitForConfirms(int msecs) 360 | { 361 | Q_D(QAmqpExchange); 362 | 363 | QEventLoop loop; 364 | connect(this, SIGNAL(allMessagesDelivered()), &loop, SLOT(quit())); 365 | QTimer::singleShot(msecs, &loop, SLOT(quit())); 366 | loop.exec(); 367 | 368 | return (d->unconfirmedDeliveryTags.isEmpty()); 369 | } 370 | -------------------------------------------------------------------------------- /src/qamqpexchange.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2014 Alexey Shcherbakov 3 | * Copyright (C) 2014-2015 Matt Broadstone 4 | * Contact: https://github.com/mbroadst/qamqp 5 | * 6 | * This file is part of the QAMQP Library. 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | */ 18 | #ifndef QAMQPEXCHANGE_H 19 | #define QAMQPEXCHANGE_H 20 | 21 | #include "qamqptable.h" 22 | #include "qamqpchannel.h" 23 | #include "qamqpmessage.h" 24 | 25 | class QAmqpClient; 26 | class QAmqpQueue; 27 | class QAmqpClientPrivate; 28 | class QAmqpExchangePrivate; 29 | class QAMQP_EXPORT QAmqpExchange : public QAmqpChannel 30 | { 31 | Q_OBJECT 32 | Q_PROPERTY(QString type READ type CONSTANT) 33 | Q_PROPERTY(ExchangeOptions options READ options CONSTANT) 34 | Q_ENUMS(ExchangeOptions) 35 | 36 | public: 37 | virtual ~QAmqpExchange(); 38 | 39 | enum ExchangeType { 40 | Direct, 41 | FanOut, 42 | Topic, 43 | Headers 44 | }; 45 | QString type() const; 46 | 47 | enum PublishOption { 48 | poNoOptions = 0x0, 49 | poMandatory = 0x01, 50 | poImmediate = 0x02 51 | }; 52 | Q_DECLARE_FLAGS(PublishOptions, PublishOption) 53 | 54 | enum RemoveOption { 55 | roForce = 0x0, 56 | roIfUnused = 0x01, 57 | roNoWait = 0x04 58 | }; 59 | Q_DECLARE_FLAGS(RemoveOptions, RemoveOption) 60 | 61 | enum ExchangeOption { 62 | NoOptions = 0x0, 63 | Passive = 0x01, 64 | Durable = 0x02, 65 | AutoDelete = 0x04, 66 | Internal = 0x08, 67 | NoWait = 0x10 68 | }; 69 | Q_DECLARE_FLAGS(ExchangeOptions, ExchangeOption) 70 | ExchangeOptions options() const; 71 | 72 | bool isDeclared() const; 73 | 74 | void enableConfirms(bool noWait = false); 75 | bool waitForConfirms(int msecs = 30000); 76 | 77 | Q_SIGNALS: 78 | void declared(); 79 | void removed(); 80 | 81 | void confirmsEnabled(); 82 | void allMessagesDelivered(); 83 | 84 | public Q_SLOTS: 85 | // AMQP Exchange 86 | void declare(ExchangeType type = Direct, 87 | ExchangeOptions options = NoOptions, 88 | const QAmqpTable &args = QAmqpTable()); 89 | void declare(const QString &type, 90 | ExchangeOptions options = NoOptions, 91 | const QAmqpTable &args = QAmqpTable()); 92 | void remove(int options = roIfUnused|roNoWait); 93 | 94 | // AMQP Basic 95 | void publish(const QString &message, const QString &routingKey, 96 | const QAmqpMessage::PropertyHash &properties = QAmqpMessage::PropertyHash(), 97 | int publishOptions = poNoOptions); 98 | void publish(const QByteArray &message, const QString &routingKey, const QString &mimeType, 99 | const QAmqpMessage::PropertyHash &properties = QAmqpMessage::PropertyHash(), 100 | int publishOptions = poNoOptions); 101 | void publish(const QByteArray &message, const QString &routingKey, 102 | const QString &mimeType, const QAmqpTable &headers, 103 | const QAmqpMessage::PropertyHash &properties = QAmqpMessage::PropertyHash(), 104 | int publishOptions = poNoOptions); 105 | 106 | protected: 107 | virtual void channelOpened(); 108 | virtual void channelClosed(); 109 | 110 | private: 111 | explicit QAmqpExchange(int channelNumber = -1, QAmqpClient *parent = 0); 112 | 113 | Q_DISABLE_COPY(QAmqpExchange) 114 | Q_DECLARE_PRIVATE(QAmqpExchange) 115 | friend class QAmqpClient; 116 | friend class QAmqpClientPrivate; 117 | 118 | }; 119 | 120 | Q_DECLARE_OPERATORS_FOR_FLAGS(QAmqpExchange::ExchangeOptions) 121 | Q_DECLARE_METATYPE(QAmqpExchange::ExchangeType) 122 | 123 | #endif // QAMQPEXCHANGE_H 124 | -------------------------------------------------------------------------------- /src/qamqpexchange_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QAMQPEXCHANGE_P_H 2 | #define QAMQPEXCHANGE_P_H 3 | 4 | #include "qamqptable.h" 5 | #include "qamqpexchange.h" 6 | #include "qamqpchannel_p.h" 7 | 8 | class QAmqpExchangePrivate: public QAmqpChannelPrivate 9 | { 10 | public: 11 | enum MethodId { 12 | METHOD_ID_ENUM(miDeclare, 10), 13 | METHOD_ID_ENUM(miDelete, 20) 14 | }; 15 | 16 | enum ConfirmMethod { 17 | METHOD_ID_ENUM(cmConfirm, 10) 18 | }; 19 | 20 | QAmqpExchangePrivate(QAmqpExchange *q); 21 | static QString typeToString(QAmqpExchange::ExchangeType type); 22 | 23 | virtual void resetInternalState(); 24 | 25 | void declare(); 26 | 27 | // method handler related 28 | virtual void _q_disconnected(); 29 | virtual bool _q_method(const QAmqpMethodFrame &frame); 30 | void declareOk(const QAmqpMethodFrame &frame); 31 | void deleteOk(const QAmqpMethodFrame &frame); 32 | void basicReturn(const QAmqpMethodFrame &frame); 33 | void handleAckOrNack(const QAmqpMethodFrame &frame); 34 | 35 | QString type; 36 | QAmqpExchange::ExchangeOptions options; 37 | bool delayedDeclare; 38 | bool declared; 39 | qlonglong nextDeliveryTag; 40 | QVector unconfirmedDeliveryTags; 41 | 42 | Q_DECLARE_PUBLIC(QAmqpExchange) 43 | }; 44 | 45 | #endif // QAMQPEXCHANGE_P_H 46 | -------------------------------------------------------------------------------- /src/qamqpframe.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "qamqptable.h" 6 | #include "qamqpglobal.h" 7 | #include "qamqpframe_p.h" 8 | 9 | QReadWriteLock QAmqpFrame::lock_; 10 | int QAmqpFrame::writeTimeout_ = 1000; 11 | 12 | QAmqpFrame::QAmqpFrame(FrameType type) 13 | : size_(0), 14 | type_(type), 15 | channel_(0) 16 | { 17 | } 18 | 19 | QAmqpFrame::FrameType QAmqpFrame::type() const 20 | { 21 | return static_cast(type_); 22 | } 23 | 24 | QAmqpFrame::~QAmqpFrame() 25 | { 26 | } 27 | 28 | void QAmqpFrame::setChannel(quint16 channel) 29 | { 30 | channel_ = channel; 31 | } 32 | 33 | int QAmqpFrame::writeTimeout() 34 | { 35 | QReadLocker locker(&lock_); 36 | return writeTimeout_; 37 | } 38 | 39 | void QAmqpFrame::setWriteTimeout(int msecs) 40 | { 41 | QWriteLocker locker(&lock_); 42 | writeTimeout_ = msecs; 43 | } 44 | 45 | quint16 QAmqpFrame::channel() const 46 | { 47 | return channel_; 48 | } 49 | 50 | qint32 QAmqpFrame::size() const 51 | { 52 | return 0; 53 | } 54 | 55 | /* 56 | void QAmqpFrame::readEnd(QDataStream &stream) 57 | { 58 | unsigned char end_ = 0; 59 | stream.readRawData(reinterpret_cast(&end_), sizeof(end_)); 60 | if (end_ != FRAME_END) 61 | qAmqpDebug("Wrong end of frame"); 62 | } 63 | */ 64 | 65 | QDataStream &operator<<(QDataStream &stream, const QAmqpFrame &frame) 66 | { 67 | // write header 68 | stream << frame.type_; 69 | stream << frame.channel_; 70 | stream << frame.size(); 71 | 72 | frame.writePayload(stream); 73 | 74 | // write end 75 | stream << qint8(QAmqpFrame::FRAME_END); 76 | 77 | int writeTimeout = QAmqpFrame::writeTimeout(); 78 | if(writeTimeout >= -1) 79 | { 80 | stream.device()->waitForBytesWritten(writeTimeout); 81 | } 82 | 83 | return stream; 84 | } 85 | 86 | QDataStream &operator>>(QDataStream &stream, QAmqpFrame &frame) 87 | { 88 | stream >> frame.type_; 89 | stream >> frame.channel_; 90 | stream >> frame.size_; 91 | frame.readPayload(stream); 92 | return stream; 93 | } 94 | 95 | ////////////////////////////////////////////////////////////////////////// 96 | 97 | QAmqpMethodFrame::QAmqpMethodFrame() 98 | : QAmqpFrame(QAmqpFrame::Method), 99 | methodClass_(0), 100 | id_(0) 101 | { 102 | } 103 | 104 | QAmqpMethodFrame::QAmqpMethodFrame(MethodClass methodClass, qint16 id) 105 | : QAmqpFrame(QAmqpFrame::Method), 106 | methodClass_(methodClass), 107 | id_(id) 108 | { 109 | } 110 | 111 | QAmqpFrame::MethodClass QAmqpMethodFrame::methodClass() const 112 | { 113 | return MethodClass(methodClass_); 114 | } 115 | 116 | qint16 QAmqpMethodFrame::id() const 117 | { 118 | return id_; 119 | } 120 | 121 | qint32 QAmqpMethodFrame::size() const 122 | { 123 | return sizeof(id_) + sizeof(methodClass_) + arguments_.size(); 124 | } 125 | 126 | void QAmqpMethodFrame::setArguments(const QByteArray &data) 127 | { 128 | arguments_ = data; 129 | } 130 | 131 | QByteArray QAmqpMethodFrame::arguments() const 132 | { 133 | return arguments_; 134 | } 135 | 136 | void QAmqpMethodFrame::readPayload(QDataStream &stream) 137 | { 138 | stream >> methodClass_; 139 | stream >> id_; 140 | 141 | arguments_.resize(size_ - (sizeof(id_) + sizeof(methodClass_))); 142 | stream.readRawData(arguments_.data(), arguments_.size()); 143 | } 144 | 145 | void QAmqpMethodFrame::writePayload(QDataStream &stream) const 146 | { 147 | stream << quint16(methodClass_); 148 | stream << quint16(id_); 149 | stream.writeRawData(arguments_.data(), arguments_.size()); 150 | } 151 | 152 | ////////////////////////////////////////////////////////////////////////// 153 | 154 | QVariant QAmqpFrame::readAmqpField(QDataStream &s, QAmqpMetaType::ValueType type) 155 | { 156 | switch (type) { 157 | case QAmqpMetaType::Boolean: 158 | { 159 | quint8 octet = 0; 160 | s >> octet; 161 | return QVariant::fromValue(octet > 0); 162 | } 163 | case QAmqpMetaType::ShortShortUint: 164 | { 165 | quint8 octet = 0; 166 | s >> octet; 167 | return QVariant::fromValue(octet); 168 | } 169 | case QAmqpMetaType::ShortUint: 170 | { 171 | quint16 tmp_value = 0; 172 | s >> tmp_value; 173 | return QVariant::fromValue(tmp_value); 174 | } 175 | case QAmqpMetaType::LongUint: 176 | { 177 | quint32 tmp_value = 0; 178 | s >> tmp_value; 179 | return QVariant::fromValue(tmp_value); 180 | } 181 | case QAmqpMetaType::LongLongUint: 182 | { 183 | qulonglong v = 0 ; 184 | s >> v; 185 | return v; 186 | } 187 | case QAmqpMetaType::ShortString: 188 | { 189 | qint8 size = 0; 190 | QByteArray buffer; 191 | 192 | s >> size; 193 | buffer.resize(size); 194 | s.readRawData(buffer.data(), buffer.size()); 195 | return QString::fromLatin1(buffer.data(), size); 196 | } 197 | case QAmqpMetaType::LongString: 198 | { 199 | quint32 size = 0; 200 | QByteArray buffer; 201 | 202 | s >> size; 203 | buffer.resize(size); 204 | s.readRawData(buffer.data(), buffer.size()); 205 | return QString::fromUtf8(buffer.data(), buffer.size()); 206 | } 207 | case QAmqpMetaType::Timestamp: 208 | { 209 | qulonglong tmp_value; 210 | s >> tmp_value; 211 | return QDateTime::fromTime_t(tmp_value); 212 | } 213 | case QAmqpMetaType::Hash: 214 | { 215 | QAmqpTable table; 216 | s >> table; 217 | return table; 218 | } 219 | case QAmqpMetaType::Void: 220 | return QVariant(); 221 | default: 222 | qAmqpDebug() << Q_FUNC_INFO << "unsupported value type: " << type; 223 | } 224 | 225 | return QVariant(); 226 | } 227 | 228 | void QAmqpFrame::writeAmqpField(QDataStream &s, QAmqpMetaType::ValueType type, const QVariant &value) 229 | { 230 | switch (type) { 231 | case QAmqpMetaType::Boolean: 232 | s << (value.toBool() ? qint8(1) : qint8(0)); 233 | break; 234 | case QAmqpMetaType::ShortShortUint: 235 | s << qint8(value.toUInt()); 236 | break; 237 | case QAmqpMetaType::ShortUint: 238 | s << quint16(value.toUInt()); 239 | break; 240 | case QAmqpMetaType::LongUint: 241 | s << quint32(value.toUInt()); 242 | break; 243 | case QAmqpMetaType::LongLongUint: 244 | s << qulonglong(value.toULongLong()); 245 | break; 246 | case QAmqpMetaType::ShortString: 247 | { 248 | QString str = value.toString(); 249 | if (str.length() >= 256) { 250 | qAmqpDebug() << Q_FUNC_INFO << "invalid shortstr length: " << str.length(); 251 | } 252 | 253 | s << quint8(str.length()); 254 | s.writeRawData(str.toUtf8().data(), str.length()); 255 | } 256 | break; 257 | case QAmqpMetaType::LongString: 258 | { 259 | QString str = value.toString(); 260 | s << quint32(str.length()); 261 | s.writeRawData(str.toLatin1().data(), str.length()); 262 | } 263 | break; 264 | case QAmqpMetaType::Timestamp: 265 | s << qulonglong(value.toDateTime().toTime_t()); 266 | break; 267 | case QAmqpMetaType::Hash: 268 | { 269 | QAmqpTable table(value.toHash()); 270 | s << table; 271 | } 272 | break; 273 | default: 274 | qAmqpDebug() << Q_FUNC_INFO << "unsupported value type: " << type; 275 | } 276 | } 277 | 278 | ////////////////////////////////////////////////////////////////////////// 279 | 280 | QAmqpContentFrame::QAmqpContentFrame() 281 | : QAmqpFrame(QAmqpFrame::Header) 282 | { 283 | } 284 | 285 | QAmqpContentFrame::QAmqpContentFrame(QAmqpFrame::MethodClass methodClass) 286 | : QAmqpFrame(QAmqpFrame::Header) 287 | { 288 | methodClass_ = methodClass; 289 | } 290 | 291 | QAmqpFrame::MethodClass QAmqpContentFrame::methodClass() const 292 | { 293 | return MethodClass(methodClass_); 294 | } 295 | 296 | qint32 QAmqpContentFrame::size() const 297 | { 298 | QDataStream out(&buffer_, QIODevice::WriteOnly); 299 | buffer_.clear(); 300 | out << qint16(methodClass_); 301 | out << qint16(0); //weight 302 | out << qlonglong(bodySize_); 303 | 304 | qint16 prop_ = 0; 305 | foreach (int p, properties_.keys()) 306 | prop_ |= p; 307 | out << prop_; 308 | 309 | if (prop_ & QAmqpMessage::ContentType) 310 | writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::ContentType]); 311 | 312 | if (prop_ & QAmqpMessage::ContentEncoding) 313 | writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::ContentEncoding]); 314 | 315 | if (prop_ & QAmqpMessage::Headers) 316 | writeAmqpField(out, QAmqpMetaType::Hash, properties_[QAmqpMessage::Headers]); 317 | 318 | if (prop_ & QAmqpMessage::DeliveryMode) 319 | writeAmqpField(out, QAmqpMetaType::ShortShortUint, properties_[QAmqpMessage::DeliveryMode]); 320 | 321 | if (prop_ & QAmqpMessage::Priority) 322 | writeAmqpField(out, QAmqpMetaType::ShortShortUint, properties_[QAmqpMessage::Priority]); 323 | 324 | if (prop_ & QAmqpMessage::CorrelationId) 325 | writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::CorrelationId]); 326 | 327 | if (prop_ & QAmqpMessage::ReplyTo) 328 | writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::ReplyTo]); 329 | 330 | if (prop_ & QAmqpMessage::Expiration) 331 | writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::Expiration]); 332 | 333 | if (prop_ & QAmqpMessage::MessageId) 334 | writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::MessageId]); 335 | 336 | if (prop_ & QAmqpMessage::Timestamp) 337 | writeAmqpField(out, QAmqpMetaType::Timestamp, properties_[QAmqpMessage::Timestamp]); 338 | 339 | if (prop_ & QAmqpMessage::Type) 340 | writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::Type]); 341 | 342 | if (prop_ & QAmqpMessage::UserId) 343 | writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::UserId]); 344 | 345 | if (prop_ & QAmqpMessage::AppId) 346 | writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::AppId]); 347 | 348 | if (prop_ & QAmqpMessage::ClusterID) 349 | writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::ClusterID]); 350 | 351 | return buffer_.size(); 352 | } 353 | 354 | qlonglong QAmqpContentFrame::bodySize() const 355 | { 356 | return bodySize_; 357 | } 358 | 359 | void QAmqpContentFrame::setBodySize(qlonglong size) 360 | { 361 | bodySize_ = size; 362 | } 363 | 364 | void QAmqpContentFrame::setProperty(QAmqpMessage::Property prop, const QVariant &value) 365 | { 366 | properties_[prop] = value; 367 | } 368 | 369 | QVariant QAmqpContentFrame::property(QAmqpMessage::Property prop) const 370 | { 371 | return properties_.value(prop); 372 | } 373 | 374 | void QAmqpContentFrame::writePayload(QDataStream &out) const 375 | { 376 | out.writeRawData(buffer_.data(), buffer_.size()); 377 | } 378 | 379 | void QAmqpContentFrame::readPayload(QDataStream &in) 380 | { 381 | in >> methodClass_; 382 | in.skipRawData(2); //weight 383 | in >> bodySize_; 384 | qint16 flags_ = 0; 385 | in >> flags_; 386 | if (flags_ & QAmqpMessage::ContentType) 387 | properties_[QAmqpMessage::ContentType] = readAmqpField(in, QAmqpMetaType::ShortString); 388 | 389 | if (flags_ & QAmqpMessage::ContentEncoding) 390 | properties_[QAmqpMessage::ContentEncoding] = readAmqpField(in, QAmqpMetaType::ShortString); 391 | 392 | if (flags_ & QAmqpMessage::Headers) 393 | properties_[QAmqpMessage::Headers] = readAmqpField(in, QAmqpMetaType::Hash); 394 | 395 | if (flags_ & QAmqpMessage::DeliveryMode) 396 | properties_[QAmqpMessage::DeliveryMode] = readAmqpField(in, QAmqpMetaType::ShortShortUint); 397 | 398 | if (flags_ & QAmqpMessage::Priority) 399 | properties_[QAmqpMessage::Priority] = readAmqpField(in, QAmqpMetaType::ShortShortUint); 400 | 401 | if (flags_ & QAmqpMessage::CorrelationId) 402 | properties_[QAmqpMessage::CorrelationId] = readAmqpField(in, QAmqpMetaType::ShortString); 403 | 404 | if (flags_ & QAmqpMessage::ReplyTo) 405 | properties_[QAmqpMessage::ReplyTo] = readAmqpField(in, QAmqpMetaType::ShortString); 406 | 407 | if (flags_ & QAmqpMessage::Expiration) 408 | properties_[QAmqpMessage::Expiration] = readAmqpField(in, QAmqpMetaType::ShortString); 409 | 410 | if (flags_ & QAmqpMessage::MessageId) 411 | properties_[QAmqpMessage::MessageId] = readAmqpField(in, QAmqpMetaType::ShortString); 412 | 413 | if (flags_ & QAmqpMessage::Timestamp) 414 | properties_[QAmqpMessage::Timestamp] = readAmqpField(in, QAmqpMetaType::Timestamp); 415 | 416 | if (flags_ & QAmqpMessage::Type) 417 | properties_[QAmqpMessage::Type] = readAmqpField(in, QAmqpMetaType::ShortString); 418 | 419 | if (flags_ & QAmqpMessage::UserId) 420 | properties_[QAmqpMessage::UserId] = readAmqpField(in, QAmqpMetaType::ShortString); 421 | 422 | if (flags_ & QAmqpMessage::AppId) 423 | properties_[QAmqpMessage::AppId] = readAmqpField(in, QAmqpMetaType::ShortString); 424 | 425 | if (flags_ & QAmqpMessage::ClusterID) 426 | properties_[QAmqpMessage::ClusterID] = readAmqpField(in, QAmqpMetaType::ShortString); 427 | } 428 | 429 | ////////////////////////////////////////////////////////////////////////// 430 | 431 | QAmqpContentBodyFrame::QAmqpContentBodyFrame() 432 | : QAmqpFrame(QAmqpFrame::Body) 433 | { 434 | } 435 | 436 | void QAmqpContentBodyFrame::setBody(const QByteArray &data) 437 | { 438 | body_ = data; 439 | } 440 | 441 | QByteArray QAmqpContentBodyFrame::body() const 442 | { 443 | return body_; 444 | } 445 | 446 | void QAmqpContentBodyFrame::writePayload(QDataStream &out) const 447 | { 448 | out.writeRawData(body_.data(), body_.size()); 449 | } 450 | 451 | void QAmqpContentBodyFrame::readPayload(QDataStream &in) 452 | { 453 | body_.resize(size_); 454 | in.readRawData(body_.data(), body_.size()); 455 | } 456 | 457 | qint32 QAmqpContentBodyFrame::size() const 458 | { 459 | return body_.size(); 460 | } 461 | 462 | ////////////////////////////////////////////////////////////////////////// 463 | 464 | QAmqpHeartbeatFrame::QAmqpHeartbeatFrame() 465 | : QAmqpFrame(QAmqpFrame::Heartbeat) 466 | { 467 | } 468 | 469 | void QAmqpHeartbeatFrame::readPayload(QDataStream &stream) 470 | { 471 | Q_UNUSED(stream) 472 | } 473 | 474 | void QAmqpHeartbeatFrame::writePayload(QDataStream &stream) const 475 | { 476 | Q_UNUSED(stream) 477 | } 478 | -------------------------------------------------------------------------------- /src/qamqpframe_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QAMQPFRAME_P_H 2 | #define QAMQPFRAME_P_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "qamqpglobal.h" 10 | #include "qamqpmessage.h" 11 | 12 | class QAmqpFramePrivate; 13 | class QAmqpFrame 14 | { 15 | public: 16 | static const qint64 HEADER_SIZE = 7; 17 | static const qint64 FRAME_END_SIZE = 1; 18 | static const quint8 FRAME_END = 0xCE; 19 | 20 | enum FrameType 21 | { 22 | Method = 1, 23 | Header = 2, 24 | Body = 3, 25 | Heartbeat = 8 26 | }; 27 | 28 | enum MethodClass 29 | { 30 | Connection = 10, 31 | Channel = 20, 32 | Exchange = 40, 33 | Queue = 50, 34 | Basic = 60, 35 | Confirm = 85, 36 | Tx = 90 37 | }; 38 | 39 | virtual ~QAmqpFrame(); 40 | 41 | FrameType type() const; 42 | 43 | quint16 channel() const; 44 | void setChannel(quint16 channel); 45 | 46 | static int writeTimeout(); 47 | static void setWriteTimeout(int msecs); 48 | 49 | virtual qint32 size() const; 50 | 51 | static QVariant readAmqpField(QDataStream &s, QAmqpMetaType::ValueType type); 52 | static void writeAmqpField(QDataStream &s, QAmqpMetaType::ValueType type, const QVariant &value); 53 | 54 | protected: 55 | explicit QAmqpFrame(FrameType type); 56 | virtual void writePayload(QDataStream &stream) const = 0; 57 | virtual void readPayload(QDataStream &stream) = 0; 58 | 59 | qint32 size_; 60 | 61 | private: 62 | qint8 type_; 63 | quint16 channel_; 64 | 65 | static QReadWriteLock lock_; 66 | static int writeTimeout_; 67 | 68 | friend QDataStream &operator<<(QDataStream &stream, const QAmqpFrame &frame); 69 | friend QDataStream &operator>>(QDataStream &stream, QAmqpFrame &frame); 70 | }; 71 | 72 | QDataStream &operator<<(QDataStream &, const QAmqpFrame &frame); 73 | QDataStream &operator>>(QDataStream &, QAmqpFrame &frame); 74 | 75 | class QAMQP_EXPORT QAmqpMethodFrame : public QAmqpFrame 76 | { 77 | public: 78 | QAmqpMethodFrame(); 79 | QAmqpMethodFrame(MethodClass methodClass, qint16 id); 80 | 81 | qint16 id() const; 82 | MethodClass methodClass() const; 83 | 84 | virtual qint32 size() const; 85 | 86 | QByteArray arguments() const; 87 | void setArguments(const QByteArray &data); 88 | 89 | private: 90 | void writePayload(QDataStream &stream) const; 91 | void readPayload(QDataStream &stream); 92 | 93 | short methodClass_; 94 | qint16 id_; 95 | QByteArray arguments_; 96 | }; 97 | 98 | class QAmqpContentFrame : public QAmqpFrame 99 | { 100 | public: 101 | QAmqpContentFrame(); 102 | QAmqpContentFrame(MethodClass methodClass); 103 | 104 | MethodClass methodClass() const; 105 | 106 | virtual qint32 size() const; 107 | 108 | QVariant property(QAmqpMessage::Property prop) const; 109 | void setProperty(QAmqpMessage::Property prop, const QVariant &value); 110 | 111 | qlonglong bodySize() const; 112 | void setBodySize(qlonglong size); 113 | 114 | private: 115 | void writePayload(QDataStream &stream) const; 116 | void readPayload(QDataStream &stream); 117 | friend class QAmqpQueuePrivate; 118 | 119 | short methodClass_; 120 | qint16 id_; 121 | mutable QByteArray buffer_; 122 | QAmqpMessage::PropertyHash properties_; 123 | qlonglong bodySize_; 124 | }; 125 | 126 | class QAmqpContentBodyFrame : public QAmqpFrame 127 | { 128 | public: 129 | QAmqpContentBodyFrame(); 130 | 131 | void setBody(const QByteArray &data); 132 | QByteArray body() const; 133 | 134 | virtual qint32 size() const; 135 | 136 | private: 137 | void writePayload(QDataStream &stream) const; 138 | void readPayload(QDataStream &stream); 139 | 140 | QByteArray body_; 141 | }; 142 | 143 | class QAmqpHeartbeatFrame : public QAmqpFrame 144 | { 145 | public: 146 | QAmqpHeartbeatFrame(); 147 | 148 | private: 149 | void writePayload(QDataStream &stream) const; 150 | void readPayload(QDataStream &stream); 151 | }; 152 | 153 | class QAmqpMethodFrameHandler 154 | { 155 | public: 156 | virtual bool _q_method(const QAmqpMethodFrame &frame) = 0; 157 | }; 158 | 159 | class QAmqpContentFrameHandler 160 | { 161 | public: 162 | virtual void _q_content(const QAmqpContentFrame &frame) = 0; 163 | }; 164 | 165 | class QAmqpContentBodyFrameHandler 166 | { 167 | public: 168 | virtual void _q_body(const QAmqpContentBodyFrame &frame) = 0; 169 | }; 170 | 171 | #endif // QAMQPFRAME_P_H 172 | -------------------------------------------------------------------------------- /src/qamqpglobal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2014 Alexey Shcherbakov 3 | * Copyright (C) 2014-2015 Matt Broadstone 4 | * Contact: https://github.com/mbroadst/qamqp 5 | * 6 | * This file is part of the QAMQP Library. 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | */ 18 | #ifndef QAMQPGLOBAL_H 19 | #define QAMQPGLOBAL_H 20 | 21 | #include 22 | 23 | #define AMQP_SCHEME "amqp" 24 | #define AMQP_SSL_SCHEME "amqps" 25 | #define AMQP_PORT 5672 26 | #define AMQP_SSL_PORT 5671 27 | #define AMQP_HOST "localhost" 28 | #define AMQP_VHOST "/" 29 | #define AMQP_LOGIN "guest" 30 | #define AMQP_PSWD "guest" 31 | 32 | #define AMQP_FRAME_MAX 131072 33 | #define AMQP_FRAME_MIN_SIZE 4096 34 | 35 | #define AMQP_BASIC_CONTENT_TYPE_FLAG (1 << 15) 36 | #define AMQP_BASIC_CONTENT_ENCODING_FLAG (1 << 14) 37 | #define AMQP_BASIC_HEADERS_FLAG (1 << 13) 38 | #define AMQP_BASIC_DELIVERY_MODE_FLAG (1 << 12) 39 | #define AMQP_BASIC_PRIORITY_FLAG (1 << 11) 40 | #define AMQP_BASIC_CORRELATION_ID_FLAG (1 << 10) 41 | #define AMQP_BASIC_REPLY_TO_FLAG (1 << 9) 42 | #define AMQP_BASIC_EXPIRATION_FLAG (1 << 8) 43 | #define AMQP_BASIC_MESSAGE_ID_FLAG (1 << 7) 44 | #define AMQP_BASIC_TIMESTAMP_FLAG (1 << 6) 45 | #define AMQP_BASIC_TYPE_FLAG (1 << 5) 46 | #define AMQP_BASIC_USER_ID_FLAG (1 << 4) 47 | #define AMQP_BASIC_APP_ID_FLAG (1 << 3) 48 | #define AMQP_BASIC_CLUSTER_ID_FLAG (1 << 2) 49 | 50 | #define QAMQP_VERSION "0.5.0" 51 | 52 | #define AMQP_CONNECTION_FORCED 320 53 | 54 | #ifdef QAMQP_SHARED 55 | # ifdef QAMQP_BUILD 56 | # define QAMQP_EXPORT Q_DECL_EXPORT 57 | # else 58 | # define QAMQP_EXPORT Q_DECL_IMPORT 59 | # endif 60 | #else 61 | # define QAMQP_EXPORT 62 | #endif 63 | 64 | #define qAmqpDebug if (qgetenv("QAMQP_DEBUG").isEmpty()); else qDebug 65 | 66 | namespace QAmqpMetaType { 67 | 68 | enum ValueType 69 | { 70 | Invalid = -1, 71 | 72 | // basic AMQP types 73 | Boolean, 74 | ShortUint, 75 | LongUint, 76 | LongLongUint, 77 | ShortString, 78 | LongString, 79 | 80 | // field-value types 81 | ShortShortInt, 82 | ShortShortUint, 83 | ShortInt, 84 | LongInt, 85 | LongLongInt, 86 | Float, 87 | Double, 88 | Decimal, 89 | Array, 90 | Timestamp, 91 | Hash, 92 | Bytes, 93 | Void 94 | }; 95 | 96 | } // namespace QAmqpMetaType 97 | 98 | namespace QAMQP { 99 | 100 | enum Error 101 | { 102 | NoError = 0, 103 | ContentTooLargeError = 311, 104 | NoRouteError = 312, 105 | NoConsumersError = 313, 106 | ConnectionForcedError = 320, 107 | InvalidPathError = 402, 108 | AccessRefusedError = 403, 109 | NotFoundError = 404, 110 | ResourceLockedError = 405, 111 | PreconditionFailedError = 406, 112 | FrameError = 501, 113 | SyntaxError = 502, 114 | CommandInvalidError = 503, 115 | ChannelError = 504, 116 | UnexpectedFrameError = 505, 117 | ResourceError = 506, 118 | NotAllowedError = 530, 119 | NotImplementedError = 540, 120 | InternalError = 541 121 | }; 122 | 123 | struct Decimal 124 | { 125 | qint8 scale; 126 | quint32 value; 127 | }; 128 | 129 | } // namespace QAMQP 130 | 131 | Q_DECLARE_METATYPE(QAMQP::Error) 132 | Q_DECLARE_METATYPE(QAMQP::Decimal) 133 | 134 | #endif // QAMQPGLOBAL_H 135 | -------------------------------------------------------------------------------- /src/qamqpmessage.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "qamqpmessage.h" 4 | #include "qamqpmessage_p.h" 5 | 6 | QAmqpMessagePrivate::QAmqpMessagePrivate() 7 | : deliveryTag(0), 8 | leftSize(0) 9 | { 10 | } 11 | 12 | ////////////////////////////////////////////////////////////////////////// 13 | 14 | QAmqpMessage::QAmqpMessage() 15 | : d(new QAmqpMessagePrivate) 16 | { 17 | } 18 | 19 | QAmqpMessage::QAmqpMessage(const QAmqpMessage &other) 20 | : d(other.d) 21 | { 22 | } 23 | 24 | QAmqpMessage::~QAmqpMessage() 25 | { 26 | } 27 | 28 | QAmqpMessage &QAmqpMessage::operator=(const QAmqpMessage &other) 29 | { 30 | d = other.d; 31 | return *this; 32 | } 33 | 34 | bool QAmqpMessage::operator==(const QAmqpMessage &message) const 35 | { 36 | if (message.d == d) 37 | return true; 38 | 39 | return (message.d->deliveryTag == d->deliveryTag && 40 | message.d->redelivered == d->redelivered && 41 | message.d->exchangeName == d->exchangeName && 42 | message.d->routingKey == d->routingKey && 43 | message.d->payload == d->payload && 44 | message.d->properties == d->properties && 45 | message.d->headers == d->headers && 46 | message.d->leftSize == d->leftSize); 47 | } 48 | 49 | bool QAmqpMessage::isValid() const 50 | { 51 | return d->deliveryTag != 0 && 52 | !d->exchangeName.isNull() && 53 | !d->routingKey.isNull(); 54 | } 55 | 56 | qlonglong QAmqpMessage::deliveryTag() const 57 | { 58 | return d->deliveryTag; 59 | } 60 | 61 | bool QAmqpMessage::isRedelivered() const 62 | { 63 | return d->redelivered; 64 | } 65 | 66 | QString QAmqpMessage::exchangeName() const 67 | { 68 | return d->exchangeName; 69 | } 70 | 71 | QString QAmqpMessage::routingKey() const 72 | { 73 | return d->routingKey; 74 | } 75 | 76 | QByteArray QAmqpMessage::payload() const 77 | { 78 | return d->payload; 79 | } 80 | 81 | bool QAmqpMessage::hasProperty(Property property) const 82 | { 83 | return d->properties.contains(property); 84 | } 85 | 86 | void QAmqpMessage::setProperty(Property property, const QVariant &value) 87 | { 88 | d->properties.insert(property, value); 89 | } 90 | 91 | QVariant QAmqpMessage::property(Property property, const QVariant &defaultValue) const 92 | { 93 | return d->properties.value(property, defaultValue); 94 | } 95 | 96 | bool QAmqpMessage::hasHeader(const QString &header) const 97 | { 98 | return d->headers.contains(header); 99 | } 100 | 101 | void QAmqpMessage::setHeader(const QString &header, const QVariant &value) 102 | { 103 | d->headers.insert(header, value); 104 | } 105 | 106 | QVariant QAmqpMessage::header(const QString &header, const QVariant &defaultValue) const 107 | { 108 | return d->headers.value(header, defaultValue); 109 | } 110 | 111 | QHash QAmqpMessage::headers() const 112 | { 113 | return d->headers; 114 | } 115 | 116 | #if QT_VERSION < 0x050000 117 | bool QAmqpMessage::isDetached() const 118 | { 119 | return d && d->ref == 1; 120 | } 121 | #endif 122 | 123 | uint qHash(const QAmqpMessage &message, uint seed) 124 | { 125 | Q_UNUSED(seed); 126 | return qHash(message.deliveryTag()) ^ 127 | qHash(message.isRedelivered()) ^ 128 | qHash(message.exchangeName()) ^ 129 | qHash(message.routingKey()) ^ 130 | qHash(message.payload()); 131 | } 132 | -------------------------------------------------------------------------------- /src/qamqpmessage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2014 Alexey Shcherbakov 3 | * Copyright (C) 2014-2015 Matt Broadstone 4 | * Contact: https://github.com/mbroadst/qamqp 5 | * 6 | * This file is part of the QAMQP Library. 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | */ 18 | #ifndef QAMQPMESSAGE_H 19 | #define QAMQPMESSAGE_H 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "qamqpglobal.h" 27 | 28 | class QAmqpMessagePrivate; 29 | class QAMQP_EXPORT QAmqpMessage 30 | { 31 | public: 32 | QAmqpMessage(); 33 | QAmqpMessage(const QAmqpMessage &other); 34 | QAmqpMessage &operator=(const QAmqpMessage &other); 35 | ~QAmqpMessage(); 36 | 37 | #if QT_VERSION >= 0x050000 38 | inline void swap(QAmqpMessage &other) { qSwap(d, other.d); } 39 | #endif 40 | 41 | bool operator==(const QAmqpMessage &message) const; 42 | inline bool operator!=(const QAmqpMessage &message) const { return !(operator==(message)); } 43 | 44 | enum Property { 45 | ContentType = AMQP_BASIC_CONTENT_TYPE_FLAG, 46 | ContentEncoding = AMQP_BASIC_CONTENT_ENCODING_FLAG, 47 | Headers = AMQP_BASIC_HEADERS_FLAG, 48 | DeliveryMode = AMQP_BASIC_DELIVERY_MODE_FLAG, 49 | Priority = AMQP_BASIC_PRIORITY_FLAG, 50 | CorrelationId = AMQP_BASIC_CORRELATION_ID_FLAG, 51 | ReplyTo = AMQP_BASIC_REPLY_TO_FLAG, 52 | Expiration = AMQP_BASIC_EXPIRATION_FLAG, 53 | MessageId = AMQP_BASIC_MESSAGE_ID_FLAG, 54 | Timestamp = AMQP_BASIC_TIMESTAMP_FLAG, 55 | Type = AMQP_BASIC_TYPE_FLAG, 56 | UserId = AMQP_BASIC_USER_ID_FLAG, 57 | AppId = AMQP_BASIC_APP_ID_FLAG, 58 | ClusterID = AMQP_BASIC_CLUSTER_ID_FLAG 59 | }; 60 | Q_DECLARE_FLAGS(Properties, Property) 61 | typedef QHash PropertyHash; 62 | 63 | bool hasProperty(Property property) const; 64 | void setProperty(Property property, const QVariant &value); 65 | QVariant property(Property property, const QVariant &defaultValue = QVariant()) const; 66 | 67 | bool hasHeader(const QString &header) const; 68 | void setHeader(const QString &header, const QVariant &value); 69 | QVariant header(const QString &header, const QVariant &defaultValue = QVariant()) const; 70 | QHash headers() const; 71 | 72 | bool isValid() const; 73 | bool isRedelivered() const; 74 | qlonglong deliveryTag() const; 75 | QString exchangeName() const; 76 | QString routingKey() const; 77 | QByteArray payload() const; 78 | 79 | private: 80 | QSharedDataPointer d; 81 | friend class QAmqpQueuePrivate; 82 | friend class QAmqpQueue; 83 | 84 | #if QT_VERSION < 0x050000 85 | public: 86 | typedef QSharedDataPointer DataPtr; 87 | inline DataPtr &data_ptr() { return d; } 88 | 89 | // internal 90 | bool isDetached() const; 91 | #endif 92 | }; 93 | 94 | Q_DECLARE_METATYPE(QAmqpMessage::PropertyHash) 95 | 96 | #if QT_VERSION < 0x050000 97 | Q_DECLARE_TYPEINFO(QAmqpMessage, Q_MOVABLE_TYPE); 98 | #endif 99 | Q_DECLARE_SHARED(QAmqpMessage) 100 | 101 | // NOTE: needed only for MSVC support, don't depend on this hash 102 | QAMQP_EXPORT uint qHash(const QAmqpMessage &key, uint seed = 0); 103 | 104 | #endif // QAMQPMESSAGE_H 105 | -------------------------------------------------------------------------------- /src/qamqpmessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QAMQPMESSAGE_P_H 2 | #define QAMQPMESSAGE_P_H 3 | 4 | #include 5 | #include 6 | 7 | #include "qamqpframe_p.h" 8 | #include "qamqpmessage.h" 9 | 10 | class QAmqpMessagePrivate : public QSharedData 11 | { 12 | public: 13 | QAmqpMessagePrivate(); 14 | 15 | qlonglong deliveryTag; 16 | bool redelivered; 17 | QString exchangeName; 18 | QString routingKey; 19 | QByteArray payload; 20 | QHash properties; 21 | QHash headers; 22 | int leftSize; 23 | 24 | }; 25 | 26 | #endif // QAMQPMESSAGE_P_H 27 | -------------------------------------------------------------------------------- /src/qamqpqueue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "qamqpclient.h" 7 | #include "qamqpclient_p.h" 8 | #include "qamqpqueue.h" 9 | #include "qamqpqueue_p.h" 10 | #include "qamqpexchange.h" 11 | #include "qamqpmessage_p.h" 12 | #include "qamqptable.h" 13 | using namespace QAMQP; 14 | 15 | QAmqpQueuePrivate::QAmqpQueuePrivate(QAmqpQueue *q) 16 | : QAmqpChannelPrivate(q), 17 | delayedDeclare(false), 18 | declared(false), 19 | recievingMessage(false), 20 | consuming(false), 21 | consumeRequested(false), 22 | messageCount(0), 23 | consumerCount(0) 24 | { 25 | } 26 | 27 | QAmqpQueuePrivate::~QAmqpQueuePrivate() 28 | { 29 | if (!client.isNull()) { 30 | QAmqpClientPrivate *priv = client->d_func(); 31 | priv->contentHandlerByChannel[channelNumber].removeAll(this); 32 | priv->bodyHandlersByChannel[channelNumber].removeAll(this); 33 | } 34 | } 35 | 36 | 37 | void QAmqpQueuePrivate::resetInternalState() 38 | { 39 | QAmqpChannelPrivate::resetInternalState(); 40 | delayedDeclare = false; 41 | declared = false; 42 | recievingMessage = false; 43 | consuming = false; 44 | consumeRequested = false; 45 | } 46 | 47 | bool QAmqpQueuePrivate::_q_method(const QAmqpMethodFrame &frame) 48 | { 49 | Q_Q(QAmqpQueue); 50 | if (QAmqpChannelPrivate::_q_method(frame)) 51 | return true; 52 | 53 | if (frame.methodClass() == QAmqpFrame::Queue) { 54 | switch (frame.id()) { 55 | case miDeclareOk: 56 | declareOk(frame); 57 | break; 58 | case miDeleteOk: 59 | deleteOk(frame); 60 | break; 61 | case miBindOk: 62 | bindOk(frame); 63 | break; 64 | case miUnbindOk: 65 | unbindOk(frame); 66 | break; 67 | case miPurgeOk: 68 | purgeOk(frame); 69 | break; 70 | } 71 | 72 | return true; 73 | } 74 | 75 | if (frame.methodClass() == QAmqpFrame::Basic) { 76 | switch(frame.id()) { 77 | case bmConsumeOk: 78 | consumeOk(frame); 79 | break; 80 | case bmDeliver: 81 | deliver(frame); 82 | break; 83 | case bmGetOk: 84 | getOk(frame); 85 | break; 86 | case bmGetEmpty: 87 | Q_EMIT q->empty(); 88 | break; 89 | case bmCancelOk: 90 | cancelOk(frame); 91 | break; 92 | } 93 | 94 | return true; 95 | } 96 | 97 | return false; 98 | } 99 | 100 | void QAmqpQueuePrivate::_q_content(const QAmqpContentFrame &frame) 101 | { 102 | Q_Q(QAmqpQueue); 103 | Q_ASSERT(frame.channel() == channelNumber); 104 | if (frame.channel() != channelNumber) 105 | return; 106 | 107 | if (!currentMessage.isValid()) { 108 | qAmqpDebug() << "received content-header without delivered message"; 109 | return; 110 | } 111 | 112 | currentMessage.d->leftSize = frame.bodySize(); 113 | QAmqpMessage::PropertyHash::ConstIterator it; 114 | QAmqpMessage::PropertyHash::ConstIterator itEnd = frame.properties_.constEnd(); 115 | for (it = frame.properties_.constBegin(); it != itEnd; ++it) { 116 | QAmqpMessage::Property property = (it.key()); 117 | if (property == QAmqpMessage::Headers) 118 | currentMessage.d->headers = (it.value()).toHash(); 119 | currentMessage.d->properties[property] = it.value(); 120 | } 121 | 122 | if (currentMessage.d->leftSize == 0) { 123 | // message with an empty body 124 | q->enqueue(currentMessage); 125 | Q_EMIT q->messageReceived(); 126 | } 127 | } 128 | 129 | void QAmqpQueuePrivate::_q_body(const QAmqpContentBodyFrame &frame) 130 | { 131 | Q_Q(QAmqpQueue); 132 | Q_ASSERT(frame.channel() == channelNumber); 133 | if (frame.channel() != channelNumber) 134 | return; 135 | 136 | if (!currentMessage.isValid()) { 137 | qAmqpDebug() << "received content-body without delivered message"; 138 | return; 139 | } 140 | 141 | currentMessage.d->payload.append(frame.body()); 142 | currentMessage.d->leftSize -= frame.body().size(); 143 | if (currentMessage.d->leftSize == 0) { 144 | q->enqueue(currentMessage); 145 | Q_EMIT q->messageReceived(); 146 | } 147 | } 148 | 149 | void QAmqpQueuePrivate::declareOk(const QAmqpMethodFrame &frame) 150 | { 151 | Q_Q(QAmqpQueue); 152 | declared = true; 153 | 154 | QByteArray data = frame.arguments(); 155 | QDataStream stream(&data, QIODevice::ReadOnly); 156 | 157 | name = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::ShortString).toString(); 158 | 159 | stream >> messageCount >> consumerCount; 160 | 161 | qAmqpDebug("-> queue#declareOk( queue-name=%s, message-count=%d, consumer-count=%d )", 162 | qPrintable(name), messageCount, consumerCount); 163 | 164 | Q_EMIT q->declared(); 165 | } 166 | 167 | void QAmqpQueuePrivate::purgeOk(const QAmqpMethodFrame &frame) 168 | { 169 | Q_Q(QAmqpQueue); 170 | QByteArray data = frame.arguments(); 171 | QDataStream stream(&data, QIODevice::ReadOnly); 172 | 173 | 174 | stream >> messageCount; 175 | 176 | qAmqpDebug("-> queue#purgeOk( queue-name=%s, message-count=%d )", 177 | qPrintable(name), messageCount); 178 | 179 | Q_EMIT q->purged(messageCount); 180 | } 181 | 182 | void QAmqpQueuePrivate::deleteOk(const QAmqpMethodFrame &frame) 183 | { 184 | Q_Q(QAmqpQueue); 185 | declared = false; 186 | 187 | QByteArray data = frame.arguments(); 188 | QDataStream stream(&data, QIODevice::ReadOnly); 189 | 190 | stream >> messageCount; 191 | 192 | qAmqpDebug("-> queue#deleteOk( queue-name=%s, message-count=%d )", 193 | qPrintable(name), messageCount); 194 | 195 | 196 | Q_EMIT q->removed(); 197 | } 198 | 199 | void QAmqpQueuePrivate::bindOk(const QAmqpMethodFrame &frame) 200 | { 201 | Q_UNUSED(frame) 202 | Q_Q(QAmqpQueue); 203 | qAmqpDebug("-> queue[ %s ]#bindOk()", qPrintable(name)); 204 | Q_EMIT q->bound(); 205 | } 206 | 207 | void QAmqpQueuePrivate::unbindOk(const QAmqpMethodFrame &frame) 208 | { 209 | Q_UNUSED(frame) 210 | Q_Q(QAmqpQueue); 211 | qAmqpDebug("-> queue[ %s ]#unbindOk()", qPrintable(name)); 212 | Q_EMIT q->unbound(); 213 | } 214 | 215 | void QAmqpQueuePrivate::getOk(const QAmqpMethodFrame &frame) 216 | { 217 | qAmqpDebug("-> queue[ %s ]#getOk()", qPrintable(name)); 218 | 219 | QByteArray data = frame.arguments(); 220 | QDataStream in(&data, QIODevice::ReadOnly); 221 | 222 | QAmqpMessage message; 223 | message.d->deliveryTag = QAmqpFrame::readAmqpField(in, QAmqpMetaType::LongLongUint).toLongLong(); 224 | message.d->redelivered = QAmqpFrame::readAmqpField(in, QAmqpMetaType::Boolean).toBool(); 225 | message.d->exchangeName = QAmqpFrame::readAmqpField(in, QAmqpMetaType::ShortString).toString(); 226 | message.d->routingKey = QAmqpFrame::readAmqpField(in, QAmqpMetaType::ShortString).toString(); 227 | currentMessage = message; 228 | } 229 | 230 | void QAmqpQueuePrivate::consumeOk(const QAmqpMethodFrame &frame) 231 | { 232 | Q_Q(QAmqpQueue); 233 | QByteArray data = frame.arguments(); 234 | QDataStream stream(&data, QIODevice::ReadOnly); 235 | consumerTag = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::ShortString).toString(); 236 | consuming = true; 237 | consumeRequested = false; 238 | 239 | qAmqpDebug("-> queue[ %s ]#consumeOk( consumer-tag=%s )", qPrintable(name), qPrintable(consumerTag)); 240 | 241 | Q_EMIT q->consuming(consumerTag); 242 | } 243 | 244 | void QAmqpQueuePrivate::deliver(const QAmqpMethodFrame &frame) 245 | { 246 | qAmqpDebug() << Q_FUNC_INFO; 247 | QByteArray data = frame.arguments(); 248 | QDataStream in(&data, QIODevice::ReadOnly); 249 | QString consumer = QAmqpFrame::readAmqpField(in, QAmqpMetaType::ShortString).toString(); 250 | if (consumerTag != consumer) { 251 | qAmqpDebug() << Q_FUNC_INFO << "invalid consumer tag: " << consumer; 252 | return; 253 | } 254 | 255 | QAmqpMessage message; 256 | message.d->deliveryTag = QAmqpFrame::readAmqpField(in, QAmqpMetaType::LongLongUint).toLongLong(); 257 | message.d->redelivered = QAmqpFrame::readAmqpField(in, QAmqpMetaType::Boolean).toBool(); 258 | message.d->exchangeName = QAmqpFrame::readAmqpField(in, QAmqpMetaType::ShortString).toString(); 259 | message.d->routingKey = QAmqpFrame::readAmqpField(in, QAmqpMetaType::ShortString).toString(); 260 | currentMessage = message; 261 | } 262 | 263 | void QAmqpQueuePrivate::declare() 264 | { 265 | QAmqpMethodFrame frame(QAmqpFrame::Queue, QAmqpQueuePrivate::miDeclare); 266 | frame.setChannel(channelNumber); 267 | 268 | QByteArray args; 269 | QDataStream out(&args, QIODevice::WriteOnly); 270 | 271 | out << qint16(0); //reserved 1 272 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, name); 273 | out << qint8(options); 274 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::Hash, arguments); 275 | 276 | qAmqpDebug("<- queue#declare( queue=%s, passive=%d, durable=%d, exclusive=%d, auto-delete=%d, no-wait=%d )", 277 | qPrintable(name), options & QAmqpQueue::Passive, options & QAmqpQueue::Durable, 278 | options & QAmqpQueue::Exclusive, options & QAmqpQueue::AutoDelete, 279 | options & QAmqpQueue::NoWait); 280 | 281 | frame.setArguments(args); 282 | sendFrame(frame); 283 | 284 | if (delayedDeclare) 285 | delayedDeclare = false; 286 | } 287 | 288 | void QAmqpQueuePrivate::cancelOk(const QAmqpMethodFrame &frame) 289 | { 290 | Q_Q(QAmqpQueue); 291 | qAmqpDebug() << Q_FUNC_INFO; 292 | QByteArray data = frame.arguments(); 293 | QDataStream in(&data, QIODevice::ReadOnly); 294 | QString consumer = QAmqpFrame::readAmqpField(in, QAmqpMetaType::ShortString).toString(); 295 | if (consumerTag != consumer) { 296 | qAmqpDebug() << Q_FUNC_INFO << "invalid consumer tag: " << consumer; 297 | return; 298 | } 299 | 300 | qAmqpDebug("-> queue[ %s ]#cancelOk( consumer-tag=%s )", qPrintable(name), qPrintable(consumerTag)); 301 | 302 | consumerTag.clear(); 303 | consuming = false; 304 | consumeRequested = false; 305 | Q_EMIT q->cancelled(consumer); 306 | } 307 | 308 | ////////////////////////////////////////////////////////////////////////// 309 | 310 | QAmqpQueue::QAmqpQueue(int channelNumber, QAmqpClient *parent) 311 | : QAmqpChannel(new QAmqpQueuePrivate(this), parent) 312 | { 313 | Q_D(QAmqpQueue); 314 | d->init(channelNumber, parent); 315 | } 316 | 317 | QAmqpQueue::~QAmqpQueue() 318 | { 319 | } 320 | 321 | void QAmqpQueue::channelOpened() 322 | { 323 | Q_D(QAmqpQueue); 324 | if (d->delayedDeclare) 325 | d->declare(); 326 | 327 | if (!d->delayedBindings.isEmpty()) { 328 | typedef QPair BindingPair; 329 | foreach(BindingPair binding, d->delayedBindings) 330 | bind(binding.first, binding.second); 331 | d->delayedBindings.clear(); 332 | } 333 | } 334 | 335 | void QAmqpQueue::channelClosed() 336 | { 337 | } 338 | 339 | int QAmqpQueue::options() const 340 | { 341 | Q_D(const QAmqpQueue); 342 | return d->options; 343 | } 344 | 345 | qint32 QAmqpQueue::messageCount() const 346 | { 347 | Q_D(const QAmqpQueue); 348 | return d->messageCount; 349 | } 350 | 351 | qint32 QAmqpQueue::consumerCount() const 352 | { 353 | Q_D(const QAmqpQueue); 354 | return d->consumerCount; 355 | } 356 | 357 | void QAmqpQueue::declare(int options, const QAmqpTable &arguments) 358 | { 359 | Q_D(QAmqpQueue); 360 | d->options = options; 361 | d->arguments = arguments; 362 | 363 | if (!d->opened) { 364 | d->delayedDeclare = true; 365 | return; 366 | } 367 | 368 | d->declare(); 369 | } 370 | 371 | void QAmqpQueue::remove(int options) 372 | { 373 | Q_D(QAmqpQueue); 374 | if (!d->declared) { 375 | qAmqpDebug() << Q_FUNC_INFO << "trying to remove undeclared queue, aborting..."; 376 | return; 377 | } 378 | 379 | QAmqpMethodFrame frame(QAmqpFrame::Queue, QAmqpQueuePrivate::miDelete); 380 | frame.setChannel(d->channelNumber); 381 | 382 | QByteArray arguments; 383 | QDataStream out(&arguments, QIODevice::WriteOnly); 384 | 385 | out << qint16(0); //reserved 1 386 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->name); 387 | out << qint8(options); 388 | 389 | qAmqpDebug("<- queue#delete( queue=%s, if-unused=%d, if-empty=%d )", 390 | qPrintable(d->name), options & QAmqpQueue::roIfUnused, options & QAmqpQueue::roIfEmpty); 391 | 392 | frame.setArguments(arguments); 393 | d->sendFrame(frame); 394 | } 395 | 396 | void QAmqpQueue::purge() 397 | { 398 | Q_D(QAmqpQueue); 399 | 400 | if (!d->opened) 401 | return; 402 | 403 | QAmqpMethodFrame frame(QAmqpFrame::Queue, QAmqpQueuePrivate::miPurge); 404 | frame.setChannel(d->channelNumber); 405 | 406 | QByteArray arguments; 407 | QDataStream out(&arguments, QIODevice::WriteOnly); 408 | out << qint16(0); //reserved 1 409 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->name); 410 | out << qint8(0); // no-wait 411 | 412 | qAmqpDebug("<- queue#purge( queue=%s, no-wait=%d )", qPrintable(d->name), 0); 413 | 414 | frame.setArguments(arguments); 415 | d->sendFrame(frame); 416 | } 417 | 418 | void QAmqpQueue::bind(QAmqpExchange *exchange, const QString &key) 419 | { 420 | if (!exchange) { 421 | qAmqpDebug() << Q_FUNC_INFO << "invalid exchange provided"; 422 | return; 423 | } 424 | 425 | bind(exchange->name(), key); 426 | } 427 | 428 | void QAmqpQueue::bind(const QString &exchangeName, const QString &key) 429 | { 430 | Q_D(QAmqpQueue); 431 | if (!d->opened) { 432 | d->delayedBindings.append(QPair(exchangeName, key)); 433 | return; 434 | } 435 | 436 | QAmqpMethodFrame frame(QAmqpFrame::Queue, QAmqpQueuePrivate::miBind); 437 | frame.setChannel(d->channelNumber); 438 | 439 | QByteArray arguments; 440 | QDataStream out(&arguments, QIODevice::WriteOnly); 441 | 442 | out << qint16(0); // reserved 1 443 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->name); 444 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, exchangeName); 445 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, key); 446 | 447 | out << qint8(0); // no-wait 448 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::Hash, QAmqpTable()); 449 | 450 | qAmqpDebug("<- queue#bind( queue=%s, exchange=%s, routing-key=%s, no-wait=%d )", 451 | qPrintable(d->name), qPrintable(exchangeName), qPrintable(key), 452 | 0); 453 | 454 | frame.setArguments(arguments); 455 | d->sendFrame(frame); 456 | } 457 | 458 | void QAmqpQueue::unbind(QAmqpExchange *exchange, const QString &key) 459 | { 460 | if (!exchange) { 461 | qAmqpDebug() << Q_FUNC_INFO << "invalid exchange provided"; 462 | return; 463 | } 464 | 465 | unbind(exchange->name(), key); 466 | } 467 | 468 | void QAmqpQueue::unbind(const QString &exchangeName, const QString &key) 469 | { 470 | Q_D(QAmqpQueue); 471 | if (!d->opened) { 472 | qAmqpDebug() << Q_FUNC_INFO << "queue is not open"; 473 | return; 474 | } 475 | 476 | QAmqpMethodFrame frame(QAmqpFrame::Queue, QAmqpQueuePrivate::miUnbind); 477 | frame.setChannel(d->channelNumber); 478 | 479 | QByteArray arguments; 480 | QDataStream out(&arguments, QIODevice::WriteOnly); 481 | out << qint16(0); //reserved 1 482 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->name); 483 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, exchangeName); 484 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, key); 485 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::Hash, QAmqpTable()); 486 | 487 | qAmqpDebug("<- queue#unbind( queue=%s, exchange=%s, routing-key=%s )", 488 | qPrintable(d->name), qPrintable(exchangeName), qPrintable(key)); 489 | 490 | frame.setArguments(arguments); 491 | d->sendFrame(frame); 492 | } 493 | 494 | bool QAmqpQueue::consume(int options) 495 | { 496 | Q_D(QAmqpQueue); 497 | if (!d->opened) { 498 | qAmqpDebug() << Q_FUNC_INFO << "queue is not open"; 499 | return false; 500 | } 501 | 502 | if (d->consumeRequested) { 503 | qAmqpDebug() << Q_FUNC_INFO << "already attempting to consume"; 504 | return false; 505 | } 506 | 507 | if (d->consuming) { 508 | qAmqpDebug() << Q_FUNC_INFO << "already consuming with tag: " << d->consumerTag; 509 | return false; 510 | } 511 | 512 | QAmqpMethodFrame frame(QAmqpFrame::Basic, QAmqpQueuePrivate::bmConsume); 513 | frame.setChannel(d->channelNumber); 514 | 515 | QByteArray arguments; 516 | QDataStream out(&arguments, QIODevice::WriteOnly); 517 | 518 | out << qint16(0); //reserved 1 519 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->name); 520 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->consumerTag); 521 | 522 | out << qint8(options); 523 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::Hash, QAmqpTable()); 524 | 525 | qAmqpDebug("<- basic#consume( queue=%s, consumer-tag=%s, no-local=%d, no-ack=%d, exclusive=%d, no-wait=%d )", 526 | qPrintable(d->name), qPrintable(d->consumerTag), 527 | options & QAmqpQueue::coNoLocal, options & QAmqpQueue::coNoAck, 528 | options & QAmqpQueue::coExclusive, options & QAmqpQueue::coNoWait); 529 | 530 | frame.setArguments(arguments); 531 | d->sendFrame(frame); 532 | d->consumeRequested = true; 533 | return true; 534 | } 535 | 536 | void QAmqpQueue::setConsumerTag(const QString &consumerTag) 537 | { 538 | Q_D(QAmqpQueue); 539 | d->consumerTag = consumerTag; 540 | } 541 | 542 | QString QAmqpQueue::consumerTag() const 543 | { 544 | Q_D(const QAmqpQueue); 545 | return d->consumerTag; 546 | } 547 | 548 | bool QAmqpQueue::isConsuming() const 549 | { 550 | Q_D(const QAmqpQueue); 551 | return d->consuming; 552 | } 553 | 554 | bool QAmqpQueue::isDeclared() const 555 | { 556 | Q_D(const QAmqpQueue); 557 | return d->declared; 558 | } 559 | 560 | void QAmqpQueue::get(bool noAck) 561 | { 562 | Q_D(QAmqpQueue); 563 | if (!d->opened) { 564 | qAmqpDebug() << Q_FUNC_INFO << "channel is not open"; 565 | return; 566 | } 567 | 568 | QAmqpMethodFrame frame(QAmqpFrame::Basic, QAmqpQueuePrivate::bmGet); 569 | frame.setChannel(d->channelNumber); 570 | 571 | QByteArray arguments; 572 | QDataStream out(&arguments, QIODevice::WriteOnly); 573 | 574 | out << qint16(0); //reserved 1 575 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->name); 576 | out << qint8(noAck ? 1 : 0); // no-ack 577 | 578 | qAmqpDebug("<- basic#get( queue=%s, no-ack=%d )", qPrintable(d->name), noAck); 579 | 580 | frame.setArguments(arguments); 581 | d->sendFrame(frame); 582 | } 583 | 584 | void QAmqpQueue::ack(const QAmqpMessage &message) 585 | { 586 | ack(message.deliveryTag(), false); 587 | } 588 | 589 | void QAmqpQueue::ack(qlonglong deliveryTag, bool multiple) 590 | { 591 | Q_D(QAmqpQueue); 592 | if (!d->opened) { 593 | qAmqpDebug() << Q_FUNC_INFO << "channel is not open"; 594 | return; 595 | } 596 | 597 | QAmqpMethodFrame frame(QAmqpFrame::Basic, QAmqpQueuePrivate::bmAck); 598 | frame.setChannel(d->channelNumber); 599 | 600 | QByteArray arguments; 601 | QDataStream out(&arguments, QIODevice::WriteOnly); 602 | 603 | out << deliveryTag; 604 | out << qint8(multiple ? 1 : 0); // multiple 605 | 606 | qAmqpDebug("<- basic#ack( delivery-tag=%llu, multiple=%d )", deliveryTag, multiple); 607 | 608 | frame.setArguments(arguments); 609 | d->sendFrame(frame); 610 | } 611 | 612 | void QAmqpQueue::reject(const QAmqpMessage &message, bool requeue) 613 | { 614 | ack(message.deliveryTag(), requeue); 615 | } 616 | 617 | void QAmqpQueue::reject(qlonglong deliveryTag, bool requeue) 618 | { 619 | Q_D(QAmqpQueue); 620 | if (!d->opened) { 621 | qAmqpDebug() << Q_FUNC_INFO << "channel is not open"; 622 | return; 623 | } 624 | 625 | QAmqpMethodFrame frame(QAmqpFrame::Basic, QAmqpQueuePrivate::bmReject); 626 | frame.setChannel(d->channelNumber); 627 | 628 | QByteArray arguments; 629 | QDataStream out(&arguments, QIODevice::WriteOnly); 630 | 631 | out << deliveryTag; 632 | out << qint8(requeue ? 1 : 0); 633 | 634 | qAmqpDebug("<- basic#reject( delivery-tag=%llu, requeue=%d )", deliveryTag, requeue); 635 | 636 | frame.setArguments(arguments); 637 | d->sendFrame(frame); 638 | } 639 | 640 | bool QAmqpQueue::cancel(bool noWait) 641 | { 642 | Q_D(QAmqpQueue); 643 | if (!d->consuming) { 644 | qAmqpDebug() << Q_FUNC_INFO << "not consuming!"; 645 | return false; 646 | } 647 | 648 | if (d->consumerTag.isEmpty()) { 649 | qAmqpDebug() << Q_FUNC_INFO << "consuming with an empty consumer tag, failing..."; 650 | return false; 651 | } 652 | 653 | QAmqpMethodFrame frame(QAmqpFrame::Basic, QAmqpQueuePrivate::bmCancel); 654 | frame.setChannel(d->channelNumber); 655 | 656 | QByteArray arguments; 657 | QDataStream out(&arguments, QIODevice::WriteOnly); 658 | 659 | QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->consumerTag); 660 | out << (noWait ? qint8(0x01) : qint8(0x0)); 661 | 662 | qAmqpDebug("<- basic#cancel( consumer-tag=%s, no-wait=%d )", qPrintable(d->consumerTag), noWait); 663 | 664 | frame.setArguments(arguments); 665 | d->sendFrame(frame); 666 | return true; 667 | } 668 | -------------------------------------------------------------------------------- /src/qamqpqueue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2014 Alexey Shcherbakov 3 | * Copyright (C) 2014-2015 Matt Broadstone 4 | * Contact: https://github.com/mbroadst/qamqp 5 | * 6 | * This file is part of the QAMQP Library. 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | */ 18 | #ifndef QAMQPQUEUE_H 19 | #define QAMQPQUEUE_H 20 | 21 | #include 22 | 23 | #include "qamqpchannel.h" 24 | #include "qamqpmessage.h" 25 | #include "qamqpglobal.h" 26 | #include "qamqptable.h" 27 | 28 | class QAmqpClient; 29 | class QAmqpClientPrivate; 30 | class QAmqpExchange; 31 | class QAmqpQueuePrivate; 32 | class QAMQP_EXPORT QAmqpQueue : public QAmqpChannel, public QQueue 33 | { 34 | Q_OBJECT 35 | Q_ENUMS(QueueOptions) 36 | Q_PROPERTY(int options READ options CONSTANT) 37 | Q_PROPERTY(QString consumerTag READ consumerTag WRITE setConsumerTag) 38 | Q_ENUMS(QueueOption) 39 | Q_ENUMS(ConsumeOption) 40 | Q_ENUMS(RemoveOption) 41 | 42 | public: 43 | enum QueueOption { 44 | NoOptions = 0x0, 45 | Passive = 0x01, 46 | Durable = 0x02, 47 | Exclusive = 0x04, 48 | AutoDelete = 0x08, 49 | NoWait = 0x10 50 | }; 51 | Q_DECLARE_FLAGS(QueueOptions, QueueOption) 52 | int options() const; 53 | 54 | enum ConsumeOption { 55 | coNoLocal = 0x01, 56 | coNoAck = 0x02, 57 | coExclusive = 0x04, 58 | coNoWait = 0x08 59 | }; 60 | Q_DECLARE_FLAGS(ConsumeOptions, ConsumeOption) 61 | 62 | enum RemoveOption { 63 | roForce = 0x0, 64 | roIfUnused = 0x01, 65 | roIfEmpty = 0x02, 66 | roNoWait = 0x04 67 | }; 68 | Q_DECLARE_FLAGS(RemoveOptions, RemoveOption) 69 | 70 | ~QAmqpQueue(); 71 | 72 | bool isConsuming() const; 73 | bool isDeclared() const; 74 | 75 | void setConsumerTag(const QString &consumerTag); 76 | QString consumerTag() const; 77 | 78 | qint32 messageCount() const; 79 | qint32 consumerCount() const; 80 | 81 | Q_SIGNALS: 82 | void declared(); 83 | void bound(); 84 | void unbound(); 85 | void removed(); 86 | void purged(int messageCount); 87 | 88 | void messageReceived(); 89 | void empty(); 90 | void consuming(const QString &consumerTag); 91 | void cancelled(const QString &consumerTag); 92 | 93 | public Q_SLOTS: 94 | // AMQP Queue 95 | void declare(int options = Durable|AutoDelete, const QAmqpTable &arguments = QAmqpTable()); 96 | void bind(const QString &exchangeName, const QString &key); 97 | void bind(QAmqpExchange *exchange, const QString &key); 98 | void unbind(const QString &exchangeName, const QString &key); 99 | void unbind(QAmqpExchange *exchange, const QString &key); 100 | void purge(); 101 | void remove(int options = roIfUnused|roIfEmpty|roNoWait); 102 | 103 | // AMQP Basic 104 | bool consume(int options = NoOptions); 105 | void get(bool noAck = true); 106 | bool cancel(bool noWait = false); 107 | void ack(const QAmqpMessage &message); 108 | void ack(qlonglong deliveryTag, bool multiple); 109 | void reject(const QAmqpMessage &message, bool requeue); 110 | void reject(qlonglong deliveryTag, bool requeue); 111 | 112 | protected: 113 | // reimp Channel 114 | virtual void channelOpened(); 115 | virtual void channelClosed(); 116 | 117 | private: 118 | explicit QAmqpQueue(int channelNumber = -1, QAmqpClient *parent = 0); 119 | 120 | Q_DISABLE_COPY(QAmqpQueue) 121 | Q_DECLARE_PRIVATE(QAmqpQueue) 122 | friend class QAmqpClient; 123 | friend class QAmqpClientPrivate; 124 | 125 | }; 126 | 127 | #endif // QAMQPQUEUE_H 128 | -------------------------------------------------------------------------------- /src/qamqpqueue_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QAMQPQUEUE_P_H 2 | #define QAMQPQUEUE_P_H 3 | 4 | #include 5 | #include 6 | 7 | #include "qamqpchannel_p.h" 8 | 9 | class QAmqpQueuePrivate: public QAmqpChannelPrivate, 10 | public QAmqpContentFrameHandler, 11 | public QAmqpContentBodyFrameHandler 12 | { 13 | public: 14 | enum MethodId { 15 | METHOD_ID_ENUM(miDeclare, 10), 16 | METHOD_ID_ENUM(miBind, 20), 17 | METHOD_ID_ENUM(miUnbind, 50), 18 | METHOD_ID_ENUM(miPurge, 30), 19 | METHOD_ID_ENUM(miDelete, 40) 20 | }; 21 | 22 | QAmqpQueuePrivate(QAmqpQueue *q); 23 | ~QAmqpQueuePrivate(); 24 | 25 | virtual void resetInternalState(); 26 | 27 | void declare(); 28 | virtual bool _q_method(const QAmqpMethodFrame &frame); 29 | 30 | // AMQP Queue method handlers 31 | void declareOk(const QAmqpMethodFrame &frame); 32 | void deleteOk(const QAmqpMethodFrame &frame); 33 | void purgeOk(const QAmqpMethodFrame &frame); 34 | void bindOk(const QAmqpMethodFrame &frame); 35 | void unbindOk(const QAmqpMethodFrame &frame); 36 | void consumeOk(const QAmqpMethodFrame &frame); 37 | 38 | // AMQP Basic method handlers 39 | virtual void _q_content(const QAmqpContentFrame &frame); 40 | virtual void _q_body(const QAmqpContentBodyFrame &frame); 41 | void deliver(const QAmqpMethodFrame &frame); 42 | void getOk(const QAmqpMethodFrame &frame); 43 | void cancelOk(const QAmqpMethodFrame &frame); 44 | 45 | QString type; 46 | int options; 47 | bool delayedDeclare; 48 | bool declared; 49 | QQueue > delayedBindings; 50 | 51 | QString consumerTag; 52 | bool recievingMessage; 53 | QAmqpMessage currentMessage; 54 | bool consuming; 55 | bool consumeRequested; 56 | 57 | qint32 messageCount; 58 | qint32 consumerCount; 59 | 60 | Q_DECLARE_PUBLIC(QAmqpQueue) 61 | 62 | }; 63 | 64 | #endif // QAMQPQUEUE_P_H 65 | -------------------------------------------------------------------------------- /src/qamqptable.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "qamqpframe_p.h" 7 | #include "qamqptable.h" 8 | 9 | /* 10 | * field value types according to: https://www.rabbitmq.com/amqp-0-9-1-errata.html 11 | t - Boolean 12 | b - Signed 8-bit 13 | Unsigned 8-bit 14 | s - Signed 16-bit 15 | Unsigned 16-bit 16 | I - Signed 32-bit 17 | Unsigned 32-bit 18 | l - Signed 64-bit 19 | Unsigned 64-bit 20 | f - 32-bit float 21 | d - 64-bit float 22 | D - Decimal 23 | S - Long string 24 | A - Array 25 | T - Timestamp (u64) 26 | F - Nested Table 27 | V - Void 28 | x - Byte array 29 | */ 30 | 31 | QAmqpMetaType::ValueType valueTypeForOctet(qint8 octet) 32 | { 33 | switch (octet) { 34 | case 't': return QAmqpMetaType::Boolean; 35 | case 'b': return QAmqpMetaType::ShortShortInt; 36 | case 's': return QAmqpMetaType::ShortInt; 37 | case 'I': return QAmqpMetaType::LongInt; 38 | case 'l': return QAmqpMetaType::LongLongInt; 39 | case 'f': return QAmqpMetaType::Float; 40 | case 'd': return QAmqpMetaType::Double; 41 | case 'D': return QAmqpMetaType::Decimal; 42 | case 'S': return QAmqpMetaType::LongString; 43 | case 'A': return QAmqpMetaType::Array; 44 | case 'T': return QAmqpMetaType::Timestamp; 45 | case 'F': return QAmqpMetaType::Hash; 46 | case 'V': return QAmqpMetaType::Void; 47 | case 'x': return QAmqpMetaType::Bytes; 48 | default: 49 | qAmqpDebug() << Q_FUNC_INFO << "invalid octet received: " << char(octet); 50 | } 51 | 52 | return QAmqpMetaType::Invalid; 53 | } 54 | 55 | qint8 valueTypeToOctet(QAmqpMetaType::ValueType type) 56 | { 57 | switch (type) { 58 | case QAmqpMetaType::Boolean: return 't'; 59 | case QAmqpMetaType::ShortShortInt: return 'b'; 60 | case QAmqpMetaType::ShortInt: return 's'; 61 | case QAmqpMetaType::LongInt: return 'I'; 62 | case QAmqpMetaType::LongLongInt: return 'l'; 63 | case QAmqpMetaType::Float: return 'f'; 64 | case QAmqpMetaType::Double: return 'd'; 65 | case QAmqpMetaType::Decimal: return 'D'; 66 | case QAmqpMetaType::LongString: return 'S'; 67 | case QAmqpMetaType::Array: return 'A'; 68 | case QAmqpMetaType::Timestamp: return 'T'; 69 | case QAmqpMetaType::Hash: return 'F'; 70 | case QAmqpMetaType::Void: return 'V'; 71 | case QAmqpMetaType::Bytes: return 'x'; 72 | default: 73 | qAmqpDebug() << Q_FUNC_INFO << "invalid type received: " << char(type); 74 | } 75 | 76 | return 'V'; 77 | } 78 | 79 | void QAmqpTable::writeFieldValue(QDataStream &stream, const QVariant &value) 80 | { 81 | QAmqpMetaType::ValueType type; 82 | switch (value.userType()) { 83 | case QMetaType::Bool: 84 | type = QAmqpMetaType::Boolean; 85 | break; 86 | case QMetaType::QByteArray: 87 | type = QAmqpMetaType::Bytes; 88 | break; 89 | case QMetaType::Int: 90 | { 91 | int i = qAbs(value.toInt()); 92 | if (i <= qint8(SCHAR_MAX)) { 93 | type = QAmqpMetaType::ShortShortInt; 94 | } else if (i <= qint16(SHRT_MAX)) { 95 | type = QAmqpMetaType::ShortInt; 96 | } else { 97 | type = QAmqpMetaType::LongInt; 98 | } 99 | } 100 | break; 101 | case QMetaType::UShort: 102 | type = QAmqpMetaType::ShortInt; 103 | break; 104 | case QMetaType::UInt: 105 | { 106 | int i = value.toInt(); 107 | if (i <= qint8(SCHAR_MAX)) { 108 | type = QAmqpMetaType::ShortShortInt; 109 | } else if (i <= qint16(SHRT_MAX)) { 110 | type = QAmqpMetaType::ShortInt; 111 | } else { 112 | type = QAmqpMetaType::LongInt; 113 | } 114 | } 115 | break; 116 | case QMetaType::LongLong: 117 | case QMetaType::ULongLong: 118 | type = QAmqpMetaType::LongLongInt; 119 | break; 120 | case QMetaType::QString: 121 | type = QAmqpMetaType::LongString; 122 | break; 123 | case QMetaType::QDateTime: 124 | type = QAmqpMetaType::Timestamp; 125 | break; 126 | case QMetaType::Double: 127 | type = value.toDouble() > FLT_MAX ? QAmqpMetaType::Double : QAmqpMetaType::Float; 128 | break; 129 | case QMetaType::QVariantHash: 130 | type = QAmqpMetaType::Hash; 131 | break; 132 | case QMetaType::QVariantList: 133 | type = QAmqpMetaType::Array; 134 | break; 135 | case QMetaType::Void: 136 | type = QAmqpMetaType::Void; 137 | break; 138 | default: 139 | if (value.userType() == qMetaTypeId()) { 140 | type = QAmqpMetaType::Decimal; 141 | break; 142 | } else if (!value.isValid()) { 143 | type = QAmqpMetaType::Void; 144 | break; 145 | } 146 | 147 | qAmqpDebug() << Q_FUNC_INFO << "unhandled type: " << value.userType(); 148 | return; 149 | } 150 | 151 | // write the field value type, a requirement for field tables only 152 | stream << valueTypeToOctet(type); 153 | writeFieldValue(stream, type, value); 154 | } 155 | 156 | void QAmqpTable::writeFieldValue(QDataStream &stream, QAmqpMetaType::ValueType type, const QVariant &value) 157 | { 158 | switch (type) { 159 | case QAmqpMetaType::Boolean: 160 | case QAmqpMetaType::ShortShortUint: 161 | case QAmqpMetaType::ShortUint: 162 | case QAmqpMetaType::LongUint: 163 | case QAmqpMetaType::LongLongUint: 164 | case QAmqpMetaType::ShortString: 165 | case QAmqpMetaType::LongString: 166 | case QAmqpMetaType::Timestamp: 167 | case QAmqpMetaType::Hash: 168 | return QAmqpFrame::writeAmqpField(stream, type, value); 169 | 170 | case QAmqpMetaType::ShortShortInt: 171 | stream << qint8(value.toInt()); 172 | break; 173 | case QAmqpMetaType::ShortInt: 174 | stream << qint16(value.toInt()); 175 | break; 176 | case QAmqpMetaType::LongInt: 177 | stream << qint32(value.toInt()); 178 | break; 179 | case QAmqpMetaType::LongLongInt: 180 | stream << qlonglong(value.toLongLong()); 181 | break; 182 | case QAmqpMetaType::Float: 183 | { 184 | float g = value.toFloat(); 185 | QDataStream::FloatingPointPrecision oldPrecision = stream.floatingPointPrecision(); 186 | stream.setFloatingPointPrecision(QDataStream::SinglePrecision); 187 | stream << g; 188 | stream.setFloatingPointPrecision(oldPrecision); 189 | } 190 | break; 191 | case QAmqpMetaType::Double: 192 | { 193 | double g = value.toDouble(); 194 | QDataStream::FloatingPointPrecision oldPrecision = stream.floatingPointPrecision(); 195 | stream.setFloatingPointPrecision(QDataStream::DoublePrecision); 196 | stream << g; 197 | stream.setFloatingPointPrecision(oldPrecision); 198 | } 199 | break; 200 | case QAmqpMetaType::Decimal: 201 | { 202 | QAMQP::Decimal v(value.value()); 203 | stream << v.scale; 204 | stream << v.value; 205 | } 206 | break; 207 | case QAmqpMetaType::Array: 208 | { 209 | QByteArray buffer; 210 | QDataStream arrayStream(&buffer, QIODevice::WriteOnly); 211 | QVariantList array(value.toList()); 212 | for (int i = 0; i < array.size(); ++i) 213 | writeFieldValue(arrayStream, array.at(i)); 214 | 215 | if (buffer.isEmpty()) { 216 | stream << qint32(0); 217 | } else { 218 | stream << buffer; 219 | } 220 | } 221 | break; 222 | case QAmqpMetaType::Bytes: 223 | { 224 | QByteArray ba = value.toByteArray(); 225 | stream << quint32(ba.length()); 226 | stream.writeRawData(ba.data(), ba.length()); 227 | } 228 | break; 229 | case QAmqpMetaType::Void: 230 | stream << qint32(0); 231 | break; 232 | 233 | default: 234 | qAmqpDebug() << Q_FUNC_INFO << "unhandled type: " << type; 235 | } 236 | } 237 | 238 | QVariant QAmqpTable::readFieldValue(QDataStream &stream, QAmqpMetaType::ValueType type) 239 | { 240 | switch (type) { 241 | case QAmqpMetaType::Boolean: 242 | case QAmqpMetaType::ShortShortUint: 243 | case QAmqpMetaType::ShortUint: 244 | case QAmqpMetaType::LongUint: 245 | case QAmqpMetaType::LongLongUint: 246 | case QAmqpMetaType::ShortString: 247 | case QAmqpMetaType::LongString: 248 | case QAmqpMetaType::Timestamp: 249 | case QAmqpMetaType::Hash: 250 | return QAmqpFrame::readAmqpField(stream, type); 251 | 252 | case QAmqpMetaType::ShortShortInt: 253 | { 254 | char octet; 255 | stream.readRawData(&octet, sizeof(octet)); 256 | return QVariant::fromValue(octet); 257 | } 258 | case QAmqpMetaType::ShortInt: 259 | { 260 | qint16 tmp_value = 0; 261 | stream >> tmp_value; 262 | return QVariant::fromValue(tmp_value); 263 | } 264 | case QAmqpMetaType::LongInt: 265 | { 266 | qint32 tmp_value = 0; 267 | stream >> tmp_value; 268 | return QVariant::fromValue(tmp_value); 269 | } 270 | case QAmqpMetaType::LongLongInt: 271 | { 272 | qlonglong v = 0 ; 273 | stream >> v; 274 | return v; 275 | } 276 | case QAmqpMetaType::Float: 277 | { 278 | float tmp_value; 279 | QDataStream::FloatingPointPrecision precision = stream.floatingPointPrecision(); 280 | stream.setFloatingPointPrecision(QDataStream::SinglePrecision); 281 | stream >> tmp_value; 282 | stream.setFloatingPointPrecision(precision); 283 | return QVariant::fromValue(tmp_value); 284 | } 285 | case QAmqpMetaType::Double: 286 | { 287 | double tmp_value; 288 | QDataStream::FloatingPointPrecision precision = stream.floatingPointPrecision(); 289 | stream.setFloatingPointPrecision(QDataStream::DoublePrecision); 290 | stream >> tmp_value; 291 | stream.setFloatingPointPrecision(precision); 292 | return QVariant::fromValue(tmp_value); 293 | } 294 | case QAmqpMetaType::Decimal: 295 | { 296 | QAMQP::Decimal v; 297 | stream >> v.scale; 298 | stream >> v.value; 299 | return QVariant::fromValue(v); 300 | } 301 | case QAmqpMetaType::Array: 302 | { 303 | QByteArray data; 304 | quint32 size = 0; 305 | stream >> size; 306 | data.resize(size); 307 | stream.readRawData(data.data(), data.size()); 308 | 309 | qint8 type = 0; 310 | QVariantList result; 311 | QDataStream arrayStream(&data, QIODevice::ReadOnly); 312 | while (!arrayStream.atEnd()) { 313 | arrayStream >> type; 314 | result.append(readFieldValue(arrayStream, valueTypeForOctet(type))); 315 | } 316 | 317 | return result; 318 | } 319 | case QAmqpMetaType::Bytes: 320 | { 321 | QByteArray bytes; 322 | quint32 length = 0; 323 | stream >> length; 324 | bytes.resize(length); 325 | stream.readRawData(bytes.data(), bytes.size()); 326 | return bytes; 327 | } 328 | case QAmqpMetaType::Void: 329 | break; 330 | default: 331 | qAmqpDebug() << Q_FUNC_INFO << "unhandled type: " << type; 332 | } 333 | 334 | return QVariant(); 335 | } 336 | 337 | QDataStream &operator<<(QDataStream &stream, const QAmqpTable &table) 338 | { 339 | QByteArray data; 340 | QDataStream s(&data, QIODevice::WriteOnly); 341 | QAmqpTable::ConstIterator it; 342 | QAmqpTable::ConstIterator itEnd = table.constEnd(); 343 | for (it = table.constBegin(); it != itEnd; ++it) { 344 | QAmqpTable::writeFieldValue(s, QAmqpMetaType::ShortString, it.key()); 345 | QAmqpTable::writeFieldValue(s, it.value()); 346 | } 347 | 348 | if (data.isEmpty()) { 349 | stream << qint32(0); 350 | } else { 351 | stream << data; 352 | } 353 | 354 | return stream; 355 | } 356 | 357 | QDataStream &operator>>(QDataStream &stream, QAmqpTable &table) 358 | { 359 | QByteArray data; 360 | stream >> data; 361 | QDataStream tableStream(&data, QIODevice::ReadOnly); 362 | while (!tableStream.atEnd()) { 363 | qint8 octet = 0; 364 | QString field = QAmqpFrame::readAmqpField(tableStream, QAmqpMetaType::ShortString).toString(); 365 | tableStream >> octet; 366 | table[field] = QAmqpTable::readFieldValue(tableStream, valueTypeForOctet(octet)); 367 | } 368 | 369 | return stream; 370 | } 371 | -------------------------------------------------------------------------------- /src/qamqptable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2014 Alexey Shcherbakov 3 | * Copyright (C) 2014-2015 Matt Broadstone 4 | * Contact: https://github.com/mbroadst/qamqp 5 | * 6 | * This file is part of the QAMQP Library. 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | */ 18 | #ifndef QAMQPTABLE_H 19 | #define QAMQPTABLE_H 20 | 21 | #include 22 | 23 | #include "qamqpglobal.h" 24 | 25 | class QAMQP_EXPORT QAmqpTable : public QVariantHash 26 | { 27 | public: 28 | QAmqpTable() {} 29 | inline QAmqpTable(const QVariantHash &variantHash) 30 | : QVariantHash(variantHash) 31 | { 32 | } 33 | 34 | static void writeFieldValue(QDataStream &stream, const QVariant &value); 35 | static void writeFieldValue(QDataStream &stream, QAmqpMetaType::ValueType type, const QVariant &value); 36 | static QVariant readFieldValue(QDataStream &stream, QAmqpMetaType::ValueType type); 37 | }; 38 | 39 | QAMQP_EXPORT QDataStream &operator<<(QDataStream &, const QAmqpTable &table); 40 | QAMQP_EXPORT QDataStream &operator>>(QDataStream &, QAmqpTable &table); 41 | Q_DECLARE_METATYPE(QAmqpTable) 42 | 43 | #endif // QAMQPTABLE_H 44 | -------------------------------------------------------------------------------- /src/src.pro: -------------------------------------------------------------------------------- 1 | include(../qamqp.pri) 2 | 3 | INCLUDEPATH += . 4 | TEMPLATE = lib 5 | TARGET = qamqp 6 | build_pass:CONFIG(debug, debug|release) { 7 | TARGET = $$join(TARGET,,,d) 8 | } 9 | QT += core network 10 | QT -= gui 11 | DEFINES += QAMQP_BUILD 12 | CONFIG += $${QAMQP_LIBRARY_TYPE} 13 | VERSION = $${QAMQP_VERSION} 14 | win32:DESTDIR = $$OUT_PWD 15 | macx:QMAKE_LFLAGS_SONAME = -Wl,-install_name,@rpath/ 16 | 17 | # for some reason with Travis' qt 5.0.2 you can't chain these with an | 18 | NEED_GCOV_SUPPORT = 0 19 | greaterThan(QT_MAJOR_VERSION, 4):lessThan(QT_MINOR_VERSION, 2) { 20 | NEED_GCOV_SUPPORT = 1 21 | } 22 | lessThan(QT_MAJOR_VERSION, 5):lessThan(QT_MINOR_VERSION, 9):lessThan(QT_PATCH_VERSION, 6) { 23 | NEED_GCOV_SUPPORT = 1 24 | } 25 | 26 | greaterThan(NEED_GCOV_SUPPORT, 0) { 27 | # NOTE: remove when travis adds a newer ubuntu, or when hell freezes over 28 | gcov { 29 | QMAKE_CFLAGS += -fprofile-arcs -ftest-coverage 30 | QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage 31 | QMAKE_OBJECTIVE_CFLAGS += -fprofile-arcs -ftest-coverage 32 | QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage 33 | QMAKE_CLEAN += $(OBJECTS_DIR)*.gcno and $(OBJECTS_DIR)*.gcda 34 | } 35 | } 36 | 37 | #Define GIT Macros 38 | GIT_VERSION = $$system(git describe --long --dirty --tags) 39 | DEFINES += GIT_VERSION=\\\"$$GIT_VERSION\\\" 40 | 41 | GIT_TAG = $$system(git describe --abbrev=0) 42 | VERSION = $$replace(GIT_TAG, v,) 43 | 44 | PRIVATE_HEADERS += \ 45 | qamqpchannel_p.h \ 46 | qamqpchannelhash_p.h \ 47 | qamqpclient_p.h \ 48 | qamqpexchange_p.h \ 49 | qamqpframe_p.h \ 50 | qamqpmessage_p.h \ 51 | qamqpqueue_p.h 52 | 53 | INSTALL_HEADERS += \ 54 | qamqpauthenticator.h \ 55 | qamqpchannel.h \ 56 | qamqpclient.h \ 57 | qamqpexchange.h \ 58 | qamqpglobal.h \ 59 | qamqpmessage.h \ 60 | qamqpqueue.h \ 61 | qamqptable.h 62 | 63 | HEADERS += \ 64 | $${INSTALL_HEADERS} \ 65 | $${PRIVATE_HEADERS} 66 | 67 | SOURCES += \ 68 | qamqpauthenticator.cpp \ 69 | qamqpchannel.cpp \ 70 | qamqpchannelhash.cpp \ 71 | qamqpclient.cpp \ 72 | qamqpexchange.cpp \ 73 | qamqpframe.cpp \ 74 | qamqpmessage.cpp \ 75 | qamqpqueue.cpp \ 76 | qamqptable.cpp 77 | 78 | # install 79 | headers.files = $${INSTALL_HEADERS} 80 | headers.path = $${PREFIX}/include/qamqp 81 | target.path = $${PREFIX}/$${LIBDIR} 82 | INSTALLS += headers target 83 | 84 | # pkg-config support 85 | CONFIG += create_pc create_prl no_install_prl 86 | QMAKE_PKGCONFIG_DESTDIR = pkgconfig 87 | QMAKE_PKGCONFIG_LIBDIR = $$target.path 88 | QMAKE_PKGCONFIG_INCDIR = $$headers.path 89 | equals(QAMQP_LIBRARY_TYPE, staticlib) { 90 | QMAKE_PKGCONFIG_CFLAGS = -DQAMQP_STATIC 91 | } else { 92 | QMAKE_PKGCONFIG_CFLAGS = -DQAMQP_SHARED 93 | } 94 | unix:QMAKE_CLEAN += -r pkgconfig lib$${TARGET}.prl 95 | -------------------------------------------------------------------------------- /tests/auto/auto.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS = \ 3 | qamqpclient \ 4 | qamqpexchange \ 5 | qamqpqueue \ 6 | qamqpchannel 7 | -------------------------------------------------------------------------------- /tests/auto/qamqpchannel/qamqpchannel.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | include($${DEPTH}/tests/tests.pri) 4 | 5 | TARGET = tst_qamqpchannel 6 | SOURCES = tst_qamqpchannel.cpp 7 | -------------------------------------------------------------------------------- /tests/auto/qamqpchannel/tst_qamqpchannel.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "signalspy.h" 4 | #include "qamqptestcase.h" 5 | 6 | #include "qamqpclient.h" 7 | #include "qamqpexchange.h" 8 | #include "qamqpqueue.h" 9 | 10 | class tst_QAMQPChannel : public TestCase 11 | { 12 | Q_OBJECT 13 | private Q_SLOTS: 14 | void init(); 15 | void cleanup(); 16 | 17 | void close(); 18 | void resume(); 19 | void sharedChannel(); 20 | void defineWithChannelNumber(); 21 | 22 | private: 23 | QScopedPointer client; 24 | 25 | }; 26 | 27 | void tst_QAMQPChannel::init() 28 | { 29 | client.reset(new QAmqpClient); 30 | client->connectToHost(); 31 | QVERIFY(waitForSignal(client.data(), SIGNAL(connected()))); 32 | } 33 | 34 | void tst_QAMQPChannel::cleanup() 35 | { 36 | if (client->isConnected()) { 37 | client->disconnectFromHost(); 38 | QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected()))); 39 | } 40 | } 41 | 42 | void tst_QAMQPChannel::close() 43 | { 44 | // exchange 45 | QAmqpExchange *exchange = client->createExchange("test-close-channel"); 46 | QVERIFY(waitForSignal(exchange, SIGNAL(opened()))); 47 | exchange->declare(QAmqpExchange::Direct); 48 | QVERIFY(waitForSignal(exchange, SIGNAL(declared()))); 49 | exchange->close(); 50 | QVERIFY(waitForSignal(exchange, SIGNAL(closed()))); 51 | exchange->reopen(); 52 | QVERIFY(waitForSignal(exchange, SIGNAL(opened()))); 53 | exchange->remove(QAmqpExchange::roForce); 54 | QVERIFY(waitForSignal(exchange, SIGNAL(removed()))); 55 | 56 | // queue 57 | QAmqpQueue *queue = client->createQueue("test-close-channel"); 58 | QVERIFY(waitForSignal(queue, SIGNAL(opened()))); 59 | declareQueueAndVerifyConsuming(queue); 60 | queue->close(); 61 | QVERIFY(waitForSignal(queue, SIGNAL(closed()))); 62 | } 63 | 64 | void tst_QAMQPChannel::resume() 65 | { 66 | QAmqpQueue *queue = client->createQueue("test-resume"); 67 | QVERIFY(waitForSignal(queue, SIGNAL(opened()))); 68 | declareQueueAndVerifyConsuming(queue); 69 | 70 | queue->resume(); 71 | QVERIFY(waitForSignal(queue, SIGNAL(resumed()))); 72 | } 73 | 74 | void tst_QAMQPChannel::sharedChannel() 75 | { 76 | QString routingKey = "test-shared-channel"; 77 | QAmqpQueue *queue = client->createQueue(routingKey); 78 | declareQueueAndVerifyConsuming(queue); 79 | 80 | QAmqpExchange *defaultExchange = client->createExchange("", queue->channelNumber()); 81 | defaultExchange->publish("first message", routingKey); 82 | QVERIFY(waitForSignal(queue, SIGNAL(messageReceived()))); 83 | QAmqpMessage message = queue->dequeue(); 84 | verifyStandardMessageHeaders(message, routingKey); 85 | QCOMPARE(message.payload(), QByteArray("first message")); 86 | } 87 | 88 | void tst_QAMQPChannel::defineWithChannelNumber() 89 | { 90 | QString routingKey = "test-specific-channel-number"; 91 | QAmqpQueue *queue = client->createQueue(routingKey, 25); 92 | declareQueueAndVerifyConsuming(queue); 93 | QCOMPARE(queue->channelNumber(), 25); 94 | } 95 | 96 | QTEST_MAIN(tst_QAMQPChannel) 97 | #include "tst_qamqpchannel.moc" 98 | -------------------------------------------------------------------------------- /tests/auto/qamqpclient/certs.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | ../../files/certs/testca/cacert.pem 4 | ../../files/certs/client/cert.pem 5 | ../../files/certs/client/key.pem 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/auto/qamqpclient/qamqpclient.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | include($${DEPTH}/tests/tests.pri) 4 | 5 | TARGET = tst_qamqpclient 6 | SOURCES = tst_qamqpclient.cpp 7 | RESOURCES = certs.qrc 8 | -------------------------------------------------------------------------------- /tests/auto/qamqpclient/tst_qamqpclient.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "qamqptestcase.h" 6 | #include "qamqpauthenticator.h" 7 | #include "qamqpexchange.h" 8 | #include "qamqpqueue.h" 9 | #include "qamqpclient_p.h" 10 | #include "qamqpclient.h" 11 | 12 | class tst_QAMQPClient : public TestCase 13 | { 14 | Q_OBJECT 15 | private Q_SLOTS: 16 | void connect(); 17 | void connectProperties(); 18 | void connectHostAddress(); 19 | void connectDisconnect(); 20 | void invalidAuthenticationMechanism(); 21 | void tune(); 22 | void socketError(); 23 | void validateUri_data(); 24 | void validateUri(); 25 | void issue38(); 26 | void issue38_take2(); 27 | 28 | public Q_SLOTS: // temporarily disabled 29 | void autoReconnect(); 30 | void autoReconnectTimeout(); 31 | void sslConnect(); 32 | 33 | private: 34 | QSslConfiguration createSslConfiguration(); 35 | void issue38_helper(QAmqpClient *client); 36 | 37 | }; 38 | 39 | QSslConfiguration tst_QAMQPClient::createSslConfiguration() 40 | { 41 | QList caCerts = 42 | QSslCertificate::fromPath(QLatin1String(":/certs/ca-cert.pem")); 43 | QList localCerts = 44 | QSslCertificate::fromPath(QLatin1String(":/certs/client-cert.pem")); 45 | QFile keyFile( QLatin1String(":/certs/client-key.pem")); 46 | keyFile.open(QIODevice::ReadOnly); 47 | QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); 48 | keyFile.close(); 49 | 50 | QSslConfiguration sslConfiguration; 51 | sslConfiguration.setCaCertificates(caCerts); 52 | sslConfiguration.setLocalCertificate(localCerts.first()); 53 | sslConfiguration.setPrivateKey(key); 54 | sslConfiguration.setProtocol(QSsl::SecureProtocols); 55 | return sslConfiguration; 56 | } 57 | 58 | void tst_QAMQPClient::connect() 59 | { 60 | QAmqpClient client; 61 | client.connectToHost(); 62 | QVERIFY(waitForSignal(&client, SIGNAL(connected()))); 63 | 64 | QCOMPARE(client.host(), QLatin1String(AMQP_HOST)); 65 | QCOMPARE(client.port(), quint16(AMQP_PORT)); 66 | QCOMPARE(client.virtualHost(), QLatin1String(AMQP_VHOST)); 67 | QCOMPARE(client.username(), QLatin1String(AMQP_LOGIN)); 68 | QCOMPARE(client.password(), QLatin1String(AMQP_PSWD)); 69 | QCOMPARE(client.autoReconnect(), false); 70 | 71 | client.disconnectFromHost(); 72 | QVERIFY(waitForSignal(&client, SIGNAL(disconnected()))); 73 | } 74 | 75 | void tst_QAMQPClient::sslConnect() 76 | { 77 | QAmqpClient client; 78 | client.setSslConfiguration(createSslConfiguration()); 79 | QObject::connect(&client, SIGNAL(sslErrors(QList)), 80 | &client, SLOT(ignoreSslErrors(QList))); 81 | 82 | client.connectToHost(); 83 | QVERIFY(waitForSignal(&client, SIGNAL(connected()))); 84 | } 85 | 86 | void tst_QAMQPClient::connectProperties() 87 | { 88 | QAmqpClient client; 89 | client.setHost("localhost"); 90 | client.setPort(5672); 91 | client.setVirtualHost("/"); 92 | client.setUsername("guest"); 93 | client.setPassword("guest"); 94 | client.setAutoReconnect(false); 95 | client.connectToHost(); 96 | QVERIFY(waitForSignal(&client, SIGNAL(connected()))); 97 | client.disconnectFromHost(); 98 | QVERIFY(waitForSignal(&client, SIGNAL(disconnected()))); 99 | } 100 | 101 | void tst_QAMQPClient::connectHostAddress() 102 | { 103 | QAmqpClient client; 104 | client.connectToHost(QHostAddress::LocalHost, 5672); 105 | QVERIFY(waitForSignal(&client, SIGNAL(connected()))); 106 | client.disconnectFromHost(); 107 | QVERIFY(waitForSignal(&client, SIGNAL(disconnected()))); 108 | } 109 | 110 | void tst_QAMQPClient::connectDisconnect() 111 | { 112 | QAmqpClient client; 113 | client.connectToHost(); 114 | QVERIFY(waitForSignal(&client, SIGNAL(connected()))); 115 | client.disconnectFromHost(); 116 | QVERIFY(waitForSignal(&client, SIGNAL(disconnected()))); 117 | } 118 | 119 | class InvalidAuthenticator : public QAmqpAuthenticator 120 | { 121 | public: 122 | virtual QString type() const { return "CRAZYAUTH"; } 123 | virtual void write(QDataStream &out) { 124 | Q_UNUSED(out); 125 | } 126 | }; 127 | 128 | void tst_QAMQPClient::invalidAuthenticationMechanism() 129 | { 130 | QAmqpClient client; 131 | client.setAuth(new InvalidAuthenticator); 132 | client.connectToHost(); 133 | QVERIFY(waitForSignal(&client, SIGNAL(disconnected()))); 134 | } 135 | 136 | void tst_QAMQPClient::autoReconnect() 137 | { 138 | // TODO: this is a fairly crude way of testing this, research 139 | // better alternatives 140 | 141 | QAmqpClient client; 142 | client.setAutoReconnect(true); 143 | client.connectToHost(); 144 | QVERIFY(waitForSignal(&client, SIGNAL(connected()))); 145 | QProcess::execute("rabbitmqctl", QStringList() << "stop_app"); 146 | QVERIFY(waitForSignal(&client, SIGNAL(disconnected()))); 147 | QProcess::execute("rabbitmqctl", QStringList() << "start_app"); 148 | QVERIFY(waitForSignal(&client, SIGNAL(connected()), 2)); 149 | } 150 | 151 | void tst_QAMQPClient::autoReconnectTimeout() 152 | { 153 | // TODO: this is a fairly crude way of testing this, research 154 | // better alternatives 155 | 156 | QAmqpClient client; 157 | client.setAutoReconnect(true, 3); 158 | client.connectToHost(); 159 | QVERIFY(waitForSignal(&client, SIGNAL(connected()), 60)); 160 | qDebug() <<"connected" ; 161 | QProcess::execute("rabbitmqctl", QStringList() << "stop_app"); 162 | QVERIFY(waitForSignal(&client, SIGNAL(disconnected()), 60)); 163 | qDebug() <<"disconnected" ; 164 | QProcess::execute("rabbitmqctl", QStringList() << "start_app"); 165 | QVERIFY(waitForSignal(&client, SIGNAL(connected()), 60)); 166 | qDebug() <<"connected" ; 167 | 168 | QVERIFY(waitForSignal(&client, SIGNAL(disconnected()), 60)); 169 | QProcess::execute("rabbitmqctl", QStringList() << "start_app"); 170 | QVERIFY(waitForSignal(&client, SIGNAL(connected()), 60)); 171 | } 172 | 173 | void tst_QAMQPClient::tune() 174 | { 175 | QAmqpClient client; 176 | client.setChannelMax(15); 177 | client.setFrameMax(5000); 178 | client.setHeartbeatDelay(600); 179 | 180 | client.connectToHost(); 181 | QVERIFY(waitForSignal(&client, SIGNAL(connected()))); 182 | QCOMPARE((int)client.channelMax(), 15); 183 | QCOMPARE((int)client.heartbeatDelay(), 600); 184 | QCOMPARE((int)client.frameMax(), 5000); 185 | 186 | client.disconnectFromHost(); 187 | QVERIFY(waitForSignal(&client, SIGNAL(disconnected()))); 188 | } 189 | 190 | void tst_QAMQPClient::socketError() 191 | { 192 | QAmqpClient client; 193 | client.connectToHost("amqp://127.0.0.1:56725/"); 194 | QVERIFY(waitForSignal(&client, SIGNAL(socketError(QAbstractSocket::SocketError)))); 195 | QCOMPARE(client.socketError(), QAbstractSocket::ConnectionRefusedError); 196 | } 197 | 198 | void tst_QAMQPClient::validateUri_data() 199 | { 200 | QTest::addColumn("uri"); 201 | QTest::addColumn("expectedUsername"); 202 | QTest::addColumn("expectedPassword"); 203 | QTest::addColumn("expectedHost"); 204 | QTest::addColumn("expectedPort"); 205 | QTest::addColumn("expectedVirtualHost"); 206 | 207 | QTest::newRow("default vhost") << "amqp://guest:guest@192.168.1.10:5672/" 208 | << "guest" << "guest" << "192.168.1.10" << quint16(5672) << "/"; 209 | QTest::newRow("standard") << "amqp://user:pass@host:10000/vhost" 210 | << "user" << "pass" << "host" << quint16(10000) << "vhost"; 211 | #if QT_VERSION >= 0x040806 212 | QTest::newRow("urlencoded") << "amqp://user%61:%61pass@ho%61st:10000/v%2fhost" 213 | << "usera" << "apass" << "hoast" << quint16(10000) << "v/host"; 214 | #endif 215 | QTest::newRow("empty") << "amqp://" << "" << "" << "" << quint16(AMQP_PORT) << ""; 216 | QTest::newRow("empty2") << "amqp://:@/" << "" << "" << "" << quint16(AMQP_PORT) << "/"; 217 | QTest::newRow("onlyuser") << "amqp://user@" << "user" << "" << "" << quint16(AMQP_PORT) << ""; 218 | QTest::newRow("userpass") << "amqp://user:pass@" << "user" << "pass" << "" << quint16(AMQP_PORT) << ""; 219 | QTest::newRow("onlyhost") << "amqp://host" << "" << "" << "host" << quint16(AMQP_PORT) << ""; 220 | QTest::newRow("onlyport") << "amqp://:10000" << "" << "" << "" << quint16(10000) << ""; 221 | QTest::newRow("onlyvhost") << "amqp:///vhost" << "" << "" << "" << quint16(AMQP_PORT) << "vhost"; 222 | QTest::newRow("urlencodedvhost") << "amqp://host/%2f" 223 | << "" << "" << "host" << quint16(AMQP_PORT) << "/"; 224 | QTest::newRow("ipv6") << "amqp://[::1]" << "" << "" << "::1" << quint16(AMQP_PORT) << ""; 225 | } 226 | 227 | void tst_QAMQPClient::validateUri() 228 | { 229 | QFETCH(QString, uri); 230 | QFETCH(QString, expectedUsername); 231 | QFETCH(QString, expectedPassword); 232 | QFETCH(QString, expectedHost); 233 | QFETCH(quint16, expectedPort); 234 | QFETCH(QString, expectedVirtualHost); 235 | 236 | QAmqpClientPrivate clientPrivate(0); 237 | // fake init 238 | clientPrivate.authenticator = QSharedPointer( 239 | new QAmqpPlainAuthenticator(QString::fromLatin1(AMQP_LOGIN), QString::fromLatin1(AMQP_PSWD))); 240 | 241 | // test parsing 242 | clientPrivate.parseConnectionString(uri); 243 | QAmqpPlainAuthenticator *auth = 244 | static_cast(clientPrivate.authenticator.data()); 245 | 246 | QCOMPARE(auth->login(), expectedUsername); 247 | QCOMPARE(auth->password(), expectedPassword); 248 | QCOMPARE(clientPrivate.host, expectedHost); 249 | QCOMPARE(clientPrivate.port, expectedPort); 250 | QCOMPARE(clientPrivate.virtualHost, expectedVirtualHost); 251 | } 252 | 253 | void tst_QAMQPClient::issue38_helper(QAmqpClient *client) 254 | { 255 | // connect 256 | client->connectToHost(); 257 | QVERIFY(waitForSignal(client, SIGNAL(connected()))); 258 | 259 | // create then declare, remove and close queue 260 | QAmqpQueue *queue = client->createQueue(); 261 | QVERIFY(waitForSignal(queue, SIGNAL(opened()))); 262 | queue->declare(); 263 | QVERIFY(waitForSignal(queue, SIGNAL(declared()))); 264 | queue->remove(QAmqpExchange::roForce); 265 | QVERIFY(waitForSignal(queue, SIGNAL(removed()))); 266 | queue->close(); 267 | QVERIFY(waitForSignal(queue, SIGNAL(closed()))); 268 | queue->deleteLater(); 269 | 270 | // disconnect 271 | client->disconnectFromHost(); 272 | QVERIFY(waitForSignal(client, SIGNAL(disconnected()))); 273 | } 274 | 275 | void tst_QAMQPClient::issue38() 276 | { 277 | QAmqpClient client; 278 | issue38_helper(&client); 279 | issue38_helper(&client); 280 | } 281 | 282 | void tst_QAMQPClient::issue38_take2() 283 | { 284 | QAmqpClient client; 285 | client.connectToHost(); 286 | QVERIFY(waitForSignal(&client, SIGNAL(connected()))); 287 | QAmqpExchange *exchange = client.createExchange("myexchange"); 288 | exchange->declare(QAmqpExchange::Topic); 289 | QVERIFY(waitForSignal(exchange, SIGNAL(declared()))); 290 | QAmqpQueue *queue = client.createQueue(); 291 | queue->declare(); 292 | QVERIFY(waitForSignal(queue, SIGNAL(declared()))); 293 | queue->bind(exchange, "routingKeyin"); 294 | QVERIFY(waitForSignal(queue, SIGNAL(bound()))); 295 | queue->consume(QAmqpQueue::coNoAck); 296 | QVERIFY(waitForSignal(queue, SIGNAL(consuming(QString)))); 297 | exchange->publish("test message", "routingKeyout"); 298 | 299 | // delete everything 300 | queue->unbind(exchange, "routingKeyin"); 301 | QVERIFY(waitForSignal(queue, SIGNAL(unbound()))); 302 | queue->close(); 303 | QVERIFY(waitForSignal(queue, SIGNAL(closed()))); 304 | queue->deleteLater(); 305 | 306 | exchange->close(); 307 | QVERIFY(waitForSignal(exchange, SIGNAL(closed()))); 308 | exchange->deleteLater(); 309 | 310 | client.disconnectFromHost(); 311 | QVERIFY(waitForSignal(&client,SIGNAL(disconnected()))); 312 | 313 | // repeat the connection and create again here 314 | client.connectToHost(); 315 | QVERIFY(waitForSignal(&client, SIGNAL(connected()))); 316 | exchange = client.createExchange("myexchange"); 317 | exchange->declare(QAmqpExchange::Topic); 318 | QVERIFY(waitForSignal(exchange, SIGNAL(declared()))); 319 | queue = client.createQueue(); 320 | queue->declare(); 321 | QVERIFY(waitForSignal(queue, SIGNAL(declared()))); 322 | queue->bind(exchange, "routingKeyin"); 323 | QVERIFY(waitForSignal(queue, SIGNAL(bound()))); 324 | queue->consume(QAmqpQueue::coNoAck); 325 | QVERIFY(waitForSignal(queue, SIGNAL(consuming(QString)))); 326 | exchange->publish("test message", "routingKeyout"); 327 | client.disconnectFromHost(); 328 | QVERIFY(waitForSignal(&client,SIGNAL(disconnected()))); 329 | } 330 | 331 | 332 | QTEST_MAIN(tst_QAMQPClient) 333 | #include "tst_qamqpclient.moc" 334 | -------------------------------------------------------------------------------- /tests/auto/qamqpexchange/qamqpexchange.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | include($${DEPTH}/tests/tests.pri) 4 | 5 | TARGET = tst_qamqpexchange 6 | SOURCES = tst_qamqpexchange.cpp 7 | -------------------------------------------------------------------------------- /tests/auto/qamqpexchange/tst_qamqpexchange.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "signalspy.h" 4 | #include "qamqptestcase.h" 5 | 6 | #include "qamqpclient.h" 7 | #include "qamqpexchange.h" 8 | #include "qamqpqueue.h" 9 | 10 | class tst_QAMQPExchange : public TestCase 11 | { 12 | Q_OBJECT 13 | private Q_SLOTS: 14 | void init(); 15 | void cleanup(); 16 | 17 | void standardTypes_data(); 18 | void standardTypes(); 19 | void invalidStandardDeclaration_data(); 20 | void invalidStandardDeclaration(); 21 | void invalidDeclaration(); 22 | void invalidRedeclaration(); 23 | void removeIfUnused(); 24 | void invalidMandatoryRouting(); 25 | void invalidImmediateRouting(); 26 | void confirmsSupport(); 27 | void confirmDontLoseMessages(); 28 | void passiveDeclareNotFound(); 29 | void cleanupOnDeletion(); 30 | void testQueuedPublish(); 31 | 32 | private: 33 | QScopedPointer client; 34 | 35 | }; 36 | 37 | void tst_QAMQPExchange::init() 38 | { 39 | client.reset(new QAmqpClient); 40 | client->connectToHost(); 41 | QVERIFY(waitForSignal(client.data(), SIGNAL(connected()))); 42 | } 43 | 44 | void tst_QAMQPExchange::cleanup() 45 | { 46 | if (client->isConnected()) { 47 | client->disconnectFromHost(); 48 | QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected()))); 49 | } 50 | } 51 | 52 | void tst_QAMQPExchange::standardTypes_data() 53 | { 54 | QTest::addColumn("type"); 55 | QTest::addColumn("delayedDeclaration"); 56 | 57 | QTest::newRow("direct") << QAmqpExchange::Direct << false; 58 | QTest::newRow("direct-delayed") << QAmqpExchange::Direct << true; 59 | QTest::newRow("fanout") << QAmqpExchange::FanOut << false; 60 | QTest::newRow("fanout-delayed") << QAmqpExchange::FanOut << true; 61 | QTest::newRow("topic") << QAmqpExchange::Topic << false; 62 | QTest::newRow("topic-delayed") << QAmqpExchange::Topic << true; 63 | QTest::newRow("headers") << QAmqpExchange::Headers << false; 64 | QTest::newRow("headers-delayed") << QAmqpExchange::Headers << true; 65 | } 66 | 67 | void tst_QAMQPExchange::standardTypes() 68 | { 69 | QFETCH(QAmqpExchange::ExchangeType, type); 70 | QFETCH(bool, delayedDeclaration); 71 | 72 | QAmqpExchange *exchange = client->createExchange("test"); 73 | if (!delayedDeclaration) 74 | QVERIFY(waitForSignal(exchange, SIGNAL(opened()))); 75 | 76 | exchange->declare(type); 77 | QVERIFY(waitForSignal(exchange, SIGNAL(declared()))); 78 | exchange->remove(QAmqpExchange::roForce); 79 | QVERIFY(waitForSignal(exchange, SIGNAL(removed()))); 80 | } 81 | 82 | void tst_QAMQPExchange::invalidStandardDeclaration_data() 83 | { 84 | QTest::addColumn("exchangeName"); 85 | QTest::addColumn("type"); 86 | QTest::addColumn("error"); 87 | 88 | QTest::newRow("amq.direct") << "amq.direct" << QAmqpExchange::Direct << QAMQP::PreconditionFailedError; 89 | QTest::newRow("amq.fanout") << "amq.fanout" << QAmqpExchange::FanOut << QAMQP::PreconditionFailedError; 90 | QTest::newRow("amq.headers") << "amq.headers" << QAmqpExchange::Headers << QAMQP::PreconditionFailedError; 91 | QTest::newRow("amq.match") << "amq.match" << QAmqpExchange::Headers << QAMQP::PreconditionFailedError; 92 | QTest::newRow("amq.topic") << "amq.topic" << QAmqpExchange::Topic << QAMQP::PreconditionFailedError; 93 | QTest::newRow("amq.reserved") << "amq.reserved" << QAmqpExchange::Direct << QAMQP::AccessRefusedError; 94 | } 95 | 96 | void tst_QAMQPExchange::invalidStandardDeclaration() 97 | { 98 | QFETCH(QString, exchangeName); 99 | QFETCH(QAmqpExchange::ExchangeType, type); 100 | QFETCH(QAMQP::Error, error); 101 | 102 | QAmqpExchange *exchange = client->createExchange(exchangeName); 103 | exchange->declare(type); 104 | QVERIFY(waitForSignal(exchange, SIGNAL(error(QAMQP::Error)))); 105 | QCOMPARE(exchange->error(), error); 106 | } 107 | 108 | void tst_QAMQPExchange::invalidDeclaration() 109 | { 110 | QAmqpExchange *exchange = client->createExchange("test-invalid-declaration"); 111 | exchange->declare("invalidExchangeType"); 112 | QVERIFY(waitForSignal(client.data(), SIGNAL(error(QAMQP::Error)))); 113 | QCOMPARE(client->error(), QAMQP::CommandInvalidError); 114 | } 115 | 116 | void tst_QAMQPExchange::invalidRedeclaration() 117 | { 118 | QAmqpExchange *exchange = client->createExchange("test-invalid-redeclaration"); 119 | exchange->declare(QAmqpExchange::Direct); 120 | QVERIFY(waitForSignal(exchange, SIGNAL(declared()))); 121 | 122 | QAmqpExchange *redeclared = client->createExchange("test-invalid-redeclaration"); 123 | redeclared->declare(QAmqpExchange::FanOut); 124 | QVERIFY(waitForSignal(redeclared, SIGNAL(error(QAMQP::Error)))); 125 | 126 | // this is per spec: 127 | // QCOMPARE(redeclared->error(), QAMQP::NotAllowedError); 128 | 129 | // this is for rabbitmq: 130 | QCOMPARE(redeclared->error(), QAMQP::PreconditionFailedError); 131 | 132 | // Server has probably closed the channel on us, if so, re-open it. 133 | if (!exchange->isOpen()) { 134 | exchange->reopen(); 135 | QVERIFY(waitForSignal(exchange, SIGNAL(opened()))); 136 | } 137 | 138 | // cleanup 139 | exchange->remove(); 140 | QVERIFY(waitForSignal(exchange, SIGNAL(removed()))); 141 | } 142 | 143 | void tst_QAMQPExchange::removeIfUnused() 144 | { 145 | QAmqpExchange *exchange = client->createExchange("test-if-unused-exchange"); 146 | exchange->declare(QAmqpExchange::Direct, QAmqpExchange::AutoDelete); 147 | QVERIFY(waitForSignal(exchange, SIGNAL(declared()))); 148 | 149 | QAmqpQueue *queue = client->createQueue("test-if-unused-queue"); 150 | queue->declare(); 151 | QVERIFY(waitForSignal(queue, SIGNAL(declared()))); 152 | queue->bind("test-if-unused-exchange", "testRoutingKey"); 153 | QVERIFY(waitForSignal(queue, SIGNAL(bound()))); 154 | 155 | exchange->remove(QAmqpExchange::roIfUnused); 156 | QVERIFY(waitForSignal(exchange, SIGNAL(error(QAMQP::Error)))); 157 | QCOMPARE(exchange->error(), QAMQP::PreconditionFailedError); 158 | QVERIFY(!exchange->errorString().isEmpty()); 159 | 160 | // cleanup 161 | queue->remove(QAmqpQueue::roForce); 162 | QVERIFY(waitForSignal(queue, SIGNAL(removed()))); 163 | } 164 | 165 | void tst_QAMQPExchange::invalidMandatoryRouting() 166 | { 167 | QAmqpExchange *defaultExchange = client->createExchange(); 168 | defaultExchange->publish("some message", "unroutable-key", QAmqpMessage::PropertyHash(), QAmqpExchange::poMandatory); 169 | QVERIFY(waitForSignal(defaultExchange, SIGNAL(error(QAMQP::Error)))); 170 | QCOMPARE(defaultExchange->error(), QAMQP::NoRouteError); 171 | } 172 | 173 | void tst_QAMQPExchange::invalidImmediateRouting() 174 | { 175 | QAmqpExchange *defaultExchange = client->createExchange(); 176 | defaultExchange->publish("some message", "unroutable-key", QAmqpMessage::PropertyHash(), QAmqpExchange::poImmediate); 177 | QVERIFY(waitForSignal(client.data(), SIGNAL(error(QAMQP::Error)))); 178 | QCOMPARE(client->error(), QAMQP::NotImplementedError); 179 | } 180 | 181 | void tst_QAMQPExchange::confirmsSupport() 182 | { 183 | QAmqpExchange *exchange = client->createExchange("confirm-test"); 184 | exchange->enableConfirms(); 185 | QVERIFY(waitForSignal(exchange, SIGNAL(confirmsEnabled()))); 186 | } 187 | 188 | void tst_QAMQPExchange::confirmDontLoseMessages() 189 | { 190 | QAmqpExchange *defaultExchange = client->createExchange(); 191 | defaultExchange->enableConfirms(); 192 | QVERIFY(waitForSignal(defaultExchange, SIGNAL(confirmsEnabled()))); 193 | 194 | QAmqpMessage::PropertyHash properties; 195 | properties[QAmqpMessage::DeliveryMode] = "2"; // make message persistent 196 | 197 | for (int i = 0; i < 10000; ++i) 198 | defaultExchange->publish("noop", "confirms-test", properties); 199 | QVERIFY(defaultExchange->waitForConfirms()); 200 | } 201 | 202 | void tst_QAMQPExchange::passiveDeclareNotFound() 203 | { 204 | QAmqpExchange *nonExistentExchange = client->createExchange("this-does-not-exist"); 205 | nonExistentExchange->declare(QAmqpExchange::Direct, QAmqpExchange::Passive); 206 | QVERIFY(waitForSignal(nonExistentExchange, SIGNAL(error(QAMQP::Error)))); 207 | QCOMPARE(nonExistentExchange->error(), QAMQP::NotFoundError); 208 | } 209 | 210 | void tst_QAMQPExchange::cleanupOnDeletion() 211 | { 212 | // create, declare, and close the wrong way 213 | QAmqpExchange *exchange = client->createExchange("test-deletion"); 214 | exchange->declare(); 215 | QVERIFY(waitForSignal(exchange, SIGNAL(declared()))); 216 | exchange->close(); 217 | exchange->deleteLater(); 218 | QVERIFY(waitForSignal(exchange, SIGNAL(destroyed()))); 219 | 220 | // now create, declare, and close the right way 221 | exchange = client->createExchange("test-deletion"); 222 | exchange->declare(); 223 | QVERIFY(waitForSignal(exchange, SIGNAL(declared()))); 224 | exchange->close(); 225 | QVERIFY(waitForSignal(exchange, SIGNAL(closed()))); 226 | } 227 | 228 | void tst_QAMQPExchange::testQueuedPublish() 229 | { 230 | QAmqpExchange *defaultExchange = client->createExchange(); 231 | defaultExchange->enableConfirms(); 232 | QVERIFY(waitForSignal(defaultExchange, SIGNAL(confirmsEnabled()))); 233 | 234 | QAmqpMessage::PropertyHash properties; 235 | properties[QAmqpMessage::DeliveryMode] = "2"; // make message persistent 236 | for (int i = 0; i < 10000; ++i) { 237 | QMetaObject::invokeMethod(defaultExchange, "publish", Qt::QueuedConnection, 238 | Q_ARG(QString, "noop"), Q_ARG(QString, "confirms-test"), 239 | Q_ARG(QAmqpMessage::PropertyHash, properties)); 240 | } 241 | 242 | QVERIFY(defaultExchange->waitForConfirms()); 243 | } 244 | 245 | QTEST_MAIN(tst_QAMQPExchange) 246 | #include "tst_qamqpexchange.moc" 247 | -------------------------------------------------------------------------------- /tests/auto/qamqpqueue/qamqpqueue.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | include($${DEPTH}/tests/tests.pri) 4 | 5 | TARGET = tst_qamqpqueue 6 | SOURCES = tst_qamqpqueue.cpp 7 | -------------------------------------------------------------------------------- /tests/common/qamqptestcase.h: -------------------------------------------------------------------------------- 1 | #ifndef QAMQPTESTCASE_H 2 | #define QAMQPTESTCASE_H 3 | 4 | #include 5 | #include 6 | 7 | #include "qamqpqueue.h" 8 | 9 | class TestCase : public QObject 10 | { 11 | public: 12 | TestCase() {} 13 | virtual ~TestCase() {} 14 | 15 | protected: 16 | bool waitForSignal(QObject *obj, const char *signal, int delay = 5) 17 | { 18 | QObject::connect(obj, signal, &QTestEventLoop::instance(), SLOT(exitLoop())); 19 | QPointer safe = obj; 20 | 21 | QTestEventLoop::instance().enterLoop(delay); 22 | if (!safe.isNull()) 23 | QObject::disconnect(safe, signal, &QTestEventLoop::instance(), SLOT(exitLoop())); 24 | return !QTestEventLoop::instance().timeout(); 25 | } 26 | 27 | void declareQueueAndVerifyConsuming(QAmqpQueue *queue) 28 | { 29 | queue->declare(); 30 | QVERIFY(waitForSignal(queue, SIGNAL(declared()))); 31 | QVERIFY(queue->consume()); 32 | QSignalSpy spy(queue, SIGNAL(consuming(QString))); 33 | QVERIFY(waitForSignal(queue, SIGNAL(consuming(QString)))); 34 | QVERIFY(queue->isConsuming()); 35 | QVERIFY(!spy.isEmpty()); 36 | QList arguments = spy.takeFirst(); 37 | QCOMPARE(arguments.at(0).toString(), queue->consumerTag()); 38 | } 39 | 40 | void verifyStandardMessageHeaders(const QAmqpMessage &message, const QString &routingKey, 41 | const QString &exchangeName = QLatin1String(""), 42 | bool redelivered = false) 43 | { 44 | QCOMPARE(message.routingKey(), routingKey); 45 | QCOMPARE(message.exchangeName(), exchangeName); 46 | QCOMPARE(message.isRedelivered(), redelivered); 47 | } 48 | }; 49 | 50 | #endif // QAMQPTESTCASE_H 51 | -------------------------------------------------------------------------------- /tests/common/signalspy.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGNALSPY_H 2 | #define SIGNALSPY_H 3 | 4 | namespace QAMQP { 5 | namespace Test { 6 | 7 | bool waitForSignal(QObject *obj, const char *signal, int delay) 8 | { 9 | QObject::connect(obj, signal, &QTestEventLoop::instance(), SLOT(exitLoop())); 10 | QPointer safe = obj; 11 | 12 | QTestEventLoop::instance().enterLoop(delay); 13 | if (!safe.isNull()) 14 | QObject::disconnect(safe, signal, &QTestEventLoop::instance(), SLOT(exitLoop())); 15 | return !QTestEventLoop::instance().timeout(); 16 | } 17 | 18 | } // namespace Test 19 | } // namespace QAMQP 20 | 21 | 22 | 23 | #if QT_VERSION >= 0x050000 24 | typedef QSignalSpy SignalSpy; 25 | #else 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | class QVariant; 35 | class SignalSpy: public QObject, public QList > 36 | { 37 | public: 38 | explicit SignalSpy(const QObject *obj, const char *aSignal) 39 | : m_waiting(false) 40 | { 41 | static const int memberOffset = QObject::staticMetaObject.methodCount(); 42 | if (!obj) { 43 | qWarning("SignalSpy: Cannot spy on a null object"); 44 | return; 45 | } 46 | 47 | if (!aSignal) { 48 | qWarning("SignalSpy: Null signal name is not valid"); 49 | return; 50 | } 51 | 52 | if (((aSignal[0] - '0') & 0x03) != QSIGNAL_CODE) { 53 | qWarning("SignalSpy: Not a valid signal, use the SIGNAL macro"); 54 | return; 55 | } 56 | 57 | const QByteArray ba = QMetaObject::normalizedSignature(aSignal + 1); 58 | const QMetaObject * const mo = obj->metaObject(); 59 | const int sigIndex = mo->indexOfMethod(ba.constData()); 60 | if (sigIndex < 0) { 61 | qWarning("SignalSpy: No such signal: '%s'", ba.constData()); 62 | return; 63 | } 64 | 65 | if (!QMetaObject::connect(obj, sigIndex, this, memberOffset, 66 | Qt::DirectConnection, 0)) { 67 | qWarning("SignalSpy: QMetaObject::connect returned false. Unable to connect."); 68 | return; 69 | } 70 | sig = ba; 71 | initArgs(mo->method(sigIndex), obj); 72 | } 73 | 74 | inline bool isValid() const { return !sig.isEmpty(); } 75 | inline QByteArray signal() const { return sig; } 76 | 77 | bool wait(int timeout = 5) 78 | { 79 | Q_ASSERT(!m_waiting); 80 | const int origCount = count(); 81 | m_waiting = true; 82 | m_loop.enterLoop(timeout); 83 | m_waiting = false; 84 | return count() > origCount; 85 | } 86 | 87 | int qt_metacall(QMetaObject::Call call, int methodId, void **a) 88 | { 89 | methodId = QObject::qt_metacall(call, methodId, a); 90 | if (methodId < 0) 91 | return methodId; 92 | 93 | if (call == QMetaObject::InvokeMetaMethod) { 94 | if (methodId == 0) { 95 | appendArgs(a); 96 | } 97 | --methodId; 98 | } 99 | return methodId; 100 | } 101 | 102 | private: 103 | void initArgs(const QMetaMethod &member) 104 | { 105 | initArgs(member, 0); 106 | } 107 | 108 | void initArgs(const QMetaMethod &member, const QObject *obj) 109 | { 110 | Q_UNUSED(obj) 111 | QList params = member.parameterTypes(); 112 | for (int i = 0; i < params.count(); ++i) { 113 | int tp = QMetaType::type(params.at(i).constData()); 114 | if (tp == QMetaType::Void) 115 | qWarning("Don't know how to handle '%s', use qRegisterMetaType to register it.", 116 | params.at(i).constData()); 117 | args << tp; 118 | } 119 | } 120 | 121 | void appendArgs(void **a) 122 | { 123 | QList list; 124 | for (int i = 0; i < args.count(); ++i) { 125 | QMetaType::Type type = static_cast(args.at(i)); 126 | list << QVariant(type, a[i + 1]); 127 | } 128 | append(list); 129 | 130 | if (m_waiting) 131 | m_loop.exitLoop(); 132 | } 133 | 134 | // the full, normalized signal name 135 | QByteArray sig; 136 | // holds the QMetaType types for the argument list of the signal 137 | QVector args; 138 | 139 | QTestEventLoop m_loop; 140 | bool m_waiting; 141 | }; 142 | #endif 143 | #endif 144 | -------------------------------------------------------------------------------- /tests/files/certs/client/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC5zCCAc+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl 3 | c3RDQTAeFw0xNDA4MjcxOTI2MDVaFw0xNTA4MjcxOTI2MDVaMCoxFzAVBgNVBAMM 4 | Dm1icm9hZHN0LWJ1aWxkMQ8wDQYDVQQKDAZjbGllbnQwggEiMA0GCSqGSIb3DQEB 5 | AQUAA4IBDwAwggEKAoIBAQDrzmzjgxNXxXX+fgfjB5Pt+YbO2uQR9PDADUyk+8Kw 6 | /v1xjZBqKSHaBJLMv2nHlfGM8p92XQoepWKtG4z49UsT6MMppfUnZ/TO6LgUuJtw 7 | FaVYdJmzK8SPvsQ331id9f4grgMTiff+i6hM2Bb9Jq83/jnglrBm8T4KHjPjJXQi 8 | MN8d7ZkV2bo2vFQcO/KNTODntqINp5+OFPboyjDbMoMgUTqnXJBQsWwA9EVq2JYs 9 | FYtA5xsqk0yG9DBgI5ClfxESQQo6lHKYeX2KIuHVO5awPpm+wZbIeR3l5QFqQrQZ 10 | zfw7ANsA1RK4c85jb8K0vHxX1wV3kB+2kqpi4jxm/ucnAgMBAAGjLzAtMAkGA1Ud 11 | EwQCMAAwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3 12 | DQEBBQUAA4IBAQAxoTOMViXAKveeYx7I0dve/Te3TXe6XTlF0iFNIMp0FB3X0OeA 13 | Bjknf6SUxY4qYV9DsFBGtXg8irkbothVNQKrhSedb6n+OQGy5z24oJ+vWW5jCyf3 14 | TBoWRLnHY52j/4KElNpbEddacreYY6Ft5VYLZuyXy2G18xWjUnE5EG+QkizgAWzw 15 | w9aTxS7qyGb7/FklJhH5OA8izi4JNbIrLEcUw4ECgYihtdLnZz/ANTp4kwz7qjaj 16 | X7+8V3h7R59/HOHglCbjtkhBVuRyz5ljTfMbCava4Za2solujAo4tRxvmhioog0t 17 | QplQjUP4QM5jfFlD/1HXY2SzYPG0FIiRj93L 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /tests/files/certs/client/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEA685s44MTV8V1/n4H4weT7fmGztrkEfTwwA1MpPvCsP79cY2Q 3 | aikh2gSSzL9px5XxjPKfdl0KHqVirRuM+PVLE+jDKaX1J2f0zui4FLibcBWlWHSZ 4 | syvEj77EN99YnfX+IK4DE4n3/ouoTNgW/SavN/454JawZvE+Ch4z4yV0IjDfHe2Z 5 | Fdm6NrxUHDvyjUzg57aiDaefjhT26Mow2zKDIFE6p1yQULFsAPRFatiWLBWLQOcb 6 | KpNMhvQwYCOQpX8REkEKOpRymHl9iiLh1TuWsD6ZvsGWyHkd5eUBakK0Gc38OwDb 7 | ANUSuHPOY2/CtLx8V9cFd5AftpKqYuI8Zv7nJwIDAQABAoIBAQDj32PSqIQ0uZlB 8 | CcHNXzFRM2VW2Ki1waI1taRveuu153Q8G7WHIaCY8vp56i/qs7ftoTkARQDWhLRK 9 | 3OjqXQDkiHaw9LNoFUm5+aKKQ6vSMNjMFkHBp3YYAx3TcH5Oh73BDufiJd4FmihV 10 | uizdDlkdHwwHQRfPIyn01SMHStZjgkOqIOkKq1Me8uggiYpTh/2sbX931cwxJnSF 11 | EvDOLTvLjJdj6aWjupUaMvMsZDHJdtTZxl/YPV/KO49EkaOz0Ijv4mD8a0FQ5QRa 12 | ud1xITFlFXOeZNjH3n6/+4ypIJDkXddpfZUuetoZ3DPRZY5aalKW+SGy3zqLu8qh 13 | 0VGPRQ7BAoGBAP7xNXis1ErCybdI1wvo3XIcsq7YHsssD+2IFmNomdBF5e9QzAwU 14 | Q63WD6qmcLCSzjSm4dYZNvFL9RLWUCIkC7nkpqt0bftDw//NTdyinJo/JNf4Lprx 15 | uji5njju+FuU83Whu3QoBXFTv7Ql09bX/6EgCfx1cWrJEHC6L3oGE3SpAoGBAOzI 16 | 5BfC+5TTbqWbjoH8ycdpjbEvyhpRKT920spa2j0kNjduryJHtq1AemLsR9NOH67h 17 | cO5YHD9ClRMXxI4ogVbzOGqVAy3LdYXCJIV8GO/WTjjDINoPNb2+VfaHCkboS+8y 18 | d1HwwcFbK7p3dJFNF3ppDVXsTfZZzDAQfFqa6A9PAoGAPzmYtjW+bFAEcJT65/Q3 19 | Pv6I/b2RXXeu94yBaOPfCXzcOk6CXBiGdE0bE4o1dkTiKMKeTVdxfcQFokdOFjl0 20 | QwTGpMy6Hc8/g2fqAGa/ia1RONJO1JRQR5MY/yucojG9cxXKBFOMjf9kEowzDhwB 21 | RHdKoraJix8UGbDC53MsTgkCgYBepze23/Td219ByFtBTyICGwnPKMFrn8ITYpaE 22 | 2aigBFe/9PkBhRVbUIkb/kQADhzQNcKFJKe2ChG5niiugzag4X1N7d9lcQ27uI4M 23 | 5jy5szt1qVr6kFX1UZ7fe7/59GZWaiAUm194wc9LLPFmHCEkh9YS4PGRZvgexphP 24 | R9k4NQKBgQDXYokjEt6jl67724/J8gP09oTAxZCBSweZkTHErUg8NdsUJWqBGLP9 25 | zFg1pOfAV9gy/qKm01SdG81lWcf8sDLa3QjB4WOW6x99DH2mQ7y69tStn8B3mAVB 26 | o8Ddf50gjv54oSqFPrF1DAbBXWOEWfeLM44zyaBR9t28bNBJM4CEiQ== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/files/certs/client/keycert.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinsonSir/qamqp/ff81962201e4ae183e2b433e094eef1814999667/tests/files/certs/client/keycert.p12 -------------------------------------------------------------------------------- /tests/files/certs/client/req.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICbzCCAVcCAQAwKjEXMBUGA1UEAwwObWJyb2Fkc3QtYnVpbGQxDzANBgNVBAoM 3 | BmNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOvObOODE1fF 4 | df5+B+MHk+35hs7a5BH08MANTKT7wrD+/XGNkGopIdoEksy/aceV8Yzyn3ZdCh6l 5 | Yq0bjPj1SxPowyml9Sdn9M7ouBS4m3AVpVh0mbMrxI++xDffWJ31/iCuAxOJ9/6L 6 | qEzYFv0mrzf+OeCWsGbxPgoeM+MldCIw3x3tmRXZuja8VBw78o1M4Oe2og2nn44U 7 | 9ujKMNsygyBROqdckFCxbAD0RWrYliwVi0DnGyqTTIb0MGAjkKV/ERJBCjqUcph5 8 | fYoi4dU7lrA+mb7Blsh5HeXlAWpCtBnN/DsA2wDVErhzzmNvwrS8fFfXBXeQH7aS 9 | qmLiPGb+5ycCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQAyDAY1l3GDSkLXOKId 10 | GM0sB0Ve7tT64IsqFacp29wV15fgJH1368VOMwxiXRQVSvGQGWog0JzuX0qH12ZZ 11 | +6zQnGhumuKtoqfwlPBFNtvFRFxQ61Dzk6RZaO5fC7ZW+cLrfcEjTh9X3ts2POwP 12 | /iuFdr+r+422YDOmHY3gNKBYKg8MtaDUNSLSiwNEQ/CPNs3FsyObHutiMPgIKwqt 13 | vZ2hkvvMWcYPf2dtPTS3AfMPWVP+zR4eDfeiKYoxCyYZHsvQEyYqP5P5U1elqia1 14 | gR9WUuC6Li+7wju6ksFrrLKGPNDXvfOm3Ecqfc5JPgU+U4bJLFRT1CFEOuYRnViK 15 | V/jK 16 | -----END CERTIFICATE REQUEST----- 17 | -------------------------------------------------------------------------------- /tests/files/certs/server/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC5zCCAc+gAwIBAgIBATANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl 3 | c3RDQTAeFw0xNDA4MjcxOTI0MjNaFw0xNTA4MjcxOTI0MjNaMCoxFzAVBgNVBAMM 4 | Dm1icm9hZHN0LWJ1aWxkMQ8wDQYDVQQKDAZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEB 5 | AQUAA4IBDwAwggEKAoIBAQDDV2SFR4wdqcGTJjXoxufcRcg1QPBrsglR2rvQL40i 6 | oF9U9QAASwtn5c1+A5pkEdOb6xOrND/qiCW1jQgBKzi9qMnL9+61Z/Xykq5Op4qj 7 | oqf1l6DV5nyHo9DOmqMKlBUGFR1PvwRcxmtl76+ekLxRP3Z38YbJHj1FT2H/9Dno 8 | ThoImcxiSeMI1T7yBfv5SZ4TVheRIabkRcwT5FrU3P6TkVJq2PBjH4n6cNlLAMka 9 | Ias4Jnxip4Xg/kk9JXlfce45EAMlgEpp/6zSYQqvpESo/2elElP39sFBPvv7HNIh 10 | si7AKzIsFlEpsUFlcBkC1SD9jxV2xVbXZssCiX3ZM5F1AgMBAAGjLzAtMAkGA1Ud 11 | EwQCMAAwCwYDVR0PBAQDAgUgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3 12 | DQEBBQUAA4IBAQCHXuSqK4vEDNIqZxMQiFqB4zwkz5KG3uZrbhqfHaqxxjinwlNJ 13 | Sky9lAx2QN/sRDuk8M+8HZxRMsASIPzELMjjj19CduadkLFV4cj+0nP2m6K1li8y 14 | RyGQpEwQi5MG2o+iQt3Ygw07KQJYhOXaifjEFJ8Q1U00KO+e9H7iLF8GrhLzmOv3 15 | usLPIvE8dnNu+EkrC57c48g9vkzR+BWl4TA1TcJBy9r219Z4jGrIysPWJUPwhKJj 16 | tf9Uk9oHbMkuv5Qc+NhCumkB82phIt5WxeL1mKgwKVxiZJ+4DysfD7cgni8jhq86 17 | KZgEOMel6CekBa7ToLzUdvjU0SjT2DBBK6YD 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /tests/files/certs/server/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEAw1dkhUeMHanBkyY16Mbn3EXINUDwa7IJUdq70C+NIqBfVPUA 3 | AEsLZ+XNfgOaZBHTm+sTqzQ/6ogltY0IASs4vajJy/futWf18pKuTqeKo6Kn9Zeg 4 | 1eZ8h6PQzpqjCpQVBhUdT78EXMZrZe+vnpC8UT92d/GGyR49RU9h//Q56E4aCJnM 5 | YknjCNU+8gX7+UmeE1YXkSGm5EXME+Ra1Nz+k5FSatjwYx+J+nDZSwDJGiGrOCZ8 6 | YqeF4P5JPSV5X3HuORADJYBKaf+s0mEKr6REqP9npRJT9/bBQT77+xzSIbIuwCsy 7 | LBZRKbFBZXAZAtUg/Y8VdsVW12bLAol92TORdQIDAQABAoIBAFKRwEWuBoYLWW2P 8 | uz3Xxe4P+R65gmajbNkSsky/rNK0I1fP794v2nRiaMgZUct21ZGUfk3h2hqSzg29 9 | vWJxGJzimdoDxP0dIpMUeWV54FpmyMRBAZUoxf63ue164+v2yCQ4DJnGzltA6+i8 10 | tek6mL9nKfZtO2ILzC5d7bi5TTjp/SXUiKG3VAFSxgxoBC9PGlL7BNFbm9JXSket 11 | LVIWNj781pqBMEHvj9aLVG0uKpkY5jRjShHQ1a1v3l/WSDBsoVaG8xzvZSE5wd7s 12 | Fjzk53siyzapOBhTCJc8NFoA88SfYYQfxCVrhIxpDhH6rYBMi/j99DTlj+Goi6eo 13 | 7aqEkwECgYEA7YwtwqGtPbakc5Y6shmLyniDah8xaVfrK4duGBvuoZCMek+ee2DN 14 | WaeUKcSBBL0wWGVxnTm5MHleeadc92vF8eI/T7LKDnqPGfg9I9nteI43wCuRqKbz 15 | YDseZnngBWFM6QnhYJrL1mH66zTAolaW8e+4U0ZsNO/Wk3RP8FrZDFUCgYEA0oPp 16 | DIW+6i43dC9AOKxPv6lWdYOHnnh050WftR3sYfQ5FEqLln0jbio1WvaukQtPeruz 17 | WhhAYbrkSjy1286NMjkhO3FbofiUkTgpI9YSubIchbGcem9G58IfhA41mAGzrGer 18 | t65ip6f2jwOZkRM+t5/65iqQuGoCIWlnBpO3kKECgYB6mX6ElSz0TO9TOJXSlZyw 19 | QsKQYsj9tYKKVLtddg0TFadq+OyygKN7QiIV7HUqHPp2pOSeYMxTWFCKOPaiO91N 20 | mZdTatMd5eM1ZAkqF6+YKM5dQB9NC91QLTLjcMNOA4nOPGs1kK7jVm5KNk+1eTsu 21 | YqqfUBlIuP/l2oHnavvagQKBgFPIYiE0vbXwLOvVvmaP1bF/EMT2Uyxz3nsJD7YC 22 | sciObYUw4ftD1K0MqW2JjhJ2AOzk9U2fJ0h+HEube/l+bF2XtS02QXTmPSLKyjzT 23 | /2HejFF9TbzAuuSUMvzYtuXHj53HKOWSxvrY810Z3q2JjkWAq1edizmKH0zy6SkJ 24 | 813hAoGAIGMMqi8HsqsvgTQebYohwkRBG+G+JPVF6rPD/+WfglnIoo4sNWNBnh6Z 25 | e/+TkLsZR0QVnbQtStabroxxCkBkjzoDgu2Ff2mKhcFMsuNwWm/2hWHD8VLMomWi 26 | 7BK4OjVcBxOoQelmBEuwIaCiuADZBFgGEbV5yBdv8yD+ewUP/Z0= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/files/certs/server/keycert.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinsonSir/qamqp/ff81962201e4ae183e2b433e094eef1814999667/tests/files/certs/server/keycert.p12 -------------------------------------------------------------------------------- /tests/files/certs/server/req.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICbzCCAVcCAQAwKjEXMBUGA1UEAwwObWJyb2Fkc3QtYnVpbGQxDzANBgNVBAoM 3 | BnNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMNXZIVHjB2p 4 | wZMmNejG59xFyDVA8GuyCVHau9AvjSKgX1T1AABLC2flzX4DmmQR05vrE6s0P+qI 5 | JbWNCAErOL2oycv37rVn9fKSrk6niqOip/WXoNXmfIej0M6aowqUFQYVHU+/BFzG 6 | a2Xvr56QvFE/dnfxhskePUVPYf/0OehOGgiZzGJJ4wjVPvIF+/lJnhNWF5EhpuRF 7 | zBPkWtTc/pORUmrY8GMfifpw2UsAyRohqzgmfGKnheD+ST0leV9x7jkQAyWASmn/ 8 | rNJhCq+kRKj/Z6USU/f2wUE++/sc0iGyLsArMiwWUSmxQWVwGQLVIP2PFXbFVtdm 9 | ywKJfdkzkXUCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQB3B0Rve1QC6ygBlbFj 10 | jYSwmyIID3OYuF4RvXGIzCQsh8+aJYWe4dMUcqRLlr13PmWQlle5v5F3x903Y5QN 11 | IeQudApEelqJMI0QLOKALZWgX5YjF+z0AW/yhAu3QufEsERG4T5x2BJVKcrSIewl 12 | ang2Hr4isGmlXS/VVPYa0K50lv7GgHsCookOSS52/MA7r5f48EmJeC2JO0sKKKkf 13 | sMY9urBAIeGYNvXw/JuswlnfMpuUGEBoGnByc+3SecXiHGaUBn3xXSsbL+Ht8x9D 14 | Sa0gyGqelTqxhcOU0YcvorxIPb6Jbms2J8GEmeq25vMlRTlDKJV01F7PMo/1reXU 15 | KEn6 16 | -----END CERTIFICATE REQUEST----- 17 | -------------------------------------------------------------------------------- /tests/files/certs/testca/cacert.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobinsonSir/qamqp/ff81962201e4ae183e2b433e094eef1814999667/tests/files/certs/testca/cacert.cer -------------------------------------------------------------------------------- /tests/files/certs/testca/cacert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICxjCCAa6gAwIBAgIJAOZK1btq1p0yMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV 3 | BAMTCE15VGVzdENBMB4XDTE0MDgyNzE5MjI0MloXDTE1MDgyNzE5MjI0MlowEzER 4 | MA8GA1UEAxMITXlUZXN0Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB 5 | AQC/T4RhynLiTGkcgfq6TVwKVtvRy2jAOFOG7p9g4NofVTa0HvEUjNITwPUrYQDa 6 | OLSK6BtStss1aTeSDfkY9wejl1PZ02lgz2CeznOvWp/74Rz8Mjc7BGz3WFOqcfJt 7 | 6DyTj/wgE/lJXTVGXsojQtDChYwEPNSWmAXLz1nLj2Ac1B4uy5kVsBCXkhWcu4E8 8 | xEaf6mIA9KvF1MWBgHkNbZ2DruYsdlA4h95+40wn2qDkm9RgmE2MyFjV8YYjwv2s 9 | 5G48+pj7o7Vg/3/QZFuoGnU8GJ4gFFVOQQRqKOUrVFrJGduiVXxqPNjTt1rfopX4 10 | pC8GZ69NotARfrwlBflM+Dm/AgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0P 11 | BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAJxWhxMpYywwJOkB243RhD76Y9OJ0q 12 | RAboh03wrHpx5jgRZj4PxJrMdoDop/7mP9e/2UfIWVkVzKGH3ZPSrDaJ7bRooqgu 13 | nR1T8yWm+/zDoKoZGl+pdc25rr+PcWbzXOuPZTukSM01AqgGuwmiRB70HzqJpV3u 14 | IPLvkvrqUIcjpdi7ULmfB1caNzTMizviTK7b3ORG+pZUVMRmOzSkJOD1PoNXg7GQ 15 | p5FisMP7ULL0RLtOMrqwwyCslMJ+8g9pJuCqNJEeoBQsh/lmEZANWTSYTPRIbQAM 16 | cnhx6GDsER2zvDoTLLM4SXqWEXHsV5D06Z41fKXIDSgsSZVnzb6ZWxvd 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /tests/files/certs/testca/certs/01.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC5zCCAc+gAwIBAgIBATANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl 3 | c3RDQTAeFw0xNDA4MjcxOTI0MjNaFw0xNTA4MjcxOTI0MjNaMCoxFzAVBgNVBAMM 4 | Dm1icm9hZHN0LWJ1aWxkMQ8wDQYDVQQKDAZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEB 5 | AQUAA4IBDwAwggEKAoIBAQDDV2SFR4wdqcGTJjXoxufcRcg1QPBrsglR2rvQL40i 6 | oF9U9QAASwtn5c1+A5pkEdOb6xOrND/qiCW1jQgBKzi9qMnL9+61Z/Xykq5Op4qj 7 | oqf1l6DV5nyHo9DOmqMKlBUGFR1PvwRcxmtl76+ekLxRP3Z38YbJHj1FT2H/9Dno 8 | ThoImcxiSeMI1T7yBfv5SZ4TVheRIabkRcwT5FrU3P6TkVJq2PBjH4n6cNlLAMka 9 | Ias4Jnxip4Xg/kk9JXlfce45EAMlgEpp/6zSYQqvpESo/2elElP39sFBPvv7HNIh 10 | si7AKzIsFlEpsUFlcBkC1SD9jxV2xVbXZssCiX3ZM5F1AgMBAAGjLzAtMAkGA1Ud 11 | EwQCMAAwCwYDVR0PBAQDAgUgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3 12 | DQEBBQUAA4IBAQCHXuSqK4vEDNIqZxMQiFqB4zwkz5KG3uZrbhqfHaqxxjinwlNJ 13 | Sky9lAx2QN/sRDuk8M+8HZxRMsASIPzELMjjj19CduadkLFV4cj+0nP2m6K1li8y 14 | RyGQpEwQi5MG2o+iQt3Ygw07KQJYhOXaifjEFJ8Q1U00KO+e9H7iLF8GrhLzmOv3 15 | usLPIvE8dnNu+EkrC57c48g9vkzR+BWl4TA1TcJBy9r219Z4jGrIysPWJUPwhKJj 16 | tf9Uk9oHbMkuv5Qc+NhCumkB82phIt5WxeL1mKgwKVxiZJ+4DysfD7cgni8jhq86 17 | KZgEOMel6CekBa7ToLzUdvjU0SjT2DBBK6YD 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /tests/files/certs/testca/certs/02.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC5zCCAc+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl 3 | c3RDQTAeFw0xNDA4MjcxOTI2MDVaFw0xNTA4MjcxOTI2MDVaMCoxFzAVBgNVBAMM 4 | Dm1icm9hZHN0LWJ1aWxkMQ8wDQYDVQQKDAZjbGllbnQwggEiMA0GCSqGSIb3DQEB 5 | AQUAA4IBDwAwggEKAoIBAQDrzmzjgxNXxXX+fgfjB5Pt+YbO2uQR9PDADUyk+8Kw 6 | /v1xjZBqKSHaBJLMv2nHlfGM8p92XQoepWKtG4z49UsT6MMppfUnZ/TO6LgUuJtw 7 | FaVYdJmzK8SPvsQ331id9f4grgMTiff+i6hM2Bb9Jq83/jnglrBm8T4KHjPjJXQi 8 | MN8d7ZkV2bo2vFQcO/KNTODntqINp5+OFPboyjDbMoMgUTqnXJBQsWwA9EVq2JYs 9 | FYtA5xsqk0yG9DBgI5ClfxESQQo6lHKYeX2KIuHVO5awPpm+wZbIeR3l5QFqQrQZ 10 | zfw7ANsA1RK4c85jb8K0vHxX1wV3kB+2kqpi4jxm/ucnAgMBAAGjLzAtMAkGA1Ud 11 | EwQCMAAwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3 12 | DQEBBQUAA4IBAQAxoTOMViXAKveeYx7I0dve/Te3TXe6XTlF0iFNIMp0FB3X0OeA 13 | Bjknf6SUxY4qYV9DsFBGtXg8irkbothVNQKrhSedb6n+OQGy5z24oJ+vWW5jCyf3 14 | TBoWRLnHY52j/4KElNpbEddacreYY6Ft5VYLZuyXy2G18xWjUnE5EG+QkizgAWzw 15 | w9aTxS7qyGb7/FklJhH5OA8izi4JNbIrLEcUw4ECgYihtdLnZz/ANTp4kwz7qjaj 16 | X7+8V3h7R59/HOHglCbjtkhBVuRyz5ljTfMbCava4Za2solujAo4tRxvmhioog0t 17 | QplQjUP4QM5jfFlD/1HXY2SzYPG0FIiRj93L 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /tests/files/certs/testca/index.txt: -------------------------------------------------------------------------------- 1 | V 150827192423Z 01 unknown /CN=mbroadst-build/O=server 2 | V 150827192605Z 02 unknown /CN=mbroadst-build/O=client 3 | -------------------------------------------------------------------------------- /tests/files/certs/testca/index.txt.attr: -------------------------------------------------------------------------------- 1 | unique_subject = yes 2 | -------------------------------------------------------------------------------- /tests/files/certs/testca/index.txt.attr.old: -------------------------------------------------------------------------------- 1 | unique_subject = yes 2 | -------------------------------------------------------------------------------- /tests/files/certs/testca/index.txt.old: -------------------------------------------------------------------------------- 1 | V 150827192423Z 01 unknown /CN=mbroadst-build/O=server 2 | -------------------------------------------------------------------------------- /tests/files/certs/testca/openssl.cnf: -------------------------------------------------------------------------------- 1 | [ ca ] 2 | default_ca = testca 3 | 4 | [ testca ] 5 | dir = . 6 | certificate = $dir/cacert.pem 7 | database = $dir/index.txt 8 | new_certs_dir = $dir/certs 9 | private_key = $dir/private/cakey.pem 10 | serial = $dir/serial 11 | 12 | default_crl_days = 7 13 | default_days = 365 14 | default_md = sha1 15 | 16 | policy = testca_policy 17 | x509_extensions = certificate_extensions 18 | 19 | [ testca_policy ] 20 | commonName = supplied 21 | stateOrProvinceName = optional 22 | countryName = optional 23 | emailAddress = optional 24 | organizationName = optional 25 | organizationalUnitName = optional 26 | 27 | [ certificate_extensions ] 28 | basicConstraints = CA:false 29 | 30 | [ req ] 31 | default_bits = 2048 32 | default_keyfile = ./private/cakey.pem 33 | default_md = sha1 34 | prompt = yes 35 | distinguished_name = root_ca_distinguished_name 36 | x509_extensions = root_ca_extensions 37 | 38 | [ root_ca_distinguished_name ] 39 | commonName = hostname 40 | 41 | [ root_ca_extensions ] 42 | basicConstraints = CA:true 43 | keyUsage = keyCertSign, cRLSign 44 | 45 | [ client_ca_extensions ] 46 | basicConstraints = CA:false 47 | keyUsage = digitalSignature 48 | extendedKeyUsage = 1.3.6.1.5.5.7.3.2 49 | 50 | [ server_ca_extensions ] 51 | basicConstraints = CA:false 52 | keyUsage = keyEncipherment 53 | extendedKeyUsage = 1.3.6.1.5.5.7.3.1 -------------------------------------------------------------------------------- /tests/files/certs/testca/private/cakey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/T4RhynLiTGkc 3 | gfq6TVwKVtvRy2jAOFOG7p9g4NofVTa0HvEUjNITwPUrYQDaOLSK6BtStss1aTeS 4 | DfkY9wejl1PZ02lgz2CeznOvWp/74Rz8Mjc7BGz3WFOqcfJt6DyTj/wgE/lJXTVG 5 | XsojQtDChYwEPNSWmAXLz1nLj2Ac1B4uy5kVsBCXkhWcu4E8xEaf6mIA9KvF1MWB 6 | gHkNbZ2DruYsdlA4h95+40wn2qDkm9RgmE2MyFjV8YYjwv2s5G48+pj7o7Vg/3/Q 7 | ZFuoGnU8GJ4gFFVOQQRqKOUrVFrJGduiVXxqPNjTt1rfopX4pC8GZ69NotARfrwl 8 | BflM+Dm/AgMBAAECggEAUGYEhmxkN4JRMi/VxPG52oaCPvqy/QUu5SfnRvl38W8I 9 | XE4clrxPlQmkfyR3DT6DcVT2Fp7Ha5zaQ8EnjDxUs4VnMcXNJWhBfLvaljkJvvru 10 | CXa5C05i1NgD4T+d2F6fBoyeMoTyYMiRGQ/A92ye+wDQxP8jgF5HIU30uL16cOJh 11 | /Znu6JJBjYgE9g7ce8REEpi2Fru2Ixj147ge1ICW801i0Xy5susCJvH3I817GKoq 12 | NonAn5P+5zTv9mECDnNkhRViATigrQ8DYikNewPknrmfb0IMAvF8dTnCWI4KuorD 13 | c4TD7w/zzrpncWNCnsDgWfgq9u9Anp6bvhED0VLiMQKBgQDgewv8skGmm4xAUKdR 14 | BsDYIUgip57qj4EmPkjypn8lzVjDUnbBhr/NAUQK5pKnrzFE2H9/H7M1zlNwk1FS 15 | m6GYjx4DmnGAvQ0LCBs4gxlT878n7TYTxkTge69tYQ0lmmAGGajmv2G4TtVADMlG 16 | rojrQIYoSggVkUI+AyGhHhm8xQKBgQDaLCyBUSWPOMc33AozWMm2OYJ4nFWd1A0C 17 | SLgpR6/+D8mT3o6YRYIMmh6AUFCENAKitbKujQOaKRll5aaNWO4JohhgcuzGEj5C 18 | 4F++7SXd6E/1+gtExnOHkPJ9z3FIeSoGCDK3DmfE8H9fcMM5mFZG7OVna3arINv4 19 | nT8s3aAMswKBgQDDM5yn3+Zg17AtGTV1qxa0mrRclkAFnkZjGBRdFNVJ7Pf72VC1 20 | VtSgkzI0/G2Y7So9wLmVtN4ksscyBJjZ6cWqoQErhvieR0b5SdJJ4Q58R1/5ezfk 21 | GCw6vLM+vP8urMBFbbjG9rMmDz83FCdOlGUxlQlULZQ8FPVycUykC0W8NQKBgEjA 22 | fj7JLnsp9dS8vXIN44Wue8F4cFxm/8eJNFAfpaJU5WU3y9kfJJTLN+yV26OaLF7R 23 | tDncsBzSI7QE9psf0pDHytUuvaH3J2fppkPmlMAA3dkqfmN6wb+tKA+oAyCltsu4 24 | JCFC3nufrvnGgnNMR0jzajQoc7PxCylGVnDBnsNdAoGAV62Nc+T6HdZa9yDSPU5p 25 | bNT40q0iZHmTUa6QQl+ZsRZP8u4w+RnfcUOK+QKJr43DraJgjWtwbO2VnCIMTA21 26 | EsSGuOCEMuYLMkswOrAJfM80FalsF3I74s5TbGYaczXXOe54XZJ8tyWSP0IiwreO 27 | +eejI2bW3rU9TfBDdpR5Ks8= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/files/certs/testca/serial: -------------------------------------------------------------------------------- 1 | 03 2 | -------------------------------------------------------------------------------- /tests/files/certs/testca/serial.old: -------------------------------------------------------------------------------- 1 | 02 2 | -------------------------------------------------------------------------------- /tests/files/travis/rabbitmq-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "[ 4 | {rabbit, [ 5 | {ssl_listeners, [5671]}, 6 | {ssl_options, [{cacertfile,'${TRAVIS_BUILD_DIR}/tests/files/certs/testca/cacert.pem'}, 7 | {certfile,'${TRAVIS_BUILD_DIR}/tests/files/certs/server/cert.pem'}, 8 | {keyfile, '${TRAVIS_BUILD_DIR}/tests/files/certs/server/key.pem'}, 9 | {verify,verify_peer}, 10 | {fail_if_no_peer_cert,false}]} 11 | ]} 12 | ]." >> rabbitmq.config 13 | 14 | sudo CONFIG_FILE=$PWD RABBITMQ_NODENAME=test-rabbitmq rabbitmq-server -detached 15 | -------------------------------------------------------------------------------- /tests/files/travis/test-deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "$QT_SELECT" = "qt4" ]; then 4 | sudo apt-get update 5 | sudo apt-get install libqt4-dev 6 | else 7 | sudo add-apt-repository -y ppa:canonical-qt5-edgers/ubuntu1204-qt5 8 | sudo apt-get update 9 | sudo apt-get install qtbase5-dev 10 | fi -------------------------------------------------------------------------------- /tests/gen-coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | lcov --capture --directory . --output-file coverage-gcov.info --no-external 3 | lcov --output-file coverage-gcov.info --remove coverage-gcov.info 'moc_*.cpp' '*.moc*' '.*rcc*' '*3rdparty*' 4 | genhtml coverage-gcov.info --output-directory doc/coverage 5 | -------------------------------------------------------------------------------- /tests/tests.pri: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += $${QAMQP_INCLUDEPATH} $${PWD}/common 2 | LIBS += -L$${DEPTH}/src $${QAMQP_LIBS} 3 | 4 | unix:!macx:QMAKE_RPATHDIR += $${OUT_PWD}/$${DEPTH}/src 5 | macx { 6 | QMAKE_RPATHDIR += @loader_path/$${DEPTH}/src 7 | QMAKE_LFLAGS += -Wl,-rpath,@loader_path/$${DEPTH}/src 8 | } 9 | 10 | QT = core network testlib 11 | QT -= gui 12 | CONFIG -= app_bundle 13 | CONFIG += testcase no_testcase_installs 14 | 15 | HEADERS += \ 16 | $${PWD}/common/signalspy.h \ 17 | $${PWD}/common/qamqptestcase.h 18 | -------------------------------------------------------------------------------- /tests/tests.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS = \ 3 | auto 4 | -------------------------------------------------------------------------------- /tutorials/helloworld/helloworld.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS = \ 3 | send \ 4 | receive 5 | -------------------------------------------------------------------------------- /tutorials/helloworld/receive/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "qamqpclient.h" 5 | #include "qamqpexchange.h" 6 | #include "qamqpqueue.h" 7 | 8 | class Receiver : public QObject 9 | { 10 | Q_OBJECT 11 | public: 12 | Receiver(QObject *parent = 0) : QObject(parent) { 13 | m_client.setAutoReconnect(true); 14 | } 15 | 16 | public Q_SLOTS: 17 | void start() { 18 | connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected())); 19 | m_client.connectToHost(); 20 | } 21 | 22 | private Q_SLOTS: 23 | void clientConnected() { 24 | QAmqpQueue *queue = m_client.createQueue("hello"); 25 | disconnect(queue, 0, 0, 0); // in case this is a reconnect 26 | connect(queue, SIGNAL(declared()), this, SLOT(queueDeclared())); 27 | queue->declare(); 28 | } 29 | 30 | void queueDeclared() { 31 | QAmqpQueue *queue = qobject_cast(sender()); 32 | if (!queue) 33 | return; 34 | 35 | connect(queue, SIGNAL(messageReceived()), this, SLOT(messageReceived())); 36 | queue->consume(QAmqpQueue::coNoAck); 37 | qDebug() << " [*] Waiting for messages. To exit press CTRL+C"; 38 | } 39 | 40 | void messageReceived() { 41 | QAmqpQueue *queue = qobject_cast(sender()); 42 | if (!queue) 43 | return; 44 | 45 | QAmqpMessage message = queue->dequeue(); 46 | qDebug() << " [x] Received " << message.payload(); 47 | } 48 | 49 | private: 50 | QAmqpClient m_client; 51 | 52 | }; 53 | 54 | int main(int argc, char **argv) 55 | { 56 | QCoreApplication app(argc, argv); 57 | Receiver receiver; 58 | receiver.start(); 59 | return app.exec(); 60 | } 61 | 62 | #include "main.moc" 63 | -------------------------------------------------------------------------------- /tutorials/helloworld/receive/receive.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | 4 | TEMPLATE = app 5 | INCLUDEPATH += $${QAMQP_INCLUDEPATH} 6 | LIBS += -L$${DEPTH}/src $${QAMQP_LIBS} 7 | macx:CONFIG -= app_bundle 8 | 9 | SOURCES += main.cpp 10 | -------------------------------------------------------------------------------- /tutorials/helloworld/send/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "qamqpclient.h" 6 | #include "qamqpexchange.h" 7 | #include "qamqpqueue.h" 8 | 9 | class Sender : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | Sender(QObject *parent = 0) : QObject(parent) {} 14 | 15 | public Q_SLOTS: 16 | void start() { 17 | connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected())); 18 | connect(&m_client, SIGNAL(disconnected()), qApp, SLOT(quit())); 19 | m_client.connectToHost(); 20 | } 21 | 22 | private Q_SLOTS: 23 | void clientConnected() { 24 | QAmqpQueue *queue = m_client.createQueue("hello"); 25 | connect(queue, SIGNAL(declared()), this, SLOT(queueDeclared())); 26 | queue->declare(); 27 | } 28 | 29 | void queueDeclared() { 30 | QAmqpQueue *queue = qobject_cast(sender()); 31 | if (!queue) 32 | return; 33 | QAmqpExchange *defaultExchange = m_client.createExchange(); 34 | defaultExchange->publish("Hello World!", "hello"); 35 | qDebug() << " [x] Sent 'Hello World!'"; 36 | m_client.disconnectFromHost(); 37 | } 38 | 39 | private: 40 | QAmqpClient m_client; 41 | 42 | }; 43 | 44 | int main(int argc, char **argv) 45 | { 46 | QCoreApplication app(argc, argv); 47 | Sender sender; 48 | sender.start(); 49 | return app.exec(); 50 | } 51 | 52 | #include "main.moc" 53 | -------------------------------------------------------------------------------- /tutorials/helloworld/send/send.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | 4 | TEMPLATE = app 5 | INCLUDEPATH += $${QAMQP_INCLUDEPATH} 6 | LIBS += -L$${DEPTH}/src $${QAMQP_LIBS} 7 | macx:CONFIG -= app_bundle 8 | 9 | SOURCES += main.cpp 10 | -------------------------------------------------------------------------------- /tutorials/pubsub/emit_log/emit_log.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | 4 | TEMPLATE = app 5 | INCLUDEPATH += $${QAMQP_INCLUDEPATH} 6 | LIBS += -L$${DEPTH}/src $${QAMQP_LIBS} 7 | macx:CONFIG -= app_bundle 8 | 9 | SOURCES += main.cpp 10 | -------------------------------------------------------------------------------- /tutorials/pubsub/emit_log/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "qamqpclient.h" 6 | #include "qamqpexchange.h" 7 | #include "qamqpqueue.h" 8 | 9 | class LogEmitter : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | LogEmitter(QObject *parent = 0) : QObject(parent) {} 14 | 15 | public Q_SLOTS: 16 | void start() { 17 | connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected())); 18 | connect(&m_client, SIGNAL(disconnected()), qApp, SLOT(quit())); 19 | m_client.connectToHost(); 20 | } 21 | 22 | private Q_SLOTS: 23 | void clientConnected() { 24 | QAmqpExchange *exchange = m_client.createExchange("logs"); 25 | connect(exchange, SIGNAL(declared()), this, SLOT(exchangeDeclared())); 26 | exchange->declare(QAmqpExchange::FanOut); 27 | } 28 | 29 | void exchangeDeclared() { 30 | QAmqpExchange *exchange = qobject_cast(sender()); 31 | if (!exchange) 32 | return; 33 | 34 | QString message; 35 | if (qApp->arguments().size() < 2) 36 | message = "info: Hello World!"; 37 | else 38 | message = qApp->arguments().at(1); 39 | exchange->publish(message, ""); 40 | qDebug() << " [x] Sent " << message; 41 | m_client.disconnectFromHost(); 42 | } 43 | 44 | private: 45 | QAmqpClient m_client; 46 | 47 | }; 48 | 49 | int main(int argc, char **argv) 50 | { 51 | QCoreApplication app(argc, argv); 52 | LogEmitter logEmitter; 53 | logEmitter.start(); 54 | return app.exec(); 55 | } 56 | 57 | #include "main.moc" 58 | -------------------------------------------------------------------------------- /tutorials/pubsub/pubsub.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS = \ 3 | receive_logs \ 4 | emit_log 5 | -------------------------------------------------------------------------------- /tutorials/pubsub/receive_logs/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "qamqpclient.h" 6 | #include "qamqpexchange.h" 7 | #include "qamqpqueue.h" 8 | 9 | class LogReceiver : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | LogReceiver(QObject *parent = 0) : QObject(parent) {} 14 | 15 | public Q_SLOTS: 16 | void start() { 17 | connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected())); 18 | m_client.connectToHost(); 19 | } 20 | 21 | private Q_SLOTS: 22 | void clientConnected() { 23 | QAmqpExchange *exchange = m_client.createExchange("logs"); 24 | connect(exchange, SIGNAL(declared()), this, SLOT(exchangeDeclared())); 25 | exchange->declare(QAmqpExchange::FanOut); 26 | } 27 | 28 | void exchangeDeclared() { 29 | QAmqpQueue *temporaryQueue = m_client.createQueue(); 30 | connect(temporaryQueue, SIGNAL(declared()), this, SLOT(queueDeclared())); 31 | connect(temporaryQueue, SIGNAL(bound()), this, SLOT(queueBound())); 32 | connect(temporaryQueue, SIGNAL(messageReceived()), this, SLOT(messageReceived())); 33 | temporaryQueue->declare(QAmqpQueue::Exclusive); 34 | } 35 | 36 | void queueDeclared() { 37 | QAmqpQueue *temporaryQueue = qobject_cast(sender()); 38 | if (!temporaryQueue) 39 | return; 40 | 41 | temporaryQueue->bind("logs", temporaryQueue->name()); 42 | } 43 | 44 | void queueBound() { 45 | QAmqpQueue *temporaryQueue = qobject_cast(sender()); 46 | if (!temporaryQueue) 47 | return; 48 | 49 | qDebug() << " [*] Waiting for logs. To exit press CTRL+C"; 50 | temporaryQueue->consume(QAmqpQueue::coNoAck); 51 | } 52 | 53 | void messageReceived() { 54 | QAmqpQueue *temporaryQueue = qobject_cast(sender()); 55 | if (!temporaryQueue) 56 | return; 57 | 58 | QAmqpMessage message = temporaryQueue->dequeue(); 59 | qDebug() << " [x] " << message.payload(); 60 | } 61 | 62 | private: 63 | QAmqpClient m_client; 64 | 65 | }; 66 | 67 | int main(int argc, char **argv) 68 | { 69 | QCoreApplication app(argc, argv); 70 | LogReceiver logReceiver; 71 | logReceiver.start(); 72 | return app.exec(); 73 | } 74 | 75 | #include "main.moc" 76 | -------------------------------------------------------------------------------- /tutorials/pubsub/receive_logs/receive_logs.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | 4 | TEMPLATE = app 5 | INCLUDEPATH += $${QAMQP_INCLUDEPATH} 6 | LIBS += -L$${DEPTH}/src $${QAMQP_LIBS} 7 | macx:CONFIG -= app_bundle 8 | 9 | SOURCES += main.cpp 10 | -------------------------------------------------------------------------------- /tutorials/routing/emit_log_direct/emit_log_direct.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | 4 | TEMPLATE = app 5 | INCLUDEPATH += $${QAMQP_INCLUDEPATH} 6 | LIBS += -L$${DEPTH}/src $${QAMQP_LIBS} 7 | macx:CONFIG -= app_bundle 8 | 9 | SOURCES += main.cpp 10 | -------------------------------------------------------------------------------- /tutorials/routing/emit_log_direct/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "qamqpclient.h" 6 | #include "qamqpexchange.h" 7 | #include "qamqpqueue.h" 8 | 9 | class DirectLogEmitter : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | DirectLogEmitter(QObject *parent = 0) : QObject(parent) {} 14 | 15 | public Q_SLOTS: 16 | void start() { 17 | connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected())); 18 | connect(&m_client, SIGNAL(disconnected()), qApp, SLOT(quit())); 19 | m_client.connectToHost(); 20 | } 21 | 22 | private Q_SLOTS: 23 | void clientConnected() { 24 | QAmqpExchange *direct_logs = m_client.createExchange("direct_logs"); 25 | connect(direct_logs, SIGNAL(declared()), this, SLOT(exchangeDeclared())); 26 | direct_logs->declare(QAmqpExchange::Direct); 27 | } 28 | 29 | void exchangeDeclared() { 30 | QAmqpExchange *direct_logs = qobject_cast(sender()); 31 | if (!direct_logs) 32 | return; 33 | 34 | QStringList args = qApp->arguments(); 35 | args.takeFirst(); // remove executable name 36 | 37 | QString severity = (args.isEmpty() ? "info" : args.first()); 38 | QString message; 39 | if (args.size() > 1) { 40 | args.takeFirst(); 41 | message = args.join(" "); 42 | } else { 43 | message = "Hello World!"; 44 | } 45 | 46 | direct_logs->publish(message, severity); 47 | qDebug(" [x] Sent %s:%s", severity.toLatin1().constData(), message.toLatin1().constData()); 48 | m_client.disconnectFromHost(); 49 | } 50 | 51 | private: 52 | QAmqpClient m_client; 53 | 54 | }; 55 | 56 | int main(int argc, char **argv) 57 | { 58 | QCoreApplication app(argc, argv); 59 | DirectLogEmitter logEmitter; 60 | logEmitter.start(); 61 | return app.exec(); 62 | } 63 | 64 | #include "main.moc" 65 | -------------------------------------------------------------------------------- /tutorials/routing/receive_logs_direct/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "qamqpclient.h" 6 | #include "qamqpexchange.h" 7 | #include "qamqpqueue.h" 8 | 9 | class DirectLogReceiver : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | DirectLogReceiver(QObject *parent = 0) : QObject(parent) {} 14 | 15 | public Q_SLOTS: 16 | void start(const QStringList &severities) { 17 | m_severities = severities; 18 | connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected())); 19 | m_client.connectToHost(); 20 | } 21 | 22 | private Q_SLOTS: 23 | void clientConnected() { 24 | QAmqpExchange *exchange = m_client.createExchange("direct_logs"); 25 | connect(exchange, SIGNAL(declared()), this, SLOT(exchangeDeclared())); 26 | exchange->declare(QAmqpExchange::Direct); 27 | } 28 | 29 | void exchangeDeclared() { 30 | QAmqpQueue *temporaryQueue = m_client.createQueue(); 31 | connect(temporaryQueue, SIGNAL(declared()), this, SLOT(queueDeclared())); 32 | connect(temporaryQueue, SIGNAL(messageReceived()), this, SLOT(messageReceived())); 33 | temporaryQueue->declare(QAmqpQueue::Exclusive); 34 | } 35 | 36 | void queueDeclared() { 37 | QAmqpQueue *temporaryQueue = qobject_cast(sender()); 38 | if (!temporaryQueue) 39 | return; 40 | 41 | // start consuming 42 | temporaryQueue->consume(QAmqpQueue::coNoAck); 43 | 44 | foreach (QString severity, m_severities) 45 | temporaryQueue->bind("direct_logs", severity); 46 | qDebug() << " [*] Waiting for logs. To exit press CTRL+C"; 47 | } 48 | 49 | void messageReceived() { 50 | QAmqpQueue *temporaryQueue = qobject_cast(sender()); 51 | if (!temporaryQueue) 52 | return; 53 | 54 | QAmqpMessage message = temporaryQueue->dequeue(); 55 | qDebug() << " [x] " << message.routingKey() << ":" << message.payload(); 56 | } 57 | 58 | private: 59 | QAmqpClient m_client; 60 | QStringList m_severities; 61 | 62 | }; 63 | 64 | int main(int argc, char **argv) 65 | { 66 | QCoreApplication app(argc, argv); 67 | QStringList severities = app.arguments().mid(1); 68 | if (severities.isEmpty()) { 69 | qDebug("usage: %s [info] [warning] [error]", argv[0]); 70 | return 1; 71 | } 72 | 73 | DirectLogReceiver logReceiver; 74 | logReceiver.start(severities); 75 | return app.exec(); 76 | } 77 | 78 | #include "main.moc" 79 | -------------------------------------------------------------------------------- /tutorials/routing/receive_logs_direct/receive_logs_direct.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | 4 | TEMPLATE = app 5 | INCLUDEPATH += $${QAMQP_INCLUDEPATH} 6 | LIBS += -L$${DEPTH}/src $${QAMQP_LIBS} 7 | macx:CONFIG -= app_bundle 8 | 9 | SOURCES += main.cpp 10 | -------------------------------------------------------------------------------- /tutorials/routing/routing.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS = \ 3 | emit_log_direct \ 4 | receive_logs_direct 5 | -------------------------------------------------------------------------------- /tutorials/rpc/rpc.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS = \ 3 | rpc_server \ 4 | rpc_client 5 | -------------------------------------------------------------------------------- /tutorials/rpc/rpc_client/fibonaccirpcclient.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "qamqpclient.h" 6 | #include "qamqpexchange.h" 7 | #include "qamqpqueue.h" 8 | 9 | #include "fibonaccirpcclient.h" 10 | 11 | FibonacciRpcClient::FibonacciRpcClient(QObject *parent) 12 | : QObject(parent), 13 | m_client(0), 14 | m_responseQueue(0), 15 | m_defaultExchange(0) 16 | { 17 | m_client = new QAmqpClient(this); 18 | connect(m_client, SIGNAL(connected()), this, SLOT(clientConnected())); 19 | } 20 | 21 | FibonacciRpcClient::~FibonacciRpcClient() 22 | { 23 | } 24 | 25 | bool FibonacciRpcClient::connectToServer() 26 | { 27 | QEventLoop loop; 28 | connect(this, SIGNAL(connected()), &loop, SLOT(quit())); 29 | m_client->connectToHost(); 30 | loop.exec(); 31 | 32 | return m_client->isConnected(); 33 | } 34 | 35 | void FibonacciRpcClient::call(int number) 36 | { 37 | qDebug() << " [x] Requesting fib(" << number << ")"; 38 | m_correlationId = QUuid::createUuid().toString(); 39 | QAmqpMessage::PropertyHash properties; 40 | properties.insert(QAmqpMessage::ReplyTo, m_responseQueue->name()); 41 | properties.insert(QAmqpMessage::CorrelationId, m_correlationId); 42 | 43 | m_defaultExchange->publish(QByteArray::number(number), "rpc_queue", properties); 44 | } 45 | 46 | void FibonacciRpcClient::clientConnected() 47 | { 48 | m_responseQueue = m_client->createQueue(); 49 | connect(m_responseQueue, SIGNAL(declared()), this, SLOT(queueDeclared())); 50 | connect(m_responseQueue, SIGNAL(messageReceived()), this, SLOT(responseReceived())); 51 | m_responseQueue->declare(QAmqpQueue::Exclusive | QAmqpQueue::AutoDelete); 52 | m_defaultExchange = m_client->createExchange(); 53 | } 54 | 55 | void FibonacciRpcClient::queueDeclared() 56 | { 57 | m_responseQueue->consume(); 58 | Q_EMIT connected(); 59 | } 60 | 61 | void FibonacciRpcClient::responseReceived() 62 | { 63 | QAmqpMessage message = m_responseQueue->dequeue(); 64 | if (message.property(QAmqpMessage::CorrelationId).toString() != m_correlationId) { 65 | // requeue message, it wasn't meant for us 66 | m_responseQueue->reject(message, true); 67 | return; 68 | } 69 | 70 | qDebug() << " [.] Got " << message.payload(); 71 | qApp->quit(); 72 | } 73 | -------------------------------------------------------------------------------- /tutorials/rpc/rpc_client/fibonaccirpcclient.h: -------------------------------------------------------------------------------- 1 | #ifndef FIBONACCIRPCCLIENT_H 2 | #define FIBONACCIRPCCLIENT_H 3 | 4 | #include 5 | 6 | class QAmqpQueue; 7 | class QAmqpExchange; 8 | class QAmqpClient; 9 | class FibonacciRpcClient : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | explicit FibonacciRpcClient(QObject *parent = 0); 14 | ~FibonacciRpcClient(); 15 | 16 | Q_SIGNALS: 17 | void connected(); 18 | 19 | public Q_SLOTS: 20 | bool connectToServer(); 21 | void call(int number); 22 | 23 | private Q_SLOTS: 24 | void clientConnected(); 25 | void queueDeclared(); 26 | void responseReceived(); 27 | 28 | private: 29 | QAmqpClient *m_client; 30 | QAmqpQueue *m_responseQueue; 31 | QAmqpExchange *m_defaultExchange; 32 | QString m_correlationId; 33 | 34 | }; 35 | 36 | #endif // FIBONACCIRPCCLIENT_H 37 | -------------------------------------------------------------------------------- /tutorials/rpc/rpc_client/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fibonaccirpcclient.h" 3 | 4 | int main(int argc, char **argv) 5 | { 6 | QCoreApplication app(argc, argv); 7 | FibonacciRpcClient client; 8 | if (!client.connectToServer()) 9 | return EXIT_FAILURE; 10 | 11 | client.call(30); 12 | return app.exec(); 13 | } 14 | -------------------------------------------------------------------------------- /tutorials/rpc/rpc_client/rpc_client.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | 4 | TEMPLATE = app 5 | INCLUDEPATH += $${QAMQP_INCLUDEPATH} 6 | LIBS += -L$${DEPTH}/src $${QAMQP_LIBS} 7 | macx:CONFIG -= app_bundle 8 | 9 | HEADERS += \ 10 | fibonaccirpcclient.h 11 | SOURCES += \ 12 | fibonaccirpcclient.cpp \ 13 | main.cpp 14 | -------------------------------------------------------------------------------- /tutorials/rpc/rpc_server/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "server.h" 3 | 4 | int main(int argc, char **argv) 5 | { 6 | QCoreApplication app(argc, argv); 7 | Server server; 8 | server.listen(); 9 | return app.exec(); 10 | } 11 | -------------------------------------------------------------------------------- /tutorials/rpc/rpc_server/rpc_server.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | 4 | TEMPLATE = app 5 | INCLUDEPATH += $${QAMQP_INCLUDEPATH} 6 | LIBS += -L$${DEPTH}/src $${QAMQP_LIBS} 7 | macx:CONFIG -= app_bundle 8 | 9 | HEADERS += \ 10 | server.h 11 | SOURCES += \ 12 | server.cpp \ 13 | main.cpp 14 | -------------------------------------------------------------------------------- /tutorials/rpc/rpc_server/server.cpp: -------------------------------------------------------------------------------- 1 | #include "qamqpclient.h" 2 | #include "qamqpqueue.h" 3 | #include "qamqpexchange.h" 4 | 5 | #include "server.h" 6 | 7 | Server::Server(QObject *parent) 8 | : QObject(parent), 9 | m_client(0), 10 | m_rpcQueue(0), 11 | m_defaultExchange(0) 12 | { 13 | m_client = new QAmqpClient(this); 14 | connect(m_client, SIGNAL(connected()), this, SLOT(clientConnected())); 15 | } 16 | 17 | Server::~Server() 18 | { 19 | } 20 | 21 | void Server::listen() 22 | { 23 | m_client->connectToHost(); 24 | } 25 | 26 | int Server::fib(int n) 27 | { 28 | if (n == 0) 29 | return 0; 30 | 31 | if (n == 1) 32 | return 1; 33 | 34 | return fib(n - 1) + fib(n - 2); 35 | } 36 | 37 | void Server::clientConnected() 38 | { 39 | m_rpcQueue = m_client->createQueue("rpc_queue"); 40 | connect(m_rpcQueue, SIGNAL(declared()), this, SLOT(queueDeclared())); 41 | connect(m_rpcQueue, SIGNAL(qosDefined()), this, SLOT(qosDefined())); 42 | connect(m_rpcQueue, SIGNAL(messageReceived()), this, SLOT(processRpcMessage())); 43 | m_rpcQueue->declare(); 44 | 45 | m_defaultExchange = m_client->createExchange(); 46 | } 47 | 48 | void Server::queueDeclared() 49 | { 50 | m_rpcQueue->qos(1); 51 | } 52 | 53 | void Server::qosDefined() 54 | { 55 | m_rpcQueue->consume(); 56 | qDebug() << " [x] Awaiting RPC requests"; 57 | } 58 | 59 | void Server::processRpcMessage() 60 | { 61 | QAmqpMessage rpcMessage = m_rpcQueue->dequeue(); 62 | int n = rpcMessage.payload().toInt(); 63 | 64 | int response = fib(n); 65 | m_rpcQueue->ack(rpcMessage); 66 | 67 | QString replyTo = rpcMessage.property(QAmqpMessage::ReplyTo).toString(); 68 | QAmqpMessage::PropertyHash properties; 69 | properties.insert(QAmqpMessage::CorrelationId, rpcMessage.property(QAmqpMessage::CorrelationId)); 70 | m_defaultExchange->publish(QByteArray::number(response), replyTo, properties); 71 | } 72 | -------------------------------------------------------------------------------- /tutorials/rpc/rpc_server/server.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVER_H 2 | #define SERVER_H 3 | 4 | #include 5 | 6 | class QAmqpQueue; 7 | class QAmqpExchange; 8 | class QAmqpClient; 9 | class Server : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | explicit Server(QObject *parent = 0); 14 | ~Server(); 15 | 16 | public Q_SLOTS: 17 | void listen(); 18 | int fib(int n); 19 | 20 | private Q_SLOTS: 21 | void clientConnected(); 22 | void queueDeclared(); 23 | void qosDefined(); 24 | void processRpcMessage(); 25 | 26 | private: 27 | QAmqpClient *m_client; 28 | QAmqpQueue *m_rpcQueue; 29 | QAmqpExchange *m_defaultExchange; 30 | 31 | }; 32 | 33 | #endif // SERVER_H 34 | -------------------------------------------------------------------------------- /tutorials/topics/emit_log_topic/emit_log_topic.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | 4 | TEMPLATE = app 5 | INCLUDEPATH += $${QAMQP_INCLUDEPATH} 6 | LIBS += -L$${DEPTH}/src $${QAMQP_LIBS} 7 | macx:CONFIG -= app_bundle 8 | 9 | SOURCES += main.cpp 10 | -------------------------------------------------------------------------------- /tutorials/topics/emit_log_topic/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "qamqpclient.h" 6 | #include "qamqpexchange.h" 7 | #include "qamqpqueue.h" 8 | 9 | class TopicLogEmitter : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | TopicLogEmitter(QObject *parent = 0) : QObject(parent) {} 14 | 15 | public Q_SLOTS: 16 | void start() { 17 | connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected())); 18 | connect(&m_client, SIGNAL(disconnected()), qApp, SLOT(quit())); 19 | m_client.connectToHost(); 20 | } 21 | 22 | private Q_SLOTS: 23 | void clientConnected() { 24 | QAmqpExchange *topic_logs = m_client.createExchange("topic_logs"); 25 | connect(topic_logs, SIGNAL(declared()), this, SLOT(exchangeDeclared())); 26 | topic_logs->declare(QAmqpExchange::Topic); 27 | } 28 | 29 | void exchangeDeclared() { 30 | QAmqpExchange *topic_logs = qobject_cast(sender()); 31 | if (!topic_logs) 32 | return; 33 | 34 | QStringList args = qApp->arguments(); 35 | args.takeFirst(); // remove executable name 36 | 37 | QString routingKey = (args.isEmpty() ? "anonymous.info" : args.first()); 38 | QString message; 39 | if (args.size() > 1) { 40 | args.takeFirst(); 41 | message = args.join(" "); 42 | } else { 43 | message = "Hello World!"; 44 | } 45 | 46 | topic_logs->publish(message, routingKey); 47 | qDebug(" [x] Sent %s:%s", routingKey.toLatin1().constData(), message.toLatin1().constData()); 48 | m_client.disconnectFromHost(); 49 | } 50 | 51 | private: 52 | QAmqpClient m_client; 53 | 54 | }; 55 | 56 | int main(int argc, char **argv) 57 | { 58 | QCoreApplication app(argc, argv); 59 | TopicLogEmitter logEmitter; 60 | logEmitter.start(); 61 | return app.exec(); 62 | } 63 | 64 | #include "main.moc" 65 | -------------------------------------------------------------------------------- /tutorials/topics/receive_logs_topic/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "qamqpclient.h" 6 | #include "qamqpexchange.h" 7 | #include "qamqpqueue.h" 8 | 9 | class TopicLogReceiver : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | TopicLogReceiver(QObject *parent = 0) : QObject(parent) {} 14 | 15 | public Q_SLOTS: 16 | void start(const QStringList &bindingKeys) { 17 | m_bindingKeys = bindingKeys; 18 | connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected())); 19 | m_client.connectToHost(); 20 | } 21 | 22 | private Q_SLOTS: 23 | void clientConnected() { 24 | QAmqpExchange *topic_logs = m_client.createExchange("topic_logs"); 25 | connect(topic_logs, SIGNAL(declared()), this, SLOT(exchangeDeclared())); 26 | topic_logs->declare(QAmqpExchange::Topic); 27 | } 28 | 29 | void exchangeDeclared() { 30 | QAmqpQueue *temporaryQueue = m_client.createQueue(); 31 | connect(temporaryQueue, SIGNAL(declared()), this, SLOT(queueDeclared())); 32 | connect(temporaryQueue, SIGNAL(bound()), this, SLOT(queueBound())); 33 | connect(temporaryQueue, SIGNAL(messageReceived()), this, SLOT(messageReceived())); 34 | temporaryQueue->declare(QAmqpQueue::Exclusive); 35 | } 36 | 37 | void queueDeclared() { 38 | QAmqpQueue *temporaryQueue = qobject_cast(sender()); 39 | if (!temporaryQueue) 40 | return; 41 | 42 | foreach (QString bindingKey, m_bindingKeys) 43 | temporaryQueue->bind("topic_logs", bindingKey); 44 | qDebug() << " [*] Waiting for logs. To exit press CTRL+C"; 45 | } 46 | 47 | void queueBound() { 48 | QAmqpQueue *temporaryQueue = qobject_cast(sender()); 49 | if (!temporaryQueue) 50 | return; 51 | temporaryQueue->consume(QAmqpQueue::coNoAck); 52 | } 53 | 54 | void messageReceived() { 55 | QAmqpQueue *temporaryQueue = qobject_cast(sender()); 56 | if (!temporaryQueue) 57 | return; 58 | 59 | QAmqpMessage message = temporaryQueue->dequeue(); 60 | qDebug() << " [x] " << message.routingKey() << ":" << message.payload(); 61 | } 62 | 63 | private: 64 | QAmqpClient m_client; 65 | QStringList m_bindingKeys; 66 | 67 | }; 68 | 69 | int main(int argc, char **argv) 70 | { 71 | QCoreApplication app(argc, argv); 72 | QStringList bindingKeys = app.arguments().mid(1); 73 | if (bindingKeys.isEmpty()) { 74 | qDebug("usage: %s [binding_key] ...", argv[0]); 75 | return 1; 76 | } 77 | 78 | TopicLogReceiver logReceiver; 79 | logReceiver.start(bindingKeys); 80 | return app.exec(); 81 | } 82 | 83 | #include "main.moc" 84 | -------------------------------------------------------------------------------- /tutorials/topics/receive_logs_topic/receive_logs_topic.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | 4 | TEMPLATE = app 5 | INCLUDEPATH += $${QAMQP_INCLUDEPATH} 6 | LIBS += -L$${DEPTH}/src $${QAMQP_LIBS} 7 | macx:CONFIG -= app_bundle 8 | 9 | SOURCES += main.cpp 10 | -------------------------------------------------------------------------------- /tutorials/topics/topics.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS = \ 3 | emit_log_topic \ 4 | receive_logs_topic 5 | -------------------------------------------------------------------------------- /tutorials/tutorials.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS = \ 3 | helloworld \ 4 | workqueues \ 5 | pubsub \ 6 | routing \ 7 | topics \ 8 | rpc 9 | -------------------------------------------------------------------------------- /tutorials/workqueues/new_task/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "qamqpclient.h" 6 | #include "qamqpexchange.h" 7 | #include "qamqpqueue.h" 8 | 9 | class TaskCreator : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | TaskCreator(QObject *parent = 0) : QObject(parent) {} 14 | 15 | public Q_SLOTS: 16 | void start() { 17 | connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected())); 18 | connect(&m_client, SIGNAL(disconnected()), qApp, SLOT(quit())); 19 | m_client.connectToHost(); 20 | } 21 | 22 | private Q_SLOTS: 23 | void clientConnected() { 24 | QAmqpQueue *queue = m_client.createQueue("task_queue"); 25 | connect(queue, SIGNAL(declared()), this, SLOT(queueDeclared())); 26 | queue->declare(); 27 | } 28 | 29 | void queueDeclared() { 30 | QAmqpQueue *queue = qobject_cast(sender()); 31 | if (!queue) 32 | return; 33 | 34 | QAmqpExchange *defaultExchange = m_client.createExchange(); 35 | QAmqpMessage::PropertyHash properties; 36 | properties[QAmqpMessage::DeliveryMode] = "2"; // make message persistent 37 | 38 | QString message; 39 | if (qApp->arguments().size() < 2) 40 | message = "Hello World!"; 41 | else 42 | message = qApp->arguments().at(1); 43 | 44 | defaultExchange->publish(message, "task_queue", properties); 45 | qDebug(" [x] Sent '%s'", message.toLatin1().constData()); 46 | m_client.disconnectFromHost(); 47 | } 48 | 49 | private: 50 | QAmqpClient m_client; 51 | 52 | }; 53 | 54 | int main(int argc, char **argv) 55 | { 56 | QCoreApplication app(argc, argv); 57 | TaskCreator taskCreator; 58 | taskCreator.start(); 59 | return app.exec(); 60 | } 61 | 62 | #include "main.moc" 63 | -------------------------------------------------------------------------------- /tutorials/workqueues/new_task/new_task.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | 4 | TEMPLATE = app 5 | INCLUDEPATH += $${QAMQP_INCLUDEPATH} 6 | LIBS += -L$${DEPTH}/src $${QAMQP_LIBS} 7 | macx:CONFIG -= app_bundle 8 | 9 | SOURCES += main.cpp 10 | -------------------------------------------------------------------------------- /tutorials/workqueues/worker/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "qamqpclient.h" 6 | #include "qamqpqueue.h" 7 | 8 | class Worker : public QObject 9 | { 10 | Q_OBJECT 11 | public: 12 | Worker(QObject *parent = 0) : QObject(parent), m_queue(0) {} 13 | 14 | public Q_SLOTS: 15 | void start() { 16 | connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected())); 17 | m_client.connectToHost(); 18 | } 19 | 20 | private Q_SLOTS: 21 | void clientConnected() { 22 | m_queue = m_client.createQueue("task_queue"); 23 | connect(m_queue, SIGNAL(declared()), this, SLOT(queueDeclared())); 24 | m_queue->declare(); 25 | qDebug() << " [*] Waiting for messages. To exit press CTRL+C"; 26 | } 27 | 28 | void queueDeclared() { 29 | // m_queue->setPrefetchCount(1); 30 | m_queue->consume(); 31 | connect(m_queue, SIGNAL(messageReceived()), this, SLOT(messageReceived())); 32 | } 33 | 34 | void messageReceived() { 35 | m_currentMessage = m_queue->dequeue(); 36 | qDebug() << " [x] Received " << m_currentMessage.payload(); 37 | 38 | int delay = m_currentMessage.payload().count(".") * 1000; 39 | QTimer::singleShot(delay, this, SLOT(ackMessage())); 40 | } 41 | 42 | void ackMessage() { 43 | qDebug() << " [x] Done"; 44 | m_queue->ack(m_currentMessage); 45 | } 46 | 47 | private: 48 | QAmqpClient m_client; 49 | QAmqpQueue *m_queue; 50 | QAmqpMessage m_currentMessage; 51 | 52 | }; 53 | 54 | int main(int argc, char **argv) 55 | { 56 | QCoreApplication app(argc, argv); 57 | Worker worker; 58 | worker.start(); 59 | return app.exec(); 60 | } 61 | 62 | #include "main.moc" 63 | -------------------------------------------------------------------------------- /tutorials/workqueues/worker/worker.pro: -------------------------------------------------------------------------------- 1 | DEPTH = ../../.. 2 | include($${DEPTH}/qamqp.pri) 3 | 4 | TEMPLATE = app 5 | INCLUDEPATH += $${QAMQP_INCLUDEPATH} 6 | LIBS += -L$${DEPTH}/src $${QAMQP_LIBS} 7 | macx:CONFIG -= app_bundle 8 | 9 | SOURCES += main.cpp 10 | -------------------------------------------------------------------------------- /tutorials/workqueues/workqueues.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS = \ 3 | new_task \ 4 | worker 5 | --------------------------------------------------------------------------------