first commit

This commit is contained in:
jessequ 2025-08-25 21:10:21 +08:00
commit 9a849b5b9d
106 changed files with 8356 additions and 0 deletions

20
.drone.yml Normal file
View File

@ -0,0 +1,20 @@
kind: pipeline
type: ssh
name: default
server:
host: 192.168.46.100:2223
user: jessequ
password:
from_secret: password
workspace:
path: /home/tmp
steps:
- name: build
commands:
- mkdir -p build/debug
- cd build/debug
- /home/jessequ/Qt/Tools/CMake/bin/cmake -S ../.. -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_GENERATOR:STRING=Ninja -DCMAKE_MAKE_PROGRAM:FILEPATH=/home/jessequ/Qt/Tools/Ninja/ninja -DCMAKE_PREFIX_PATH:PATH=/home/jessequ/Qt/6.7.2/gcc_64 -DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=/home/jessequ/Qt/Platforms/package-manager/auto-setup.cmake -DPostgreSQL_INCLUDE_DIR:FILEPATH=/usr/pgsql-17/include -DPostgreSQL_LIBRARY:FILEPATH=/usr/pgsql-17/lib
- /home/jessequ/Qt/Tools/Ninja/ninja

105
.gitignore vendored Normal file
View File

@ -0,0 +1,105 @@
build/
.vscode/
# ---> CMake
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
# ---> C++
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# ---> C
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf

74
CMakeLists.txt Normal file
View File

@ -0,0 +1,74 @@
cmake_minimum_required(VERSION 3.16)
project(events VERSION 0.0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Git QUIET)
if(GIT_FOUND)
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --long --dirty --tags
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_VERSION
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --abbrev=0
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_TAG
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(GIT_TAG)
string(REGEX REPLACE "^v" "" VERSION ${GIT_TAG})
else()
set(VERSION ${PROJECT_VERSION})
endif()
else()
set(GIT_VERSION "unknown")
set(VERSION ${PROJECT_VERSION})
endif()
add_compile_definitions(GIT_VERSION="${GIT_VERSION}")
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
find_package(Qt6 COMPONENTS Core Network REQUIRED)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
add_subdirectory(qamqp)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR})
add_executable(events
main.cpp
)
target_link_libraries(events Qt6::Core Qt6::Network qamqp)
set_target_properties(events PROPERTIES
AUTOMOC ON
AUTORCC ON
AUTOUIC ON
CXX_STANDARD 14
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
VERSION 0.0.1
EXPORT_NAME "Event Queue"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)
add_subdirectory(send)

4
README.md Normal file
View File

@ -0,0 +1,4 @@
# events
[![Build Status](http://192.168.46.100:4080/api/badges/CL-Softwares/events/status.svg)](http://192.168.46.100:4080/CL-Softwares/events)

81
main.cpp Normal file
View File

@ -0,0 +1,81 @@
#include <QCoreApplication>
#include <QDebug>
#include "qamqpclient.h"
#include "qamqpexchange.h"
#include "qamqpqueue.h"
class Receiver : public QObject
{
Q_OBJECT
public:
Receiver(QObject *parent = 0) : QObject(parent) {
m_client.setAutoReconnect(true);
}
public Q_SLOTS:
void start() {
connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected()));
m_client.connectToHost();
}
private Q_SLOTS:
void clientConnected() {
QAmqpQueue *queue = m_client.createQueue("hello");
disconnect(queue, 0, 0, 0); // in case this is a reconnect
connect(queue, SIGNAL(declared()), this, SLOT(queueDeclared()));
queue->declare();
}
void queueDeclared() {
QAmqpQueue *queue = qobject_cast<QAmqpQueue*>(sender());
if (!queue)
return;
connect(queue, SIGNAL(messageReceived()), this, SLOT(messageReceived()));
// queue->consume(QAmqpQueue::coNoAck);
// queue->consume(QAmqpQueue::coNoLocal);
qint32 sizeQueue = queue->messageCount();
while (sizeQueue--) {
queue->get(false);
}
qDebug() << " [*] Waiting for messages. To exit press CTRL+C";
queue->ack(3, false); // Acknowledgement the 3rd message.
queue->reopen();
// m_client.disconnectFromHost();
}
void messageReceived() {
QAmqpQueue *queue = qobject_cast<QAmqpQueue*>(sender());
if (!queue)
return;
QAmqpMessage message = queue->dequeue();
qDebug() << " [x] Received in" << message.payload();
int input=0;
// std::scanf("%d", &input);
qDebug() << " [x] Received out, " << message.deliveryTag() << " | " << message.payload() << " , input = " << input;
}
private:
QAmqpClient m_client;
};
int main(int argc, char **argv)
{
qDebug() << " Recieve starts ... ";
QCoreApplication app(argc, argv);
Receiver receiver;
receiver.start();
return app.exec();
}
#include "main.moc"

90
qamqp/CMakeLists.txt Normal file
View File

@ -0,0 +1,90 @@
cmake_minimum_required(VERSION 3.16)
project(qamqp VERSION 0.0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Git QUIET)
if(GIT_FOUND)
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --long --dirty --tags
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_VERSION
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --abbrev=0
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_TAG
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(GIT_TAG)
string(REGEX REPLACE "^v" "" VERSION ${GIT_TAG})
else()
set(VERSION ${PROJECT_VERSION})
endif()
else()
set(GIT_VERSION "unknown")
set(VERSION ${PROJECT_VERSION})
endif()
add_compile_definitions(GIT_VERSION="${GIT_VERSION}")
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
find_package(Qt6 COMPONENTS Core Network REQUIRED)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
add_subdirectory(src)
export(TARGETS qamqp
NAMESPACE qamqp::
FILE "${CMAKE_CURRENT_BINARY_DIR}/qamqpTargets.cmake"
)
option(BUILD_TESTS "Build tests" OFF)
if(BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
option(BUILD_TUTORIALS "Build tutorials" OFF)
if(BUILD_TUTORIALS)
add_subdirectory(tutorials)
endif()
include(GNUInstallDirs)
install(EXPORT qamqpTargets
FILE qamqpTargets.cmake
NAMESPACE qamqp::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/qamqp
)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/qamqpConfigVersion.cmake"
VERSION ${VERSION}
COMPATIBILITY SameMajorVersion
)
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/qamqpConfig.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/qamqpConfig.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/qamqp
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/qamqpConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/qamqpConfigVersion.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/qamqp
)

View File

@ -0,0 +1,8 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
find_dependency(Qt6 COMPONENTS Core Network)
include("${CMAKE_CURRENT_LIST_DIR}/qamqpTargets.cmake")
check_required_components(qamqp)

95
qamqp/src/CMakeLists.txt Normal file
View File

@ -0,0 +1,95 @@
set(QAMQP_HEADERS
qamqpauthenticator.h
qamqpchannel.h
qamqpchannel_p.h
qamqpchannelhash_p.h
qamqpclient.h
qamqpclient_p.h
qamqpexchange.h
qamqpexchange_p.h
qamqpglobal.h
qamqpmessage.h
qamqpmessage_p.h
qamqpqueue.h
qamqpqueue_p.h
qamqptable.h
qamqpframe_p.h
)
set(QAMQP_SOURCES
qamqpauthenticator.cpp
qamqpchannel.cpp
qamqpchannelhash.cpp
qamqpclient.cpp
qamqpexchange.cpp
qamqpframe.cpp
qamqpmessage.cpp
qamqpqueue.cpp
qamqptable.cpp
)
if(MSVC)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build static library for MSVC" FORCE)
endif()
if(BUILD_SHARED_LIBS)
add_library(qamqp SHARED ${QAMQP_HEADERS} ${QAMQP_SOURCES})
else()
add_library(qamqp STATIC ${QAMQP_HEADERS} ${QAMQP_SOURCES})
endif()
add_library(qamqp::qamqp ALIAS qamqp)
set_target_properties(qamqp PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
EXPORT_NAME qamqp
OUTPUT_NAME qamqp
DEBUG_POSTFIX d
)
target_include_directories(qamqp
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include/qamqp>
)
target_link_libraries(qamqp
PUBLIC
Qt6::Core
Qt6::Network
)
target_compile_definitions(qamqp
PRIVATE
QAMQP_BUILD
PUBLIC
$<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:QAMQP_STATIC>
)
set_target_properties(qamqp PROPERTIES
AUTOMOC ON
AUTORCC ON
AUTOUIC ON
CXX_STANDARD 14
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
EXPORT_NAME qamqp
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)
install(TARGETS qamqp
EXPORT qamqpTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qamqp
)
install(FILES ${QAMQP_HEADERS}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qamqp
)

View File

@ -0,0 +1,47 @@
#include "qamqptable.h"
#include "qamqpframe_p.h"
#include "qamqpauthenticator.h"
QAmqpPlainAuthenticator::QAmqpPlainAuthenticator(const QString &l, const QString &p)
: login_(l),
password_(p)
{
}
QAmqpPlainAuthenticator::~QAmqpPlainAuthenticator()
{
}
QString QAmqpPlainAuthenticator::login() const
{
return login_;
}
QString QAmqpPlainAuthenticator::password() const
{
return password_;
}
QString QAmqpPlainAuthenticator::type() const
{
return "AMQPLAIN";
}
void QAmqpPlainAuthenticator::setLogin(const QString &l)
{
login_ = l;
}
void QAmqpPlainAuthenticator::setPassword(const QString &p)
{
password_ = p;
}
void QAmqpPlainAuthenticator::write(QDataStream &out)
{
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, type());
QAmqpTable response;
response["LOGIN"] = login_;
response["PASSWORD"] = password_;
out << response;
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2012-2014 Alexey Shcherbakov
* Copyright (C) 2014-2015 Matt Broadstone
* Contact: https://github.com/mbroadst/qamqp
*
* This file is part of the QAMQP Library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef QAMQPAUTHENTICATOR_H
#define QAMQPAUTHENTICATOR_H
#include <QString>
#include <QDataStream>
#include "qamqpglobal.h"
class QAMQP_EXPORT QAmqpAuthenticator
{
public:
virtual ~QAmqpAuthenticator() {}
virtual QString type() const = 0;
virtual void write(QDataStream &out) = 0;
};
class QAMQP_EXPORT QAmqpPlainAuthenticator : public QAmqpAuthenticator
{
public:
QAmqpPlainAuthenticator(const QString &login = QString(), const QString &password = QString());
virtual ~QAmqpPlainAuthenticator();
QString login() const;
void setLogin(const QString &l);
QString password() const;
void setPassword(const QString &p);
virtual QString type() const;
virtual void write(QDataStream &out);
private:
QString login_;
QString password_;
};
#endif // QAMQPAUTHENTICATOR_H

368
qamqp/src/qamqpchannel.cpp Normal file
View File

@ -0,0 +1,368 @@
#include <QDataStream>
#include <QDebug>
#include "qamqpchannel.h"
#include "qamqpchannel_p.h"
#include "qamqpclient.h"
#include "qamqpclient_p.h"
quint16 QAmqpChannelPrivate::nextChannelNumber = 0;
QAmqpChannelPrivate::QAmqpChannelPrivate(QAmqpChannel *q)
: channelNumber(0),
opened(false),
needOpen(true),
prefetchSize(0),
requestedPrefetchSize(0),
prefetchCount(0),
requestedPrefetchCount(0),
error(QAMQP::NoError),
q_ptr(q)
{
}
QAmqpChannelPrivate::~QAmqpChannelPrivate()
{
if (!client.isNull()) {
QAmqpClientPrivate *priv = client->d_func();
priv->methodHandlersByChannel[channelNumber].removeAll(this);
}
}
void QAmqpChannelPrivate::init(int channel, QAmqpClient *c)
{
client = c;
needOpen = (channel <= nextChannelNumber && channel != -1) ? false : true;
channelNumber = channel == -1 ? ++nextChannelNumber : channel;
nextChannelNumber = qMax(channelNumber, nextChannelNumber);
}
bool QAmqpChannelPrivate::_q_method(const QAmqpMethodFrame &frame)
{
Q_ASSERT(frame.channel() == channelNumber);
if (frame.channel() != channelNumber)
return true;
if (frame.methodClass() == QAmqpFrame::Basic) {
if (frame.id() == bmQosOk) {
qosOk(frame);
return true;
}
return false;
}
if (frame.methodClass() != QAmqpFrame::Channel)
return false;
switch (frame.id()) {
case miOpenOk:
openOk(frame);
break;
case miFlow:
flow(frame);
break;
case miFlowOk:
flowOk(frame);
break;
case miClose:
close(frame);
break;
case miCloseOk:
closeOk(frame);
break;
}
return true;
}
void QAmqpChannelPrivate::_q_open()
{
open();
}
void QAmqpChannelPrivate::sendFrame(const QAmqpFrame &frame)
{
if (!client) {
qAmqpDebug() << Q_FUNC_INFO << "invalid client";
return;
}
client->d_func()->sendFrame(frame);
}
void QAmqpChannelPrivate::resetInternalState()
{
if (!opened) return;
opened = false;
needOpen = true;
}
void QAmqpChannelPrivate::open()
{
if (!needOpen || opened)
return;
if (!client->isConnected())
return;
qAmqpDebug("<- channel#open( channel=%d, name=%s )", channelNumber, qPrintable(name));
QAmqpMethodFrame frame(QAmqpFrame::Channel, miOpen);
frame.setChannel(channelNumber);
QByteArray arguments;
arguments.resize(1);
arguments[0] = 0;
frame.setArguments(arguments);
sendFrame(frame);
}
void QAmqpChannelPrivate::flow(bool active)
{
QByteArray arguments;
QDataStream stream(&arguments, QIODevice::WriteOnly);
QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortShortUint, (active ? 1 : 0));
QAmqpMethodFrame frame(QAmqpFrame::Channel, miFlow);
frame.setChannel(channelNumber);
frame.setArguments(arguments);
sendFrame(frame);
}
// NOTE: not implemented until I can figure out a good way to force the server
// to pause the channel in a test. It seems like RabbitMQ just doesn't
// care about flow control, preferring rather to use basic.qos
void QAmqpChannelPrivate::flow(const QAmqpMethodFrame &frame)
{
Q_UNUSED(frame);
qAmqpDebug("-> channel#flow( channel=%d, name=%s )", channelNumber, qPrintable(name));
}
void QAmqpChannelPrivate::flowOk()
{
qAmqpDebug("<- channel#flowOk( channel=%d, name=%s )", channelNumber, qPrintable(name));
}
void QAmqpChannelPrivate::flowOk(const QAmqpMethodFrame &frame)
{
Q_Q(QAmqpChannel);
qAmqpDebug("-> channel#flowOk( channel=%d, name=%s )", channelNumber, qPrintable(name));
QByteArray data = frame.arguments();
QDataStream stream(&data, QIODevice::ReadOnly);
bool active = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::Boolean).toBool();
if (active)
Q_EMIT q->resumed();
else
Q_EMIT q->paused();
}
void QAmqpChannelPrivate::close(int code, const QString &text, int classId, int methodId)
{
qAmqpDebug("<- channel#close( channel=%d, name=%s, reply-code=%d, text=%s class-id=%d, method-id:%d, )",
channelNumber, qPrintable(name), code, qPrintable(text), classId, methodId);
QByteArray arguments;
QDataStream stream(&arguments, QIODevice::WriteOnly);
if (!code) code = 200;
QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortUint, code);
if (!text.isEmpty()) {
QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortString, text);
} else {
QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortString, QLatin1String("OK"));
}
QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortUint, classId);
QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortUint, methodId);
QAmqpMethodFrame frame(QAmqpFrame::Channel, miClose);
frame.setChannel(channelNumber);
frame.setArguments(arguments);
sendFrame(frame);
}
void QAmqpChannelPrivate::close(const QAmqpMethodFrame &frame)
{
Q_Q(QAmqpChannel);
QByteArray data = frame.arguments();
QDataStream stream(&data, QIODevice::ReadOnly);
qint16 code = 0, classId, methodId;
stream >> code;
QString text =
QAmqpFrame::readAmqpField(stream, QAmqpMetaType::ShortString).toString();
stream >> classId;
stream >> methodId;
QAMQP::Error checkError = static_cast<QAMQP::Error>(code);
if (checkError != QAMQP::NoError) {
error = checkError;
errorString = qPrintable(text);
Q_EMIT q->error(error);
}
qAmqpDebug("-> channel#close( channel=%d, name=%s, reply-code=%d, reply-text=%s, class-id=%d, method-id=%d, )",
channelNumber, qPrintable(name), code, qPrintable(text), classId, methodId);
// complete handshake
QAmqpMethodFrame closeOkFrame(QAmqpFrame::Channel, miCloseOk);
closeOkFrame.setChannel(channelNumber);
sendFrame(closeOkFrame);
// notify everyone that the channel was closed on us.
notifyClosed();
}
void QAmqpChannelPrivate::closeOk(const QAmqpMethodFrame &)
{
qAmqpDebug("-> channel#closeOk( channel=%d, name=%s )", channelNumber, qPrintable(name));
notifyClosed();
}
void QAmqpChannelPrivate::notifyClosed()
{
Q_Q(QAmqpChannel);
Q_EMIT q->closed();
q->channelClosed();
opened = false;
}
void QAmqpChannelPrivate::openOk(const QAmqpMethodFrame &)
{
Q_Q(QAmqpChannel);
qAmqpDebug("-> channel#openOk( channel=%d, name=%s )", channelNumber, qPrintable(name));
opened = true;
Q_EMIT q->opened();
q->channelOpened();
}
void QAmqpChannelPrivate::_q_disconnected()
{
nextChannelNumber = 0;
opened = false;
}
void QAmqpChannelPrivate::qosOk(const QAmqpMethodFrame &frame)
{
Q_Q(QAmqpChannel);
Q_UNUSED(frame)
qAmqpDebug("-> basic#qosOk( channel=%d, name=%s )", channelNumber, qPrintable(name));
prefetchCount = requestedPrefetchCount;
prefetchSize = requestedPrefetchSize;
Q_EMIT q->qosDefined();
}
//////////////////////////////////////////////////////////////////////////
QAmqpChannel::QAmqpChannel(QAmqpChannelPrivate *dd, QAmqpClient *parent)
: QObject(parent),
d_ptr(dd)
{
}
QAmqpChannel::~QAmqpChannel()
{
}
void QAmqpChannel::close()
{
Q_D(QAmqpChannel);
d->needOpen = true;
if (d->opened)
d->close(0, QString(), 0,0);
}
void QAmqpChannel::reopen()
{
Q_D(QAmqpChannel);
if (d->opened)
close();
d->open();
}
QString QAmqpChannel::name() const
{
Q_D(const QAmqpChannel);
return d->name;
}
int QAmqpChannel::channelNumber() const
{
Q_D(const QAmqpChannel);
return d->channelNumber;
}
void QAmqpChannel::setName(const QString &name)
{
Q_D(QAmqpChannel);
d->name = name;
}
bool QAmqpChannel::isOpen() const
{
Q_D(const QAmqpChannel);
return d->opened;
}
void QAmqpChannel::qos(qint16 prefetchCount, qint32 prefetchSize)
{
Q_D(QAmqpChannel);
QAmqpMethodFrame frame(QAmqpFrame::Basic, QAmqpChannelPrivate::bmQos);
frame.setChannel(d->channelNumber);
QByteArray arguments;
QDataStream stream(&arguments, QIODevice::WriteOnly);
d->requestedPrefetchSize = prefetchSize;
d->requestedPrefetchCount = prefetchCount;
stream << qint32(prefetchSize);
stream << qint16(prefetchCount);
stream << qint8(0x0); // global
qAmqpDebug("<- basic#qos( channel=%d, name=%s, prefetch-size=%d, prefetch-count=%d, global=%d )",
d->channelNumber, qPrintable(d->name), prefetchSize, prefetchCount, 0);
frame.setArguments(arguments);
d->sendFrame(frame);
}
qint32 QAmqpChannel::prefetchSize() const
{
Q_D(const QAmqpChannel);
return d->prefetchSize;
}
qint16 QAmqpChannel::prefetchCount() const
{
Q_D(const QAmqpChannel);
return d->prefetchCount;
}
void QAmqpChannel::reset()
{
Q_D(QAmqpChannel);
d->resetInternalState();
}
QAMQP::Error QAmqpChannel::error() const
{
Q_D(const QAmqpChannel);
return d->error;
}
QString QAmqpChannel::errorString() const
{
Q_D(const QAmqpChannel);
return d->errorString;
}
void QAmqpChannel::resume()
{
Q_D(QAmqpChannel);
d->flow(true);
}
#include "moc_qamqpchannel.cpp"

83
qamqp/src/qamqpchannel.h Normal file
View File

@ -0,0 +1,83 @@
/*
* Copyright (C) 2012-2014 Alexey Shcherbakov
* Copyright (C) 2014-2015 Matt Broadstone
* Contact: https://github.com/mbroadst/qamqp
*
* This file is part of the QAMQP Library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef QAMQPCHANNEL_H
#define QAMQPCHANNEL_H
#include <QObject>
#include "qamqpglobal.h"
class QAmqpClient;
class QAmqpChannelPrivate;
class QAMQP_EXPORT QAmqpChannel : public QObject
{
Q_OBJECT
Q_PROPERTY(int number READ channelNumber CONSTANT)
Q_PROPERTY(bool open READ isOpen CONSTANT)
Q_PROPERTY(QString name READ name WRITE setName)
public:
virtual ~QAmqpChannel();
int channelNumber() const;
bool isOpen() const;
QString name() const;
void setName(const QString &name);
QAMQP::Error error() const;
QString errorString() const;
qint32 prefetchSize() const;
qint16 prefetchCount() const;
void reset();
// AMQP Basic
void qos(qint16 prefetchCount, qint32 prefetchSize = 0);
public Q_SLOTS:
void close();
void reopen();
void resume();
Q_SIGNALS:
void opened();
void closed();
void resumed();
void paused();
void error(QAMQP::Error error);
void qosDefined();
protected:
virtual void channelOpened() = 0;
virtual void channelClosed() = 0;
protected:
explicit QAmqpChannel(QAmqpChannelPrivate *dd, QAmqpClient *client);
Q_DISABLE_COPY(QAmqpChannel)
Q_DECLARE_PRIVATE(QAmqpChannel)
QScopedPointer<QAmqpChannelPrivate> d_ptr;
Q_PRIVATE_SLOT(d_func(), void _q_open())
Q_PRIVATE_SLOT(d_func(), void _q_disconnected())
friend class QAmqpClientPrivate;
friend class QAmqpExchangePrivate;
};
#endif // QAMQPCHANNEL_H

View File

@ -0,0 +1,84 @@
#ifndef QAMQPCHANNEL_P_H
#define QAMQPCHANNEL_P_H
#include <QPointer>
#include "qamqpframe_p.h"
#include "qamqptable.h"
#define METHOD_ID_ENUM(name, id) name = id, name ## Ok
class QAmqpChannel;
class QAmqpClient;
class QAmqpClientPrivate;
class QAmqpChannelPrivate : public QAmqpMethodFrameHandler
{
public:
enum MethodId {
METHOD_ID_ENUM(miOpen, 10),
METHOD_ID_ENUM(miFlow, 20),
METHOD_ID_ENUM(miClose, 40)
};
enum BasicMethod {
METHOD_ID_ENUM(bmQos, 10),
METHOD_ID_ENUM(bmConsume, 20),
METHOD_ID_ENUM(bmCancel, 30),
bmPublish = 40,
bmReturn = 50,
bmDeliver = 60,
METHOD_ID_ENUM(bmGet, 70),
bmGetEmpty = 72,
bmAck = 80,
bmReject = 90,
bmRecoverAsync = 100,
METHOD_ID_ENUM(bmRecover, 110),
bmNack = 120
};
QAmqpChannelPrivate(QAmqpChannel *q);
virtual ~QAmqpChannelPrivate();
void init(int channel, QAmqpClient *client);
void sendFrame(const QAmqpFrame &frame);
virtual void resetInternalState();
void open();
void flow(bool active);
void flowOk();
void close(int code, const QString &text, int classId, int methodId);
void notifyClosed();
// reimp MethodHandler
virtual bool _q_method(const QAmqpMethodFrame &frame);
void openOk(const QAmqpMethodFrame &frame);
void flow(const QAmqpMethodFrame &frame);
void flowOk(const QAmqpMethodFrame &frame);
void close(const QAmqpMethodFrame &frame);
void closeOk(const QAmqpMethodFrame &frame);
void qosOk(const QAmqpMethodFrame &frame);
// private slots
virtual void _q_disconnected();
void _q_open();
QPointer<QAmqpClient> client;
QString name;
quint16 channelNumber;
static quint16 nextChannelNumber;
bool opened;
bool needOpen;
qint32 prefetchSize;
qint32 requestedPrefetchSize;
qint16 prefetchCount;
qint16 requestedPrefetchCount;
QAMQP::Error error;
QString errorString;
Q_DECLARE_PUBLIC(QAmqpChannel)
QAmqpChannel * const q_ptr;
QAmqpTable arguments;
};
#endif // QAMQPCHANNEL_P_H

View File

@ -0,0 +1,113 @@
/*
* Copyright (C) 2012-2014 Alexey Shcherbakov
* Copyright (C) 2014-2015 Matt Broadstone
* Contact: https://github.com/mbroadst/qamqp
*
* This file is part of the QAMQP Library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "qamqpqueue.h"
#include "qamqpexchange.h"
#include "qamqpchannelhash_p.h"
/*!
* Retrieve a pointer to the named channel.
*
* A NULL string is assumed to be equivalent to "" for the purpose
* of retrieving the nameless (default) exchange.
*
* \param[in] name The name of the channel to retrieve.
* \retval NULL Channel does not exist.
*/
QAmqpChannel* QAmqpChannelHash::get(const QString& name) const
{
if (name.isEmpty())
return m_channels.value(QString());
return m_channels.value(name);
}
QStringList QAmqpChannelHash::channels() const
{
return m_channels.keys();
}
/*!
* Return true if the named channel exists.
*/
bool QAmqpChannelHash::contains(const QString& name) const
{
if (name.isEmpty())
return m_channels.contains(QString());
return m_channels.contains(name);
}
/*!
* Store an exchange in the hash. The nameless exchange is stored under
* the name "".
*/
void QAmqpChannelHash::put(QAmqpExchange* exchange)
{
if (exchange->name().isEmpty())
put(QString(), exchange);
else
put(exchange->name(), exchange);
}
/*!
* Store a queue in the hash. If the queue is nameless, we hook its
* declared signal and store it when the queue receives a name from the
* broker, otherwise we store it under the name given.
*/
void QAmqpChannelHash::put(QAmqpQueue* queue)
{
if (queue->name().isEmpty())
connect(queue, SIGNAL(declared()), this, SLOT(queueDeclared()));
else
put(queue->name(), queue);
}
/*!
* Handle destruction of a channel. Do a full garbage collection run.
*/
void QAmqpChannelHash::channelDestroyed(QObject* object)
{
QList<QString> names(m_channels.keys());
QList<QString>::iterator it;
for (it = names.begin(); it != names.end(); it++) {
if (m_channels.value(*it) == object)
m_channels.remove(*it);
}
}
/*!
* Handle a queue that has just been declared and given a new name. The
* caller is assumed to be a QAmqpQueue instance.
*/
void QAmqpChannelHash::queueDeclared()
{
QAmqpQueue *queue = qobject_cast<QAmqpQueue*>(sender());
if (queue)
put(queue);
}
/*!
* Store a channel in the hash. The channel is assumed
* to be named at the time of storage. This hooks the 'destroyed' signal
* so the channel can be removed from our list.
*/
void QAmqpChannelHash::put(const QString& name, QAmqpChannel* channel)
{
connect(channel, SIGNAL(destroyed(QObject*)), this, SLOT(channelDestroyed(QObject*)));
m_channels[name] = channel;
}
/* vim: set ts=4 sw=4 et */

View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2012-2014 Alexey Shcherbakov
* Copyright (C) 2014-2015 Matt Broadstone
* Contact: https://github.com/mbroadst/qamqp
*
* This file is part of the QAMQP Library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef QAMQPCHANNELHASH_P_H
#define QAMQPCHANNELHASH_P_H
#include <QHash>
#include <QString>
#include <QStringList>
#include <QObject>
/* Forward declarations */
class QAmqpChannel;
class QAmqpQueue;
class QAmqpExchange;
/*!
* QAmqpChannelHash is a container for storing queues and exchanges for later
* retrieval. When the objects are destroyed, they are automatically removed
* from the container.
*/
class QAmqpChannelHash : public QObject
{
Q_OBJECT
public:
/*!
* Retrieve a pointer to the named channel.
*
* A NULL string is assumed to be equivalent to "" for the purpose
* of retrieving the nameless (default) exchange.
*
* \param[in] name The name of the channel to retrieve.
* \retval NULL Channel does not exist.
*/
QAmqpChannel* get(const QString& name) const;
/*!
* Return true if the named channel exists.
*/
bool contains(const QString& name) const;
/**
* Returns a list of channels tracked by this hash
*/
QStringList channels() const;
/*!
* Store an exchange in the hash. The nameless exchange is stored under
* the name "".
*/
void put(QAmqpExchange* exchange);
/*!
* Store a queue in the hash. If the queue is nameless, we hook its
* declared signal and store it when the queue receives a name from the
* broker, otherwise we store it under the name given.
*/
void put(QAmqpQueue* queue);
private Q_SLOTS:
/*!
* Handle destruction of a channel. Do a full garbage collection run.
*/
void channelDestroyed(QObject* object);
/*!
* Handle a queue that has just been declared and given a new name. The
* caller is assumed to be a QAmqpQueue instance.
*/
void queueDeclared();
private:
/*!
* Store a channel in the hash. This hooks the 'destroyed' signal
* so the channel can be removed from our list.
*/
void put(const QString& name, QAmqpChannel* channel);
/*! A collection of channels. Key is the channel's "name". */
QHash<QString, QAmqpChannel*> m_channels;
};
/* vim: set ts=4 sw=4 et */
#endif

959
qamqp/src/qamqpclient.cpp Normal file
View File

@ -0,0 +1,959 @@
#include <QTimer>
#include <QTextStream>
#include <QStringList>
#include <QSslSocket>
#include <QtEndian>
#include "qamqpglobal.h"
#include "qamqpexchange.h"
#include "qamqpexchange_p.h"
#include "qamqpqueue.h"
#include "qamqpqueue_p.h"
#include "qamqpauthenticator.h"
#include "qamqptable.h"
#include "qamqpclient_p.h"
#include "qamqpclient.h"
QAmqpClientPrivate::QAmqpClientPrivate(QAmqpClient *q)
: port(AMQP_PORT),
host(AMQP_HOST),
virtualHost(AMQP_VHOST),
autoReconnect(false),
reconnectFixedTimeout(false),
timeout(0),
connecting(false),
useSsl(false),
socket(0),
closed(false),
connected(false),
channelMax(0),
heartbeatDelay(0),
frameMax(AMQP_FRAME_MAX),
error(QAMQP::NoError),
q_ptr(q)
{
qRegisterMetaType<QAmqpMessage::PropertyHash>();
}
QAmqpClientPrivate::~QAmqpClientPrivate()
{
}
void QAmqpClientPrivate::init()
{
Q_Q(QAmqpClient);
initSocket();
heartbeatTimer = new QTimer(q);
QObject::connect(heartbeatTimer, SIGNAL(timeout()), q, SLOT(_q_heartbeat()));
reconnectTimer = new QTimer(q);
reconnectTimer->setSingleShot(true);
QObject::connect(reconnectTimer, SIGNAL(timeout()), q, SLOT(_q_connect()));
authenticator = QSharedPointer<QAmqpAuthenticator>(
new QAmqpPlainAuthenticator(QString::fromLatin1(AMQP_LOGIN), QString::fromLatin1(AMQP_PSWD)));
}
void QAmqpClientPrivate::initSocket()
{
Q_Q(QAmqpClient);
socket = new QSslSocket(q);
socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
QObject::connect(socket, SIGNAL(connected()), q, SLOT(_q_socketConnected()));
QObject::connect(socket, SIGNAL(disconnected()), q, SLOT(_q_socketDisconnected()));
QObject::connect(socket, SIGNAL(readyRead()), q, SLOT(_q_readyRead()));
#if QT_VERSION >= 0x060000
QObject::connect(socket,
SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
q,
SLOT(_q_socketError(QAbstractSocket::SocketError)));
QObject::connect(socket,
SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
q,
SIGNAL(socketErrorOccurred(QAbstractSocket::SocketError)));
#else
QObject::connect(socket,
SIGNAL(error(QAbstractSocket::SocketError)),
q,
SLOT(_q_socketError(QAbstractSocket::SocketError)));
QObject::connect(socket,
SIGNAL(error(QAbstractSocket::SocketError)),
q,
SIGNAL(socketErrorOccurred(QAbstractSocket::SocketError)));
#endif
QObject::connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
q, SIGNAL(socketStateChanged(QAbstractSocket::SocketState)));
QObject::connect(socket, SIGNAL(sslErrors(QList<QSslError>)),
q, SIGNAL(sslErrors(QList<QSslError>)));
}
void QAmqpClientPrivate::resetChannelState()
{
foreach (QString exchangeName, exchanges.channels()) {
QAmqpExchange *exchange =
qobject_cast<QAmqpExchange*>(exchanges.get(exchangeName));
if (exchange) exchange->d_ptr->resetInternalState();
}
foreach (QString queueName, queues.channels()) {
QAmqpQueue *queue =
qobject_cast<QAmqpQueue*>(queues.get(queueName));
if (queue) queue->d_ptr->resetInternalState();
}
}
void QAmqpClientPrivate::setUsername(const QString &username)
{
QAmqpAuthenticator *auth = authenticator.data();
if (auth && auth->type() == QLatin1String("AMQPLAIN")) {
QAmqpPlainAuthenticator *a = static_cast<QAmqpPlainAuthenticator*>(auth);
a->setLogin(username);
}
}
void QAmqpClientPrivate::setPassword(const QString &password)
{
QAmqpAuthenticator *auth = authenticator.data();
if (auth && auth->type() == QLatin1String("AMQPLAIN")) {
QAmqpPlainAuthenticator *a = static_cast<QAmqpPlainAuthenticator*>(auth);
a->setPassword(password);
}
}
void QAmqpClientPrivate::parseConnectionString(const QString &uri)
{
QUrl connectionString = QUrl::fromUserInput(uri);
if (connectionString.scheme() != AMQP_SCHEME &&
connectionString.scheme() != AMQP_SSL_SCHEME) {
qAmqpDebug() << Q_FUNC_INFO << "invalid scheme: " << connectionString.scheme();
return;
}
useSsl = (connectionString.scheme() == AMQP_SSL_SCHEME);
port = connectionString.port((useSsl ? AMQP_SSL_PORT : AMQP_PORT));
host = connectionString.host();
QString vhost = connectionString.path();
if (vhost.startsWith("/") && vhost.size() > 1)
vhost = vhost.mid(1);
virtualHost = vhost;
setPassword(connectionString.password());
setUsername(connectionString.userName());
}
void QAmqpClientPrivate::_q_connect()
{
if (reconnectTimer)
reconnectTimer->stop();
if (socket->state() != QAbstractSocket::UnconnectedState) {
qAmqpDebug() << Q_FUNC_INFO << "socket already connected, disconnecting..";
_q_disconnect();
// We need to explicitly close connection here because either way it will not be closed until we receive closeOk
closeConnection();
}
qAmqpDebug() << "connecting to host: " << host << ", port: " << port;
if (useSsl)
socket->connectToHostEncrypted(host, port);
else
socket->connectToHost(host, port);
}
void QAmqpClientPrivate::_q_disconnect()
{
if (reconnectTimer)
reconnectTimer->stop();
if (socket->state() == QAbstractSocket::UnconnectedState) {
qAmqpDebug() << Q_FUNC_INFO << "already disconnected";
return;
}
buffer.clear();
close(200, "client disconnect");
}
// private slots
void QAmqpClientPrivate::_q_socketConnected()
{
if (reconnectTimer)
reconnectTimer->stop();
if(reconnectFixedTimeout == false)
timeout = 0;
char header[8] = {'A', 'M', 'Q', 'P', 0, 0, 9, 1};
socket->write(header, 8);
}
void QAmqpClientPrivate::_q_socketDisconnected()
{
Q_Q(QAmqpClient);
buffer.clear();
resetChannelState();
if (connected)
connected = false;
Q_EMIT q->disconnected();
}
void QAmqpClientPrivate::_q_heartbeat()
{
QAmqpHeartbeatFrame frame;
sendFrame(frame);
}
void QAmqpClientPrivate::_q_socketError(QAbstractSocket::SocketError error)
{
if(reconnectFixedTimeout == false)
{
if (timeout <= 0) {
timeout = 1000;
} else {
if (timeout < 120000)
timeout *= 5;
}
}
switch (error) {
case QAbstractSocket::ConnectionRefusedError:
case QAbstractSocket::RemoteHostClosedError:
case QAbstractSocket::SocketTimeoutError:
case QAbstractSocket::NetworkError:
case QAbstractSocket::ProxyConnectionClosedError:
case QAbstractSocket::ProxyConnectionRefusedError:
case QAbstractSocket::ProxyConnectionTimeoutError:
default:
qAmqpDebug() << "socket error: " << socket->errorString();
break;
}
// per spec, on any error we need to close the socket immediately
// and send no more data. only try to send the close message if we
// are actively connected
if (socket->state() == QAbstractSocket::ConnectedState ||
socket->state() == QAbstractSocket::ConnectingState) {
socket->abort();
}
errorString = socket->errorString();
if (autoReconnect && reconnectTimer) {
qAmqpDebug() << "trying to reconnect after: " << timeout << "ms";
reconnectTimer->start(timeout);
}
}
void QAmqpClientPrivate::_q_readyRead()
{
Q_Q(QAmqpClient);
while (socket->bytesAvailable() >= QAmqpFrame::HEADER_SIZE) {
unsigned char headerData[QAmqpFrame::HEADER_SIZE];
socket->peek((char*)headerData, QAmqpFrame::HEADER_SIZE);
const quint32 payloadSize = qFromBigEndian<quint32>(headerData + 3);
const qint64 readSize = QAmqpFrame::HEADER_SIZE + payloadSize + QAmqpFrame::FRAME_END_SIZE;
if (socket->bytesAvailable() < readSize)
return;
buffer.resize(readSize);
socket->read(buffer.data(), readSize);
const char *bufferData = buffer.constData();
const quint8 type = *(quint8*)&bufferData[0];
const quint8 magic = *(quint8*)&bufferData[QAmqpFrame::HEADER_SIZE + payloadSize];
if (Q_UNLIKELY(magic != QAmqpFrame::FRAME_END)) {
close(QAMQP::UnexpectedFrameError, "wrong end of frame");
return;
}
QDataStream streamB(&buffer, QIODevice::ReadOnly);
switch (static_cast<QAmqpFrame::FrameType>(type)) {
case QAmqpFrame::Method:
{
QAmqpMethodFrame frame;
streamB >> frame;
if (Q_UNLIKELY(frame.size() > frameMax)) {
close(QAMQP::FrameError, "frame size too large");
return;
}
if (frame.methodClass() == QAmqpFrame::Connection) {
_q_method(frame);
} else {
foreach (QAmqpMethodFrameHandler *methodHandler, methodHandlersByChannel[frame.channel()])
methodHandler->_q_method(frame);
}
}
break;
case QAmqpFrame::Header:
{
QAmqpContentFrame frame;
streamB >> frame;
if (Q_UNLIKELY(frame.size() > frameMax)) {
close(QAMQP::FrameError, "frame size too large");
return;
} else if (Q_UNLIKELY(frame.channel() <= 0)) {
close(QAMQP::ChannelError, "channel number must be greater than zero");
return;
}
foreach (QAmqpContentFrameHandler *methodHandler, contentHandlerByChannel[frame.channel()])
methodHandler->_q_content(frame);
}
break;
case QAmqpFrame::Body:
{
QAmqpContentBodyFrame frame;
streamB >> frame;
if (Q_UNLIKELY(frame.size() > frameMax)) {
close(QAMQP::FrameError, "frame size too large");
return;
} else if (Q_UNLIKELY(frame.channel() <= 0)) {
close(QAMQP::ChannelError, "channel number must be greater than zero");
return;
}
foreach (QAmqpContentBodyFrameHandler *methodHandler, bodyHandlersByChannel[frame.channel()])
methodHandler->_q_body(frame);
}
break;
case QAmqpFrame::Heartbeat:
{
QAmqpMethodFrame frame;
streamB >> frame;
if (Q_UNLIKELY(frame.channel() != 0)) {
close(QAMQP::FrameError, "heartbeat must have channel id zero");
return;
}
qAmqpDebug("AMQP: Heartbeat");
Q_EMIT q->heartbeat();
}
break;
default:
qAmqpDebug() << "AMQP: Unknown frame type: " << type;
close(QAMQP::FrameError, "invalid frame type");
return;
}
}
}
void QAmqpClientPrivate::sendFrame(const QAmqpFrame &frame)
{
if (socket->state() != QAbstractSocket::ConnectedState) {
qAmqpDebug() << Q_FUNC_INFO << "socket not connected: " << socket->state();
return;
}
QDataStream stream(socket);
stream << frame;
}
void QAmqpClientPrivate::closeConnection()
{
qAmqpDebug("AMQP: closing connection");
connected = false;
if (reconnectTimer)
reconnectTimer->stop();
if (heartbeatTimer)
heartbeatTimer->stop();
socket->disconnectFromHost();
}
bool QAmqpClientPrivate::_q_method(const QAmqpMethodFrame &frame)
{
Q_ASSERT(frame.methodClass() == QAmqpFrame::Connection);
if (frame.methodClass() != QAmqpFrame::Connection)
return false;
if (closed) {
if (frame.id() == QAmqpClientPrivate::miCloseOk)
closeOk(frame);
return false;
}
switch (QAmqpClientPrivate::MethodId(frame.id())) {
case QAmqpClientPrivate::miStart:
start(frame);
break;
case QAmqpClientPrivate::miSecure:
secure(frame);
break;
case QAmqpClientPrivate::miTune:
tune(frame);
break;
case QAmqpClientPrivate::miOpenOk:
openOk(frame);
break;
case QAmqpClientPrivate::miClose:
close(frame);
break;
case QAmqpClientPrivate::miCloseOk:
closeOk(frame);
break;
default:
qAmqpDebug("Unknown method-id %d", frame.id());
}
return true;
}
void QAmqpClientPrivate::start(const QAmqpMethodFrame &frame)
{
QByteArray data = frame.arguments();
QDataStream stream(&data, QIODevice::ReadOnly);
quint8 version_major = 0;
quint8 version_minor = 0;
stream >> version_major >> version_minor;
QAmqpTable table;
stream >> table;
QStringList mechanisms =
QAmqpFrame::readAmqpField(stream, QAmqpMetaType::LongString).toString().split(' ');
QString locales = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::LongString).toString();
qAmqpDebug("-> connection#start( version_major=%d, version_minor=%d, mechanisms=(%s), locales=%s )",
version_major, version_minor, qPrintable(mechanisms.join(",")), qPrintable(locales));
if (!mechanisms.contains(authenticator->type())) {
socket->disconnectFromHost();
return;
}
startOk();
}
void QAmqpClientPrivate::secure(const QAmqpMethodFrame &frame)
{
Q_UNUSED(frame)
qAmqpDebug("-> connection#secure()");
}
void QAmqpClientPrivate::tune(const QAmqpMethodFrame &frame)
{
QByteArray data = frame.arguments();
QDataStream stream(&data, QIODevice::ReadOnly);
qint16 channel_max = 0,
heartbeat_delay = 0;
qint32 frame_max = 0;
stream >> channel_max;
stream >> frame_max;
stream >> heartbeat_delay;
if (!frameMax)
frameMax = frame_max;
channelMax = !channelMax ? channel_max : qMax(channel_max, channelMax);
heartbeatDelay = !heartbeatDelay ? heartbeat_delay: heartbeatDelay;
qAmqpDebug("-> connection#tune( channel_max=%d, frame_max=%d, heartbeat=%d )",
channelMax, frameMax, heartbeatDelay);
if (heartbeatTimer) {
heartbeatTimer->setInterval(heartbeatDelay * 1000);
if (heartbeatTimer->interval())
heartbeatTimer->start();
else
heartbeatTimer->stop();
}
tuneOk();
open();
}
void QAmqpClientPrivate::openOk(const QAmqpMethodFrame &frame)
{
Q_Q(QAmqpClient);
Q_UNUSED(frame)
qAmqpDebug("-> connection#openOk()");
connected = true;
Q_EMIT q->connected();
}
void QAmqpClientPrivate::closeOk(const QAmqpMethodFrame &frame)
{
Q_UNUSED(frame)
qAmqpDebug("-> connection#closeOk()");
closeConnection();
}
void QAmqpClientPrivate::close(const QAmqpMethodFrame &frame)
{
Q_Q(QAmqpClient);
QByteArray data = frame.arguments();
QDataStream stream(&data, QIODevice::ReadOnly);
qint16 code = 0, classId, methodId;
stream >> code;
QString text = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::ShortString).toString();
stream >> classId;
stream >> methodId;
qAmqpDebug("-> connection#close( reply-code=%d, reply-text=%s, class-id=%d, method-id:%d )",
code, qPrintable(text), classId, methodId);
QAMQP::Error checkError = static_cast<QAMQP::Error>(code);
if (checkError != QAMQP::NoError) {
error = checkError;
errorString = qPrintable(text);
Q_EMIT q->error(error);
// if it was a force disconnect, simulate receiving a closeOk
if (checkError == QAMQP::ConnectionForcedError) {
closeConnection();
if (autoReconnect) {
qAmqpDebug() << "trying to reconnect after: " << timeout << "ms";
QTimer::singleShot(timeout, q, SLOT(_q_connect()));
}
return;
}
}
connected = false;
Q_EMIT q->disconnected();
// complete handshake
QAmqpMethodFrame closeOkFrame(QAmqpFrame::Connection, QAmqpClientPrivate::miCloseOk);
qAmqpDebug("<- connection#closeOk()");
sendFrame(closeOkFrame);
closeConnection();
}
void QAmqpClientPrivate::startOk()
{
QAmqpMethodFrame frame(QAmqpFrame::Connection, QAmqpClientPrivate::miStartOk);
QByteArray arguments;
QDataStream stream(&arguments, QIODevice::WriteOnly);
QAmqpTable clientProperties;
clientProperties["version"] = QString(QAMQP_VERSION);
clientProperties["platform"] = QString("Qt %1").arg(qVersion());
clientProperties["product"] = QString("QAMQP");
#if QT_VERSION >= 0x060000
clientProperties.insert(customProperties);
#else
clientProperties.unite(customProperties);
#endif
stream << clientProperties;
authenticator->write(stream);
QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortString, QLatin1String("en_US"));
frame.setArguments(arguments);
qAmqpDebug("<- connection#startOk()"); // @todo: fill this out
sendFrame(frame);
}
void QAmqpClientPrivate::secureOk()
{
qAmqpDebug("-> connection#secureOk()");
}
void QAmqpClientPrivate::tuneOk()
{
QAmqpMethodFrame frame(QAmqpFrame::Connection, QAmqpClientPrivate::miTuneOk);
QByteArray arguments;
QDataStream stream(&arguments, QIODevice::WriteOnly);
stream << qint16(channelMax);
stream << qint32(frameMax);
stream << qint16(heartbeatDelay);
qAmqpDebug("<- connection#tuneOk( channelMax=%d, frameMax=%d, heartbeatDelay=%d )",
channelMax, frameMax, heartbeatDelay);
frame.setArguments(arguments);
sendFrame(frame);
}
void QAmqpClientPrivate::open()
{
QAmqpMethodFrame frame(QAmqpFrame::Connection, QAmqpClientPrivate::miOpen);
QByteArray arguments;
QDataStream stream(&arguments, QIODevice::WriteOnly);
QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortString, virtualHost);
stream << qint8(0);
stream << qint8(0);
qAmqpDebug("<- connection#open( virtualHost=%s, reserved-1=%d, reserved-2=%d )",
qPrintable(virtualHost), 0, 0);
frame.setArguments(arguments);
sendFrame(frame);
}
void QAmqpClientPrivate::close(int code, const QString &text, int classId, int methodId)
{
QByteArray arguments;
QDataStream stream(&arguments, QIODevice::WriteOnly);
stream << qint16(code);
QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortString, text);
stream << qint16(classId);
stream << qint16(methodId);
qAmqpDebug("<- connection#close( reply-code=%d, reply-text=%s, class-id=%d, method-id:%d )",
code, qPrintable(text), classId, methodId);
QAmqpMethodFrame frame(QAmqpFrame::Connection, QAmqpClientPrivate::miClose);
frame.setArguments(arguments);
sendFrame(frame);
}
//////////////////////////////////////////////////////////////////////////
QAmqpClient::QAmqpClient(QObject *parent)
: QObject(parent),
d_ptr(new QAmqpClientPrivate(this))
{
Q_D(QAmqpClient);
d->init();
}
QAmqpClient::QAmqpClient(QAmqpClientPrivate *dd, QObject *parent)
: QObject(parent),
d_ptr(dd)
{
}
QAmqpClient::~QAmqpClient()
{
Q_D(QAmqpClient);
if (d->connected)
d->_q_disconnect();
}
bool QAmqpClient::isConnected() const
{
Q_D(const QAmqpClient);
return d->connected;
}
quint16 QAmqpClient::port() const
{
Q_D(const QAmqpClient);
return d->port;
}
void QAmqpClient::setPort(quint16 port)
{
Q_D(QAmqpClient);
d->port = port;
}
QString QAmqpClient::host() const
{
Q_D(const QAmqpClient);
return d->host;
}
void QAmqpClient::setHost(const QString &host)
{
Q_D(QAmqpClient);
d->host = host;
}
QString QAmqpClient::virtualHost() const
{
Q_D(const QAmqpClient);
return d->virtualHost;
}
void QAmqpClient::setVirtualHost(const QString &virtualHost)
{
Q_D(QAmqpClient);
d->virtualHost = virtualHost;
}
QString QAmqpClient::username() const
{
Q_D(const QAmqpClient);
const QAmqpAuthenticator *auth = d->authenticator.data();
if (auth && auth->type() == QLatin1String("AMQPLAIN")) {
const QAmqpPlainAuthenticator *a = static_cast<const QAmqpPlainAuthenticator*>(auth);
return a->login();
}
return QString();
}
void QAmqpClient::setUsername(const QString &username)
{
Q_D(QAmqpClient);
d->setUsername(username);
}
QString QAmqpClient::password() const
{
Q_D(const QAmqpClient);
const QAmqpAuthenticator *auth = d->authenticator.data();
if (auth && auth->type() == QLatin1String("AMQPLAIN")) {
const QAmqpPlainAuthenticator *a = static_cast<const QAmqpPlainAuthenticator*>(auth);
return a->password();
}
return QString();
}
void QAmqpClient::setPassword(const QString &password)
{
Q_D(QAmqpClient);
d->setPassword(password);
}
QAmqpExchange *QAmqpClient::createExchange(int channelNumber)
{
return createExchange(QString(), channelNumber);
}
QAmqpExchange *QAmqpClient::createExchange(const QString &name, int channelNumber)
{
Q_D(QAmqpClient);
QAmqpExchange *exchange;
if (d->exchanges.contains(name)) {
exchange = qobject_cast<QAmqpExchange*>(d->exchanges.get(name));
if (exchange)
return exchange;
}
exchange = new QAmqpExchange(channelNumber, this);
d->methodHandlersByChannel[exchange->channelNumber()].append(exchange->d_func());
connect(this, SIGNAL(connected()), exchange, SLOT(_q_open()));
connect(this, SIGNAL(disconnected()), exchange, SLOT(_q_disconnected()));
exchange->d_func()->open();
if (!name.isEmpty())
exchange->setName(name);
d->exchanges.put(exchange);
return exchange;
}
QAmqpQueue *QAmqpClient::createQueue(int channelNumber)
{
return createQueue(QString(), channelNumber);
}
QAmqpQueue *QAmqpClient::createQueue(const QString &name, int channelNumber)
{
Q_D(QAmqpClient);
QAmqpQueue *queue;
if (d->queues.contains(name)) {
queue = qobject_cast<QAmqpQueue*>(d->queues.get(name));
if (queue)
return queue;
}
queue = new QAmqpQueue(channelNumber, this);
d->methodHandlersByChannel[queue->channelNumber()].append(queue->d_func());
d->contentHandlerByChannel[queue->channelNumber()].append(queue->d_func());
d->bodyHandlersByChannel[queue->channelNumber()].append(queue->d_func());
connect(this, SIGNAL(connected()), queue, SLOT(_q_open()));
connect(this, SIGNAL(disconnected()), queue, SLOT(_q_disconnected()));
queue->d_func()->open();
if (!name.isEmpty())
queue->setName(name);
d->queues.put(queue);
return queue;
}
void QAmqpClient::setAuth(QAmqpAuthenticator *authenticator)
{
Q_D(QAmqpClient);
d->authenticator = QSharedPointer<QAmqpAuthenticator>(authenticator);
}
QAmqpAuthenticator *QAmqpClient::auth() const
{
Q_D(const QAmqpClient);
return d->authenticator.data();
}
bool QAmqpClient::autoReconnect() const
{
Q_D(const QAmqpClient);
return d->autoReconnect;
}
void QAmqpClient::setAutoReconnect(bool value, int timeout)
{
Q_D(QAmqpClient);
d->autoReconnect = value;
if((value == true) && (timeout > 0))
{
d->timeout = timeout;
d->reconnectFixedTimeout = true;
}
else
{
d->timeout = 0;
d->reconnectFixedTimeout = false;
}
}
qint16 QAmqpClient::channelMax() const
{
Q_D(const QAmqpClient);
return d->channelMax;
}
void QAmqpClient::setChannelMax(qint16 channelMax)
{
Q_D(QAmqpClient);
if (d->connected) {
qAmqpDebug() << Q_FUNC_INFO << "can't modify value while connected";
return;
}
d->channelMax = channelMax;
}
qint32 QAmqpClient::frameMax() const
{
Q_D(const QAmqpClient);
return d->frameMax;
}
void QAmqpClient::setFrameMax(qint32 frameMax)
{
Q_D(QAmqpClient);
if (d->connected) {
qAmqpDebug() << Q_FUNC_INFO << "can't modify value while connected";
return;
}
d->frameMax = qMax(frameMax, AMQP_FRAME_MIN_SIZE);
}
qint16 QAmqpClient::heartbeatDelay() const
{
Q_D(const QAmqpClient);
return d->heartbeatDelay;
}
void QAmqpClient::setHeartbeatDelay(qint16 delay)
{
Q_D(QAmqpClient);
if (d->connected) {
qAmqpDebug() << Q_FUNC_INFO << "can't modify value while connected";
return;
}
d->heartbeatDelay = delay;
}
int QAmqpClient::writeTimeout() const
{
return QAmqpFrame::writeTimeout();
}
void QAmqpClient::setWriteTimeout(int msecs)
{
QAmqpFrame::setWriteTimeout(msecs);
}
void QAmqpClient::addCustomProperty(const QString &name, const QString &value)
{
Q_D(QAmqpClient);
d->customProperties.insert(name, value);
}
QString QAmqpClient::customProperty(const QString &name) const
{
Q_D(const QAmqpClient);
return d->customProperties.value(name).toString();
}
QAbstractSocket::SocketError QAmqpClient::socketError() const
{
Q_D(const QAmqpClient);
return d->socket->error();
}
QAbstractSocket::SocketState QAmqpClient::socketState() const
{
Q_D(const QAmqpClient);
return d->socket->state();
}
QAMQP::Error QAmqpClient::error() const
{
Q_D(const QAmqpClient);
return d->error;
}
QString QAmqpClient::errorString() const
{
Q_D(const QAmqpClient);
return d->errorString;
}
QSslConfiguration QAmqpClient::sslConfiguration() const
{
Q_D(const QAmqpClient);
return d->socket->sslConfiguration();
}
void QAmqpClient::setSslConfiguration(const QSslConfiguration &config)
{
Q_D(QAmqpClient);
if (!config.isNull()) {
d->useSsl = true;
d->port = AMQP_SSL_PORT;
d->socket->setSslConfiguration(config);
}
}
QString QAmqpClient::gitVersion()
{
return QString(GIT_VERSION);
}
void QAmqpClient::ignoreSslErrors(const QList<QSslError> &errors)
{
Q_D(QAmqpClient);
d->socket->ignoreSslErrors(errors);
}
void QAmqpClient::connectToHost(const QString &uri)
{
Q_D(QAmqpClient);
if (uri.isEmpty()) {
d->_q_connect();
return;
}
d->parseConnectionString(uri);
d->_q_connect();
}
void QAmqpClient::connectToHost(const QHostAddress &address, quint16 port)
{
Q_D(QAmqpClient);
d->host = address.toString();
d->port = port;
d->_q_connect();
}
void QAmqpClient::disconnectFromHost()
{
Q_D(QAmqpClient);
d->_q_disconnect();
}
void QAmqpClient::abort()
{
Q_D(QAmqpClient);
d->closeConnection();
}
#include "moc_qamqpclient.cpp"

146
qamqp/src/qamqpclient.h Normal file
View File

@ -0,0 +1,146 @@
/*
* Copyright (C) 2012-2014 Alexey Shcherbakov
* Copyright (C) 2014-2015 Matt Broadstone
* Contact: https://github.com/mbroadst/qamqp
*
* This file is part of the QAMQP Library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef QAMQPCLIENT_H
#define QAMQPCLIENT_H
#include <QObject>
#include <QUrl>
#include <QHostAddress>
#include <QSslConfiguration>
#include <QSslError>
#include "qamqpglobal.h"
class QAmqpExchange;
class QAmqpQueue;
class QAmqpAuthenticator;
class QAmqpClientPrivate;
class QAMQP_EXPORT QAmqpClient : public QObject
{
Q_OBJECT
Q_PROPERTY(quint32 port READ port WRITE setPort)
Q_PROPERTY(QString host READ host WRITE setHost)
Q_PROPERTY(QString virtualHost READ virtualHost WRITE setVirtualHost)
Q_PROPERTY(QString user READ username WRITE setUsername)
Q_PROPERTY(QString password READ password WRITE setPassword)
Q_PROPERTY(bool autoReconnect READ autoReconnect WRITE setAutoReconnect)
Q_PROPERTY(qint16 channelMax READ channelMax WRITE setChannelMax)
Q_PROPERTY(qint32 frameMax READ frameMax WRITE setFrameMax)
Q_PROPERTY(qint16 heartbeatDelay READ heartbeatDelay() WRITE setHeartbeatDelay)
public:
explicit QAmqpClient(QObject *parent = 0);
~QAmqpClient();
// properties
quint16 port() const;
void setPort(quint16 port);
QString host() const;
void setHost(const QString &host);
QString virtualHost() const;
void setVirtualHost(const QString &virtualHost);
QString username() const;
void setUsername(const QString &username);
QString password() const;
void setPassword(const QString &password);
void setAuth(QAmqpAuthenticator *auth);
QAmqpAuthenticator *auth() const;
bool autoReconnect() const;
void setAutoReconnect(bool value, int timeout = 0);
bool isConnected() const;
qint16 channelMax() const;
void setChannelMax(qint16 channelMax);
qint32 frameMax() const;
void setFrameMax(qint32 frameMax);
qint16 heartbeatDelay() const;
void setHeartbeatDelay(qint16 delay);
int writeTimeout() const;
void setWriteTimeout(int msecs);
void addCustomProperty(const QString &name, const QString &value);
QString customProperty(const QString &name) const;
QAbstractSocket::SocketError socketError() const;
QAbstractSocket::SocketState socketState() const;
QAMQP::Error error() const;
QString errorString() const;
QSslConfiguration sslConfiguration() const;
void setSslConfiguration(const QSslConfiguration &config);
static QString gitVersion();
// channels
QAmqpExchange *createExchange(int channelNumber = -1);
QAmqpExchange *createExchange(const QString &name, int channelNumber = -1);
QAmqpQueue *createQueue(int channelNumber = -1);
QAmqpQueue *createQueue(const QString &name, int channelNumber = -1);
// methods
void connectToHost(const QString &uri = QString());
void connectToHost(const QHostAddress &address, quint16 port = AMQP_PORT);
void disconnectFromHost();
void abort();
Q_SIGNALS:
void connected();
void disconnected();
void heartbeat();
void error(QAMQP::Error error);
void socketErrorOccurred(QAbstractSocket::SocketError error);
void socketStateChanged(QAbstractSocket::SocketState state);
void sslErrors(const QList<QSslError> &errors);
public Q_SLOTS:
void ignoreSslErrors(const QList<QSslError> &errors);
protected:
QAmqpClient(QAmqpClientPrivate *dd, QObject *parent = 0);
Q_DISABLE_COPY(QAmqpClient)
Q_DECLARE_PRIVATE(QAmqpClient)
QScopedPointer<QAmqpClientPrivate> d_ptr;
private:
Q_PRIVATE_SLOT(d_func(), void _q_socketConnected())
Q_PRIVATE_SLOT(d_func(), void _q_socketDisconnected())
Q_PRIVATE_SLOT(d_func(), void _q_readyRead())
Q_PRIVATE_SLOT(d_func(), void _q_socketError(QAbstractSocket::SocketError error))
Q_PRIVATE_SLOT(d_func(), void _q_heartbeat())
Q_PRIVATE_SLOT(d_func(), void _q_connect())
Q_PRIVATE_SLOT(d_func(), void _q_disconnect())
friend class QAmqpChannelPrivate;
friend class QAmqpQueuePrivate;
};
#endif // QAMQPCLIENT_H

120
qamqp/src/qamqpclient_p.h Normal file
View File

@ -0,0 +1,120 @@
#ifndef QAMQPCLIENT_P_H
#define QAMQPCLIENT_P_H
#include <QHash>
#include <QSharedPointer>
#include <QPointer>
#include <QAbstractSocket>
#include <QSslError>
#include "qamqpchannelhash_p.h"
#include "qamqpglobal.h"
#include "qamqpauthenticator.h"
#include "qamqptable.h"
#include "qamqpframe_p.h"
#define METHOD_ID_ENUM(name, id) name = id, name ## Ok
class QTimer;
class QSslSocket;
class QAmqpClient;
class QAmqpQueue;
class QAmqpExchange;
class QAmqpConnection;
class QAmqpAuthenticator;
class QAMQP_EXPORT QAmqpClientPrivate : public QAmqpMethodFrameHandler
{
public:
enum MethodId {
METHOD_ID_ENUM(miStart, 10),
METHOD_ID_ENUM(miSecure, 20),
METHOD_ID_ENUM(miTune, 30),
METHOD_ID_ENUM(miOpen, 40),
METHOD_ID_ENUM(miClose, 50)
};
QAmqpClientPrivate(QAmqpClient *q);
virtual ~QAmqpClientPrivate();
virtual void init();
virtual void initSocket();
void resetChannelState();
void setUsername(const QString &username);
void setPassword(const QString &password);
void parseConnectionString(const QString &uri);
void sendFrame(const QAmqpFrame &frame);
void closeConnection();
// private slots
void _q_socketConnected();
void _q_socketDisconnected();
void _q_readyRead();
void _q_socketError(QAbstractSocket::SocketError error);
void _q_heartbeat();
virtual void _q_connect();
void _q_disconnect();
virtual bool _q_method(const QAmqpMethodFrame &frame);
// method handlers, FROM server
void start(const QAmqpMethodFrame &frame);
void secure(const QAmqpMethodFrame &frame);
void tune(const QAmqpMethodFrame &frame);
void openOk(const QAmqpMethodFrame &frame);
void closeOk(const QAmqpMethodFrame &frame);
// method handlers, TO server
void startOk();
void secureOk();
void tuneOk();
void open();
// method handlers, BOTH ways
void close(int code, const QString &text, int classId = 0, int methodId = 0);
void close(const QAmqpMethodFrame &frame);
quint16 port;
QString host;
QString virtualHost;
QSharedPointer<QAmqpAuthenticator> authenticator;
// Network
QByteArray buffer;
bool autoReconnect;
bool reconnectFixedTimeout;
int timeout;
bool connecting;
bool useSsl;
QSslSocket *socket;
QHash<quint16, QList<QAmqpMethodFrameHandler*> > methodHandlersByChannel;
QHash<quint16, QList<QAmqpContentFrameHandler*> > contentHandlerByChannel;
QHash<quint16, QList<QAmqpContentBodyFrameHandler*> > bodyHandlersByChannel;
// Connection
bool closed;
bool connected;
QPointer<QTimer> heartbeatTimer;
QPointer<QTimer> reconnectTimer;
QAmqpTable customProperties;
qint16 channelMax;
qint16 heartbeatDelay;
qint32 frameMax;
QAMQP::Error error;
QString errorString;
/*! Exchange objects */
QAmqpChannelHash exchanges;
/*! Named queue objects */
QAmqpChannelHash queues;
QAmqpClient * const q_ptr;
Q_DECLARE_PUBLIC(QAmqpClient)
};
#endif // QAMQPCLIENT_P_H

369
qamqp/src/qamqpexchange.cpp Normal file
View File

@ -0,0 +1,369 @@
#include <QEventLoop>
#include <QDataStream>
#include <QTimer>
#include <QDebug>
#include "qamqpexchange.h"
#include "qamqpexchange_p.h"
#include "qamqpqueue.h"
#include "qamqpglobal.h"
#include "qamqpclient.h"
QString QAmqpExchangePrivate::typeToString(QAmqpExchange::ExchangeType type)
{
switch (type) {
case QAmqpExchange::Direct: return QLatin1String("direct");
case QAmqpExchange::FanOut: return QLatin1String("fanout");
case QAmqpExchange::Topic: return QLatin1String("topic");
case QAmqpExchange::Headers: return QLatin1String("headers");
}
return QLatin1String("direct");
}
QAmqpExchangePrivate::QAmqpExchangePrivate(QAmqpExchange *q)
: QAmqpChannelPrivate(q),
delayedDeclare(false),
declared(false),
nextDeliveryTag(0)
{
}
void QAmqpExchangePrivate::resetInternalState()
{
QAmqpChannelPrivate::resetInternalState();
delayedDeclare = false;
declared = false;
nextDeliveryTag = 0;
}
void QAmqpExchangePrivate::declare()
{
if (!opened) {
delayedDeclare = true;
return;
}
if (name.isEmpty()) {
qAmqpDebug() << Q_FUNC_INFO << "attempting to declare an unnamed exchange, aborting...";
return;
}
QAmqpMethodFrame frame(QAmqpFrame::Exchange, QAmqpExchangePrivate::miDeclare);
frame.setChannel(channelNumber);
QByteArray args;
QDataStream stream(&args, QIODevice::WriteOnly);
stream << qint16(0); //reserved 1
QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortString, name);
QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortString, type);
stream << qint8(options);
QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::Hash, arguments);
qAmqpDebug("<- exchange#declare( name=%s, type=%s, passive=%d, durable=%d, no-wait=%d )",
qPrintable(name), qPrintable(type),
options.testFlag(QAmqpExchange::Passive), options.testFlag(QAmqpExchange::Durable),
options.testFlag(QAmqpExchange::NoWait));
frame.setArguments(args);
sendFrame(frame);
delayedDeclare = false;
}
bool QAmqpExchangePrivate::_q_method(const QAmqpMethodFrame &frame)
{
Q_Q(QAmqpExchange);
if (QAmqpChannelPrivate::_q_method(frame))
return true;
if (frame.methodClass() == QAmqpFrame::Basic) {
switch (frame.id()) {
case bmAck:
case bmNack:
handleAckOrNack(frame);
break;
case bmReturn: basicReturn(frame); break;
default:
break;
}
return true;
}
if (frame.methodClass() == QAmqpFrame::Confirm) {
if (frame.id() == cmConfirmOk) {
Q_EMIT q->confirmsEnabled();
return true;
}
}
if (frame.methodClass() == QAmqpFrame::Exchange) {
switch (frame.id()) {
case miDeclareOk: declareOk(frame); break;
case miDeleteOk: deleteOk(frame); break;
default:
break;
}
return true;
}
return false;
}
void QAmqpExchangePrivate::declareOk(const QAmqpMethodFrame &frame)
{
Q_UNUSED(frame)
Q_Q(QAmqpExchange);
qAmqpDebug("-> exchange[ %s ]#declareOk()", qPrintable(name));
declared = true;
Q_EMIT q->declared();
}
void QAmqpExchangePrivate::deleteOk(const QAmqpMethodFrame &frame)
{
Q_UNUSED(frame)
Q_Q(QAmqpExchange);
qAmqpDebug("-> exchange#deleteOk[ %s ]()", qPrintable(name));
declared = false;
Q_EMIT q->removed();
}
void QAmqpExchangePrivate::_q_disconnected()
{
QAmqpChannelPrivate::_q_disconnected();
qAmqpDebug() << "exchange disconnected: " << name;
delayedDeclare = false;
declared = false;
unconfirmedDeliveryTags.clear();
}
void QAmqpExchangePrivate::basicReturn(const QAmqpMethodFrame &frame)
{
Q_Q(QAmqpExchange);
QByteArray data = frame.arguments();
QDataStream stream(&data, QIODevice::ReadOnly);
quint16 replyCode;
stream >> replyCode;
QString replyText = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::ShortString).toString();
QString exchangeName = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::ShortString).toString();
QString routingKey = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::ShortString).toString();
QAMQP::Error checkError = static_cast<QAMQP::Error>(replyCode);
if (checkError != QAMQP::NoError) {
error = checkError;
errorString = qPrintable(replyText);
Q_EMIT q->error(error);
}
qAmqpDebug("-> basic#return( reply-code=%d, reply-text=%s, exchange=%s, routing-key=%s )",
replyCode, qPrintable(replyText), qPrintable(exchangeName), qPrintable(routingKey));
}
void QAmqpExchangePrivate::handleAckOrNack(const QAmqpMethodFrame &frame)
{
Q_Q(QAmqpExchange);
QByteArray data = frame.arguments();
QDataStream stream(&data, QIODevice::ReadOnly);
qlonglong deliveryTag =
QAmqpFrame::readAmqpField(stream, QAmqpMetaType::LongLongUint).toLongLong();
bool multiple = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::Boolean).toBool();
if (frame.id() == QAmqpExchangePrivate::bmAck) {
if (deliveryTag == 0) {
unconfirmedDeliveryTags.clear();
} else {
int idx = unconfirmedDeliveryTags.indexOf(deliveryTag);
if (idx == -1) {
return;
}
if (multiple) {
unconfirmedDeliveryTags.remove(0, idx + 1);
} else {
unconfirmedDeliveryTags.remove(idx);
}
}
if (unconfirmedDeliveryTags.isEmpty())
Q_EMIT q->allMessagesDelivered();
} else {
qAmqpDebug() << "nacked(" << deliveryTag << "), multiple=" << multiple;
}
}
//////////////////////////////////////////////////////////////////////////
QAmqpExchange::QAmqpExchange(int channelNumber, QAmqpClient *parent)
: QAmqpChannel(new QAmqpExchangePrivate(this), parent)
{
Q_D(QAmqpExchange);
d->init(channelNumber, parent);
}
QAmqpExchange::~QAmqpExchange()
{
}
void QAmqpExchange::channelOpened()
{
Q_D(QAmqpExchange);
if (d->delayedDeclare)
d->declare();
}
void QAmqpExchange::channelClosed()
{
}
QAmqpExchange::ExchangeOptions QAmqpExchange::options() const
{
Q_D(const QAmqpExchange);
return d->options;
}
QString QAmqpExchange::type() const
{
Q_D(const QAmqpExchange);
return d->type;
}
bool QAmqpExchange::isDeclared() const
{
Q_D(const QAmqpExchange);
return d->declared;
}
void QAmqpExchange::declare(ExchangeType type, ExchangeOptions options, const QAmqpTable &args)
{
declare(QAmqpExchangePrivate::typeToString(type), options, args);
}
void QAmqpExchange::declare(const QString &type, ExchangeOptions options, const QAmqpTable &args)
{
Q_D(QAmqpExchange);
d->type = type;
d->options = options;
d->arguments = args;
d->declare();
}
void QAmqpExchange::remove(int options)
{
Q_D(QAmqpExchange);
QAmqpMethodFrame frame(QAmqpFrame::Exchange, QAmqpExchangePrivate::miDelete);
frame.setChannel(d->channelNumber);
QByteArray arguments;
QDataStream stream(&arguments, QIODevice::WriteOnly);
stream << qint16(0); //reserved 1
QAmqpFrame::writeAmqpField(stream, QAmqpMetaType::ShortString, d->name);
stream << qint8(options);
qAmqpDebug("<- exchange#delete( exchange=%s, if-unused=%d, no-wait=%d )",
qPrintable(d->name), options & QAmqpExchange::roIfUnused, options & QAmqpExchange::roNoWait);
frame.setArguments(arguments);
d->sendFrame(frame);
}
void QAmqpExchange::publish(const QString &message, const QString &routingKey,
const QAmqpMessage::PropertyHash &properties, int publishOptions)
{
publish(message.toUtf8(), routingKey, QLatin1String("text.plain"),
QAmqpTable(), properties, publishOptions);
}
void QAmqpExchange::publish(const QByteArray &message, const QString &routingKey,
const QString &mimeType, const QAmqpMessage::PropertyHash &properties,
int publishOptions)
{
publish(message, routingKey, mimeType, QAmqpTable(), properties, publishOptions);
}
void QAmqpExchange::publish(const QByteArray &message, const QString &routingKey,
const QString &mimeType, const QAmqpTable &headers,
const QAmqpMessage::PropertyHash &properties, int publishOptions)
{
Q_D(QAmqpExchange);
if (d->nextDeliveryTag > 0) {
d->unconfirmedDeliveryTags.append(d->nextDeliveryTag);
d->nextDeliveryTag++;
}
QAmqpMethodFrame frame(QAmqpFrame::Basic, QAmqpExchangePrivate::bmPublish);
frame.setChannel(d->channelNumber);
QByteArray arguments;
QDataStream out(&arguments, QIODevice::WriteOnly);
out << qint16(0); //reserved 1
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->name);
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, routingKey);
out << qint8(publishOptions);
qAmqpDebug("<- basic#publish( exchange=%s, routing-key=%s, mandatory=%d, immediate=%d )",
qPrintable(d->name), qPrintable(routingKey),
publishOptions & QAmqpExchange::poMandatory, publishOptions & QAmqpExchange::poImmediate);
frame.setArguments(arguments);
d->sendFrame(frame);
QAmqpContentFrame content(QAmqpFrame::Basic);
content.setChannel(d->channelNumber);
content.setProperty(QAmqpMessage::ContentType, mimeType);
content.setProperty(QAmqpMessage::ContentEncoding, "utf-8");
content.setProperty(QAmqpMessage::Headers, headers);
QAmqpMessage::PropertyHash::ConstIterator it;
QAmqpMessage::PropertyHash::ConstIterator itEnd = properties.constEnd();
for (it = properties.constBegin(); it != itEnd; ++it)
content.setProperty(it.key(), it.value());
content.setBodySize(message.size());
d->sendFrame(content);
int fullSize = message.size();
for (int sent = 0; sent < fullSize; sent += (d->client->frameMax() - 7)) {
QAmqpContentBodyFrame body;
QByteArray partition = message.mid(sent, (d->client->frameMax() - 7));
body.setChannel(d->channelNumber);
body.setBody(partition);
d->sendFrame(body);
}
}
void QAmqpExchange::enableConfirms(bool noWait)
{
Q_D(QAmqpExchange);
QAmqpMethodFrame frame(QAmqpFrame::Confirm, QAmqpExchangePrivate::cmConfirm);
frame.setChannel(d->channelNumber);
QByteArray arguments;
QDataStream stream(&arguments, QIODevice::WriteOnly);
stream << qint8(noWait ? 1 : 0);
frame.setArguments(arguments);
d->sendFrame(frame);
// for tracking acks and nacks
if (d->nextDeliveryTag == 0) d->nextDeliveryTag = 1;
}
bool QAmqpExchange::waitForConfirms(int msecs)
{
Q_D(QAmqpExchange);
QEventLoop loop;
connect(this, SIGNAL(allMessagesDelivered()), &loop, SLOT(quit()));
QTimer::singleShot(msecs, &loop, SLOT(quit()));
loop.exec();
return (d->unconfirmedDeliveryTags.isEmpty());
}

123
qamqp/src/qamqpexchange.h Normal file
View File

@ -0,0 +1,123 @@
/*
* Copyright (C) 2012-2014 Alexey Shcherbakov
* Copyright (C) 2014-2015 Matt Broadstone
* Contact: https://github.com/mbroadst/qamqp
*
* This file is part of the QAMQP Library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef QAMQPEXCHANGE_H
#define QAMQPEXCHANGE_H
#include "qamqptable.h"
#include "qamqpchannel.h"
#include "qamqpmessage.h"
class QAmqpClient;
class QAmqpQueue;
class QAmqpClientPrivate;
class QAmqpExchangePrivate;
class QAMQP_EXPORT QAmqpExchange : public QAmqpChannel
{
Q_OBJECT
Q_PROPERTY(QString type READ type CONSTANT)
Q_PROPERTY(ExchangeOptions options READ options CONSTANT)
public:
virtual ~QAmqpExchange();
enum ExchangeType {
Direct,
FanOut,
Topic,
Headers
};
QString type() const;
enum PublishOption {
poNoOptions = 0x0,
poMandatory = 0x01,
poImmediate = 0x02
};
Q_DECLARE_FLAGS(PublishOptions, PublishOption)
enum RemoveOption {
roForce = 0x0,
roIfUnused = 0x01,
roNoWait = 0x04
};
Q_DECLARE_FLAGS(RemoveOptions, RemoveOption)
enum ExchangeOption {
NoOptions = 0x0,
Passive = 0x01,
Durable = 0x02,
AutoDelete = 0x04,
Internal = 0x08,
NoWait = 0x10
};
Q_DECLARE_FLAGS(ExchangeOptions, ExchangeOption)
ExchangeOptions options() const;
Q_ENUM(ExchangeOptions)
bool isDeclared() const;
void enableConfirms(bool noWait = false);
bool waitForConfirms(int msecs = 30000);
Q_SIGNALS:
void declared();
void removed();
void confirmsEnabled();
void allMessagesDelivered();
public Q_SLOTS:
// AMQP Exchange
void declare(QAmqpExchange::ExchangeType type = Direct,
QAmqpExchange::ExchangeOptions options = NoOptions,
const QAmqpTable &args = QAmqpTable());
void declare(const QString &type,
QAmqpExchange::ExchangeOptions options = NoOptions,
const QAmqpTable &args = QAmqpTable());
void remove(int options = roIfUnused|roNoWait);
// AMQP Basic
void publish(const QString &message, const QString &routingKey,
const QAmqpMessage::PropertyHash &properties = QAmqpMessage::PropertyHash(),
int publishOptions = poNoOptions);
void publish(const QByteArray &message, const QString &routingKey, const QString &mimeType,
const QAmqpMessage::PropertyHash &properties = QAmqpMessage::PropertyHash(),
int publishOptions = poNoOptions);
void publish(const QByteArray &message, const QString &routingKey,
const QString &mimeType, const QAmqpTable &headers,
const QAmqpMessage::PropertyHash &properties = QAmqpMessage::PropertyHash(),
int publishOptions = poNoOptions);
protected:
virtual void channelOpened();
virtual void channelClosed();
private:
explicit QAmqpExchange(int channelNumber = -1, QAmqpClient *parent = 0);
Q_DISABLE_COPY(QAmqpExchange)
Q_DECLARE_PRIVATE(QAmqpExchange)
friend class QAmqpClient;
friend class QAmqpClientPrivate;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QAmqpExchange::ExchangeOptions)
Q_DECLARE_METATYPE(QAmqpExchange::ExchangeType)
#endif // QAMQPEXCHANGE_H

View File

@ -0,0 +1,45 @@
#ifndef QAMQPEXCHANGE_P_H
#define QAMQPEXCHANGE_P_H
#include "qamqptable.h"
#include "qamqpexchange.h"
#include "qamqpchannel_p.h"
class QAmqpExchangePrivate: public QAmqpChannelPrivate
{
public:
enum MethodId {
METHOD_ID_ENUM(miDeclare, 10),
METHOD_ID_ENUM(miDelete, 20)
};
enum ConfirmMethod {
METHOD_ID_ENUM(cmConfirm, 10)
};
QAmqpExchangePrivate(QAmqpExchange *q);
static QString typeToString(QAmqpExchange::ExchangeType type);
virtual void resetInternalState();
void declare();
// method handler related
virtual void _q_disconnected();
virtual bool _q_method(const QAmqpMethodFrame &frame);
void declareOk(const QAmqpMethodFrame &frame);
void deleteOk(const QAmqpMethodFrame &frame);
void basicReturn(const QAmqpMethodFrame &frame);
void handleAckOrNack(const QAmqpMethodFrame &frame);
QString type;
QAmqpExchange::ExchangeOptions options;
bool delayedDeclare;
bool declared;
qlonglong nextDeliveryTag;
QVector<qlonglong> unconfirmedDeliveryTags;
Q_DECLARE_PUBLIC(QAmqpExchange)
};
#endif // QAMQPEXCHANGE_P_H

486
qamqp/src/qamqpframe.cpp Normal file
View File

@ -0,0 +1,486 @@
#include <QDateTime>
#include <QDebug>
#include <QIODevice>
#include <QList>
#include "qamqptable.h"
#include "qamqpglobal.h"
#include "qamqpframe_p.h"
QReadWriteLock QAmqpFrame::lock_;
int QAmqpFrame::writeTimeout_ = 1000;
QAmqpFrame::QAmqpFrame(FrameType type)
: size_(0),
type_(type),
channel_(0)
{
}
QAmqpFrame::FrameType QAmqpFrame::type() const
{
return static_cast<QAmqpFrame::FrameType>(type_);
}
QAmqpFrame::~QAmqpFrame()
{
}
void QAmqpFrame::setChannel(quint16 channel)
{
channel_ = channel;
}
int QAmqpFrame::writeTimeout()
{
QReadLocker locker(&lock_);
return writeTimeout_;
}
void QAmqpFrame::setWriteTimeout(int msecs)
{
QWriteLocker locker(&lock_);
writeTimeout_ = msecs;
}
quint16 QAmqpFrame::channel() const
{
return channel_;
}
qint32 QAmqpFrame::size() const
{
return 0;
}
/*
void QAmqpFrame::readEnd(QDataStream &stream)
{
unsigned char end_ = 0;
stream.readRawData(reinterpret_cast<char*>(&end_), sizeof(end_));
if (end_ != FRAME_END)
qAmqpDebug("Wrong end of frame");
}
*/
QDataStream &operator<<(QDataStream &stream, const QAmqpFrame &frame)
{
// write header
stream << frame.type_;
stream << frame.channel_;
stream << frame.size();
frame.writePayload(stream);
// write end
stream << qint8(QAmqpFrame::FRAME_END);
int writeTimeout = QAmqpFrame::writeTimeout();
if(writeTimeout >= -1)
{
stream.device()->waitForBytesWritten(writeTimeout);
}
return stream;
}
QDataStream &operator>>(QDataStream &stream, QAmqpFrame &frame)
{
stream >> frame.type_;
stream >> frame.channel_;
stream >> frame.size_;
frame.readPayload(stream);
return stream;
}
//////////////////////////////////////////////////////////////////////////
QAmqpMethodFrame::QAmqpMethodFrame()
: QAmqpFrame(QAmqpFrame::Method),
methodClass_(0),
id_(0)
{
}
QAmqpMethodFrame::QAmqpMethodFrame(MethodClass methodClass, qint16 id)
: QAmqpFrame(QAmqpFrame::Method),
methodClass_(methodClass),
id_(id)
{
}
QAmqpFrame::MethodClass QAmqpMethodFrame::methodClass() const
{
return MethodClass(methodClass_);
}
qint16 QAmqpMethodFrame::id() const
{
return id_;
}
qint32 QAmqpMethodFrame::size() const
{
return sizeof(id_) + sizeof(methodClass_) + arguments_.size();
}
void QAmqpMethodFrame::setArguments(const QByteArray &data)
{
arguments_ = data;
}
QByteArray QAmqpMethodFrame::arguments() const
{
return arguments_;
}
void QAmqpMethodFrame::readPayload(QDataStream &stream)
{
stream >> methodClass_;
stream >> id_;
arguments_.resize(size_ - (sizeof(id_) + sizeof(methodClass_)));
stream.readRawData(arguments_.data(), arguments_.size());
}
void QAmqpMethodFrame::writePayload(QDataStream &stream) const
{
stream << quint16(methodClass_);
stream << quint16(id_);
stream.writeRawData(arguments_.data(), arguments_.size());
}
//////////////////////////////////////////////////////////////////////////
QVariant QAmqpFrame::readAmqpField(QDataStream &s, QAmqpMetaType::ValueType type)
{
switch (type) {
case QAmqpMetaType::Boolean:
{
quint8 octet = 0;
s >> octet;
return QVariant::fromValue<bool>(octet > 0);
}
case QAmqpMetaType::ShortShortUint:
{
quint8 octet = 0;
s >> octet;
return QVariant::fromValue<int>(octet);
}
case QAmqpMetaType::ShortUint:
{
quint16 tmp_value = 0;
s >> tmp_value;
return QVariant::fromValue<uint>(tmp_value);
}
case QAmqpMetaType::LongUint:
{
quint32 tmp_value = 0;
s >> tmp_value;
return QVariant::fromValue<uint>(tmp_value);
}
case QAmqpMetaType::LongLongUint:
{
qulonglong v = 0 ;
s >> v;
return v;
}
case QAmqpMetaType::ShortString:
{
qint8 size = 0;
QByteArray buffer;
s >> size;
buffer.resize(size);
s.readRawData(buffer.data(), buffer.size());
return QString::fromLatin1(buffer.data(), size);
}
case QAmqpMetaType::LongString:
{
quint32 size = 0;
QByteArray buffer;
s >> size;
buffer.resize(size);
s.readRawData(buffer.data(), buffer.size());
return QString::fromUtf8(buffer.data(), buffer.size());
}
case QAmqpMetaType::Timestamp:
{
qulonglong tmp_value;
s >> tmp_value;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
return QDateTime::fromSecsSinceEpoch(tmp_value);
#else
return QDateTime::fromTime_t(tmp_value);
#endif
}
case QAmqpMetaType::Hash:
{
QAmqpTable table;
s >> table;
return table;
}
case QAmqpMetaType::Void:
return QVariant();
default:
qAmqpDebug() << Q_FUNC_INFO << "unsupported value type: " << type;
}
return QVariant();
}
void QAmqpFrame::writeAmqpField(QDataStream &s, QAmqpMetaType::ValueType type, const QVariant &value)
{
switch (type) {
case QAmqpMetaType::Boolean:
s << (value.toBool() ? qint8(1) : qint8(0));
break;
case QAmqpMetaType::ShortShortUint:
s << qint8(value.toUInt());
break;
case QAmqpMetaType::ShortUint:
s << quint16(value.toUInt());
break;
case QAmqpMetaType::LongUint:
s << quint32(value.toUInt());
break;
case QAmqpMetaType::LongLongUint:
s << qulonglong(value.toULongLong());
break;
case QAmqpMetaType::ShortString:
{
QString str = value.toString();
if (str.length() >= 256) {
qAmqpDebug() << Q_FUNC_INFO << "invalid shortstr length: " << str.length();
}
s << quint8(str.length());
s.writeRawData(str.toUtf8().data(), str.length());
}
break;
case QAmqpMetaType::LongString:
{
QString str = value.toString();
s << quint32(str.length());
s.writeRawData(str.toLatin1().data(), str.length());
}
break;
case QAmqpMetaType::Timestamp:
#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
s << qulonglong(value.toDateTime().toSecsSinceEpoch());
#else
s << qulonglong(value.toDateTime().toTime_t());
#endif
break;
case QAmqpMetaType::Hash:
{
QAmqpTable table(value.toHash());
s << table;
}
break;
default:
qAmqpDebug() << Q_FUNC_INFO << "unsupported value type: " << type;
}
}
//////////////////////////////////////////////////////////////////////////
QAmqpContentFrame::QAmqpContentFrame()
: QAmqpFrame(QAmqpFrame::Header)
{
}
QAmqpContentFrame::QAmqpContentFrame(QAmqpFrame::MethodClass methodClass)
: QAmqpFrame(QAmqpFrame::Header)
{
methodClass_ = methodClass;
}
QAmqpFrame::MethodClass QAmqpContentFrame::methodClass() const
{
return MethodClass(methodClass_);
}
qint32 QAmqpContentFrame::size() const
{
QDataStream out(&buffer_, QIODevice::WriteOnly);
buffer_.clear();
out << qint16(methodClass_);
out << qint16(0); //weight
out << qlonglong(bodySize_);
qint16 prop_ = 0;
foreach (int p, properties_.keys())
prop_ |= p;
out << prop_;
if (prop_ & QAmqpMessage::ContentType)
writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::ContentType]);
if (prop_ & QAmqpMessage::ContentEncoding)
writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::ContentEncoding]);
if (prop_ & QAmqpMessage::Headers)
writeAmqpField(out, QAmqpMetaType::Hash, properties_[QAmqpMessage::Headers]);
if (prop_ & QAmqpMessage::DeliveryMode)
writeAmqpField(out, QAmqpMetaType::ShortShortUint, properties_[QAmqpMessage::DeliveryMode]);
if (prop_ & QAmqpMessage::Priority)
writeAmqpField(out, QAmqpMetaType::ShortShortUint, properties_[QAmqpMessage::Priority]);
if (prop_ & QAmqpMessage::CorrelationId)
writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::CorrelationId]);
if (prop_ & QAmqpMessage::ReplyTo)
writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::ReplyTo]);
if (prop_ & QAmqpMessage::Expiration)
writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::Expiration]);
if (prop_ & QAmqpMessage::MessageId)
writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::MessageId]);
if (prop_ & QAmqpMessage::Timestamp)
writeAmqpField(out, QAmqpMetaType::Timestamp, properties_[QAmqpMessage::Timestamp]);
if (prop_ & QAmqpMessage::Type)
writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::Type]);
if (prop_ & QAmqpMessage::UserId)
writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::UserId]);
if (prop_ & QAmqpMessage::AppId)
writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::AppId]);
if (prop_ & QAmqpMessage::ClusterID)
writeAmqpField(out, QAmqpMetaType::ShortString, properties_[QAmqpMessage::ClusterID]);
return buffer_.size();
}
qlonglong QAmqpContentFrame::bodySize() const
{
return bodySize_;
}
void QAmqpContentFrame::setBodySize(qlonglong size)
{
bodySize_ = size;
}
void QAmqpContentFrame::setProperty(QAmqpMessage::Property prop, const QVariant &value)
{
properties_[prop] = value;
}
QVariant QAmqpContentFrame::property(QAmqpMessage::Property prop) const
{
return properties_.value(prop);
}
void QAmqpContentFrame::writePayload(QDataStream &out) const
{
out.writeRawData(buffer_.data(), buffer_.size());
}
void QAmqpContentFrame::readPayload(QDataStream &in)
{
in >> methodClass_;
in.skipRawData(2); //weight
in >> bodySize_;
qint16 flags_ = 0;
in >> flags_;
if (flags_ & QAmqpMessage::ContentType)
properties_[QAmqpMessage::ContentType] = readAmqpField(in, QAmqpMetaType::ShortString);
if (flags_ & QAmqpMessage::ContentEncoding)
properties_[QAmqpMessage::ContentEncoding] = readAmqpField(in, QAmqpMetaType::ShortString);
if (flags_ & QAmqpMessage::Headers)
properties_[QAmqpMessage::Headers] = readAmqpField(in, QAmqpMetaType::Hash);
if (flags_ & QAmqpMessage::DeliveryMode)
properties_[QAmqpMessage::DeliveryMode] = readAmqpField(in, QAmqpMetaType::ShortShortUint);
if (flags_ & QAmqpMessage::Priority)
properties_[QAmqpMessage::Priority] = readAmqpField(in, QAmqpMetaType::ShortShortUint);
if (flags_ & QAmqpMessage::CorrelationId)
properties_[QAmqpMessage::CorrelationId] = readAmqpField(in, QAmqpMetaType::ShortString);
if (flags_ & QAmqpMessage::ReplyTo)
properties_[QAmqpMessage::ReplyTo] = readAmqpField(in, QAmqpMetaType::ShortString);
if (flags_ & QAmqpMessage::Expiration)
properties_[QAmqpMessage::Expiration] = readAmqpField(in, QAmqpMetaType::ShortString);
if (flags_ & QAmqpMessage::MessageId)
properties_[QAmqpMessage::MessageId] = readAmqpField(in, QAmqpMetaType::ShortString);
if (flags_ & QAmqpMessage::Timestamp)
properties_[QAmqpMessage::Timestamp] = readAmqpField(in, QAmqpMetaType::Timestamp);
if (flags_ & QAmqpMessage::Type)
properties_[QAmqpMessage::Type] = readAmqpField(in, QAmqpMetaType::ShortString);
if (flags_ & QAmqpMessage::UserId)
properties_[QAmqpMessage::UserId] = readAmqpField(in, QAmqpMetaType::ShortString);
if (flags_ & QAmqpMessage::AppId)
properties_[QAmqpMessage::AppId] = readAmqpField(in, QAmqpMetaType::ShortString);
if (flags_ & QAmqpMessage::ClusterID)
properties_[QAmqpMessage::ClusterID] = readAmqpField(in, QAmqpMetaType::ShortString);
}
//////////////////////////////////////////////////////////////////////////
QAmqpContentBodyFrame::QAmqpContentBodyFrame()
: QAmqpFrame(QAmqpFrame::Body)
{
}
void QAmqpContentBodyFrame::setBody(const QByteArray &data)
{
body_ = data;
}
QByteArray QAmqpContentBodyFrame::body() const
{
return body_;
}
void QAmqpContentBodyFrame::writePayload(QDataStream &out) const
{
out.writeRawData(body_.data(), body_.size());
}
void QAmqpContentBodyFrame::readPayload(QDataStream &in)
{
body_.resize(size_);
in.readRawData(body_.data(), body_.size());
}
qint32 QAmqpContentBodyFrame::size() const
{
return body_.size();
}
//////////////////////////////////////////////////////////////////////////
QAmqpHeartbeatFrame::QAmqpHeartbeatFrame()
: QAmqpFrame(QAmqpFrame::Heartbeat)
{
}
void QAmqpHeartbeatFrame::readPayload(QDataStream &stream)
{
Q_UNUSED(stream)
}
void QAmqpHeartbeatFrame::writePayload(QDataStream &stream) const
{
Q_UNUSED(stream)
}

171
qamqp/src/qamqpframe_p.h Normal file
View File

@ -0,0 +1,171 @@
#ifndef QAMQPFRAME_P_H
#define QAMQPFRAME_P_H
#include <QDataStream>
#include <QReadWriteLock>
#include <QHash>
#include <QVariant>
#include "qamqpglobal.h"
#include "qamqpmessage.h"
class QAmqpFramePrivate;
class QAmqpFrame
{
public:
static const qint64 HEADER_SIZE = 7;
static const qint64 FRAME_END_SIZE = 1;
static const quint8 FRAME_END = 0xCE;
enum FrameType
{
Method = 1,
Header = 2,
Body = 3,
Heartbeat = 8
};
enum MethodClass
{
Connection = 10,
Channel = 20,
Exchange = 40,
Queue = 50,
Basic = 60,
Confirm = 85,
Tx = 90
};
virtual ~QAmqpFrame();
FrameType type() const;
quint16 channel() const;
void setChannel(quint16 channel);
static int writeTimeout();
static void setWriteTimeout(int msecs);
virtual qint32 size() const;
static QVariant readAmqpField(QDataStream &s, QAmqpMetaType::ValueType type);
static void writeAmqpField(QDataStream &s, QAmqpMetaType::ValueType type, const QVariant &value);
protected:
explicit QAmqpFrame(FrameType type);
virtual void writePayload(QDataStream &stream) const = 0;
virtual void readPayload(QDataStream &stream) = 0;
qint32 size_;
private:
qint8 type_;
quint16 channel_;
static QReadWriteLock lock_;
static int writeTimeout_;
friend QDataStream &operator<<(QDataStream &stream, const QAmqpFrame &frame);
friend QDataStream &operator>>(QDataStream &stream, QAmqpFrame &frame);
};
QDataStream &operator<<(QDataStream &, const QAmqpFrame &frame);
QDataStream &operator>>(QDataStream &, QAmqpFrame &frame);
class QAMQP_EXPORT QAmqpMethodFrame : public QAmqpFrame
{
public:
QAmqpMethodFrame();
QAmqpMethodFrame(MethodClass methodClass, qint16 id);
qint16 id() const;
MethodClass methodClass() const;
virtual qint32 size() const;
QByteArray arguments() const;
void setArguments(const QByteArray &data);
private:
void writePayload(QDataStream &stream) const;
void readPayload(QDataStream &stream);
short methodClass_;
qint16 id_;
QByteArray arguments_;
};
class QAmqpContentFrame : public QAmqpFrame
{
public:
QAmqpContentFrame();
QAmqpContentFrame(MethodClass methodClass);
MethodClass methodClass() const;
virtual qint32 size() const;
QVariant property(QAmqpMessage::Property prop) const;
void setProperty(QAmqpMessage::Property prop, const QVariant &value);
qlonglong bodySize() const;
void setBodySize(qlonglong size);
private:
void writePayload(QDataStream &stream) const;
void readPayload(QDataStream &stream);
friend class QAmqpQueuePrivate;
short methodClass_;
qint16 id_;
mutable QByteArray buffer_;
QAmqpMessage::PropertyHash properties_;
qlonglong bodySize_;
};
class QAmqpContentBodyFrame : public QAmqpFrame
{
public:
QAmqpContentBodyFrame();
void setBody(const QByteArray &data);
QByteArray body() const;
virtual qint32 size() const;
private:
void writePayload(QDataStream &stream) const;
void readPayload(QDataStream &stream);
QByteArray body_;
};
class QAmqpHeartbeatFrame : public QAmqpFrame
{
public:
QAmqpHeartbeatFrame();
private:
void writePayload(QDataStream &stream) const;
void readPayload(QDataStream &stream);
};
class QAmqpMethodFrameHandler
{
public:
virtual bool _q_method(const QAmqpMethodFrame &frame) = 0;
};
class QAmqpContentFrameHandler
{
public:
virtual void _q_content(const QAmqpContentFrame &frame) = 0;
};
class QAmqpContentBodyFrameHandler
{
public:
virtual void _q_body(const QAmqpContentBodyFrame &frame) = 0;
};
#endif // QAMQPFRAME_P_H

134
qamqp/src/qamqpglobal.h Normal file
View File

@ -0,0 +1,134 @@
/*
* Copyright (C) 2012-2014 Alexey Shcherbakov
* Copyright (C) 2014-2015 Matt Broadstone
* Contact: https://github.com/mbroadst/qamqp
*
* This file is part of the QAMQP Library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef QAMQPGLOBAL_H
#define QAMQPGLOBAL_H
#include <QMetaType>
#define AMQP_SCHEME "amqp"
#define AMQP_SSL_SCHEME "amqps"
#define AMQP_PORT 5672
#define AMQP_SSL_PORT 5671
#define AMQP_HOST "192.168.46.100"
#define AMQP_VHOST "/"
#define AMQP_LOGIN "ecl3000"
#define AMQP_PSWD "ecl3000"
#define AMQP_FRAME_MAX 131072
#define AMQP_FRAME_MIN_SIZE 4096
#define AMQP_BASIC_CONTENT_TYPE_FLAG (1 << 15)
#define AMQP_BASIC_CONTENT_ENCODING_FLAG (1 << 14)
#define AMQP_BASIC_HEADERS_FLAG (1 << 13)
#define AMQP_BASIC_DELIVERY_MODE_FLAG (1 << 12)
#define AMQP_BASIC_PRIORITY_FLAG (1 << 11)
#define AMQP_BASIC_CORRELATION_ID_FLAG (1 << 10)
#define AMQP_BASIC_REPLY_TO_FLAG (1 << 9)
#define AMQP_BASIC_EXPIRATION_FLAG (1 << 8)
#define AMQP_BASIC_MESSAGE_ID_FLAG (1 << 7)
#define AMQP_BASIC_TIMESTAMP_FLAG (1 << 6)
#define AMQP_BASIC_TYPE_FLAG (1 << 5)
#define AMQP_BASIC_USER_ID_FLAG (1 << 4)
#define AMQP_BASIC_APP_ID_FLAG (1 << 3)
#define AMQP_BASIC_CLUSTER_ID_FLAG (1 << 2)
#define QAMQP_VERSION "0.6.0"
#define AMQP_CONNECTION_FORCED 320
#ifdef QAMQP_SHARED
# ifdef QAMQP_BUILD
# define QAMQP_EXPORT Q_DECL_EXPORT
# else
# define QAMQP_EXPORT Q_DECL_IMPORT
# endif
#else
# define QAMQP_EXPORT
#endif
#define qAmqpDebug if (qEnvironmentVariableIsEmpty("QAMQP_DEBUG")); else qDebug
namespace QAmqpMetaType {
enum ValueType
{
Invalid = -1,
// basic AMQP types
Boolean,
ShortUint,
LongUint,
LongLongUint,
ShortString,
LongString,
// field-value types
ShortShortInt,
ShortShortUint,
ShortInt,
LongInt,
LongLongInt,
Float,
Double,
Decimal,
Array,
Timestamp,
Hash,
Bytes,
Void
};
} // namespace QAmqpMetaType
namespace QAMQP {
enum Error
{
NoError = 0,
ContentTooLargeError = 311,
NoRouteError = 312,
NoConsumersError = 313,
ConnectionForcedError = 320,
InvalidPathError = 402,
AccessRefusedError = 403,
NotFoundError = 404,
ResourceLockedError = 405,
PreconditionFailedError = 406,
FrameError = 501,
SyntaxError = 502,
CommandInvalidError = 503,
ChannelError = 504,
UnexpectedFrameError = 505,
ResourceError = 506,
NotAllowedError = 530,
NotImplementedError = 540,
InternalError = 541
};
struct Decimal
{
qint8 scale;
quint32 value;
};
} // namespace QAMQP
Q_DECLARE_METATYPE(QAMQP::Error)
Q_DECLARE_METATYPE(QAMQP::Decimal)
#endif // QAMQPGLOBAL_H

124
qamqp/src/qamqpmessage.cpp Normal file
View File

@ -0,0 +1,124 @@
#include <QHash>
#include "qamqpmessage.h"
#include "qamqpmessage_p.h"
QAmqpMessagePrivate::QAmqpMessagePrivate()
: deliveryTag(0),
leftSize(0)
{
}
//////////////////////////////////////////////////////////////////////////
QAmqpMessage::QAmqpMessage()
: d(new QAmqpMessagePrivate)
{
}
QAmqpMessage::QAmqpMessage(const QAmqpMessage &other)
: d(other.d)
{
}
QAmqpMessage::~QAmqpMessage()
{
}
QAmqpMessage &QAmqpMessage::operator=(const QAmqpMessage &other)
{
d = other.d;
return *this;
}
bool QAmqpMessage::operator==(const QAmqpMessage &message) const
{
if (message.d == d)
return true;
return (message.d->deliveryTag == d->deliveryTag &&
message.d->redelivered == d->redelivered &&
message.d->exchangeName == d->exchangeName &&
message.d->routingKey == d->routingKey &&
message.d->payload == d->payload &&
message.d->properties == d->properties &&
message.d->headers == d->headers &&
message.d->leftSize == d->leftSize);
}
bool QAmqpMessage::isValid() const
{
return d->deliveryTag != 0 &&
!d->exchangeName.isNull() &&
!d->routingKey.isNull();
}
qlonglong QAmqpMessage::deliveryTag() const
{
return d->deliveryTag;
}
bool QAmqpMessage::isRedelivered() const
{
return d->redelivered;
}
QString QAmqpMessage::exchangeName() const
{
return d->exchangeName;
}
QString QAmqpMessage::routingKey() const
{
return d->routingKey;
}
QByteArray QAmqpMessage::payload() const
{
return d->payload;
}
bool QAmqpMessage::hasProperty(Property property) const
{
return d->properties.contains(property);
}
void QAmqpMessage::setProperty(Property property, const QVariant &value)
{
d->properties.insert(property, value);
}
QVariant QAmqpMessage::property(Property property, const QVariant &defaultValue) const
{
return d->properties.value(property, defaultValue);
}
bool QAmqpMessage::hasHeader(const QString &header) const
{
return d->headers.contains(header);
}
void QAmqpMessage::setHeader(const QString &header, const QVariant &value)
{
d->headers.insert(header, value);
}
QVariant QAmqpMessage::header(const QString &header, const QVariant &defaultValue) const
{
return d->headers.value(header, defaultValue);
}
QHash<QString, QVariant> QAmqpMessage::headers() const
{
return d->headers;
}
uint qHash(const QAmqpMessage &message, uint seed)
{
Q_UNUSED(seed);
return qHash(message.deliveryTag()) ^
qHash(message.isRedelivered()) ^
qHash(message.exchangeName()) ^
qHash(message.routingKey()) ^
qHash(message.payload());
}

89
qamqp/src/qamqpmessage.h Normal file
View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2012-2014 Alexey Shcherbakov
* Copyright (C) 2014-2015 Matt Broadstone
* Contact: https://github.com/mbroadst/qamqp
*
* This file is part of the QAMQP Library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef QAMQPMESSAGE_H
#define QAMQPMESSAGE_H
#include <QByteArray>
#include <QHash>
#include <QSharedDataPointer>
#include <QVariant>
#include "qamqpglobal.h"
class QAmqpMessagePrivate;
class QAMQP_EXPORT QAmqpMessage
{
public:
QAmqpMessage();
QAmqpMessage(const QAmqpMessage &other);
QAmqpMessage &operator=(const QAmqpMessage &other);
~QAmqpMessage();
inline void swap(QAmqpMessage &other) { qSwap(d, other.d); }
bool operator==(const QAmqpMessage &message) const;
inline bool operator!=(const QAmqpMessage &message) const { return !(operator==(message)); }
enum Property {
ContentType = AMQP_BASIC_CONTENT_TYPE_FLAG,
ContentEncoding = AMQP_BASIC_CONTENT_ENCODING_FLAG,
Headers = AMQP_BASIC_HEADERS_FLAG,
DeliveryMode = AMQP_BASIC_DELIVERY_MODE_FLAG,
Priority = AMQP_BASIC_PRIORITY_FLAG,
CorrelationId = AMQP_BASIC_CORRELATION_ID_FLAG,
ReplyTo = AMQP_BASIC_REPLY_TO_FLAG,
Expiration = AMQP_BASIC_EXPIRATION_FLAG,
MessageId = AMQP_BASIC_MESSAGE_ID_FLAG,
Timestamp = AMQP_BASIC_TIMESTAMP_FLAG,
Type = AMQP_BASIC_TYPE_FLAG,
UserId = AMQP_BASIC_USER_ID_FLAG,
AppId = AMQP_BASIC_APP_ID_FLAG,
ClusterID = AMQP_BASIC_CLUSTER_ID_FLAG
};
Q_DECLARE_FLAGS(Properties, Property)
typedef QHash<Property, QVariant> PropertyHash;
bool hasProperty(Property property) const;
void setProperty(Property property, const QVariant &value);
QVariant property(Property property, const QVariant &defaultValue = QVariant()) const;
bool hasHeader(const QString &header) const;
void setHeader(const QString &header, const QVariant &value);
QVariant header(const QString &header, const QVariant &defaultValue = QVariant()) const;
QHash<QString, QVariant> headers() const;
bool isValid() const;
bool isRedelivered() const;
qlonglong deliveryTag() const;
QString exchangeName() const;
QString routingKey() const;
QByteArray payload() const;
private:
QSharedDataPointer<QAmqpMessagePrivate> d;
friend class QAmqpQueuePrivate;
friend class QAmqpQueue;
};
Q_DECLARE_METATYPE(QAmqpMessage::PropertyHash)
Q_DECLARE_SHARED(QAmqpMessage)
// NOTE: needed only for MSVC support, don't depend on this hash
QAMQP_EXPORT uint qHash(const QAmqpMessage &key, uint seed = 0);
#endif // QAMQPMESSAGE_H

View File

@ -0,0 +1,26 @@
#ifndef QAMQPMESSAGE_P_H
#define QAMQPMESSAGE_P_H
#include <QHash>
#include <QSharedData>
#include "qamqpframe_p.h"
#include "qamqpmessage.h"
class QAmqpMessagePrivate : public QSharedData
{
public:
QAmqpMessagePrivate();
qlonglong deliveryTag;
bool redelivered;
QString exchangeName;
QString routingKey;
QByteArray payload;
QHash<QAmqpMessage::Property, QVariant> properties;
QHash<QString, QVariant> headers;
int leftSize;
};
#endif // QAMQPMESSAGE_P_H

667
qamqp/src/qamqpqueue.cpp Normal file
View File

@ -0,0 +1,667 @@
#include <QCoreApplication>
#include <QDebug>
#include <QDataStream>
#include <QFile>
#include "qamqpclient.h"
#include "qamqpclient_p.h"
#include "qamqpqueue.h"
#include "qamqpqueue_p.h"
#include "qamqpexchange.h"
#include "qamqpmessage_p.h"
#include "qamqptable.h"
using namespace QAMQP;
QAmqpQueuePrivate::QAmqpQueuePrivate(QAmqpQueue *q)
: QAmqpChannelPrivate(q),
delayedDeclare(false),
declared(false),
recievingMessage(false),
consuming(false),
consumeRequested(false),
messageCount(0),
consumerCount(0)
{
}
QAmqpQueuePrivate::~QAmqpQueuePrivate()
{
if (!client.isNull()) {
QAmqpClientPrivate *priv = client->d_func();
priv->contentHandlerByChannel[channelNumber].removeAll(this);
priv->bodyHandlersByChannel[channelNumber].removeAll(this);
}
}
void QAmqpQueuePrivate::resetInternalState()
{
QAmqpChannelPrivate::resetInternalState();
delayedDeclare = false;
declared = false;
recievingMessage = false;
consuming = false;
consumeRequested = false;
}
bool QAmqpQueuePrivate::_q_method(const QAmqpMethodFrame &frame)
{
Q_Q(QAmqpQueue);
if (QAmqpChannelPrivate::_q_method(frame))
return true;
if (frame.methodClass() == QAmqpFrame::Queue) {
switch (frame.id()) {
case miDeclareOk:
declareOk(frame);
break;
case miDeleteOk:
deleteOk(frame);
break;
case miBindOk:
bindOk(frame);
break;
case miUnbindOk:
unbindOk(frame);
break;
case miPurgeOk:
purgeOk(frame);
break;
}
return true;
}
if (frame.methodClass() == QAmqpFrame::Basic) {
switch(frame.id()) {
case bmConsumeOk:
consumeOk(frame);
break;
case bmDeliver:
deliver(frame);
break;
case bmGetOk:
getOk(frame);
break;
case bmGetEmpty:
Q_EMIT q->empty();
break;
case bmCancelOk:
cancelOk(frame);
break;
}
return true;
}
return false;
}
void QAmqpQueuePrivate::_q_content(const QAmqpContentFrame &frame)
{
Q_Q(QAmqpQueue);
Q_ASSERT(frame.channel() == channelNumber);
if (frame.channel() != channelNumber)
return;
if (!currentMessage.isValid()) {
qAmqpDebug() << "received content-header without delivered message";
return;
}
currentMessage.d->leftSize = frame.bodySize();
QAmqpMessage::PropertyHash::ConstIterator it;
QAmqpMessage::PropertyHash::ConstIterator itEnd = frame.properties_.constEnd();
for (it = frame.properties_.constBegin(); it != itEnd; ++it) {
QAmqpMessage::Property property = (it.key());
if (property == QAmqpMessage::Headers)
currentMessage.d->headers = (it.value()).toHash();
currentMessage.d->properties[property] = it.value();
}
if (currentMessage.d->leftSize == 0) {
// message with an empty body
q->enqueue(currentMessage);
Q_EMIT q->messageReceived();
}
}
void QAmqpQueuePrivate::_q_body(const QAmqpContentBodyFrame &frame)
{
Q_Q(QAmqpQueue);
Q_ASSERT(frame.channel() == channelNumber);
if (frame.channel() != channelNumber)
return;
if (!currentMessage.isValid()) {
qAmqpDebug() << "received content-body without delivered message";
return;
}
currentMessage.d->payload.append(frame.body());
currentMessage.d->leftSize -= frame.body().size();
if (currentMessage.d->leftSize == 0) {
q->enqueue(currentMessage);
Q_EMIT q->messageReceived();
}
}
void QAmqpQueuePrivate::declareOk(const QAmqpMethodFrame &frame)
{
Q_Q(QAmqpQueue);
declared = true;
QByteArray data = frame.arguments();
QDataStream stream(&data, QIODevice::ReadOnly);
name = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::ShortString).toString();
stream >> messageCount >> consumerCount;
qAmqpDebug("-> queue#declareOk( queue-name=%s, message-count=%d, consumer-count=%d )",
qPrintable(name), messageCount, consumerCount);
Q_EMIT q->declared();
}
void QAmqpQueuePrivate::purgeOk(const QAmqpMethodFrame &frame)
{
Q_Q(QAmqpQueue);
QByteArray data = frame.arguments();
QDataStream stream(&data, QIODevice::ReadOnly);
stream >> messageCount;
qAmqpDebug("-> queue#purgeOk( queue-name=%s, message-count=%d )",
qPrintable(name), messageCount);
Q_EMIT q->purged(messageCount);
}
void QAmqpQueuePrivate::deleteOk(const QAmqpMethodFrame &frame)
{
Q_Q(QAmqpQueue);
declared = false;
QByteArray data = frame.arguments();
QDataStream stream(&data, QIODevice::ReadOnly);
stream >> messageCount;
qAmqpDebug("-> queue#deleteOk( queue-name=%s, message-count=%d )",
qPrintable(name), messageCount);
Q_EMIT q->removed();
}
void QAmqpQueuePrivate::bindOk(const QAmqpMethodFrame &frame)
{
Q_UNUSED(frame)
Q_Q(QAmqpQueue);
qAmqpDebug("-> queue[ %s ]#bindOk()", qPrintable(name));
Q_EMIT q->bound();
}
void QAmqpQueuePrivate::unbindOk(const QAmqpMethodFrame &frame)
{
Q_UNUSED(frame)
Q_Q(QAmqpQueue);
qAmqpDebug("-> queue[ %s ]#unbindOk()", qPrintable(name));
Q_EMIT q->unbound();
}
void QAmqpQueuePrivate::getOk(const QAmqpMethodFrame &frame)
{
qAmqpDebug("-> queue[ %s ]#getOk()", qPrintable(name));
QByteArray data = frame.arguments();
QDataStream in(&data, QIODevice::ReadOnly);
QAmqpMessage message;
message.d->deliveryTag = QAmqpFrame::readAmqpField(in, QAmqpMetaType::LongLongUint).toLongLong();
message.d->redelivered = QAmqpFrame::readAmqpField(in, QAmqpMetaType::Boolean).toBool();
message.d->exchangeName = QAmqpFrame::readAmqpField(in, QAmqpMetaType::ShortString).toString();
message.d->routingKey = QAmqpFrame::readAmqpField(in, QAmqpMetaType::ShortString).toString();
currentMessage = message;
}
void QAmqpQueuePrivate::consumeOk(const QAmqpMethodFrame &frame)
{
Q_Q(QAmqpQueue);
QByteArray data = frame.arguments();
QDataStream stream(&data, QIODevice::ReadOnly);
consumerTag = QAmqpFrame::readAmqpField(stream, QAmqpMetaType::ShortString).toString();
consuming = true;
consumeRequested = false;
qAmqpDebug("-> queue[ %s ]#consumeOk( consumer-tag=%s )", qPrintable(name), qPrintable(consumerTag));
Q_EMIT q->consuming(consumerTag);
}
void QAmqpQueuePrivate::deliver(const QAmqpMethodFrame &frame)
{
qAmqpDebug() << Q_FUNC_INFO;
QByteArray data = frame.arguments();
QDataStream in(&data, QIODevice::ReadOnly);
QString consumer = QAmqpFrame::readAmqpField(in, QAmqpMetaType::ShortString).toString();
if (consumerTag != consumer) {
qAmqpDebug() << Q_FUNC_INFO << "invalid consumer tag: " << consumer;
return;
}
QAmqpMessage message;
message.d->deliveryTag = QAmqpFrame::readAmqpField(in, QAmqpMetaType::LongLongUint).toLongLong();
message.d->redelivered = QAmqpFrame::readAmqpField(in, QAmqpMetaType::Boolean).toBool();
message.d->exchangeName = QAmqpFrame::readAmqpField(in, QAmqpMetaType::ShortString).toString();
message.d->routingKey = QAmqpFrame::readAmqpField(in, QAmqpMetaType::ShortString).toString();
currentMessage = message;
}
void QAmqpQueuePrivate::declare()
{
QAmqpMethodFrame frame(QAmqpFrame::Queue, QAmqpQueuePrivate::miDeclare);
frame.setChannel(channelNumber);
QByteArray args;
QDataStream out(&args, QIODevice::WriteOnly);
out << qint16(0); //reserved 1
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, name);
out << qint8(options);
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::Hash, arguments);
qAmqpDebug("<- queue#declare( queue=%s, passive=%d, durable=%d, exclusive=%d, auto-delete=%d, no-wait=%d )",
qPrintable(name), options & QAmqpQueue::Passive, options & QAmqpQueue::Durable,
options & QAmqpQueue::Exclusive, options & QAmqpQueue::AutoDelete,
options & QAmqpQueue::NoWait);
frame.setArguments(args);
sendFrame(frame);
if (delayedDeclare)
delayedDeclare = false;
}
void QAmqpQueuePrivate::cancelOk(const QAmqpMethodFrame &frame)
{
Q_Q(QAmqpQueue);
qAmqpDebug() << Q_FUNC_INFO;
QByteArray data = frame.arguments();
QDataStream in(&data, QIODevice::ReadOnly);
QString consumer = QAmqpFrame::readAmqpField(in, QAmqpMetaType::ShortString).toString();
if (consumerTag != consumer) {
qAmqpDebug() << Q_FUNC_INFO << "invalid consumer tag: " << consumer;
return;
}
qAmqpDebug("-> queue[ %s ]#cancelOk( consumer-tag=%s )", qPrintable(name), qPrintable(consumerTag));
consumerTag.clear();
consuming = false;
consumeRequested = false;
Q_EMIT q->cancelled(consumer);
}
//////////////////////////////////////////////////////////////////////////
QAmqpQueue::QAmqpQueue(int channelNumber, QAmqpClient *parent)
: QAmqpChannel(new QAmqpQueuePrivate(this), parent)
{
Q_D(QAmqpQueue);
d->init(channelNumber, parent);
}
QAmqpQueue::~QAmqpQueue()
{
}
void QAmqpQueue::channelOpened()
{
Q_D(QAmqpQueue);
if (d->delayedDeclare)
d->declare();
if (!d->delayedBindings.isEmpty()) {
typedef QPair<QString, QString> BindingPair;
foreach(BindingPair binding, d->delayedBindings)
bind(binding.first, binding.second);
d->delayedBindings.clear();
}
}
void QAmqpQueue::channelClosed()
{
}
int QAmqpQueue::options() const
{
Q_D(const QAmqpQueue);
return d->options;
}
qint32 QAmqpQueue::messageCount() const
{
Q_D(const QAmqpQueue);
return d->messageCount;
}
qint32 QAmqpQueue::consumerCount() const
{
Q_D(const QAmqpQueue);
return d->consumerCount;
}
void QAmqpQueue::declare(int options, const QAmqpTable &arguments)
{
Q_D(QAmqpQueue);
d->options = options;
d->arguments = arguments;
if (!d->opened) {
d->delayedDeclare = true;
return;
}
d->declare();
}
void QAmqpQueue::remove(int options)
{
Q_D(QAmqpQueue);
if (!d->declared) {
qAmqpDebug() << Q_FUNC_INFO << "trying to remove undeclared queue, aborting...";
return;
}
QAmqpMethodFrame frame(QAmqpFrame::Queue, QAmqpQueuePrivate::miDelete);
frame.setChannel(d->channelNumber);
QByteArray arguments;
QDataStream out(&arguments, QIODevice::WriteOnly);
out << qint16(0); //reserved 1
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->name);
out << qint8(options);
qAmqpDebug("<- queue#delete( queue=%s, if-unused=%d, if-empty=%d )",
qPrintable(d->name), options & QAmqpQueue::roIfUnused, options & QAmqpQueue::roIfEmpty);
frame.setArguments(arguments);
d->sendFrame(frame);
}
void QAmqpQueue::purge()
{
Q_D(QAmqpQueue);
if (!d->opened)
return;
QAmqpMethodFrame frame(QAmqpFrame::Queue, QAmqpQueuePrivate::miPurge);
frame.setChannel(d->channelNumber);
QByteArray arguments;
QDataStream out(&arguments, QIODevice::WriteOnly);
out << qint16(0); //reserved 1
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->name);
out << qint8(0); // no-wait
qAmqpDebug("<- queue#purge( queue=%s, no-wait=%d )", qPrintable(d->name), 0);
frame.setArguments(arguments);
d->sendFrame(frame);
}
void QAmqpQueue::bind(QAmqpExchange *exchange, const QString &key)
{
if (!exchange) {
qAmqpDebug() << Q_FUNC_INFO << "invalid exchange provided";
return;
}
bind(exchange->name(), key);
}
void QAmqpQueue::bind(const QString &exchangeName, const QString &key)
{
Q_D(QAmqpQueue);
if (!d->opened) {
d->delayedBindings.append(QPair<QString,QString>(exchangeName, key));
return;
}
QAmqpMethodFrame frame(QAmqpFrame::Queue, QAmqpQueuePrivate::miBind);
frame.setChannel(d->channelNumber);
QByteArray arguments;
QDataStream out(&arguments, QIODevice::WriteOnly);
out << qint16(0); // reserved 1
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->name);
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, exchangeName);
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, key);
out << qint8(0); // no-wait
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::Hash, QAmqpTable());
qAmqpDebug("<- queue#bind( queue=%s, exchange=%s, routing-key=%s, no-wait=%d )",
qPrintable(d->name), qPrintable(exchangeName), qPrintable(key),
0);
frame.setArguments(arguments);
d->sendFrame(frame);
}
void QAmqpQueue::unbind(QAmqpExchange *exchange, const QString &key)
{
if (!exchange) {
qAmqpDebug() << Q_FUNC_INFO << "invalid exchange provided";
return;
}
unbind(exchange->name(), key);
}
void QAmqpQueue::unbind(const QString &exchangeName, const QString &key)
{
Q_D(QAmqpQueue);
if (!d->opened) {
qAmqpDebug() << Q_FUNC_INFO << "queue is not open";
return;
}
QAmqpMethodFrame frame(QAmqpFrame::Queue, QAmqpQueuePrivate::miUnbind);
frame.setChannel(d->channelNumber);
QByteArray arguments;
QDataStream out(&arguments, QIODevice::WriteOnly);
out << qint16(0); //reserved 1
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->name);
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, exchangeName);
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, key);
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::Hash, QAmqpTable());
qAmqpDebug("<- queue#unbind( queue=%s, exchange=%s, routing-key=%s )",
qPrintable(d->name), qPrintable(exchangeName), qPrintable(key));
frame.setArguments(arguments);
d->sendFrame(frame);
}
bool QAmqpQueue::consume(int options)
{
Q_D(QAmqpQueue);
if (!d->opened) {
qAmqpDebug() << Q_FUNC_INFO << "queue is not open";
return false;
}
if (d->consumeRequested) {
qAmqpDebug() << Q_FUNC_INFO << "already attempting to consume";
return false;
}
if (d->consuming) {
qAmqpDebug() << Q_FUNC_INFO << "already consuming with tag: " << d->consumerTag;
return false;
}
QAmqpMethodFrame frame(QAmqpFrame::Basic, QAmqpQueuePrivate::bmConsume);
frame.setChannel(d->channelNumber);
QByteArray arguments;
QDataStream out(&arguments, QIODevice::WriteOnly);
out << qint16(0); //reserved 1
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->name);
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->consumerTag);
out << qint8(options);
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::Hash, QAmqpTable());
qAmqpDebug("<- basic#consume( queue=%s, consumer-tag=%s, no-local=%d, no-ack=%d, exclusive=%d, no-wait=%d )",
qPrintable(d->name), qPrintable(d->consumerTag),
options & QAmqpQueue::coNoLocal, options & QAmqpQueue::coNoAck,
options & QAmqpQueue::coExclusive, options & QAmqpQueue::coNoWait);
frame.setArguments(arguments);
d->sendFrame(frame);
d->consumeRequested = true;
return true;
}
void QAmqpQueue::setConsumerTag(const QString &consumerTag)
{
Q_D(QAmqpQueue);
d->consumerTag = consumerTag;
}
QString QAmqpQueue::consumerTag() const
{
Q_D(const QAmqpQueue);
return d->consumerTag;
}
bool QAmqpQueue::isConsuming() const
{
Q_D(const QAmqpQueue);
return d->consuming;
}
bool QAmqpQueue::isDeclared() const
{
Q_D(const QAmqpQueue);
return d->declared;
}
void QAmqpQueue::get(bool noAck)
{
Q_D(QAmqpQueue);
if (!d->opened) {
qAmqpDebug() << Q_FUNC_INFO << "channel is not open";
return;
}
QAmqpMethodFrame frame(QAmqpFrame::Basic, QAmqpQueuePrivate::bmGet);
frame.setChannel(d->channelNumber);
QByteArray arguments;
QDataStream out(&arguments, QIODevice::WriteOnly);
out << qint16(0); //reserved 1
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->name);
out << qint8(noAck ? 1 : 0); // no-ack
qAmqpDebug("<- basic#get( queue=%s, no-ack=%d )", qPrintable(d->name), noAck);
frame.setArguments(arguments);
d->sendFrame(frame);
}
void QAmqpQueue::ack(const QAmqpMessage &message)
{
ack(message.deliveryTag(), false);
}
void QAmqpQueue::ack(qlonglong deliveryTag, bool multiple)
{
Q_D(QAmqpQueue);
if (!d->opened) {
qAmqpDebug() << Q_FUNC_INFO << "channel is not open";
return;
}
QAmqpMethodFrame frame(QAmqpFrame::Basic, QAmqpQueuePrivate::bmAck);
frame.setChannel(d->channelNumber);
QByteArray arguments;
QDataStream out(&arguments, QIODevice::WriteOnly);
out << deliveryTag;
out << qint8(multiple ? 1 : 0); // multiple
qAmqpDebug("<- basic#ack( delivery-tag=%llu, multiple=%d )", deliveryTag, multiple);
frame.setArguments(arguments);
d->sendFrame(frame);
}
void QAmqpQueue::reject(const QAmqpMessage &message, bool requeue)
{
reject(message.deliveryTag(), requeue);
}
void QAmqpQueue::reject(qlonglong deliveryTag, bool requeue)
{
Q_D(QAmqpQueue);
if (!d->opened) {
qAmqpDebug() << Q_FUNC_INFO << "channel is not open";
return;
}
QAmqpMethodFrame frame(QAmqpFrame::Basic, QAmqpQueuePrivate::bmReject);
frame.setChannel(d->channelNumber);
QByteArray arguments;
QDataStream out(&arguments, QIODevice::WriteOnly);
out << deliveryTag;
out << qint8(requeue ? 1 : 0);
qAmqpDebug("<- basic#reject( delivery-tag=%llu, requeue=%d )", deliveryTag, requeue);
frame.setArguments(arguments);
d->sendFrame(frame);
}
bool QAmqpQueue::cancel(bool noWait)
{
Q_D(QAmqpQueue);
if (!d->consuming) {
qAmqpDebug() << Q_FUNC_INFO << "not consuming!";
return false;
}
if (d->consumerTag.isEmpty()) {
qAmqpDebug() << Q_FUNC_INFO << "consuming with an empty consumer tag, failing...";
return false;
}
QAmqpMethodFrame frame(QAmqpFrame::Basic, QAmqpQueuePrivate::bmCancel);
frame.setChannel(d->channelNumber);
QByteArray arguments;
QDataStream out(&arguments, QIODevice::WriteOnly);
QAmqpFrame::writeAmqpField(out, QAmqpMetaType::ShortString, d->consumerTag);
out << (noWait ? qint8(0x01) : qint8(0x0));
qAmqpDebug("<- basic#cancel( consumer-tag=%s, no-wait=%d )", qPrintable(d->consumerTag), noWait);
frame.setArguments(arguments);
d->sendFrame(frame);
return true;
}

127
qamqp/src/qamqpqueue.h Normal file
View File

@ -0,0 +1,127 @@
/*
* Copyright (C) 2012-2014 Alexey Shcherbakov
* Copyright (C) 2014-2015 Matt Broadstone
* Contact: https://github.com/mbroadst/qamqp
*
* This file is part of the QAMQP Library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef QAMQPQUEUE_H
#define QAMQPQUEUE_H
#include <QQueue>
#include "qamqpchannel.h"
#include "qamqpmessage.h"
#include "qamqpglobal.h"
#include "qamqptable.h"
class QAmqpClient;
class QAmqpClientPrivate;
class QAmqpExchange;
class QAmqpQueuePrivate;
class QAMQP_EXPORT QAmqpQueue : public QAmqpChannel, public QQueue<QAmqpMessage>
{
Q_OBJECT
Q_PROPERTY(int options READ options CONSTANT)
Q_PROPERTY(QString consumerTag READ consumerTag WRITE setConsumerTag)
public:
enum QueueOption {
NoOptions = 0x0,
Passive = 0x01,
Durable = 0x02,
Exclusive = 0x04,
AutoDelete = 0x08,
NoWait = 0x10
};
Q_DECLARE_FLAGS(QueueOptions, QueueOption)
Q_ENUM(QueueOption)
Q_ENUM(QueueOptions)
int options() const;
enum ConsumeOption {
coNoLocal = 0x01,
coNoAck = 0x02,
coExclusive = 0x04,
coNoWait = 0x08
};
Q_DECLARE_FLAGS(ConsumeOptions, ConsumeOption)
Q_ENUM(ConsumeOption)
enum RemoveOption {
roForce = 0x0,
roIfUnused = 0x01,
roIfEmpty = 0x02,
roNoWait = 0x04
};
Q_DECLARE_FLAGS(RemoveOptions, RemoveOption)
Q_ENUM(RemoveOption)
~QAmqpQueue();
bool isConsuming() const;
bool isDeclared() const;
void setConsumerTag(const QString &consumerTag);
QString consumerTag() const;
qint32 messageCount() const;
qint32 consumerCount() const;
Q_SIGNALS:
void declared();
void bound();
void unbound();
void removed();
void purged(int messageCount);
void messageReceived();
void empty();
void consuming(const QString &consumerTag);
void cancelled(const QString &consumerTag);
public Q_SLOTS:
// AMQP Queue
void declare(int options = Durable|AutoDelete, const QAmqpTable &arguments = QAmqpTable());
void bind(const QString &exchangeName, const QString &key);
void bind(QAmqpExchange *exchange, const QString &key);
void unbind(const QString &exchangeName, const QString &key);
void unbind(QAmqpExchange *exchange, const QString &key);
void purge();
void remove(int options = roIfUnused|roIfEmpty|roNoWait);
// AMQP Basic
bool consume(int options = NoOptions);
void get(bool noAck = true);
bool cancel(bool noWait = false);
void ack(const QAmqpMessage &message);
void ack(qlonglong deliveryTag, bool multiple);
void reject(const QAmqpMessage &message, bool requeue);
void reject(qlonglong deliveryTag, bool requeue);
protected:
// reimp Channel
virtual void channelOpened();
virtual void channelClosed();
private:
explicit QAmqpQueue(int channelNumber = -1, QAmqpClient *parent = 0);
Q_DISABLE_COPY(QAmqpQueue)
Q_DECLARE_PRIVATE(QAmqpQueue)
friend class QAmqpClient;
friend class QAmqpClientPrivate;
};
#endif // QAMQPQUEUE_H

64
qamqp/src/qamqpqueue_p.h Normal file
View File

@ -0,0 +1,64 @@
#ifndef QAMQPQUEUE_P_H
#define QAMQPQUEUE_P_H
#include <QQueue>
#include <QStringList>
#include "qamqpchannel_p.h"
class QAmqpQueuePrivate: public QAmqpChannelPrivate,
public QAmqpContentFrameHandler,
public QAmqpContentBodyFrameHandler
{
public:
enum MethodId {
METHOD_ID_ENUM(miDeclare, 10),
METHOD_ID_ENUM(miBind, 20),
METHOD_ID_ENUM(miUnbind, 50),
METHOD_ID_ENUM(miPurge, 30),
METHOD_ID_ENUM(miDelete, 40)
};
QAmqpQueuePrivate(QAmqpQueue *q);
~QAmqpQueuePrivate();
virtual void resetInternalState();
void declare();
virtual bool _q_method(const QAmqpMethodFrame &frame);
// AMQP Queue method handlers
void declareOk(const QAmqpMethodFrame &frame);
void deleteOk(const QAmqpMethodFrame &frame);
void purgeOk(const QAmqpMethodFrame &frame);
void bindOk(const QAmqpMethodFrame &frame);
void unbindOk(const QAmqpMethodFrame &frame);
void consumeOk(const QAmqpMethodFrame &frame);
// AMQP Basic method handlers
virtual void _q_content(const QAmqpContentFrame &frame);
virtual void _q_body(const QAmqpContentBodyFrame &frame);
void deliver(const QAmqpMethodFrame &frame);
void getOk(const QAmqpMethodFrame &frame);
void cancelOk(const QAmqpMethodFrame &frame);
QString type;
int options;
bool delayedDeclare;
bool declared;
QQueue<QPair<QString, QString> > delayedBindings;
QString consumerTag;
bool recievingMessage;
QAmqpMessage currentMessage;
bool consuming;
bool consumeRequested;
qint32 messageCount;
qint32 consumerCount;
Q_DECLARE_PUBLIC(QAmqpQueue)
};
#endif // QAMQPQUEUE_P_H

371
qamqp/src/qamqptable.cpp Normal file
View File

@ -0,0 +1,371 @@
#include <float.h>
#include <QDateTime>
#include <QDebug>
#include <QIODevice>
#include "qamqpframe_p.h"
#include "qamqptable.h"
/*
* field value types according to: https://www.rabbitmq.com/amqp-0-9-1-errata.html
t - Boolean
b - Signed 8-bit
Unsigned 8-bit
s - Signed 16-bit
Unsigned 16-bit
I - Signed 32-bit
Unsigned 32-bit
l - Signed 64-bit
Unsigned 64-bit
f - 32-bit float
d - 64-bit float
D - Decimal
S - Long string
A - Array
T - Timestamp (u64)
F - Nested Table
V - Void
x - Byte array
*/
QAmqpMetaType::ValueType valueTypeForOctet(qint8 octet)
{
switch (octet) {
case 't': return QAmqpMetaType::Boolean;
case 'b': return QAmqpMetaType::ShortShortInt;
case 's': return QAmqpMetaType::ShortInt;
case 'I': return QAmqpMetaType::LongInt;
case 'l': return QAmqpMetaType::LongLongInt;
case 'f': return QAmqpMetaType::Float;
case 'd': return QAmqpMetaType::Double;
case 'D': return QAmqpMetaType::Decimal;
case 'S': return QAmqpMetaType::LongString;
case 'A': return QAmqpMetaType::Array;
case 'T': return QAmqpMetaType::Timestamp;
case 'F': return QAmqpMetaType::Hash;
case 'V': return QAmqpMetaType::Void;
case 'x': return QAmqpMetaType::Bytes;
default:
qAmqpDebug() << Q_FUNC_INFO << "invalid octet received: " << char(octet);
}
return QAmqpMetaType::Invalid;
}
qint8 valueTypeToOctet(QAmqpMetaType::ValueType type)
{
switch (type) {
case QAmqpMetaType::Boolean: return 't';
case QAmqpMetaType::ShortShortInt: return 'b';
case QAmqpMetaType::ShortInt: return 's';
case QAmqpMetaType::LongInt: return 'I';
case QAmqpMetaType::LongLongInt: return 'l';
case QAmqpMetaType::Float: return 'f';
case QAmqpMetaType::Double: return 'd';
case QAmqpMetaType::Decimal: return 'D';
case QAmqpMetaType::LongString: return 'S';
case QAmqpMetaType::Array: return 'A';
case QAmqpMetaType::Timestamp: return 'T';
case QAmqpMetaType::Hash: return 'F';
case QAmqpMetaType::Void: return 'V';
case QAmqpMetaType::Bytes: return 'x';
default:
qAmqpDebug() << Q_FUNC_INFO << "invalid type received: " << char(type);
}
return 'V';
}
void QAmqpTable::writeFieldValue(QDataStream &stream, const QVariant &value)
{
QAmqpMetaType::ValueType type;
switch (value.userType()) {
case QMetaType::Bool:
type = QAmqpMetaType::Boolean;
break;
case QMetaType::QByteArray:
type = QAmqpMetaType::Bytes;
break;
case QMetaType::Int:
{
int i = qAbs(value.toInt());
if (i <= qint8(SCHAR_MAX)) {
type = QAmqpMetaType::ShortShortInt;
} else if (i <= qint16(SHRT_MAX)) {
type = QAmqpMetaType::ShortInt;
} else {
type = QAmqpMetaType::LongInt;
}
}
break;
case QMetaType::UShort:
type = QAmqpMetaType::ShortInt;
break;
case QMetaType::UInt:
{
int i = value.toInt();
if (i <= qint8(SCHAR_MAX)) {
type = QAmqpMetaType::ShortShortInt;
} else if (i <= qint16(SHRT_MAX)) {
type = QAmqpMetaType::ShortInt;
} else {
type = QAmqpMetaType::LongInt;
}
}
break;
case QMetaType::LongLong:
case QMetaType::ULongLong:
type = QAmqpMetaType::LongLongInt;
break;
case QMetaType::QString:
type = QAmqpMetaType::LongString;
break;
case QMetaType::QDateTime:
type = QAmqpMetaType::Timestamp;
break;
case QMetaType::Double:
type = value.toDouble() > FLT_MAX ? QAmqpMetaType::Double : QAmqpMetaType::Float;
break;
case QMetaType::QVariantHash:
type = QAmqpMetaType::Hash;
break;
case QMetaType::QVariantList:
type = QAmqpMetaType::Array;
break;
case QMetaType::Void:
type = QAmqpMetaType::Void;
break;
default:
if (value.userType() == qMetaTypeId<QAMQP::Decimal>()) {
type = QAmqpMetaType::Decimal;
break;
} else if (!value.isValid()) {
type = QAmqpMetaType::Void;
break;
}
qAmqpDebug() << Q_FUNC_INFO << "unhandled type: " << value.userType();
return;
}
// write the field value type, a requirement for field tables only
stream << valueTypeToOctet(type);
writeFieldValue(stream, type, value);
}
void QAmqpTable::writeFieldValue(QDataStream &stream, QAmqpMetaType::ValueType type, const QVariant &value)
{
switch (type) {
case QAmqpMetaType::Boolean:
case QAmqpMetaType::ShortShortUint:
case QAmqpMetaType::ShortUint:
case QAmqpMetaType::LongUint:
case QAmqpMetaType::LongLongUint:
case QAmqpMetaType::ShortString:
case QAmqpMetaType::LongString:
case QAmqpMetaType::Timestamp:
case QAmqpMetaType::Hash:
return QAmqpFrame::writeAmqpField(stream, type, value);
case QAmqpMetaType::ShortShortInt:
stream << qint8(value.toInt());
break;
case QAmqpMetaType::ShortInt:
stream << qint16(value.toInt());
break;
case QAmqpMetaType::LongInt:
stream << qint32(value.toInt());
break;
case QAmqpMetaType::LongLongInt:
stream << qlonglong(value.toLongLong());
break;
case QAmqpMetaType::Float:
{
float g = value.toFloat();
QDataStream::FloatingPointPrecision oldPrecision = stream.floatingPointPrecision();
stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
stream << g;
stream.setFloatingPointPrecision(oldPrecision);
}
break;
case QAmqpMetaType::Double:
{
double g = value.toDouble();
QDataStream::FloatingPointPrecision oldPrecision = stream.floatingPointPrecision();
stream.setFloatingPointPrecision(QDataStream::DoublePrecision);
stream << g;
stream.setFloatingPointPrecision(oldPrecision);
}
break;
case QAmqpMetaType::Decimal:
{
QAMQP::Decimal v(value.value<QAMQP::Decimal>());
stream << v.scale;
stream << v.value;
}
break;
case QAmqpMetaType::Array:
{
QByteArray buffer;
QDataStream arrayStream(&buffer, QIODevice::WriteOnly);
QVariantList array(value.toList());
for (int i = 0; i < array.size(); ++i)
writeFieldValue(arrayStream, array.at(i));
if (buffer.isEmpty()) {
stream << qint32(0);
} else {
stream << buffer;
}
}
break;
case QAmqpMetaType::Bytes:
{
QByteArray ba = value.toByteArray();
stream << quint32(ba.length());
stream.writeRawData(ba.data(), ba.length());
}
break;
case QAmqpMetaType::Void:
stream << qint32(0);
break;
default:
qAmqpDebug() << Q_FUNC_INFO << "unhandled type: " << type;
}
}
QVariant QAmqpTable::readFieldValue(QDataStream &stream, QAmqpMetaType::ValueType type)
{
switch (type) {
case QAmqpMetaType::Boolean:
case QAmqpMetaType::ShortShortUint:
case QAmqpMetaType::ShortUint:
case QAmqpMetaType::LongUint:
case QAmqpMetaType::LongLongUint:
case QAmqpMetaType::ShortString:
case QAmqpMetaType::LongString:
case QAmqpMetaType::Timestamp:
case QAmqpMetaType::Hash:
return QAmqpFrame::readAmqpField(stream, type);
case QAmqpMetaType::ShortShortInt:
{
char octet;
stream.readRawData(&octet, sizeof(octet));
return QVariant::fromValue<int>(octet);
}
case QAmqpMetaType::ShortInt:
{
qint16 tmp_value = 0;
stream >> tmp_value;
return QVariant::fromValue<int>(tmp_value);
}
case QAmqpMetaType::LongInt:
{
qint32 tmp_value = 0;
stream >> tmp_value;
return QVariant::fromValue<int>(tmp_value);
}
case QAmqpMetaType::LongLongInt:
{
qlonglong v = 0 ;
stream >> v;
return v;
}
case QAmqpMetaType::Float:
{
float tmp_value;
QDataStream::FloatingPointPrecision precision = stream.floatingPointPrecision();
stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
stream >> tmp_value;
stream.setFloatingPointPrecision(precision);
return QVariant::fromValue<float>(tmp_value);
}
case QAmqpMetaType::Double:
{
double tmp_value;
QDataStream::FloatingPointPrecision precision = stream.floatingPointPrecision();
stream.setFloatingPointPrecision(QDataStream::DoublePrecision);
stream >> tmp_value;
stream.setFloatingPointPrecision(precision);
return QVariant::fromValue<double>(tmp_value);
}
case QAmqpMetaType::Decimal:
{
QAMQP::Decimal v;
stream >> v.scale;
stream >> v.value;
return QVariant::fromValue<QAMQP::Decimal>(v);
}
case QAmqpMetaType::Array:
{
QByteArray data;
quint32 size = 0;
stream >> size;
data.resize(size);
stream.readRawData(data.data(), data.size());
qint8 type = 0;
QVariantList result;
QDataStream arrayStream(&data, QIODevice::ReadOnly);
while (!arrayStream.atEnd()) {
arrayStream >> type;
result.append(readFieldValue(arrayStream, valueTypeForOctet(type)));
}
return result;
}
case QAmqpMetaType::Bytes:
{
QByteArray bytes;
quint32 length = 0;
stream >> length;
bytes.resize(length);
stream.readRawData(bytes.data(), bytes.size());
return bytes;
}
case QAmqpMetaType::Void:
break;
default:
qAmqpDebug() << Q_FUNC_INFO << "unhandled type: " << type;
}
return QVariant();
}
QDataStream &operator<<(QDataStream &stream, const QAmqpTable &table)
{
QByteArray data;
QDataStream s(&data, QIODevice::WriteOnly);
QAmqpTable::ConstIterator it;
QAmqpTable::ConstIterator itEnd = table.constEnd();
for (it = table.constBegin(); it != itEnd; ++it) {
QAmqpTable::writeFieldValue(s, QAmqpMetaType::ShortString, it.key());
QAmqpTable::writeFieldValue(s, it.value());
}
if (data.isEmpty()) {
stream << qint32(0);
} else {
stream << data;
}
return stream;
}
QDataStream &operator>>(QDataStream &stream, QAmqpTable &table)
{
QByteArray data;
stream >> data;
QDataStream tableStream(&data, QIODevice::ReadOnly);
while (!tableStream.atEnd()) {
qint8 octet = 0;
QString field = QAmqpFrame::readAmqpField(tableStream, QAmqpMetaType::ShortString).toString();
tableStream >> octet;
table[field] = QAmqpTable::readFieldValue(tableStream, valueTypeForOctet(octet));
}
return stream;
}

43
qamqp/src/qamqptable.h Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2012-2014 Alexey Shcherbakov
* Copyright (C) 2014-2015 Matt Broadstone
* Contact: https://github.com/mbroadst/qamqp
*
* This file is part of the QAMQP Library.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef QAMQPTABLE_H
#define QAMQPTABLE_H
#include <QVariantHash>
#include "qamqpglobal.h"
class QAMQP_EXPORT QAmqpTable : public QVariantHash
{
public:
QAmqpTable() {}
inline QAmqpTable(const QVariantHash &variantHash)
: QVariantHash(variantHash)
{
}
static void writeFieldValue(QDataStream &stream, const QVariant &value);
static void writeFieldValue(QDataStream &stream, QAmqpMetaType::ValueType type, const QVariant &value);
static QVariant readFieldValue(QDataStream &stream, QAmqpMetaType::ValueType type);
};
QAMQP_EXPORT QDataStream &operator<<(QDataStream &, const QAmqpTable &table);
QAMQP_EXPORT QDataStream &operator>>(QDataStream &, QAmqpTable &table);
Q_DECLARE_METATYPE(QAmqpTable)
#endif // QAMQPTABLE_H

View File

@ -0,0 +1,6 @@
TEMPLATE = subdirs
SUBDIRS = \
qamqpclient \
qamqpexchange \
qamqpqueue \
qamqpchannel

View File

@ -0,0 +1,6 @@
DEPTH = ../../..
include($${DEPTH}/qamqp.pri)
include($${DEPTH}/tests/tests.pri)
TARGET = tst_qamqpchannel
SOURCES = tst_qamqpchannel.cpp

View File

@ -0,0 +1,97 @@
#include <QtTest/QtTest>
#include "signalspy.h"
#include "qamqptestcase.h"
#include "qamqpclient.h"
#include "qamqpexchange.h"
#include "qamqpqueue.h"
class tst_QAMQPChannel : public TestCase
{
Q_OBJECT
private Q_SLOTS:
void init();
void cleanup();
void close();
void resume();
void sharedChannel();
void defineWithChannelNumber();
private:
QScopedPointer<QAmqpClient> client;
};
void tst_QAMQPChannel::init()
{
client.reset(new QAmqpClient);
client->connectToHost();
QVERIFY(waitForSignal(client.data(), SIGNAL(connected())));
}
void tst_QAMQPChannel::cleanup()
{
if (client->isConnected()) {
client->disconnectFromHost();
QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected())));
}
}
void tst_QAMQPChannel::close()
{
// exchange
QAmqpExchange *exchange = client->createExchange("test-close-channel");
QVERIFY(waitForSignal(exchange, SIGNAL(opened())));
exchange->declare(QAmqpExchange::Direct);
QVERIFY(waitForSignal(exchange, SIGNAL(declared())));
exchange->close();
QVERIFY(waitForSignal(exchange, SIGNAL(closed())));
exchange->reopen();
QVERIFY(waitForSignal(exchange, SIGNAL(opened())));
exchange->remove(QAmqpExchange::roForce);
QVERIFY(waitForSignal(exchange, SIGNAL(removed())));
// queue
QAmqpQueue *queue = client->createQueue("test-close-channel");
QVERIFY(waitForSignal(queue, SIGNAL(opened())));
declareQueueAndVerifyConsuming(queue);
queue->close();
QVERIFY(waitForSignal(queue, SIGNAL(closed())));
}
void tst_QAMQPChannel::resume()
{
QAmqpQueue *queue = client->createQueue("test-resume");
QVERIFY(waitForSignal(queue, SIGNAL(opened())));
declareQueueAndVerifyConsuming(queue);
queue->resume();
QVERIFY(waitForSignal(queue, SIGNAL(resumed())));
}
void tst_QAMQPChannel::sharedChannel()
{
QString routingKey = "test-shared-channel";
QAmqpQueue *queue = client->createQueue(routingKey);
declareQueueAndVerifyConsuming(queue);
QAmqpExchange *defaultExchange = client->createExchange("", queue->channelNumber());
defaultExchange->publish("first message", routingKey);
QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
QAmqpMessage message = queue->dequeue();
verifyStandardMessageHeaders(message, routingKey);
QCOMPARE(message.payload(), QByteArray("first message"));
}
void tst_QAMQPChannel::defineWithChannelNumber()
{
QString routingKey = "test-specific-channel-number";
QAmqpQueue *queue = client->createQueue(routingKey, 25);
declareQueueAndVerifyConsuming(queue);
QCOMPARE(queue->channelNumber(), 25);
}
QTEST_MAIN(tst_QAMQPChannel)
#include "tst_qamqpchannel.moc"

View File

@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/certs">
<file alias="ca-cert.pem">../../files/certs/testca/cacert.pem</file>
<file alias="client-cert.pem">../../files/certs/client/cert.pem</file>
<file alias="client-key.pem">../../files/certs/client/key.pem</file>
</qresource>
</RCC>

View File

@ -0,0 +1,7 @@
DEPTH = ../../..
include($${DEPTH}/qamqp.pri)
include($${DEPTH}/tests/tests.pri)
TARGET = tst_qamqpclient
SOURCES = tst_qamqpclient.cpp
RESOURCES = certs.qrc

View File

@ -0,0 +1,331 @@
#include <QtTest/QtTest>
#include <QProcess>
#include <QSslKey>
#include "qamqptestcase.h"
#include "qamqpauthenticator.h"
#include "qamqpexchange.h"
#include "qamqpqueue.h"
#include "qamqpclient_p.h"
#include "qamqpclient.h"
class tst_QAMQPClient : public TestCase
{
Q_OBJECT
private Q_SLOTS:
void connect();
void connectProperties();
void connectHostAddress();
void connectDisconnect();
void invalidAuthenticationMechanism();
void tune();
void socketError();
void validateUri_data();
void validateUri();
void issue38();
void issue38_take2();
public Q_SLOTS: // temporarily disabled
void autoReconnect();
void autoReconnectTimeout();
void sslConnect();
private:
QSslConfiguration createSslConfiguration();
void issue38_helper(QAmqpClient *client);
};
QSslConfiguration tst_QAMQPClient::createSslConfiguration()
{
QList<QSslCertificate> caCerts =
QSslCertificate::fromPath(QLatin1String(":/certs/ca-cert.pem"));
QList<QSslCertificate> localCerts =
QSslCertificate::fromPath(QLatin1String(":/certs/client-cert.pem"));
QFile keyFile( QLatin1String(":/certs/client-key.pem"));
keyFile.open(QIODevice::ReadOnly);
QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
keyFile.close();
QSslConfiguration sslConfiguration;
sslConfiguration.setCaCertificates(caCerts);
sslConfiguration.setLocalCertificate(localCerts.first());
sslConfiguration.setPrivateKey(key);
sslConfiguration.setProtocol(QSsl::SecureProtocols);
return sslConfiguration;
}
void tst_QAMQPClient::connect()
{
QAmqpClient client;
client.connectToHost();
QVERIFY(waitForSignal(&client, SIGNAL(connected())));
QCOMPARE(client.host(), QLatin1String(AMQP_HOST));
QCOMPARE(client.port(), quint16(AMQP_PORT));
QCOMPARE(client.virtualHost(), QLatin1String(AMQP_VHOST));
QCOMPARE(client.username(), QLatin1String(AMQP_LOGIN));
QCOMPARE(client.password(), QLatin1String(AMQP_PSWD));
QCOMPARE(client.autoReconnect(), false);
client.disconnectFromHost();
QVERIFY(waitForSignal(&client, SIGNAL(disconnected())));
}
void tst_QAMQPClient::sslConnect()
{
QAmqpClient client;
client.setSslConfiguration(createSslConfiguration());
QObject::connect(&client, SIGNAL(sslErrors(QList<QSslError>)),
&client, SLOT(ignoreSslErrors(QList<QSslError>)));
client.connectToHost();
QVERIFY(waitForSignal(&client, SIGNAL(connected())));
}
void tst_QAMQPClient::connectProperties()
{
QAmqpClient client;
client.setHost("localhost");
client.setPort(5672);
client.setVirtualHost("/");
client.setUsername("guest");
client.setPassword("guest");
client.setAutoReconnect(false);
client.connectToHost();
QVERIFY(waitForSignal(&client, SIGNAL(connected())));
client.disconnectFromHost();
QVERIFY(waitForSignal(&client, SIGNAL(disconnected())));
}
void tst_QAMQPClient::connectHostAddress()
{
QAmqpClient client;
client.connectToHost(QHostAddress::LocalHost, 5672);
QVERIFY(waitForSignal(&client, SIGNAL(connected())));
client.disconnectFromHost();
QVERIFY(waitForSignal(&client, SIGNAL(disconnected())));
}
void tst_QAMQPClient::connectDisconnect()
{
QAmqpClient client;
client.connectToHost();
QVERIFY(waitForSignal(&client, SIGNAL(connected())));
client.disconnectFromHost();
QVERIFY(waitForSignal(&client, SIGNAL(disconnected())));
}
class InvalidAuthenticator : public QAmqpAuthenticator
{
public:
virtual QString type() const { return "CRAZYAUTH"; }
virtual void write(QDataStream &out) {
Q_UNUSED(out);
}
};
void tst_QAMQPClient::invalidAuthenticationMechanism()
{
QAmqpClient client;
client.setAuth(new InvalidAuthenticator);
client.connectToHost();
QVERIFY(waitForSignal(&client, SIGNAL(disconnected())));
}
void tst_QAMQPClient::autoReconnect()
{
// TODO: this is a fairly crude way of testing this, research
// better alternatives
QAmqpClient client;
client.setAutoReconnect(true);
client.connectToHost();
QVERIFY(waitForSignal(&client, SIGNAL(connected())));
QProcess::execute("rabbitmqctl", QStringList() << "stop_app");
QVERIFY(waitForSignal(&client, SIGNAL(disconnected())));
QProcess::execute("rabbitmqctl", QStringList() << "start_app");
QVERIFY(waitForSignal(&client, SIGNAL(connected()), 2));
}
void tst_QAMQPClient::autoReconnectTimeout()
{
// TODO: this is a fairly crude way of testing this, research
// better alternatives
QAmqpClient client;
client.setAutoReconnect(true, 3);
client.connectToHost();
QVERIFY(waitForSignal(&client, SIGNAL(connected()), 60));
qDebug() <<"connected" ;
QProcess::execute("rabbitmqctl", QStringList() << "stop_app");
QVERIFY(waitForSignal(&client, SIGNAL(disconnected()), 60));
qDebug() <<"disconnected" ;
QProcess::execute("rabbitmqctl", QStringList() << "start_app");
QVERIFY(waitForSignal(&client, SIGNAL(connected()), 60));
qDebug() <<"connected" ;
QVERIFY(waitForSignal(&client, SIGNAL(disconnected()), 60));
QProcess::execute("rabbitmqctl", QStringList() << "start_app");
QVERIFY(waitForSignal(&client, SIGNAL(connected()), 60));
}
void tst_QAMQPClient::tune()
{
QAmqpClient client;
client.setChannelMax(15);
client.setFrameMax(5000);
client.setHeartbeatDelay(600);
client.connectToHost();
QVERIFY(waitForSignal(&client, SIGNAL(connected())));
QCOMPARE((int) client.channelMax(), 2047);
QCOMPARE((int)client.heartbeatDelay(), 600);
QCOMPARE((int)client.frameMax(), 5000);
client.disconnectFromHost();
QVERIFY(waitForSignal(&client, SIGNAL(disconnected())));
}
void tst_QAMQPClient::socketError()
{
QAmqpClient client;
client.connectToHost("amqp://127.0.0.1:56725/");
QVERIFY(waitForSignal(&client, SIGNAL(socketErrorOccurred(QAbstractSocket::SocketError))));
QCOMPARE(client.socketError(), QAbstractSocket::ConnectionRefusedError);
}
void tst_QAMQPClient::validateUri_data()
{
QTest::addColumn<QString>("uri");
QTest::addColumn<QString>("expectedUsername");
QTest::addColumn<QString>("expectedPassword");
QTest::addColumn<QString>("expectedHost");
QTest::addColumn<quint16>("expectedPort");
QTest::addColumn<QString>("expectedVirtualHost");
QTest::newRow("default vhost") << "amqp://guest:guest@192.168.1.10:5672/"
<< "guest" << "guest" << "192.168.1.10" << quint16(5672) << "/";
QTest::newRow("standard") << "amqp://user:pass@host:10000/vhost"
<< "user" << "pass" << "host" << quint16(10000) << "vhost";
QTest::newRow("urlencoded") << "amqp://user%61:%61pass@ho%61st:10000/v%2fhost"
<< "usera" << "apass" << "hoast" << quint16(10000) << "v/host";
QTest::newRow("empty") << "amqp://" << "" << "" << "" << quint16(AMQP_PORT) << "";
QTest::newRow("empty2") << "amqp://:@/" << "" << "" << "" << quint16(AMQP_PORT) << "/";
QTest::newRow("onlyuser") << "amqp://user@" << "user" << "" << "" << quint16(AMQP_PORT) << "";
QTest::newRow("userpass") << "amqp://user:pass@" << "user" << "pass" << "" << quint16(AMQP_PORT) << "";
QTest::newRow("onlyhost") << "amqp://host" << "" << "" << "host" << quint16(AMQP_PORT) << "";
QTest::newRow("onlyport") << "amqp://:10000" << "" << "" << "" << quint16(10000) << "";
QTest::newRow("onlyvhost") << "amqp:///vhost" << "" << "" << "" << quint16(AMQP_PORT) << "vhost";
QTest::newRow("urlencodedvhost") << "amqp://host/%2f"
<< "" << "" << "host" << quint16(AMQP_PORT) << "/";
QTest::newRow("ipv6") << "amqp://[::1]" << "" << "" << "::1" << quint16(AMQP_PORT) << "";
}
void tst_QAMQPClient::validateUri()
{
QFETCH(QString, uri);
QFETCH(QString, expectedUsername);
QFETCH(QString, expectedPassword);
QFETCH(QString, expectedHost);
QFETCH(quint16, expectedPort);
QFETCH(QString, expectedVirtualHost);
QAmqpClientPrivate clientPrivate(0);
// fake init
clientPrivate.authenticator = QSharedPointer<QAmqpAuthenticator>(
new QAmqpPlainAuthenticator(QString::fromLatin1(AMQP_LOGIN), QString::fromLatin1(AMQP_PSWD)));
// test parsing
clientPrivate.parseConnectionString(uri);
QAmqpPlainAuthenticator *auth =
static_cast<QAmqpPlainAuthenticator*>(clientPrivate.authenticator.data());
QCOMPARE(auth->login(), expectedUsername);
QCOMPARE(auth->password(), expectedPassword);
QCOMPARE(clientPrivate.host, expectedHost);
QCOMPARE(clientPrivate.port, expectedPort);
QCOMPARE(clientPrivate.virtualHost, expectedVirtualHost);
}
void tst_QAMQPClient::issue38_helper(QAmqpClient *client)
{
// connect
client->connectToHost();
QVERIFY(waitForSignal(client, SIGNAL(connected())));
// create then declare, remove and close queue
QAmqpQueue *queue = client->createQueue();
QVERIFY(waitForSignal(queue, SIGNAL(opened())));
queue->declare();
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
queue->remove(QAmqpExchange::roForce);
QVERIFY(waitForSignal(queue, SIGNAL(removed())));
queue->close();
QVERIFY(waitForSignal(queue, SIGNAL(closed())));
queue->deleteLater();
// disconnect
client->disconnectFromHost();
QVERIFY(waitForSignal(client, SIGNAL(disconnected())));
}
void tst_QAMQPClient::issue38()
{
QAmqpClient client;
issue38_helper(&client);
issue38_helper(&client);
}
void tst_QAMQPClient::issue38_take2()
{
QAmqpClient client;
client.connectToHost();
QVERIFY(waitForSignal(&client, SIGNAL(connected())));
QAmqpExchange *exchange = client.createExchange("myexchange");
exchange->declare(QAmqpExchange::Topic);
QVERIFY(waitForSignal(exchange, SIGNAL(declared())));
QAmqpQueue *queue = client.createQueue();
queue->declare();
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
queue->bind(exchange, "routingKeyin");
QVERIFY(waitForSignal(queue, SIGNAL(bound())));
queue->consume(QAmqpQueue::coNoAck);
QVERIFY(waitForSignal(queue, SIGNAL(consuming(QString))));
exchange->publish("test message", "routingKeyout");
// delete everything
queue->unbind(exchange, "routingKeyin");
QVERIFY(waitForSignal(queue, SIGNAL(unbound())));
queue->close();
QVERIFY(waitForSignal(queue, SIGNAL(closed())));
queue->deleteLater();
exchange->close();
QVERIFY(waitForSignal(exchange, SIGNAL(closed())));
exchange->deleteLater();
client.disconnectFromHost();
QVERIFY(waitForSignal(&client,SIGNAL(disconnected())));
// repeat the connection and create again here
client.connectToHost();
QVERIFY(waitForSignal(&client, SIGNAL(connected())));
exchange = client.createExchange("myexchange");
exchange->declare(QAmqpExchange::Topic);
QVERIFY(waitForSignal(exchange, SIGNAL(declared())));
queue = client.createQueue();
queue->declare();
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
queue->bind(exchange, "routingKeyin");
QVERIFY(waitForSignal(queue, SIGNAL(bound())));
queue->consume(QAmqpQueue::coNoAck);
QVERIFY(waitForSignal(queue, SIGNAL(consuming(QString))));
exchange->publish("test message", "routingKeyout");
client.disconnectFromHost();
QVERIFY(waitForSignal(&client,SIGNAL(disconnected())));
}
QTEST_MAIN(tst_QAMQPClient)
#include "tst_qamqpclient.moc"

View File

@ -0,0 +1,6 @@
DEPTH = ../../..
include($${DEPTH}/qamqp.pri)
include($${DEPTH}/tests/tests.pri)
TARGET = tst_qamqpexchange
SOURCES = tst_qamqpexchange.cpp

View File

@ -0,0 +1,246 @@
#include <QtTest/QtTest>
#include "signalspy.h"
#include "qamqptestcase.h"
#include "qamqpclient.h"
#include "qamqpexchange.h"
#include "qamqpqueue.h"
class tst_QAMQPExchange : public TestCase
{
Q_OBJECT
private Q_SLOTS:
void init();
void cleanup();
void standardTypes_data();
void standardTypes();
void invalidStandardDeclaration_data();
void invalidStandardDeclaration();
void invalidDeclaration();
void invalidRedeclaration();
void removeIfUnused();
void invalidMandatoryRouting();
void invalidImmediateRouting();
void confirmsSupport();
void confirmDontLoseMessages();
void passiveDeclareNotFound();
void cleanupOnDeletion();
void testQueuedPublish();
private:
QScopedPointer<QAmqpClient> client;
};
void tst_QAMQPExchange::init()
{
client.reset(new QAmqpClient);
client->connectToHost();
QVERIFY(waitForSignal(client.data(), SIGNAL(connected())));
}
void tst_QAMQPExchange::cleanup()
{
if (client->isConnected()) {
client->disconnectFromHost();
QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected())));
}
}
void tst_QAMQPExchange::standardTypes_data()
{
QTest::addColumn<QAmqpExchange::ExchangeType>("type");
QTest::addColumn<bool>("delayedDeclaration");
QTest::newRow("direct") << QAmqpExchange::Direct << false;
QTest::newRow("direct-delayed") << QAmqpExchange::Direct << true;
QTest::newRow("fanout") << QAmqpExchange::FanOut << false;
QTest::newRow("fanout-delayed") << QAmqpExchange::FanOut << true;
QTest::newRow("topic") << QAmqpExchange::Topic << false;
QTest::newRow("topic-delayed") << QAmqpExchange::Topic << true;
QTest::newRow("headers") << QAmqpExchange::Headers << false;
QTest::newRow("headers-delayed") << QAmqpExchange::Headers << true;
}
void tst_QAMQPExchange::standardTypes()
{
QFETCH(QAmqpExchange::ExchangeType, type);
QFETCH(bool, delayedDeclaration);
QAmqpExchange *exchange = client->createExchange("test");
if (!delayedDeclaration)
QVERIFY(waitForSignal(exchange, SIGNAL(opened())));
exchange->declare(type);
QVERIFY(waitForSignal(exchange, SIGNAL(declared())));
exchange->remove(QAmqpExchange::roForce);
QVERIFY(waitForSignal(exchange, SIGNAL(removed())));
}
void tst_QAMQPExchange::invalidStandardDeclaration_data()
{
QTest::addColumn<QString>("exchangeName");
QTest::addColumn<QAmqpExchange::ExchangeType>("type");
QTest::addColumn<QAMQP::Error>("error");
QTest::newRow("amq.direct") << "amq.direct" << QAmqpExchange::Direct << QAMQP::PreconditionFailedError;
QTest::newRow("amq.fanout") << "amq.fanout" << QAmqpExchange::FanOut << QAMQP::PreconditionFailedError;
QTest::newRow("amq.headers") << "amq.headers" << QAmqpExchange::Headers << QAMQP::PreconditionFailedError;
QTest::newRow("amq.match") << "amq.match" << QAmqpExchange::Headers << QAMQP::PreconditionFailedError;
QTest::newRow("amq.topic") << "amq.topic" << QAmqpExchange::Topic << QAMQP::PreconditionFailedError;
QTest::newRow("amq.reserved") << "amq.reserved" << QAmqpExchange::Direct << QAMQP::AccessRefusedError;
}
void tst_QAMQPExchange::invalidStandardDeclaration()
{
QFETCH(QString, exchangeName);
QFETCH(QAmqpExchange::ExchangeType, type);
QFETCH(QAMQP::Error, error);
QAmqpExchange *exchange = client->createExchange(exchangeName);
exchange->declare(type);
QVERIFY(waitForSignal(exchange, SIGNAL(error(QAMQP::Error))));
QCOMPARE(exchange->error(), error);
}
void tst_QAMQPExchange::invalidDeclaration()
{
QAmqpExchange *exchange = client->createExchange("test-invalid-declaration");
exchange->declare("invalidExchangeType");
QVERIFY(waitForSignal(client.data(), SIGNAL(error(QAMQP::Error))));
QCOMPARE(client->error(), QAMQP::CommandInvalidError);
}
void tst_QAMQPExchange::invalidRedeclaration()
{
QAmqpExchange *exchange = client->createExchange("test-invalid-redeclaration");
exchange->declare(QAmqpExchange::Direct);
QVERIFY(waitForSignal(exchange, SIGNAL(declared())));
QAmqpExchange *redeclared = client->createExchange("test-invalid-redeclaration");
redeclared->declare(QAmqpExchange::FanOut);
QVERIFY(waitForSignal(redeclared, SIGNAL(error(QAMQP::Error))));
// this is per spec:
// QCOMPARE(redeclared->error(), QAMQP::NotAllowedError);
// this is for rabbitmq:
QCOMPARE(redeclared->error(), QAMQP::PreconditionFailedError);
// Server has probably closed the channel on us, if so, re-open it.
if (!exchange->isOpen()) {
exchange->reopen();
QVERIFY(waitForSignal(exchange, SIGNAL(opened())));
}
// cleanup
exchange->remove();
QVERIFY(waitForSignal(exchange, SIGNAL(removed())));
}
void tst_QAMQPExchange::removeIfUnused()
{
QAmqpExchange *exchange = client->createExchange("test-if-unused-exchange");
exchange->declare(QAmqpExchange::Direct, QAmqpExchange::AutoDelete);
QVERIFY(waitForSignal(exchange, SIGNAL(declared())));
QAmqpQueue *queue = client->createQueue("test-if-unused-queue");
queue->declare();
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
queue->bind("test-if-unused-exchange", "testRoutingKey");
QVERIFY(waitForSignal(queue, SIGNAL(bound())));
exchange->remove(QAmqpExchange::roIfUnused);
QVERIFY(waitForSignal(exchange, SIGNAL(error(QAMQP::Error))));
QCOMPARE(exchange->error(), QAMQP::PreconditionFailedError);
QVERIFY(!exchange->errorString().isEmpty());
// cleanup
queue->remove(QAmqpQueue::roForce);
QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}
void tst_QAMQPExchange::invalidMandatoryRouting()
{
QAmqpExchange *defaultExchange = client->createExchange();
defaultExchange->publish("some message", "unroutable-key", QAmqpMessage::PropertyHash(), QAmqpExchange::poMandatory);
QVERIFY(waitForSignal(defaultExchange, SIGNAL(error(QAMQP::Error))));
QCOMPARE(defaultExchange->error(), QAMQP::NoRouteError);
}
void tst_QAMQPExchange::invalidImmediateRouting()
{
QAmqpExchange *defaultExchange = client->createExchange();
defaultExchange->publish("some message", "unroutable-key", QAmqpMessage::PropertyHash(), QAmqpExchange::poImmediate);
QVERIFY(waitForSignal(client.data(), SIGNAL(error(QAMQP::Error))));
QCOMPARE(client->error(), QAMQP::NotImplementedError);
}
void tst_QAMQPExchange::confirmsSupport()
{
QAmqpExchange *exchange = client->createExchange("confirm-test");
exchange->enableConfirms();
QVERIFY(waitForSignal(exchange, SIGNAL(confirmsEnabled())));
}
void tst_QAMQPExchange::confirmDontLoseMessages()
{
QAmqpExchange *defaultExchange = client->createExchange();
defaultExchange->enableConfirms();
QVERIFY(waitForSignal(defaultExchange, SIGNAL(confirmsEnabled())));
QAmqpMessage::PropertyHash properties;
properties[QAmqpMessage::DeliveryMode] = "2"; // make message persistent
for (int i = 0; i < 10000; ++i)
defaultExchange->publish("noop", "confirms-test", properties);
QVERIFY(defaultExchange->waitForConfirms());
}
void tst_QAMQPExchange::passiveDeclareNotFound()
{
QAmqpExchange *nonExistentExchange = client->createExchange("this-does-not-exist");
nonExistentExchange->declare(QAmqpExchange::Direct, QAmqpExchange::Passive);
QVERIFY(waitForSignal(nonExistentExchange, SIGNAL(error(QAMQP::Error))));
QCOMPARE(nonExistentExchange->error(), QAMQP::NotFoundError);
}
void tst_QAMQPExchange::cleanupOnDeletion()
{
// create, declare, and close the wrong way
QAmqpExchange *exchange = client->createExchange("test-deletion");
exchange->declare();
QVERIFY(waitForSignal(exchange, SIGNAL(declared())));
exchange->close();
exchange->deleteLater();
QVERIFY(waitForSignal(exchange, SIGNAL(destroyed())));
// now create, declare, and close the right way
exchange = client->createExchange("test-deletion");
exchange->declare();
QVERIFY(waitForSignal(exchange, SIGNAL(declared())));
exchange->close();
QVERIFY(waitForSignal(exchange, SIGNAL(closed())));
}
void tst_QAMQPExchange::testQueuedPublish()
{
QAmqpExchange *defaultExchange = client->createExchange();
defaultExchange->enableConfirms();
QVERIFY(waitForSignal(defaultExchange, SIGNAL(confirmsEnabled())));
QAmqpMessage::PropertyHash properties;
properties[QAmqpMessage::DeliveryMode] = "2"; // make message persistent
for (int i = 0; i < 10000; ++i) {
QMetaObject::invokeMethod(defaultExchange, "publish", Qt::QueuedConnection,
Q_ARG(QString, "noop"), Q_ARG(QString, "confirms-test"),
Q_ARG(QAmqpMessage::PropertyHash, properties));
}
QVERIFY(defaultExchange->waitForConfirms());
}
QTEST_MAIN(tst_QAMQPExchange)
#include "tst_qamqpexchange.moc"

View File

@ -0,0 +1,6 @@
DEPTH = ../../..
include($${DEPTH}/qamqp.pri)
include($${DEPTH}/tests/tests.pri)
TARGET = tst_qamqpqueue
SOURCES = tst_qamqpqueue.cpp

View File

@ -0,0 +1,708 @@
#include <float.h>
#include <QScopedPointer>
#include <QtTest/QtTest>
#include "qamqptestcase.h"
#include "signalspy.h"
#include "qamqpclient.h"
#include "qamqpqueue.h"
#include "qamqpexchange.h"
class tst_QAMQPQueue : public TestCase
{
Q_OBJECT
private Q_SLOTS:
void init();
void cleanup();
void defaultExchange();
void standardExchanges_data();
void standardExchanges();
void invalidDeclaration_data();
void invalidDeclaration();
void invalidBind();
void unnamed();
void exclusiveAccess();
void exclusiveRemoval();
void notFound();
void remove();
void removeIfUnused();
void removeIfEmpty();
void bindUnbind();
void delayedBind();
void purge();
void canOnlyStartConsumingOnce();
void ensureConsumeOnlySentOnce();
void cancel();
void invalidCancelBecauseNotConsuming();
void invalidCancelBecauseInvalidConsumerTag();
void getEmpty();
void get();
void verifyContentEncodingIssue33();
void defineQos();
void invalidQos();
void qos();
void invalidRoutingKey();
void tableFieldDataTypes();
void messageProperties();
void emptyMessage();
void cleanupOnDeletion();
private:
QScopedPointer<QAmqpClient> client;
};
void tst_QAMQPQueue::init()
{
client.reset(new QAmqpClient);
client->connectToHost();
QVERIFY(waitForSignal(client.data(), SIGNAL(connected())));
}
void tst_QAMQPQueue::cleanup()
{
if (client->isConnected()) {
client->disconnectFromHost();
QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected())));
}
}
void tst_QAMQPQueue::defaultExchange()
{
QAmqpQueue *queue = client->createQueue("test-default-exchange");
declareQueueAndVerifyConsuming(queue);
QAmqpExchange *defaultExchange = client->createExchange();
defaultExchange->publish("first message", "test-default-exchange");
QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
QAmqpMessage message = queue->dequeue();
verifyStandardMessageHeaders(message, "test-default-exchange");
QCOMPARE(message.payload(), QByteArray("first message"));
}
void tst_QAMQPQueue::standardExchanges_data()
{
QTest::addColumn<QString>("exchange");
QTest::addColumn<bool>("delayedDeclaration");
QTest::newRow("amq.direct") << "amq.direct" << false;
QTest::newRow("amq.direct-delayed") << "amq.direct" << true;
QTest::newRow("amq.fanout") << "amq.fanout" << false;
QTest::newRow("amq.fanout-delayed") << "amq.fanout" << true;
QTest::newRow("amq.headers") << "amq.headers" << false;
QTest::newRow("amq.headers-delayed") << "amq.headers" << true;
QTest::newRow("amq.match") << "amq.match" << false;
QTest::newRow("amq.match-delayed") << "amq.match" << true;
QTest::newRow("amq.topic") << "amq.topic" << false;
QTest::newRow("amq.topic-delayed") << "amq.topic" << true;
}
void tst_QAMQPQueue::standardExchanges()
{
QFETCH(QString, exchange);
QFETCH(bool, delayedDeclaration);
QString queueName = QString("test-%1").arg(exchange);
QString routingKey = QString("testRoutingKey-%1").arg(exchange);
QAmqpQueue *queue = client->createQueue(queueName);
if (!delayedDeclaration)
QVERIFY(waitForSignal(queue, SIGNAL(opened())));
declareQueueAndVerifyConsuming(queue);
queue->bind(exchange, routingKey);
QVERIFY(waitForSignal(queue, SIGNAL(bound())));
QAmqpExchange *defaultExchange = client->createExchange(exchange);
defaultExchange->publish("test message", routingKey);
QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
QAmqpMessage message = queue->dequeue();
verifyStandardMessageHeaders(message, routingKey, exchange);
QCOMPARE(message.payload(), QByteArray("test message"));
}
void tst_QAMQPQueue::invalidDeclaration_data()
{
QTest::addColumn<QString>("queueName");
QTest::addColumn<QAMQP::Error>("error");
QTest::newRow("amq.direct") << "amq.direct" << QAMQP::AccessRefusedError;
QTest::newRow("amq.fanout") << "amq.fanout" << QAMQP::AccessRefusedError;
QTest::newRow("amq.headers") << "amq.headers" << QAMQP::AccessRefusedError;
QTest::newRow("amq.match") << "amq.match" << QAMQP::AccessRefusedError;
QTest::newRow("amq.topic") << "amq.topic" << QAMQP::AccessRefusedError;
QTest::newRow("amq.reserved") << "amq.reserved" << QAMQP::AccessRefusedError;
}
void tst_QAMQPQueue::invalidDeclaration()
{
QFETCH(QString, queueName);
QFETCH(QAMQP::Error, error);
QAmqpQueue *queue = client->createQueue(queueName);
queue->declare();
QVERIFY(waitForSignal(queue, SIGNAL(error(QAMQP::Error))));
QCOMPARE(queue->error(), error);
}
void tst_QAMQPQueue::invalidBind()
{
QAmqpQueue *queue = client->createQueue("test-invalid-bind");
declareQueueAndVerifyConsuming(queue);
queue->bind("non-existant-exchange", "routingKey");
QVERIFY(waitForSignal(queue, SIGNAL(error(QAMQP::Error))));
QCOMPARE(queue->error(), QAMQP::NotFoundError);
}
void tst_QAMQPQueue::unnamed()
{
QAmqpQueue *queue = client->createQueue();
declareQueueAndVerifyConsuming(queue);
QVERIFY(!queue->name().isEmpty());
}
void tst_QAMQPQueue::exclusiveAccess()
{
QAmqpQueue *queue = client->createQueue("test-exclusive-queue");
queue->declare(QAmqpQueue::Exclusive);
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
QVERIFY(queue->options() & QAmqpQueue::Exclusive);
QAmqpClient secondClient;
secondClient.connectToHost();
QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
QAmqpQueue *passiveQueue = secondClient.createQueue("test-exclusive-queue");
passiveQueue->declare(QAmqpQueue::Passive);
QVERIFY(waitForSignal(passiveQueue, SIGNAL(error(QAMQP::Error))));
QCOMPARE(passiveQueue->error(), QAMQP::ResourceLockedError);
secondClient.disconnectFromHost();
QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
}
void tst_QAMQPQueue::exclusiveRemoval()
{
QAmqpQueue *queue = client->createQueue("test-exclusive-queue");
queue->declare(QAmqpQueue::Exclusive);
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
QVERIFY(queue->options() & QAmqpQueue::Exclusive);
client.data()->disconnectFromHost();
QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected())));
// create a new client and try to access the queue that should
// no longer exist
QAmqpClient secondClient;
secondClient.connectToHost();
QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
QAmqpQueue *passiveQueue = secondClient.createQueue("test-exclusive-queue");
passiveQueue->declare(QAmqpQueue::Passive);
QVERIFY(waitForSignal(passiveQueue, SIGNAL(error(QAMQP::Error))));
QCOMPARE(passiveQueue->error(), QAMQP::NotFoundError);
secondClient.disconnectFromHost();
QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
}
void tst_QAMQPQueue::notFound()
{
QAmqpQueue *queue = client->createQueue("test-not-found");
queue->declare(QAmqpQueue::Passive);
QVERIFY(waitForSignal(queue, SIGNAL(error(QAMQP::Error))));
QCOMPARE(queue->error(), QAMQP::NotFoundError);
}
void tst_QAMQPQueue::remove()
{
QAmqpQueue *queue = client->createQueue("test-remove");
queue->declare();
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
queue->remove(QAmqpQueue::roIfEmpty|QAmqpQueue::roIfUnused);
QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}
void tst_QAMQPQueue::removeIfUnused()
{
QAmqpQueue *queue = client->createQueue("test-remove-if-unused");
declareQueueAndVerifyConsuming(queue);
queue->remove(QAmqpQueue::roIfUnused);
QVERIFY(waitForSignal(queue, SIGNAL(error(QAMQP::Error))));
QCOMPARE(queue->error(), QAMQP::PreconditionFailedError);
QVERIFY(!queue->errorString().isEmpty());
}
void tst_QAMQPQueue::removeIfEmpty()
{
// declare the queue and send messages to it
QAmqpQueue *queue = client->createQueue("test-remove-if-empty");
queue->declare(QAmqpQueue::Durable);
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
QVERIFY(queue->options() & QAmqpQueue::Durable);
QAmqpExchange *defaultExchange = client->createExchange();
defaultExchange->publish("first message", "test-remove-if-empty");
// create a second client and try to delete the queue
{
QAmqpClient secondClient;
secondClient.connectToHost();
QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
QAmqpQueue *testDeleteQueue = secondClient.createQueue("test-remove-if-empty");
testDeleteQueue->declare(QAmqpQueue::Passive);
QVERIFY(waitForSignal(testDeleteQueue, SIGNAL(declared())));
QVERIFY(testDeleteQueue->options() & QAmqpQueue::Passive);
testDeleteQueue->remove(QAmqpQueue::roIfEmpty);
QVERIFY(waitForSignal(testDeleteQueue, SIGNAL(error(QAMQP::Error))));
QCOMPARE(testDeleteQueue->error(), QAMQP::PreconditionFailedError);
QVERIFY(!testDeleteQueue->errorString().isEmpty());
secondClient.disconnectFromHost();
QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
}
// clean up queue
queue->remove(QAmqpQueue::roForce);
QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}
void tst_QAMQPQueue::bindUnbind()
{
QAmqpQueue *queue = client->createQueue("test-bind-unbind");
declareQueueAndVerifyConsuming(queue);
queue->bind("amq.topic", "routingKey");
QVERIFY(waitForSignal(queue, SIGNAL(bound())));
queue->unbind("amq.topic", "routingKey");
QVERIFY(waitForSignal(queue, SIGNAL(unbound())));
QAmqpExchange *amqTopic = client->createExchange("amq.topic");
amqTopic->declare(QAmqpExchange::Direct, QAmqpExchange::Passive);
QVERIFY(waitForSignal(amqTopic, SIGNAL(declared())));
queue->bind(amqTopic, "routingKey");
QVERIFY(waitForSignal(queue, SIGNAL(bound())));
queue->unbind(amqTopic, "routingKey");
QVERIFY(waitForSignal(queue, SIGNAL(unbound())));
}
void tst_QAMQPQueue::delayedBind()
{
client->disconnectFromHost();
QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected())));
QAmqpQueue *queue = client->createQueue("test-delayed-bind");
queue->declare();
queue->bind("amq.topic", "routingKey");
client->connectToHost();
QVERIFY(waitForSignal(client.data(), SIGNAL(connected())));
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
QVERIFY(waitForSignal(queue, SIGNAL(bound())));
// clean up queue
queue->remove(QAmqpQueue::roForce);
QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}
void tst_QAMQPQueue::purge()
{
QAmqpQueue *queue = client->createQueue("test-purge");
queue->declare(QAmqpQueue::Durable);
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
QVERIFY(queue->options() & QAmqpQueue::Durable);
QAmqpExchange *defaultExchange = client->createExchange();
defaultExchange->publish("first message", "test-purge");
defaultExchange->publish("second message", "test-purge");
defaultExchange->publish("third message", "test-purge");
// create second client to listen to messages and attempt purge
{
QAmqpClient secondClient;
secondClient.connectToHost();
QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
QAmqpQueue *testPurgeQueue = secondClient.createQueue("test-purge");
testPurgeQueue->declare(QAmqpQueue::Passive);
QVERIFY(waitForSignal(testPurgeQueue, SIGNAL(declared())));
QVERIFY(testPurgeQueue->options() & QAmqpQueue::Passive);
QSignalSpy spy(testPurgeQueue, SIGNAL(purged(int)));
testPurgeQueue->purge();
QVERIFY(waitForSignal(testPurgeQueue, SIGNAL(purged(int))));
QCOMPARE(spy.count(), 1);
QCOMPARE(testPurgeQueue->size(), 0);
QList<QVariant> arguments = spy.takeFirst();
QCOMPARE(arguments.at(0).toInt(), 3);
secondClient.disconnectFromHost();
QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
}
// clean up queue
queue->remove(QAmqpQueue::roForce);
QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}
void tst_QAMQPQueue::canOnlyStartConsumingOnce()
{
QAmqpQueue *queue = client->createQueue("test-single-consumer");
QSignalSpy spy(queue, SIGNAL(consuming(QString)));
declareQueueAndVerifyConsuming(queue);
QCOMPARE(queue->consume(), false);
}
void tst_QAMQPQueue::ensureConsumeOnlySentOnce()
{
QAmqpQueue *queue = client->createQueue("test-single-consumer");
QSignalSpy spy(queue, SIGNAL(consuming(QString)));
queue->declare();
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
// try to consume twice
QVERIFY(queue->consume());
QCOMPARE(queue->consume(), false);
QVERIFY(spy.wait());
QCOMPARE(spy.size(), 1);
// clean up queue
queue->remove(QAmqpQueue::roForce);
QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}
void tst_QAMQPQueue::cancel()
{
QAmqpQueue *queue = client->createQueue("test-cancel");
declareQueueAndVerifyConsuming(queue);
QString consumerTag = queue->consumerTag();
QSignalSpy cancelSpy(queue, SIGNAL(cancelled(QString)));
QVERIFY(queue->cancel());
QVERIFY(waitForSignal(queue, SIGNAL(cancelled(QString))));
QVERIFY(!cancelSpy.isEmpty());
QList<QVariant> arguments = cancelSpy.takeFirst();
QCOMPARE(arguments.at(0).toString(), consumerTag);
}
void tst_QAMQPQueue::invalidCancelBecauseNotConsuming()
{
QAmqpQueue *queue = client->createQueue("test-invalid-cancel-because-not-consuming");
queue->declare();
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
QCOMPARE(queue->cancel(), false);
// clean up queue
queue->remove(QAmqpQueue::roForce);
QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}
void tst_QAMQPQueue::invalidCancelBecauseInvalidConsumerTag()
{
QAmqpQueue *queue = client->createQueue("test-invalid-cancel-because-invalid-consumer-tag");
declareQueueAndVerifyConsuming(queue);
queue->setConsumerTag(QString());
QCOMPARE(queue->cancel(), false);
}
void tst_QAMQPQueue::getEmpty()
{
QAmqpQueue *queue = client->createQueue("test-get-empty");
declareQueueAndVerifyConsuming(queue);
queue->get();
QVERIFY(waitForSignal(queue, SIGNAL(empty())));
}
void tst_QAMQPQueue::get()
{
QAmqpQueue *queue = client->createQueue("test-get");
queue->declare();
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
const int messageCount = 200;
QAmqpExchange *defaultExchange = client->createExchange();
for (int i = 0; i < messageCount; ++i) {
QString expected = QString("message %1").arg(i);
defaultExchange->publish(expected, "test-get");
}
for (int i = 0; i < messageCount; ++i) {
QString expected = QString("message %1").arg(i);
queue->get(false);
if (!waitForSignal(queue, SIGNAL(messageReceived()))) {
// NOTE: this is here instead of waiting for messages to be
// available with a sleep above. It makes the test a little
// longer if there's a miss, look into a proper fix in the future
i--;
continue;
}
QAmqpMessage message = queue->dequeue();
verifyStandardMessageHeaders(message, "test-get");
QCOMPARE(message.payload(), expected.toUtf8());
queue->ack(message);
}
queue->get(false);
QVERIFY(waitForSignal(queue, SIGNAL(empty())));
// clean up queue
queue->remove(QAmqpQueue::roForce);
QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}
void tst_QAMQPQueue::verifyContentEncodingIssue33()
{
QAmqpQueue *queue = client->createQueue("test-issue-33");
declareQueueAndVerifyConsuming(queue);
QAmqpExchange *defaultExchange = client->createExchange();
QAmqpMessage::PropertyHash properties;
properties.insert(QAmqpMessage::ContentEncoding, "fakeContentEncoding");
defaultExchange->publish("some data", "test-issue-33", properties);
QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
QAmqpMessage message = queue->dequeue();
verifyStandardMessageHeaders(message, "test-issue-33");
QVERIFY(message.hasProperty(QAmqpMessage::ContentEncoding));
QString contentType = message.property(QAmqpMessage::ContentEncoding).toString();
QCOMPARE(contentType, QLatin1String("fakeContentEncoding"));
}
void tst_QAMQPQueue::defineQos()
{
QAmqpQueue *queue = client->createQueue("test-define-qos");
declareQueueAndVerifyConsuming(queue);
queue->qos(10);
QVERIFY(waitForSignal(queue, SIGNAL(qosDefined())));
QCOMPARE(queue->prefetchCount(), qint16(10));
QCOMPARE(queue->prefetchSize(), 0);
// clean up queue
queue->remove(QAmqpQueue::roForce);
QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}
void tst_QAMQPQueue::invalidQos()
{
QAmqpQueue *queue = client->createQueue("test-invalid-define-qos");
declareQueueAndVerifyConsuming(queue);
queue->qos(10, 10);
QVERIFY(waitForSignal(client.data(), SIGNAL(error(QAMQP::Error))));
QCOMPARE(client->error(), QAMQP::NotImplementedError);
}
void tst_QAMQPQueue::qos()
{
QAmqpQueue *queue = client->createQueue("test-qos");
queue->declare();
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
queue->qos(1);
QVERIFY(waitForSignal(queue, SIGNAL(qosDefined())));
QCOMPARE(queue->prefetchCount(), qint16(1));
QCOMPARE(queue->prefetchSize(), 0);
QVERIFY(queue->consume());
QVERIFY(waitForSignal(queue, SIGNAL(consuming(QString))));
// load up the queue
const int messageCount = 10;
QAmqpExchange *defaultExchange = client->createExchange();
for (int i = 0; i < messageCount; ++i) {
QString message = QString("message %1").arg(i);
defaultExchange->publish(message, "test-qos");
}
QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
int messageReceivedCount = 0;
while (!queue->isEmpty()) {
QString expected = QString("message %1").arg(messageReceivedCount);
QAmqpMessage message = queue->dequeue();
verifyStandardMessageHeaders(message, "test-qos");
QCOMPARE(message.payload(), expected.toUtf8());
queue->ack(message);
messageReceivedCount++;
if (messageReceivedCount < messageCount)
QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
}
QCOMPARE(messageReceivedCount, messageCount);
}
void tst_QAMQPQueue::invalidRoutingKey()
{
QString routingKey = QString("%1").arg('1', 256, QLatin1Char('0'));
QAmqpQueue *queue = client->createQueue(routingKey);
queue->declare();
QVERIFY(waitForSignal(client.data(), SIGNAL(error(QAMQP::Error))));
QCOMPARE(client->error(), QAMQP::FrameError);
}
void tst_QAMQPQueue::tableFieldDataTypes()
{
QAmqpQueue *queue = client->createQueue("test-table-field-data-types");
declareQueueAndVerifyConsuming(queue);
QAMQP::Decimal decimal;
decimal.scale = 2;
decimal.value = 12345;
QVariant decimalVariant = QVariant::fromValue<QAMQP::Decimal>(decimal);
QAmqpTable nestedTable;
nestedTable.insert("boolean", true);
nestedTable.insert("long-int", qint32(-65536));
QVariantList array;
array.append(true);
array.append(qint32(-65536));
QDateTime timestamp = QDateTime::currentDateTime();
QAmqpTable headers;
headers.insert("boolean", true);
headers.insert("short-short-int", qint8(-15));
headers.insert("short-short-uint", quint8(15));
headers.insert("short-int", qint16(-256));
headers.insert("short-uint", QVariant::fromValue(quint16(256)));
headers.insert("long-int", qint32(-65536));
headers.insert("long-uint", quint32(65536));
headers.insert("long-long-int", qint64(-2147483648));
headers.insert("long-long-uint", quint64(2147483648));
headers.insert("float", 230.7);
headers.insert("double", double(FLT_MAX));
headers.insert("decimal-value", decimalVariant);
headers.insert("short-string", QLatin1String("test"));
headers.insert("long-string", QLatin1String("test"));
headers.insert("timestamp", timestamp);
headers.insert("nested-table", nestedTable);
headers.insert("array", array);
headers.insert("bytes", QByteArray("abcdefg1234567"));
QAmqpExchange *defaultExchange = client->createExchange();
defaultExchange->publish("dummy", "test-table-field-data-types", "text.plain", headers);
QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
QAmqpMessage message = queue->dequeue();
QCOMPARE(message.header("boolean").toBool(), true);
QCOMPARE(qint8(message.header("short-short-int").toInt()), qint8(-15));
QCOMPARE(quint8(message.header("short-short-uint").toUInt()), quint8(15));
QCOMPARE(qint16(message.header("short-int").toInt()), qint16(-256));
QCOMPARE(quint16(message.header("short-uint").toUInt()), quint16(256));
QCOMPARE(qint32(message.header("long-int").toInt()), qint32(-65536));
QCOMPARE(quint32(message.header("long-uint").toUInt()), quint32(65536));
QCOMPARE(qint64(message.header("long-long-int").toLongLong()), qint64(-2147483648));
QCOMPARE(quint64(message.header("long-long-uint").toLongLong()), quint64(2147483648));
QCOMPARE(message.header("float").toFloat(), float(230.7));
QCOMPARE(message.header("double").toDouble(), double(FLT_MAX));
QCOMPARE(message.header("short-string").toString(), QLatin1String("test"));
QCOMPARE(message.header("long-string").toString(), QLatin1String("test"));
QCOMPARE(message.header("bytes").toByteArray(), QByteArray("abcdefg1234567"));
#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
QCOMPARE(message.header("timestamp").toDateTime().toSecsSinceEpoch(),
timestamp.toSecsSinceEpoch());
#else
QCOMPARE(message.header("timestamp").toDateTime().toTime_t(), timestamp.toTime_t());
#endif
QVERIFY(message.hasHeader("nested-table"));
QAmqpTable compareTable(message.header("nested-table").toHash());
foreach (QString key, nestedTable.keys()) {
QVERIFY(compareTable.contains(key));
QCOMPARE(nestedTable.value(key), compareTable.value(key));
}
QVERIFY(message.hasHeader("array"));
QVariantList compareArray = message.header("array").toList();
QCOMPARE(array, compareArray);
QAMQP::Decimal receivedDecimal = message.header("decimal-value").value<QAMQP::Decimal>();
QCOMPARE(receivedDecimal.scale, qint8(2));
QCOMPARE(receivedDecimal.value, quint32(12345));
}
void tst_QAMQPQueue::messageProperties()
{
QAmqpQueue *queue = client->createQueue("test-message-properties");
declareQueueAndVerifyConsuming(queue);
QDateTime timestamp = QDateTime::currentDateTime();
QAmqpMessage::PropertyHash properties;
properties.insert(QAmqpMessage::ContentType, "some-content-type");
properties.insert(QAmqpMessage::ContentEncoding, "some-content-encoding");
properties.insert(QAmqpMessage::DeliveryMode, 2);
properties.insert(QAmqpMessage::Priority, 5);
properties.insert(QAmqpMessage::CorrelationId, 42);
properties.insert(QAmqpMessage::ReplyTo, "another-queue");
properties.insert(QAmqpMessage::MessageId, "some-message-id");
properties.insert(QAmqpMessage::Expiration, "60000");
properties.insert(QAmqpMessage::Timestamp, timestamp);
properties.insert(QAmqpMessage::Type, "some-message-type");
properties.insert(QAmqpMessage::UserId, "guest");
properties.insert(QAmqpMessage::AppId, "some-app-id");
properties.insert(QAmqpMessage::ClusterID, "some-cluster-id");
QAmqpExchange *defaultExchange = client->createExchange();
defaultExchange->publish("dummy", "test-message-properties", properties);
QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
QAmqpMessage message = queue->dequeue();
QCOMPARE(message.property(QAmqpMessage::ContentType).toString(), QLatin1String("some-content-type"));
QCOMPARE(message.property(QAmqpMessage::ContentEncoding).toString(), QLatin1String("some-content-encoding"));
QCOMPARE(message.property(QAmqpMessage::DeliveryMode).toInt(), 2);
QCOMPARE(message.property(QAmqpMessage::Priority).toInt(), 5);
QCOMPARE(message.property(QAmqpMessage::CorrelationId).toInt(), 42);
QCOMPARE(message.property(QAmqpMessage::ReplyTo).toString(), QLatin1String("another-queue"));
QCOMPARE(message.property(QAmqpMessage::MessageId).toString(), QLatin1String("some-message-id"));
QCOMPARE(message.property(QAmqpMessage::Expiration).toString(), QLatin1String("60000"));
QCOMPARE(message.property(QAmqpMessage::Type).toString(), QLatin1String("some-message-type"));
QCOMPARE(message.property(QAmqpMessage::UserId).toString(), QLatin1String("guest"));
QCOMPARE(message.property(QAmqpMessage::AppId).toString(), QLatin1String("some-app-id"));
QCOMPARE(message.property(QAmqpMessage::ClusterID).toString(), QLatin1String("some-cluster-id"));
#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
QCOMPARE(message.property(QAmqpMessage::Timestamp).toDateTime().toSecsSinceEpoch(),
timestamp.toSecsSinceEpoch());
#else
QCOMPARE(message.property(QAmqpMessage::Timestamp).toDateTime().toTime_t(),
timestamp.toTime_t());
#endif
}
void tst_QAMQPQueue::emptyMessage()
{
QAmqpQueue *queue = client->createQueue("test-issue-43");
declareQueueAndVerifyConsuming(queue);
QAmqpExchange *defaultExchange = client->createExchange();
defaultExchange->publish("", "test-issue-43");
QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
QAmqpMessage message = queue->dequeue();
verifyStandardMessageHeaders(message, "test-issue-43");
QVERIFY(message.payload().isEmpty());
}
void tst_QAMQPQueue::cleanupOnDeletion()
{
// create, declare, and close the wrong way
QAmqpQueue *queue = client->createQueue("test-deletion");
queue->declare();
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
queue->close();
queue->deleteLater();
QVERIFY(waitForSignal(queue, SIGNAL(destroyed())));
// now create, declare, and close the right way
queue = client->createQueue("test-deletion");
queue->declare();
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
queue->close();
QVERIFY(waitForSignal(queue, SIGNAL(closed())));
}
QTEST_MAIN(tst_QAMQPQueue)
#include "tst_qamqpqueue.moc"

View File

@ -0,0 +1,50 @@
#ifndef QAMQPTESTCASE_H
#define QAMQPTESTCASE_H
#include <QObject>
#include <QTestEventLoop>
#include "qamqpqueue.h"
class TestCase : public QObject
{
public:
TestCase() {}
virtual ~TestCase() {}
protected:
bool waitForSignal(QObject *obj, const char *signal, int delay = 5)
{
QObject::connect(obj, signal, &QTestEventLoop::instance(), SLOT(exitLoop()));
QPointer<QObject> safe = obj;
QTestEventLoop::instance().enterLoop(delay);
if (!safe.isNull())
QObject::disconnect(safe, signal, &QTestEventLoop::instance(), SLOT(exitLoop()));
return !QTestEventLoop::instance().timeout();
}
void declareQueueAndVerifyConsuming(QAmqpQueue *queue)
{
queue->declare();
QVERIFY(waitForSignal(queue, SIGNAL(declared())));
QVERIFY(queue->consume());
QSignalSpy spy(queue, SIGNAL(consuming(QString)));
QVERIFY(waitForSignal(queue, SIGNAL(consuming(QString))));
QVERIFY(queue->isConsuming());
QVERIFY(!spy.isEmpty());
QList<QVariant> arguments = spy.takeFirst();
QCOMPARE(arguments.at(0).toString(), queue->consumerTag());
}
void verifyStandardMessageHeaders(const QAmqpMessage &message, const QString &routingKey,
const QString &exchangeName = QLatin1String(""),
bool redelivered = false)
{
QCOMPARE(message.routingKey(), routingKey);
QCOMPARE(message.exchangeName(), exchangeName);
QCOMPARE(message.isRedelivered(), redelivered);
}
};
#endif // QAMQPTESTCASE_H

View File

@ -0,0 +1,20 @@
#ifndef SIGNALSPY_H
#define SIGNALSPY_H
namespace QAMQP {
namespace Test {
bool waitForSignal(QObject *obj, const char *signal, int delay)
{
QObject::connect(obj, signal, &QTestEventLoop::instance(), SLOT(exitLoop()));
QPointer<QObject> safe = obj;
QTestEventLoop::instance().enterLoop(delay);
if (!safe.isNull())
QObject::disconnect(safe, signal, &QTestEventLoop::instance(), SLOT(exitLoop()));
return !QTestEventLoop::instance().timeout();
}
} // namespace Test
} // namespace QAMQP
#endif

View File

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC5zCCAc+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl
c3RDQTAeFw0xNDA4MjcxOTI2MDVaFw0xNTA4MjcxOTI2MDVaMCoxFzAVBgNVBAMM
Dm1icm9hZHN0LWJ1aWxkMQ8wDQYDVQQKDAZjbGllbnQwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQDrzmzjgxNXxXX+fgfjB5Pt+YbO2uQR9PDADUyk+8Kw
/v1xjZBqKSHaBJLMv2nHlfGM8p92XQoepWKtG4z49UsT6MMppfUnZ/TO6LgUuJtw
FaVYdJmzK8SPvsQ331id9f4grgMTiff+i6hM2Bb9Jq83/jnglrBm8T4KHjPjJXQi
MN8d7ZkV2bo2vFQcO/KNTODntqINp5+OFPboyjDbMoMgUTqnXJBQsWwA9EVq2JYs
FYtA5xsqk0yG9DBgI5ClfxESQQo6lHKYeX2KIuHVO5awPpm+wZbIeR3l5QFqQrQZ
zfw7ANsA1RK4c85jb8K0vHxX1wV3kB+2kqpi4jxm/ucnAgMBAAGjLzAtMAkGA1Ud
EwQCMAAwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3
DQEBBQUAA4IBAQAxoTOMViXAKveeYx7I0dve/Te3TXe6XTlF0iFNIMp0FB3X0OeA
Bjknf6SUxY4qYV9DsFBGtXg8irkbothVNQKrhSedb6n+OQGy5z24oJ+vWW5jCyf3
TBoWRLnHY52j/4KElNpbEddacreYY6Ft5VYLZuyXy2G18xWjUnE5EG+QkizgAWzw
w9aTxS7qyGb7/FklJhH5OA8izi4JNbIrLEcUw4ECgYihtdLnZz/ANTp4kwz7qjaj
X7+8V3h7R59/HOHglCbjtkhBVuRyz5ljTfMbCava4Za2solujAo4tRxvmhioog0t
QplQjUP4QM5jfFlD/1HXY2SzYPG0FIiRj93L
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA685s44MTV8V1/n4H4weT7fmGztrkEfTwwA1MpPvCsP79cY2Q
aikh2gSSzL9px5XxjPKfdl0KHqVirRuM+PVLE+jDKaX1J2f0zui4FLibcBWlWHSZ
syvEj77EN99YnfX+IK4DE4n3/ouoTNgW/SavN/454JawZvE+Ch4z4yV0IjDfHe2Z
Fdm6NrxUHDvyjUzg57aiDaefjhT26Mow2zKDIFE6p1yQULFsAPRFatiWLBWLQOcb
KpNMhvQwYCOQpX8REkEKOpRymHl9iiLh1TuWsD6ZvsGWyHkd5eUBakK0Gc38OwDb
ANUSuHPOY2/CtLx8V9cFd5AftpKqYuI8Zv7nJwIDAQABAoIBAQDj32PSqIQ0uZlB
CcHNXzFRM2VW2Ki1waI1taRveuu153Q8G7WHIaCY8vp56i/qs7ftoTkARQDWhLRK
3OjqXQDkiHaw9LNoFUm5+aKKQ6vSMNjMFkHBp3YYAx3TcH5Oh73BDufiJd4FmihV
uizdDlkdHwwHQRfPIyn01SMHStZjgkOqIOkKq1Me8uggiYpTh/2sbX931cwxJnSF
EvDOLTvLjJdj6aWjupUaMvMsZDHJdtTZxl/YPV/KO49EkaOz0Ijv4mD8a0FQ5QRa
ud1xITFlFXOeZNjH3n6/+4ypIJDkXddpfZUuetoZ3DPRZY5aalKW+SGy3zqLu8qh
0VGPRQ7BAoGBAP7xNXis1ErCybdI1wvo3XIcsq7YHsssD+2IFmNomdBF5e9QzAwU
Q63WD6qmcLCSzjSm4dYZNvFL9RLWUCIkC7nkpqt0bftDw//NTdyinJo/JNf4Lprx
uji5njju+FuU83Whu3QoBXFTv7Ql09bX/6EgCfx1cWrJEHC6L3oGE3SpAoGBAOzI
5BfC+5TTbqWbjoH8ycdpjbEvyhpRKT920spa2j0kNjduryJHtq1AemLsR9NOH67h
cO5YHD9ClRMXxI4ogVbzOGqVAy3LdYXCJIV8GO/WTjjDINoPNb2+VfaHCkboS+8y
d1HwwcFbK7p3dJFNF3ppDVXsTfZZzDAQfFqa6A9PAoGAPzmYtjW+bFAEcJT65/Q3
Pv6I/b2RXXeu94yBaOPfCXzcOk6CXBiGdE0bE4o1dkTiKMKeTVdxfcQFokdOFjl0
QwTGpMy6Hc8/g2fqAGa/ia1RONJO1JRQR5MY/yucojG9cxXKBFOMjf9kEowzDhwB
RHdKoraJix8UGbDC53MsTgkCgYBepze23/Td219ByFtBTyICGwnPKMFrn8ITYpaE
2aigBFe/9PkBhRVbUIkb/kQADhzQNcKFJKe2ChG5niiugzag4X1N7d9lcQ27uI4M
5jy5szt1qVr6kFX1UZ7fe7/59GZWaiAUm194wc9LLPFmHCEkh9YS4PGRZvgexphP
R9k4NQKBgQDXYokjEt6jl67724/J8gP09oTAxZCBSweZkTHErUg8NdsUJWqBGLP9
zFg1pOfAV9gy/qKm01SdG81lWcf8sDLa3QjB4WOW6x99DH2mQ7y69tStn8B3mAVB
o8Ddf50gjv54oSqFPrF1DAbBXWOEWfeLM44zyaBR9t28bNBJM4CEiQ==
-----END RSA PRIVATE KEY-----

Binary file not shown.

View File

@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICbzCCAVcCAQAwKjEXMBUGA1UEAwwObWJyb2Fkc3QtYnVpbGQxDzANBgNVBAoM
BmNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOvObOODE1fF
df5+B+MHk+35hs7a5BH08MANTKT7wrD+/XGNkGopIdoEksy/aceV8Yzyn3ZdCh6l
Yq0bjPj1SxPowyml9Sdn9M7ouBS4m3AVpVh0mbMrxI++xDffWJ31/iCuAxOJ9/6L
qEzYFv0mrzf+OeCWsGbxPgoeM+MldCIw3x3tmRXZuja8VBw78o1M4Oe2og2nn44U
9ujKMNsygyBROqdckFCxbAD0RWrYliwVi0DnGyqTTIb0MGAjkKV/ERJBCjqUcph5
fYoi4dU7lrA+mb7Blsh5HeXlAWpCtBnN/DsA2wDVErhzzmNvwrS8fFfXBXeQH7aS
qmLiPGb+5ycCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQAyDAY1l3GDSkLXOKId
GM0sB0Ve7tT64IsqFacp29wV15fgJH1368VOMwxiXRQVSvGQGWog0JzuX0qH12ZZ
+6zQnGhumuKtoqfwlPBFNtvFRFxQ61Dzk6RZaO5fC7ZW+cLrfcEjTh9X3ts2POwP
/iuFdr+r+422YDOmHY3gNKBYKg8MtaDUNSLSiwNEQ/CPNs3FsyObHutiMPgIKwqt
vZ2hkvvMWcYPf2dtPTS3AfMPWVP+zR4eDfeiKYoxCyYZHsvQEyYqP5P5U1elqia1
gR9WUuC6Li+7wju6ksFrrLKGPNDXvfOm3Ecqfc5JPgU+U4bJLFRT1CFEOuYRnViK
V/jK
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC5zCCAc+gAwIBAgIBATANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl
c3RDQTAeFw0xNDA4MjcxOTI0MjNaFw0xNTA4MjcxOTI0MjNaMCoxFzAVBgNVBAMM
Dm1icm9hZHN0LWJ1aWxkMQ8wDQYDVQQKDAZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQDDV2SFR4wdqcGTJjXoxufcRcg1QPBrsglR2rvQL40i
oF9U9QAASwtn5c1+A5pkEdOb6xOrND/qiCW1jQgBKzi9qMnL9+61Z/Xykq5Op4qj
oqf1l6DV5nyHo9DOmqMKlBUGFR1PvwRcxmtl76+ekLxRP3Z38YbJHj1FT2H/9Dno
ThoImcxiSeMI1T7yBfv5SZ4TVheRIabkRcwT5FrU3P6TkVJq2PBjH4n6cNlLAMka
Ias4Jnxip4Xg/kk9JXlfce45EAMlgEpp/6zSYQqvpESo/2elElP39sFBPvv7HNIh
si7AKzIsFlEpsUFlcBkC1SD9jxV2xVbXZssCiX3ZM5F1AgMBAAGjLzAtMAkGA1Ud
EwQCMAAwCwYDVR0PBAQDAgUgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3
DQEBBQUAA4IBAQCHXuSqK4vEDNIqZxMQiFqB4zwkz5KG3uZrbhqfHaqxxjinwlNJ
Sky9lAx2QN/sRDuk8M+8HZxRMsASIPzELMjjj19CduadkLFV4cj+0nP2m6K1li8y
RyGQpEwQi5MG2o+iQt3Ygw07KQJYhOXaifjEFJ8Q1U00KO+e9H7iLF8GrhLzmOv3
usLPIvE8dnNu+EkrC57c48g9vkzR+BWl4TA1TcJBy9r219Z4jGrIysPWJUPwhKJj
tf9Uk9oHbMkuv5Qc+NhCumkB82phIt5WxeL1mKgwKVxiZJ+4DysfD7cgni8jhq86
KZgEOMel6CekBa7ToLzUdvjU0SjT2DBBK6YD
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAw1dkhUeMHanBkyY16Mbn3EXINUDwa7IJUdq70C+NIqBfVPUA
AEsLZ+XNfgOaZBHTm+sTqzQ/6ogltY0IASs4vajJy/futWf18pKuTqeKo6Kn9Zeg
1eZ8h6PQzpqjCpQVBhUdT78EXMZrZe+vnpC8UT92d/GGyR49RU9h//Q56E4aCJnM
YknjCNU+8gX7+UmeE1YXkSGm5EXME+Ra1Nz+k5FSatjwYx+J+nDZSwDJGiGrOCZ8
YqeF4P5JPSV5X3HuORADJYBKaf+s0mEKr6REqP9npRJT9/bBQT77+xzSIbIuwCsy
LBZRKbFBZXAZAtUg/Y8VdsVW12bLAol92TORdQIDAQABAoIBAFKRwEWuBoYLWW2P
uz3Xxe4P+R65gmajbNkSsky/rNK0I1fP794v2nRiaMgZUct21ZGUfk3h2hqSzg29
vWJxGJzimdoDxP0dIpMUeWV54FpmyMRBAZUoxf63ue164+v2yCQ4DJnGzltA6+i8
tek6mL9nKfZtO2ILzC5d7bi5TTjp/SXUiKG3VAFSxgxoBC9PGlL7BNFbm9JXSket
LVIWNj781pqBMEHvj9aLVG0uKpkY5jRjShHQ1a1v3l/WSDBsoVaG8xzvZSE5wd7s
Fjzk53siyzapOBhTCJc8NFoA88SfYYQfxCVrhIxpDhH6rYBMi/j99DTlj+Goi6eo
7aqEkwECgYEA7YwtwqGtPbakc5Y6shmLyniDah8xaVfrK4duGBvuoZCMek+ee2DN
WaeUKcSBBL0wWGVxnTm5MHleeadc92vF8eI/T7LKDnqPGfg9I9nteI43wCuRqKbz
YDseZnngBWFM6QnhYJrL1mH66zTAolaW8e+4U0ZsNO/Wk3RP8FrZDFUCgYEA0oPp
DIW+6i43dC9AOKxPv6lWdYOHnnh050WftR3sYfQ5FEqLln0jbio1WvaukQtPeruz
WhhAYbrkSjy1286NMjkhO3FbofiUkTgpI9YSubIchbGcem9G58IfhA41mAGzrGer
t65ip6f2jwOZkRM+t5/65iqQuGoCIWlnBpO3kKECgYB6mX6ElSz0TO9TOJXSlZyw
QsKQYsj9tYKKVLtddg0TFadq+OyygKN7QiIV7HUqHPp2pOSeYMxTWFCKOPaiO91N
mZdTatMd5eM1ZAkqF6+YKM5dQB9NC91QLTLjcMNOA4nOPGs1kK7jVm5KNk+1eTsu
YqqfUBlIuP/l2oHnavvagQKBgFPIYiE0vbXwLOvVvmaP1bF/EMT2Uyxz3nsJD7YC
sciObYUw4ftD1K0MqW2JjhJ2AOzk9U2fJ0h+HEube/l+bF2XtS02QXTmPSLKyjzT
/2HejFF9TbzAuuSUMvzYtuXHj53HKOWSxvrY810Z3q2JjkWAq1edizmKH0zy6SkJ
813hAoGAIGMMqi8HsqsvgTQebYohwkRBG+G+JPVF6rPD/+WfglnIoo4sNWNBnh6Z
e/+TkLsZR0QVnbQtStabroxxCkBkjzoDgu2Ff2mKhcFMsuNwWm/2hWHD8VLMomWi
7BK4OjVcBxOoQelmBEuwIaCiuADZBFgGEbV5yBdv8yD+ewUP/Z0=
-----END RSA PRIVATE KEY-----

Binary file not shown.

View File

@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICbzCCAVcCAQAwKjEXMBUGA1UEAwwObWJyb2Fkc3QtYnVpbGQxDzANBgNVBAoM
BnNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMNXZIVHjB2p
wZMmNejG59xFyDVA8GuyCVHau9AvjSKgX1T1AABLC2flzX4DmmQR05vrE6s0P+qI
JbWNCAErOL2oycv37rVn9fKSrk6niqOip/WXoNXmfIej0M6aowqUFQYVHU+/BFzG
a2Xvr56QvFE/dnfxhskePUVPYf/0OehOGgiZzGJJ4wjVPvIF+/lJnhNWF5EhpuRF
zBPkWtTc/pORUmrY8GMfifpw2UsAyRohqzgmfGKnheD+ST0leV9x7jkQAyWASmn/
rNJhCq+kRKj/Z6USU/f2wUE++/sc0iGyLsArMiwWUSmxQWVwGQLVIP2PFXbFVtdm
ywKJfdkzkXUCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQB3B0Rve1QC6ygBlbFj
jYSwmyIID3OYuF4RvXGIzCQsh8+aJYWe4dMUcqRLlr13PmWQlle5v5F3x903Y5QN
IeQudApEelqJMI0QLOKALZWgX5YjF+z0AW/yhAu3QufEsERG4T5x2BJVKcrSIewl
ang2Hr4isGmlXS/VVPYa0K50lv7GgHsCookOSS52/MA7r5f48EmJeC2JO0sKKKkf
sMY9urBAIeGYNvXw/JuswlnfMpuUGEBoGnByc+3SecXiHGaUBn3xXSsbL+Ht8x9D
Sa0gyGqelTqxhcOU0YcvorxIPb6Jbms2J8GEmeq25vMlRTlDKJV01F7PMo/1reXU
KEn6
-----END CERTIFICATE REQUEST-----

Binary file not shown.

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICxjCCAa6gAwIBAgIJAOZK1btq1p0yMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMTCE15VGVzdENBMB4XDTE0MDgyNzE5MjI0MloXDTE1MDgyNzE5MjI0MlowEzER
MA8GA1UEAxMITXlUZXN0Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
AQC/T4RhynLiTGkcgfq6TVwKVtvRy2jAOFOG7p9g4NofVTa0HvEUjNITwPUrYQDa
OLSK6BtStss1aTeSDfkY9wejl1PZ02lgz2CeznOvWp/74Rz8Mjc7BGz3WFOqcfJt
6DyTj/wgE/lJXTVGXsojQtDChYwEPNSWmAXLz1nLj2Ac1B4uy5kVsBCXkhWcu4E8
xEaf6mIA9KvF1MWBgHkNbZ2DruYsdlA4h95+40wn2qDkm9RgmE2MyFjV8YYjwv2s
5G48+pj7o7Vg/3/QZFuoGnU8GJ4gFFVOQQRqKOUrVFrJGduiVXxqPNjTt1rfopX4
pC8GZ69NotARfrwlBflM+Dm/AgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0P
BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAJxWhxMpYywwJOkB243RhD76Y9OJ0q
RAboh03wrHpx5jgRZj4PxJrMdoDop/7mP9e/2UfIWVkVzKGH3ZPSrDaJ7bRooqgu
nR1T8yWm+/zDoKoZGl+pdc25rr+PcWbzXOuPZTukSM01AqgGuwmiRB70HzqJpV3u
IPLvkvrqUIcjpdi7ULmfB1caNzTMizviTK7b3ORG+pZUVMRmOzSkJOD1PoNXg7GQ
p5FisMP7ULL0RLtOMrqwwyCslMJ+8g9pJuCqNJEeoBQsh/lmEZANWTSYTPRIbQAM
cnhx6GDsER2zvDoTLLM4SXqWEXHsV5D06Z41fKXIDSgsSZVnzb6ZWxvd
-----END CERTIFICATE-----

View File

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC5zCCAc+gAwIBAgIBATANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl
c3RDQTAeFw0xNDA4MjcxOTI0MjNaFw0xNTA4MjcxOTI0MjNaMCoxFzAVBgNVBAMM
Dm1icm9hZHN0LWJ1aWxkMQ8wDQYDVQQKDAZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQDDV2SFR4wdqcGTJjXoxufcRcg1QPBrsglR2rvQL40i
oF9U9QAASwtn5c1+A5pkEdOb6xOrND/qiCW1jQgBKzi9qMnL9+61Z/Xykq5Op4qj
oqf1l6DV5nyHo9DOmqMKlBUGFR1PvwRcxmtl76+ekLxRP3Z38YbJHj1FT2H/9Dno
ThoImcxiSeMI1T7yBfv5SZ4TVheRIabkRcwT5FrU3P6TkVJq2PBjH4n6cNlLAMka
Ias4Jnxip4Xg/kk9JXlfce45EAMlgEpp/6zSYQqvpESo/2elElP39sFBPvv7HNIh
si7AKzIsFlEpsUFlcBkC1SD9jxV2xVbXZssCiX3ZM5F1AgMBAAGjLzAtMAkGA1Ud
EwQCMAAwCwYDVR0PBAQDAgUgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3
DQEBBQUAA4IBAQCHXuSqK4vEDNIqZxMQiFqB4zwkz5KG3uZrbhqfHaqxxjinwlNJ
Sky9lAx2QN/sRDuk8M+8HZxRMsASIPzELMjjj19CduadkLFV4cj+0nP2m6K1li8y
RyGQpEwQi5MG2o+iQt3Ygw07KQJYhOXaifjEFJ8Q1U00KO+e9H7iLF8GrhLzmOv3
usLPIvE8dnNu+EkrC57c48g9vkzR+BWl4TA1TcJBy9r219Z4jGrIysPWJUPwhKJj
tf9Uk9oHbMkuv5Qc+NhCumkB82phIt5WxeL1mKgwKVxiZJ+4DysfD7cgni8jhq86
KZgEOMel6CekBa7ToLzUdvjU0SjT2DBBK6YD
-----END CERTIFICATE-----

View File

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC5zCCAc+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl
c3RDQTAeFw0xNDA4MjcxOTI2MDVaFw0xNTA4MjcxOTI2MDVaMCoxFzAVBgNVBAMM
Dm1icm9hZHN0LWJ1aWxkMQ8wDQYDVQQKDAZjbGllbnQwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQDrzmzjgxNXxXX+fgfjB5Pt+YbO2uQR9PDADUyk+8Kw
/v1xjZBqKSHaBJLMv2nHlfGM8p92XQoepWKtG4z49UsT6MMppfUnZ/TO6LgUuJtw
FaVYdJmzK8SPvsQ331id9f4grgMTiff+i6hM2Bb9Jq83/jnglrBm8T4KHjPjJXQi
MN8d7ZkV2bo2vFQcO/KNTODntqINp5+OFPboyjDbMoMgUTqnXJBQsWwA9EVq2JYs
FYtA5xsqk0yG9DBgI5ClfxESQQo6lHKYeX2KIuHVO5awPpm+wZbIeR3l5QFqQrQZ
zfw7ANsA1RK4c85jb8K0vHxX1wV3kB+2kqpi4jxm/ucnAgMBAAGjLzAtMAkGA1Ud
EwQCMAAwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3
DQEBBQUAA4IBAQAxoTOMViXAKveeYx7I0dve/Te3TXe6XTlF0iFNIMp0FB3X0OeA
Bjknf6SUxY4qYV9DsFBGtXg8irkbothVNQKrhSedb6n+OQGy5z24oJ+vWW5jCyf3
TBoWRLnHY52j/4KElNpbEddacreYY6Ft5VYLZuyXy2G18xWjUnE5EG+QkizgAWzw
w9aTxS7qyGb7/FklJhH5OA8izi4JNbIrLEcUw4ECgYihtdLnZz/ANTp4kwz7qjaj
X7+8V3h7R59/HOHglCbjtkhBVuRyz5ljTfMbCava4Za2solujAo4tRxvmhioog0t
QplQjUP4QM5jfFlD/1HXY2SzYPG0FIiRj93L
-----END CERTIFICATE-----

View File

@ -0,0 +1,2 @@
V 150827192423Z 01 unknown /CN=mbroadst-build/O=server
V 150827192605Z 02 unknown /CN=mbroadst-build/O=client

View File

@ -0,0 +1 @@
unique_subject = yes

View File

@ -0,0 +1 @@
unique_subject = yes

View File

@ -0,0 +1 @@
V 150827192423Z 01 unknown /CN=mbroadst-build/O=server

View File

@ -0,0 +1,53 @@
[ ca ]
default_ca = testca
[ testca ]
dir = .
certificate = $dir/cacert.pem
database = $dir/index.txt
new_certs_dir = $dir/certs
private_key = $dir/private/cakey.pem
serial = $dir/serial
default_crl_days = 7
default_days = 365
default_md = sha1
policy = testca_policy
x509_extensions = certificate_extensions
[ testca_policy ]
commonName = supplied
stateOrProvinceName = optional
countryName = optional
emailAddress = optional
organizationName = optional
organizationalUnitName = optional
[ certificate_extensions ]
basicConstraints = CA:false
[ req ]
default_bits = 2048
default_keyfile = ./private/cakey.pem
default_md = sha1
prompt = yes
distinguished_name = root_ca_distinguished_name
x509_extensions = root_ca_extensions
[ root_ca_distinguished_name ]
commonName = hostname
[ root_ca_extensions ]
basicConstraints = CA:true
keyUsage = keyCertSign, cRLSign
[ client_ca_extensions ]
basicConstraints = CA:false
keyUsage = digitalSignature
extendedKeyUsage = 1.3.6.1.5.5.7.3.2
[ server_ca_extensions ]
basicConstraints = CA:false
keyUsage = keyEncipherment
extendedKeyUsage = 1.3.6.1.5.5.7.3.1

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/T4RhynLiTGkc
gfq6TVwKVtvRy2jAOFOG7p9g4NofVTa0HvEUjNITwPUrYQDaOLSK6BtStss1aTeS
DfkY9wejl1PZ02lgz2CeznOvWp/74Rz8Mjc7BGz3WFOqcfJt6DyTj/wgE/lJXTVG
XsojQtDChYwEPNSWmAXLz1nLj2Ac1B4uy5kVsBCXkhWcu4E8xEaf6mIA9KvF1MWB
gHkNbZ2DruYsdlA4h95+40wn2qDkm9RgmE2MyFjV8YYjwv2s5G48+pj7o7Vg/3/Q
ZFuoGnU8GJ4gFFVOQQRqKOUrVFrJGduiVXxqPNjTt1rfopX4pC8GZ69NotARfrwl
BflM+Dm/AgMBAAECggEAUGYEhmxkN4JRMi/VxPG52oaCPvqy/QUu5SfnRvl38W8I
XE4clrxPlQmkfyR3DT6DcVT2Fp7Ha5zaQ8EnjDxUs4VnMcXNJWhBfLvaljkJvvru
CXa5C05i1NgD4T+d2F6fBoyeMoTyYMiRGQ/A92ye+wDQxP8jgF5HIU30uL16cOJh
/Znu6JJBjYgE9g7ce8REEpi2Fru2Ixj147ge1ICW801i0Xy5susCJvH3I817GKoq
NonAn5P+5zTv9mECDnNkhRViATigrQ8DYikNewPknrmfb0IMAvF8dTnCWI4KuorD
c4TD7w/zzrpncWNCnsDgWfgq9u9Anp6bvhED0VLiMQKBgQDgewv8skGmm4xAUKdR
BsDYIUgip57qj4EmPkjypn8lzVjDUnbBhr/NAUQK5pKnrzFE2H9/H7M1zlNwk1FS
m6GYjx4DmnGAvQ0LCBs4gxlT878n7TYTxkTge69tYQ0lmmAGGajmv2G4TtVADMlG
rojrQIYoSggVkUI+AyGhHhm8xQKBgQDaLCyBUSWPOMc33AozWMm2OYJ4nFWd1A0C
SLgpR6/+D8mT3o6YRYIMmh6AUFCENAKitbKujQOaKRll5aaNWO4JohhgcuzGEj5C
4F++7SXd6E/1+gtExnOHkPJ9z3FIeSoGCDK3DmfE8H9fcMM5mFZG7OVna3arINv4
nT8s3aAMswKBgQDDM5yn3+Zg17AtGTV1qxa0mrRclkAFnkZjGBRdFNVJ7Pf72VC1
VtSgkzI0/G2Y7So9wLmVtN4ksscyBJjZ6cWqoQErhvieR0b5SdJJ4Q58R1/5ezfk
GCw6vLM+vP8urMBFbbjG9rMmDz83FCdOlGUxlQlULZQ8FPVycUykC0W8NQKBgEjA
fj7JLnsp9dS8vXIN44Wue8F4cFxm/8eJNFAfpaJU5WU3y9kfJJTLN+yV26OaLF7R
tDncsBzSI7QE9psf0pDHytUuvaH3J2fppkPmlMAA3dkqfmN6wb+tKA+oAyCltsu4
JCFC3nufrvnGgnNMR0jzajQoc7PxCylGVnDBnsNdAoGAV62Nc+T6HdZa9yDSPU5p
bNT40q0iZHmTUa6QQl+ZsRZP8u4w+RnfcUOK+QKJr43DraJgjWtwbO2VnCIMTA21
EsSGuOCEMuYLMkswOrAJfM80FalsF3I74s5TbGYaczXXOe54XZJ8tyWSP0IiwreO
+eejI2bW3rU9TfBDdpR5Ks8=
-----END PRIVATE KEY-----

View File

@ -0,0 +1 @@
03

View File

@ -0,0 +1 @@
02

View File

@ -0,0 +1,14 @@
#!/bin/bash
echo "[
{rabbit, [
{ssl_listeners, [5671]},
{ssl_options, [{cacertfile,'${TRAVIS_BUILD_DIR}/tests/files/certs/testca/cacert.pem'},
{certfile,'${TRAVIS_BUILD_DIR}/tests/files/certs/server/cert.pem'},
{keyfile, '${TRAVIS_BUILD_DIR}/tests/files/certs/server/key.pem'},
{verify,verify_peer},
{fail_if_no_peer_cert,false}]}
]}
]." >> rabbitmq.config
sudo CONFIG_FILE=$PWD RABBITMQ_NODENAME=test-rabbitmq rabbitmq-server -detached

View File

@ -0,0 +1,10 @@
#!/bin/sh
if [ "$QT_SELECT" = "qt4" ]; then
sudo apt-get update
sudo apt-get install libqt4-dev
else
sudo add-apt-repository -y ppa:canonical-qt5-edgers/ubuntu1204-qt5
sudo apt-get update
sudo apt-get install qtbase5-dev
fi

4
qamqp/tests/gen-coverage.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
lcov --capture --directory . --output-file coverage-gcov.info --no-external
lcov --output-file coverage-gcov.info --remove coverage-gcov.info 'moc_*.cpp' '*.moc*' '.*rcc*' '*3rdparty*'
genhtml coverage-gcov.info --output-directory doc/coverage

17
qamqp/tests/tests.pri Normal file
View File

@ -0,0 +1,17 @@
INCLUDEPATH += $${QAMQP_INCLUDEPATH} $${PWD}/common
LIBS += -L$${DEPTH}/src $${QAMQP_LIBS}
unix:!macx:QMAKE_RPATHDIR += $${OUT_PWD}/$${DEPTH}/src
macx {
QMAKE_RPATHDIR += @loader_path/$${DEPTH}/src
QMAKE_LFLAGS += -Wl,-rpath,@loader_path/$${DEPTH}/src
}
QT = core network testlib
QT -= gui
CONFIG -= app_bundle
CONFIG += testcase no_testcase_installs
HEADERS += \
$${PWD}/common/signalspy.h \
$${PWD}/common/qamqptestcase.h

3
qamqp/tests/tests.pro Normal file
View File

@ -0,0 +1,3 @@
TEMPLATE = subdirs
SUBDIRS = \
auto

View File

@ -0,0 +1,4 @@
TEMPLATE = subdirs
SUBDIRS = \
send \
receive

View File

@ -0,0 +1,81 @@
#include <QCoreApplication>
#include <QDebug>
#include "qamqpclient.h"
#include "qamqpexchange.h"
#include "qamqpqueue.h"
class Receiver : public QObject
{
Q_OBJECT
public:
Receiver(QObject *parent = 0) : QObject(parent) {
m_client.setAutoReconnect(true);
}
public Q_SLOTS:
void start() {
connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected()));
m_client.connectToHost();
}
private Q_SLOTS:
void clientConnected() {
QAmqpQueue *queue = m_client.createQueue("hello");
disconnect(queue, 0, 0, 0); // in case this is a reconnect
connect(queue, SIGNAL(declared()), this, SLOT(queueDeclared()));
queue->declare();
}
void queueDeclared() {
QAmqpQueue *queue = qobject_cast<QAmqpQueue*>(sender());
if (!queue)
return;
connect(queue, SIGNAL(messageReceived()), this, SLOT(messageReceived()));
// queue->consume(QAmqpQueue::coNoAck);
// queue->consume(QAmqpQueue::coNoLocal);
qint32 sizeQueue = queue->messageCount();
while (sizeQueue--) {
queue->get(false);
}
qDebug() << " [*] Waiting for messages. To exit press CTRL+C";
queue->ack(3, false); // Acknowledgement the 3rd message.
queue->reopen();
// m_client.disconnectFromHost();
}
void messageReceived() {
QAmqpQueue *queue = qobject_cast<QAmqpQueue*>(sender());
if (!queue)
return;
QAmqpMessage message = queue->dequeue();
qDebug() << " [x] Received in" << message.payload();
int input=0;
// std::scanf("%d", &input);
qDebug() << " [x] Received out, " << message.deliveryTag() << " | " << message.payload() << " , input = " << input;
}
private:
QAmqpClient m_client;
};
int main(int argc, char **argv)
{
qDebug() << " Recieve starts ... ";
QCoreApplication app(argc, argv);
Receiver receiver;
receiver.start();
return app.exec();
}
#include "main.moc"

View File

@ -0,0 +1,9 @@
DEPTH = ../../..
include($${DEPTH}/qamqp.pri)
TEMPLATE = app
INCLUDEPATH += $${QAMQP_INCLUDEPATH}
LIBS += -L$${DEPTH}/src $${QAMQP_LIBS}
macx:CONFIG -= app_bundle
SOURCES += main.cpp

View File

@ -0,0 +1,60 @@
#include <QCoreApplication>
#include <QTimer>
#include <QDebug>
#include "qamqpclient.h"
#include "qamqpexchange.h"
#include "qamqpqueue.h"
class Sender : public QObject
{
Q_OBJECT
public:
Sender(QObject *parent = 0) : QObject(parent) {}
public Q_SLOTS:
void start() {
connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected()));
connect(&m_client, SIGNAL(disconnected()), qApp, SLOT(quit()));
m_client.connectToHost();
}
private Q_SLOTS:
void clientConnected() {
QAmqpQueue *queue = m_client.createQueue("hello");
connect(queue, SIGNAL(declared()), this, SLOT(queueDeclared()));
queue->declare();
}
void queueDeclared() {
QAmqpQueue *queue = qobject_cast<QAmqpQueue*>(sender());
if (!queue)
return;
QAmqpExchange *defaultExchange = m_client.createExchange();
defaultExchange->publish("Hello World! A", "hello");
qDebug() << " [x] Sent 'Hello World! A'";
defaultExchange->publish("Hello World! B", "hello");
qDebug() << " [x] Sent 'Hello World! B'";
defaultExchange->publish("Hello World! C", "hello");
qDebug() << " [x] Sent 'Hello World! C'";
defaultExchange->publish("Hello World! D", "hello");
qDebug() << " [x] Sent 'Hello World! D'";
defaultExchange->publish("Hello World! E", "hello");
qDebug() << " [x] Sent 'Hello World! E'";
m_client.disconnectFromHost();
}
private:
QAmqpClient m_client;
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
Sender sender;
sender.start();
return app.exec();
}
#include "main.moc"

View File

@ -0,0 +1,9 @@
DEPTH = ../../..
include($${DEPTH}/qamqp.pri)
TEMPLATE = app
INCLUDEPATH += $${QAMQP_INCLUDEPATH}
LIBS += -L$${DEPTH}/src $${QAMQP_LIBS}
macx:CONFIG -= app_bundle
SOURCES += main.cpp

View File

@ -0,0 +1,9 @@
DEPTH = ../../..
include($${DEPTH}/qamqp.pri)
TEMPLATE = app
INCLUDEPATH += $${QAMQP_INCLUDEPATH}
LIBS += -L$${DEPTH}/src $${QAMQP_LIBS}
macx:CONFIG -= app_bundle
SOURCES += main.cpp

View File

@ -0,0 +1,57 @@
#include <QCoreApplication>
#include <QStringList>
#include <QDebug>
#include "qamqpclient.h"
#include "qamqpexchange.h"
#include "qamqpqueue.h"
class LogEmitter : public QObject
{
Q_OBJECT
public:
LogEmitter(QObject *parent = 0) : QObject(parent) {}
public Q_SLOTS:
void start() {
connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected()));
connect(&m_client, SIGNAL(disconnected()), qApp, SLOT(quit()));
m_client.connectToHost();
}
private Q_SLOTS:
void clientConnected() {
QAmqpExchange *exchange = m_client.createExchange("logs");
connect(exchange, SIGNAL(declared()), this, SLOT(exchangeDeclared()));
exchange->declare(QAmqpExchange::FanOut);
}
void exchangeDeclared() {
QAmqpExchange *exchange = qobject_cast<QAmqpExchange*>(sender());
if (!exchange)
return;
QString message;
if (qApp->arguments().size() < 2)
message = "info: Hello World!";
else
message = qApp->arguments().at(1);
exchange->publish(message, "");
qDebug() << " [x] Sent " << message;
m_client.disconnectFromHost();
}
private:
QAmqpClient m_client;
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
LogEmitter logEmitter;
logEmitter.start();
return app.exec();
}
#include "main.moc"

View File

@ -0,0 +1,4 @@
TEMPLATE = subdirs
SUBDIRS = \
receive_logs \
emit_log

View File

@ -0,0 +1,75 @@
#include <QCoreApplication>
#include <QTimer>
#include <QDebug>
#include "qamqpclient.h"
#include "qamqpexchange.h"
#include "qamqpqueue.h"
class LogReceiver : public QObject
{
Q_OBJECT
public:
LogReceiver(QObject *parent = 0) : QObject(parent) {}
public Q_SLOTS:
void start() {
connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected()));
m_client.connectToHost();
}
private Q_SLOTS:
void clientConnected() {
QAmqpExchange *exchange = m_client.createExchange("logs");
connect(exchange, SIGNAL(declared()), this, SLOT(exchangeDeclared()));
exchange->declare(QAmqpExchange::FanOut);
}
void exchangeDeclared() {
QAmqpQueue *temporaryQueue = m_client.createQueue();
connect(temporaryQueue, SIGNAL(declared()), this, SLOT(queueDeclared()));
connect(temporaryQueue, SIGNAL(bound()), this, SLOT(queueBound()));
connect(temporaryQueue, SIGNAL(messageReceived()), this, SLOT(messageReceived()));
temporaryQueue->declare(QAmqpQueue::Exclusive);
}
void queueDeclared() {
QAmqpQueue *temporaryQueue = qobject_cast<QAmqpQueue*>(sender());
if (!temporaryQueue)
return;
temporaryQueue->bind("logs", temporaryQueue->name());
}
void queueBound() {
QAmqpQueue *temporaryQueue = qobject_cast<QAmqpQueue*>(sender());
if (!temporaryQueue)
return;
qDebug() << " [*] Waiting for logs. To exit press CTRL+C";
temporaryQueue->consume(QAmqpQueue::coNoAck);
}
void messageReceived() {
QAmqpQueue *temporaryQueue = qobject_cast<QAmqpQueue*>(sender());
if (!temporaryQueue)
return;
QAmqpMessage message = temporaryQueue->dequeue();
qDebug() << " [x] " << message.payload();
}
private:
QAmqpClient m_client;
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
LogReceiver logReceiver;
logReceiver.start();
return app.exec();
}
#include "main.moc"

View File

@ -0,0 +1,9 @@
DEPTH = ../../..
include($${DEPTH}/qamqp.pri)
TEMPLATE = app
INCLUDEPATH += $${QAMQP_INCLUDEPATH}
LIBS += -L$${DEPTH}/src $${QAMQP_LIBS}
macx:CONFIG -= app_bundle
SOURCES += main.cpp

View File

@ -0,0 +1,9 @@
DEPTH = ../../..
include($${DEPTH}/qamqp.pri)
TEMPLATE = app
INCLUDEPATH += $${QAMQP_INCLUDEPATH}
LIBS += -L$${DEPTH}/src $${QAMQP_LIBS}
macx:CONFIG -= app_bundle
SOURCES += main.cpp

View File

@ -0,0 +1,64 @@
#include <QCoreApplication>
#include <QStringList>
#include <QDebug>
#include "qamqpclient.h"
#include "qamqpexchange.h"
#include "qamqpqueue.h"
class DirectLogEmitter : public QObject
{
Q_OBJECT
public:
DirectLogEmitter(QObject *parent = 0) : QObject(parent) {}
public Q_SLOTS:
void start() {
connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected()));
connect(&m_client, SIGNAL(disconnected()), qApp, SLOT(quit()));
m_client.connectToHost();
}
private Q_SLOTS:
void clientConnected() {
QAmqpExchange *direct_logs = m_client.createExchange("direct_logs");
connect(direct_logs, SIGNAL(declared()), this, SLOT(exchangeDeclared()));
direct_logs->declare(QAmqpExchange::Direct);
}
void exchangeDeclared() {
QAmqpExchange *direct_logs = qobject_cast<QAmqpExchange*>(sender());
if (!direct_logs)
return;
QStringList args = qApp->arguments();
args.takeFirst(); // remove executable name
QString severity = (args.isEmpty() ? "info" : args.first());
QString message;
if (args.size() > 1) {
args.takeFirst();
message = args.join(" ");
} else {
message = "Hello World!";
}
direct_logs->publish(message, severity);
qDebug(" [x] Sent %s:%s", severity.toLatin1().constData(), message.toLatin1().constData());
m_client.disconnectFromHost();
}
private:
QAmqpClient m_client;
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
DirectLogEmitter logEmitter;
logEmitter.start();
return app.exec();
}
#include "main.moc"

View File

@ -0,0 +1,78 @@
#include <QCoreApplication>
#include <QStringList>
#include <QDebug>
#include "qamqpclient.h"
#include "qamqpexchange.h"
#include "qamqpqueue.h"
class DirectLogReceiver : public QObject
{
Q_OBJECT
public:
DirectLogReceiver(QObject *parent = 0) : QObject(parent) {}
public Q_SLOTS:
void start(const QStringList &severities) {
m_severities = severities;
connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected()));
m_client.connectToHost();
}
private Q_SLOTS:
void clientConnected() {
QAmqpExchange *exchange = m_client.createExchange("direct_logs");
connect(exchange, SIGNAL(declared()), this, SLOT(exchangeDeclared()));
exchange->declare(QAmqpExchange::Direct);
}
void exchangeDeclared() {
QAmqpQueue *temporaryQueue = m_client.createQueue();
connect(temporaryQueue, SIGNAL(declared()), this, SLOT(queueDeclared()));
connect(temporaryQueue, SIGNAL(messageReceived()), this, SLOT(messageReceived()));
temporaryQueue->declare(QAmqpQueue::Exclusive);
}
void queueDeclared() {
QAmqpQueue *temporaryQueue = qobject_cast<QAmqpQueue*>(sender());
if (!temporaryQueue)
return;
// start consuming
temporaryQueue->consume(QAmqpQueue::coNoAck);
foreach (QString severity, m_severities)
temporaryQueue->bind("direct_logs", severity);
qDebug() << " [*] Waiting for logs. To exit press CTRL+C";
}
void messageReceived() {
QAmqpQueue *temporaryQueue = qobject_cast<QAmqpQueue*>(sender());
if (!temporaryQueue)
return;
QAmqpMessage message = temporaryQueue->dequeue();
qDebug() << " [x] " << message.routingKey() << ":" << message.payload();
}
private:
QAmqpClient m_client;
QStringList m_severities;
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
QStringList severities = app.arguments().mid(1);
if (severities.isEmpty()) {
qDebug("usage: %s [info] [warning] [error]", argv[0]);
return 1;
}
DirectLogReceiver logReceiver;
logReceiver.start(severities);
return app.exec();
}
#include "main.moc"

View File

@ -0,0 +1,9 @@
DEPTH = ../../..
include($${DEPTH}/qamqp.pri)
TEMPLATE = app
INCLUDEPATH += $${QAMQP_INCLUDEPATH}
LIBS += -L$${DEPTH}/src $${QAMQP_LIBS}
macx:CONFIG -= app_bundle
SOURCES += main.cpp

View File

@ -0,0 +1,4 @@
TEMPLATE = subdirs
SUBDIRS = \
emit_log_direct \
receive_logs_direct

View File

@ -0,0 +1,4 @@
TEMPLATE = subdirs
SUBDIRS = \
rpc_server \
rpc_client

View File

@ -0,0 +1,72 @@
#include <QCoreApplication>
#include <QEventLoop>
#include <QUuid>
#include "qamqpclient.h"
#include "qamqpexchange.h"
#include "qamqpqueue.h"
#include "fibonaccirpcclient.h"
FibonacciRpcClient::FibonacciRpcClient(QObject *parent)
: QObject(parent),
m_client(0),
m_responseQueue(0),
m_defaultExchange(0)
{
m_client = new QAmqpClient(this);
connect(m_client, SIGNAL(connected()), this, SLOT(clientConnected()));
}
FibonacciRpcClient::~FibonacciRpcClient()
{
}
bool FibonacciRpcClient::connectToServer()
{
QEventLoop loop;
connect(this, SIGNAL(connected()), &loop, SLOT(quit()));
m_client->connectToHost();
loop.exec();
return m_client->isConnected();
}
void FibonacciRpcClient::call(int number)
{
qDebug() << " [x] Requesting fib(" << number << ")";
m_correlationId = QUuid::createUuid().toString();
QAmqpMessage::PropertyHash properties;
properties.insert(QAmqpMessage::ReplyTo, m_responseQueue->name());
properties.insert(QAmqpMessage::CorrelationId, m_correlationId);
m_defaultExchange->publish(QByteArray::number(number), "rpc_queue", properties);
}
void FibonacciRpcClient::clientConnected()
{
m_responseQueue = m_client->createQueue();
connect(m_responseQueue, SIGNAL(declared()), this, SLOT(queueDeclared()));
connect(m_responseQueue, SIGNAL(messageReceived()), this, SLOT(responseReceived()));
m_responseQueue->declare(QAmqpQueue::Exclusive | QAmqpQueue::AutoDelete);
m_defaultExchange = m_client->createExchange();
}
void FibonacciRpcClient::queueDeclared()
{
m_responseQueue->consume();
Q_EMIT connected();
}
void FibonacciRpcClient::responseReceived()
{
QAmqpMessage message = m_responseQueue->dequeue();
if (message.property(QAmqpMessage::CorrelationId).toString() != m_correlationId) {
// requeue message, it wasn't meant for us
m_responseQueue->reject(message, true);
return;
}
qDebug() << " [.] Got " << message.payload();
qApp->quit();
}

View File

@ -0,0 +1,36 @@
#ifndef FIBONACCIRPCCLIENT_H
#define FIBONACCIRPCCLIENT_H
#include <QObject>
class QAmqpQueue;
class QAmqpExchange;
class QAmqpClient;
class FibonacciRpcClient : public QObject
{
Q_OBJECT
public:
explicit FibonacciRpcClient(QObject *parent = 0);
~FibonacciRpcClient();
Q_SIGNALS:
void connected();
public Q_SLOTS:
bool connectToServer();
void call(int number);
private Q_SLOTS:
void clientConnected();
void queueDeclared();
void responseReceived();
private:
QAmqpClient *m_client;
QAmqpQueue *m_responseQueue;
QAmqpExchange *m_defaultExchange;
QString m_correlationId;
};
#endif // FIBONACCIRPCCLIENT_H

View File

@ -0,0 +1,13 @@
#include <QCoreApplication>
#include "fibonaccirpcclient.h"
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
FibonacciRpcClient client;
if (!client.connectToServer())
return EXIT_FAILURE;
client.call(30);
return app.exec();
}

View File

@ -0,0 +1,13 @@
DEPTH = ../../..
include($${DEPTH}/qamqp.pri)
TEMPLATE = app
INCLUDEPATH += $${QAMQP_INCLUDEPATH}
LIBS += -L$${DEPTH}/src $${QAMQP_LIBS}
macx:CONFIG -= app_bundle
HEADERS += \
fibonaccirpcclient.h
SOURCES += \
fibonaccirpcclient.cpp \
main.cpp

View File

@ -0,0 +1,10 @@
#include <QCoreApplication>
#include "server.h"
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
Server server;
server.listen();
return app.exec();
}

View File

@ -0,0 +1,13 @@
DEPTH = ../../..
include($${DEPTH}/qamqp.pri)
TEMPLATE = app
INCLUDEPATH += $${QAMQP_INCLUDEPATH}
LIBS += -L$${DEPTH}/src $${QAMQP_LIBS}
macx:CONFIG -= app_bundle
HEADERS += \
server.h
SOURCES += \
server.cpp \
main.cpp

View File

@ -0,0 +1,71 @@
#include "qamqpclient.h"
#include "qamqpqueue.h"
#include "qamqpexchange.h"
#include "server.h"
Server::Server(QObject *parent)
: QObject(parent),
m_client(0),
m_rpcQueue(0),
m_defaultExchange(0)
{
m_client = new QAmqpClient(this);
connect(m_client, SIGNAL(connected()), this, SLOT(clientConnected()));
}
Server::~Server()
{
}
void Server::listen()
{
m_client->connectToHost();
}
int Server::fib(int n)
{
if (n == 0)
return 0;
if (n == 1)
return 1;
return fib(n - 1) + fib(n - 2);
}
void Server::clientConnected()
{
m_rpcQueue = m_client->createQueue("rpc_queue");
connect(m_rpcQueue, SIGNAL(declared()), this, SLOT(queueDeclared()));
connect(m_rpcQueue, SIGNAL(qosDefined()), this, SLOT(qosDefined()));
connect(m_rpcQueue, SIGNAL(messageReceived()), this, SLOT(processRpcMessage()));
m_rpcQueue->declare();
m_defaultExchange = m_client->createExchange();
}
void Server::queueDeclared()
{
m_rpcQueue->qos(1);
}
void Server::qosDefined()
{
m_rpcQueue->consume();
qDebug() << " [x] Awaiting RPC requests";
}
void Server::processRpcMessage()
{
QAmqpMessage rpcMessage = m_rpcQueue->dequeue();
int n = rpcMessage.payload().toInt();
int response = fib(n);
m_rpcQueue->ack(rpcMessage);
QString replyTo = rpcMessage.property(QAmqpMessage::ReplyTo).toString();
QAmqpMessage::PropertyHash properties;
properties.insert(QAmqpMessage::CorrelationId, rpcMessage.property(QAmqpMessage::CorrelationId));
m_defaultExchange->publish(QByteArray::number(response), replyTo, properties);
}

View File

@ -0,0 +1,33 @@
#ifndef SERVER_H
#define SERVER_H
#include <QObject>
class QAmqpQueue;
class QAmqpExchange;
class QAmqpClient;
class Server : public QObject
{
Q_OBJECT
public:
explicit Server(QObject *parent = 0);
~Server();
public Q_SLOTS:
void listen();
int fib(int n);
private Q_SLOTS:
void clientConnected();
void queueDeclared();
void qosDefined();
void processRpcMessage();
private:
QAmqpClient *m_client;
QAmqpQueue *m_rpcQueue;
QAmqpExchange *m_defaultExchange;
};
#endif // SERVER_H

View File

@ -0,0 +1,9 @@
DEPTH = ../../..
include($${DEPTH}/qamqp.pri)
TEMPLATE = app
INCLUDEPATH += $${QAMQP_INCLUDEPATH}
LIBS += -L$${DEPTH}/src $${QAMQP_LIBS}
macx:CONFIG -= app_bundle
SOURCES += main.cpp

View File

@ -0,0 +1,64 @@
#include <QCoreApplication>
#include <QStringList>
#include <QDebug>
#include "qamqpclient.h"
#include "qamqpexchange.h"
#include "qamqpqueue.h"
class TopicLogEmitter : public QObject
{
Q_OBJECT
public:
TopicLogEmitter(QObject *parent = 0) : QObject(parent) {}
public Q_SLOTS:
void start() {
connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected()));
connect(&m_client, SIGNAL(disconnected()), qApp, SLOT(quit()));
m_client.connectToHost();
}
private Q_SLOTS:
void clientConnected() {
QAmqpExchange *topic_logs = m_client.createExchange("topic_logs");
connect(topic_logs, SIGNAL(declared()), this, SLOT(exchangeDeclared()));
topic_logs->declare(QAmqpExchange::Topic);
}
void exchangeDeclared() {
QAmqpExchange *topic_logs = qobject_cast<QAmqpExchange*>(sender());
if (!topic_logs)
return;
QStringList args = qApp->arguments();
args.takeFirst(); // remove executable name
QString routingKey = (args.isEmpty() ? "anonymous.info" : args.first());
QString message;
if (args.size() > 1) {
args.takeFirst();
message = args.join(" ");
} else {
message = "Hello World!";
}
topic_logs->publish(message, routingKey);
qDebug(" [x] Sent %s:%s", routingKey.toLatin1().constData(), message.toLatin1().constData());
m_client.disconnectFromHost();
}
private:
QAmqpClient m_client;
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
TopicLogEmitter logEmitter;
logEmitter.start();
return app.exec();
}
#include "main.moc"

View File

@ -0,0 +1,83 @@
#include <QCoreApplication>
#include <QStringList>
#include <QDebug>
#include "qamqpclient.h"
#include "qamqpexchange.h"
#include "qamqpqueue.h"
class TopicLogReceiver : public QObject
{
Q_OBJECT
public:
TopicLogReceiver(QObject *parent = 0) : QObject(parent) {}
public Q_SLOTS:
void start(const QStringList &bindingKeys) {
m_bindingKeys = bindingKeys;
connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected()));
m_client.connectToHost();
}
private Q_SLOTS:
void clientConnected() {
QAmqpExchange *topic_logs = m_client.createExchange("topic_logs");
connect(topic_logs, SIGNAL(declared()), this, SLOT(exchangeDeclared()));
topic_logs->declare(QAmqpExchange::Topic);
}
void exchangeDeclared() {
QAmqpQueue *temporaryQueue = m_client.createQueue();
connect(temporaryQueue, SIGNAL(declared()), this, SLOT(queueDeclared()));
connect(temporaryQueue, SIGNAL(bound()), this, SLOT(queueBound()));
connect(temporaryQueue, SIGNAL(messageReceived()), this, SLOT(messageReceived()));
temporaryQueue->declare(QAmqpQueue::Exclusive);
}
void queueDeclared() {
QAmqpQueue *temporaryQueue = qobject_cast<QAmqpQueue*>(sender());
if (!temporaryQueue)
return;
foreach (QString bindingKey, m_bindingKeys)
temporaryQueue->bind("topic_logs", bindingKey);
qDebug() << " [*] Waiting for logs. To exit press CTRL+C";
}
void queueBound() {
QAmqpQueue *temporaryQueue = qobject_cast<QAmqpQueue*>(sender());
if (!temporaryQueue)
return;
temporaryQueue->consume(QAmqpQueue::coNoAck);
}
void messageReceived() {
QAmqpQueue *temporaryQueue = qobject_cast<QAmqpQueue*>(sender());
if (!temporaryQueue)
return;
QAmqpMessage message = temporaryQueue->dequeue();
qDebug() << " [x] " << message.routingKey() << ":" << message.payload();
}
private:
QAmqpClient m_client;
QStringList m_bindingKeys;
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
QStringList bindingKeys = app.arguments().mid(1);
if (bindingKeys.isEmpty()) {
qDebug("usage: %s [binding_key] ...", argv[0]);
return 1;
}
TopicLogReceiver logReceiver;
logReceiver.start(bindingKeys);
return app.exec();
}
#include "main.moc"

View File

@ -0,0 +1,9 @@
DEPTH = ../../..
include($${DEPTH}/qamqp.pri)
TEMPLATE = app
INCLUDEPATH += $${QAMQP_INCLUDEPATH}
LIBS += -L$${DEPTH}/src $${QAMQP_LIBS}
macx:CONFIG -= app_bundle
SOURCES += main.cpp

View File

@ -0,0 +1,4 @@
TEMPLATE = subdirs
SUBDIRS = \
emit_log_topic \
receive_logs_topic

View File

@ -0,0 +1,8 @@
TEMPLATE = subdirs
SUBDIRS = \
helloworld \
workqueues \
pubsub \
routing \
topics \
rpc

View File

@ -0,0 +1,62 @@
#include <QCoreApplication>
#include <QStringList>
#include <QDebug>
#include "qamqpclient.h"
#include "qamqpexchange.h"
#include "qamqpqueue.h"
class TaskCreator : public QObject
{
Q_OBJECT
public:
TaskCreator(QObject *parent = 0) : QObject(parent) {}
public Q_SLOTS:
void start() {
connect(&m_client, SIGNAL(connected()), this, SLOT(clientConnected()));
connect(&m_client, SIGNAL(disconnected()), qApp, SLOT(quit()));
m_client.connectToHost();
}
private Q_SLOTS:
void clientConnected() {
QAmqpQueue *queue = m_client.createQueue("task_queue");
connect(queue, SIGNAL(declared()), this, SLOT(queueDeclared()));
queue->declare();
}
void queueDeclared() {
QAmqpQueue *queue = qobject_cast<QAmqpQueue*>(sender());
if (!queue)
return;
QAmqpExchange *defaultExchange = m_client.createExchange();
QAmqpMessage::PropertyHash properties;
properties[QAmqpMessage::DeliveryMode] = "2"; // make message persistent
QString message;
if (qApp->arguments().size() < 2)
message = "Hello World!";
else
message = qApp->arguments().at(1);
defaultExchange->publish(message, "task_queue", properties);
qDebug(" [x] Sent '%s'", message.toLatin1().constData());
m_client.disconnectFromHost();
}
private:
QAmqpClient m_client;
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
TaskCreator taskCreator;
taskCreator.start();
return app.exec();
}
#include "main.moc"

Some files were not shown because too many files have changed in this diff Show More