Compare commits
No commits in common. "main" and "volkov_rafael_lab_2" have entirely different histories.
main
...
volkov_raf
@ -1,53 +0,0 @@
|
||||
#ifndef _CLIENT_H
|
||||
#define _CLIENT_H
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
#include "options/clientoption.h"
|
||||
#include "options/consumeoption.h"
|
||||
#include "options/exchangeoption.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define HEARBEATS "@@__Control__@@"
|
||||
|
||||
class Sender;
|
||||
class Receiver;
|
||||
|
||||
class Client : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
|
||||
QList<Sender *> *_senders;
|
||||
QList<Receiver *> *_receivers;
|
||||
|
||||
public:
|
||||
Client();
|
||||
Client(ClientOption option);
|
||||
virtual ~Client();
|
||||
|
||||
Client& operator=(Client client);
|
||||
QString getVersion() const;
|
||||
|
||||
ClientOption getClientOption() const { return clientOption; }
|
||||
|
||||
Sender *createSender(ExchangeOption& option);
|
||||
void removeSender(Sender *sender);
|
||||
|
||||
Receiver *createReceiver(ConsumeOption& option);
|
||||
void removeReceiver(Receiver *receiver);
|
||||
|
||||
signals:
|
||||
void onStop();
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(string)
|
||||
|
||||
#endif // _CLIENT_H
|
@ -1,124 +0,0 @@
|
||||
|
||||
#include "_client_.h"
|
||||
#include "sender.h"
|
||||
#include "receiver.h"
|
||||
|
||||
|
||||
// Конструктор для связи с локальным RabbitMQ
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Client::Client() : QObject(nullptr)
|
||||
{
|
||||
{
|
||||
static const int idMsg = qRegisterMetaType<ProduceMessage>();
|
||||
static const int idMsgPtr = qRegisterMetaType<PtrProduceMessage>();
|
||||
static const int idString = qRegisterMetaType<string>();
|
||||
|
||||
Q_UNUSED(idMsg)
|
||||
Q_UNUSED(idMsgPtr)
|
||||
Q_UNUSED(idString)
|
||||
}
|
||||
|
||||
_senders = new QList<Sender *>();
|
||||
_senders->clear();
|
||||
|
||||
_receivers = new QList<Receiver *>();
|
||||
_receivers->clear();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Client::Client(ClientOption option) : Client()
|
||||
{
|
||||
clientOption = option;
|
||||
}
|
||||
|
||||
|
||||
Client::~Client()
|
||||
{
|
||||
for (auto &sender : *_senders)
|
||||
delete sender;
|
||||
delete _senders;
|
||||
|
||||
for (auto &receiver : *_receivers)
|
||||
delete receiver;
|
||||
delete _receivers;
|
||||
}
|
||||
|
||||
|
||||
Client& Client::operator=(Client client)
|
||||
{
|
||||
if (this != &client) {
|
||||
this->clientOption = client.clientOption;
|
||||
|
||||
this->_senders = new QList<Sender *>();
|
||||
this->_senders->clear();
|
||||
|
||||
this->_receivers = new QList<Receiver *>();
|
||||
this->_receivers->clear();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
int majorVersion = 1;
|
||||
int minorVersion = 1;
|
||||
int releaseVersion = 1;
|
||||
|
||||
QString Client::getVersion() const
|
||||
{
|
||||
return QString::number(majorVersion) +
|
||||
"." + QString::number(minorVersion) +
|
||||
"." + QString::number(releaseVersion);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Создание публикатора (издателя) сообщений
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sender *Client::createSender(ExchangeOption& option)
|
||||
{
|
||||
Sender *sender = new Sender(clientOption, option);
|
||||
|
||||
connect(this, &Client::onStop, sender, &Sender::slotStop);
|
||||
connect(this, &Client::onStop, sender, &Sender::deleteLater);
|
||||
|
||||
_senders->append(sender);
|
||||
|
||||
return sender;
|
||||
}
|
||||
|
||||
void Client::removeSender(Sender *sender)
|
||||
{
|
||||
if ( !_senders->contains(sender))
|
||||
return;
|
||||
sender->slotStop();
|
||||
_senders->removeOne(sender);
|
||||
}
|
||||
|
||||
|
||||
// Создание потребителя сообщений
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Receiver *Client::createReceiver(ConsumeOption& option)
|
||||
{
|
||||
Receiver *receiver = new Receiver(clientOption, option);
|
||||
|
||||
connect(this, &Client::onStop, receiver, &Receiver::slotStop);
|
||||
connect(this, &Client::onStop, receiver, &Receiver::deleteLater);
|
||||
|
||||
_receivers->append(receiver);
|
||||
|
||||
return receiver;
|
||||
}
|
||||
|
||||
void Client::removeReceiver(Receiver *receiver)
|
||||
{
|
||||
if ( !_receivers->contains(receiver))
|
||||
return;
|
||||
receiver->slotStop();
|
||||
_receivers->removeOne(receiver);
|
||||
}
|
||||
|
||||
|
@ -1,22 +0,0 @@
|
||||
#ifndef CLIENT_CPP_H
|
||||
#define CLIENT_CPP_H
|
||||
|
||||
#include "clientrbcpp_global.h"
|
||||
#include "clientrbcpp.h"
|
||||
#include "_client_.h"
|
||||
#include "producemessage.h"
|
||||
#include "properties.h"
|
||||
#include "cworker.h"
|
||||
#include "headers.h"
|
||||
#include "pworker.h"
|
||||
#include "receiver.h"
|
||||
#include "sender.h"
|
||||
#include "validator.h"
|
||||
#include "vworker.h"
|
||||
|
||||
#include "options/clientoption.h"
|
||||
#include "options/consumeoption.h"
|
||||
#include "options/exchangeoption.h"
|
||||
#include "options/queueoption.h"
|
||||
|
||||
#endif // CLIENT_CPP_H
|
@ -1,6 +0,0 @@
|
||||
#include "clientrbcpp.h"
|
||||
|
||||
|
||||
ClientRBcpp::ClientRBcpp()
|
||||
{
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
#ifndef CLIENTRBCPP_H
|
||||
#define CLIENTRBCPP_H
|
||||
|
||||
#include "clientrbcpp_global.h"
|
||||
|
||||
class CLIENTRBCPPSHARED_EXPORT ClientRBcpp
|
||||
{
|
||||
|
||||
public:
|
||||
ClientRBcpp();
|
||||
};
|
||||
|
||||
#endif // CLIENTRBCPP_H
|
@ -1,12 +0,0 @@
|
||||
#ifndef CLIENTRBCPP_GLOBAL_H
|
||||
#define CLIENTRBCPP_GLOBAL_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#if defined(CLIENTRBCPP_LIBRARY)
|
||||
# define CLIENTRBCPPSHARED_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define CLIENTRBCPPSHARED_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif // CLIENTRBCPP_GLOBAL_H
|
@ -1,276 +0,0 @@
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
CWorker::CWorker(ClientOption& clientOption, ConsumeOption& consumeOption)
|
||||
: QObject(nullptr), markStop(false)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->consumeOption = consumeOption;
|
||||
this->consumeOption.receivingExchange = consumeOption.receivingExchange;
|
||||
|
||||
connection = nullptr;
|
||||
channel = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CWorker::~CWorker()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Здесь реализуется основная деятельность потока
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void CWorker::doWork()
|
||||
{
|
||||
|
||||
string host = clientOption.host.toStdString();
|
||||
string port = QString::number(clientOption.port).toStdString();
|
||||
string user = clientOption.user.toStdString();
|
||||
string password = clientOption.password.toStdString();
|
||||
string vhost = clientOption.vhost.toStdString();
|
||||
|
||||
string address = "amqp://" + user + ":" + password + "@" + host + ":" + port + vhost;
|
||||
|
||||
auto evbase = event_base_new();
|
||||
|
||||
AMQP::LibEventHandler handler(evbase);
|
||||
|
||||
// AMQP::TcpConnection connection(&handler, AMQP::Address(address));
|
||||
// AMQP::TcpChannel channel(&connection);
|
||||
|
||||
connection = new AMQP::TcpConnection(&handler, AMQP::Address(address));
|
||||
channel = new AMQP::TcpChannel(connection);
|
||||
|
||||
channel->setQos(1);
|
||||
|
||||
channel->onError([&](const char *message) {
|
||||
Q_UNUSED(message)
|
||||
emit onErrorConsume("Channel error!!!");
|
||||
});
|
||||
|
||||
QTimer tm;
|
||||
tm.stop();
|
||||
tm.setInterval(30000);
|
||||
connect(&tm, &QTimer::timeout, this, [&]() {
|
||||
tm.stop();
|
||||
connection->heartbeat();
|
||||
tm.start();
|
||||
});
|
||||
tm.start();
|
||||
|
||||
// Обработка принятого сообщения
|
||||
auto messageCb = [&](const AMQP::Message& message, uint64_t deliveryTag, bool redelivered)
|
||||
{
|
||||
Q_UNUSED(redelivered)
|
||||
|
||||
// Формируем принятое сообщениев формате ReceivedMessage
|
||||
ProduceMessage *rMsg = new ProduceMessage;
|
||||
rMsg->setBodyMsg(message.body(), message.bodySize());
|
||||
|
||||
// Формируем таблицу Properties свойств сообщения
|
||||
Properties p;
|
||||
if (message.hasContentType())
|
||||
p.setContentType(QString::fromStdString(message.contentType()));
|
||||
if (message.hasContentEncoding())
|
||||
p.setContentEncoding(QString::fromStdString(message.contentEncoding()));
|
||||
if (message.hasMessageID())
|
||||
p.setMessageID(QString::fromStdString(message.messageID()));
|
||||
if (message.hasCorrelationID())
|
||||
p.setCorrelationID(QString::fromStdString(message.correlationID()));
|
||||
if (message.timestamp())
|
||||
p.setTimestamp(message.timestamp());
|
||||
if (message.hasExpiration())
|
||||
p.setExpiration(QString::fromStdString(message.expiration()));
|
||||
if (message.hasDeliveryMode())
|
||||
p.setDeliveryMode(message.deliveryMode());
|
||||
if (message.hasAppID())
|
||||
p.setAppID(QString::fromStdString(message.appID()));
|
||||
if (message.hasUserID())
|
||||
p.setUserID(QString::fromStdString(message.userID()));
|
||||
if (message.hasTypeName())
|
||||
p.setTypeName(QString::fromStdString(message.typeName()));
|
||||
if (message.hasReplyTo())
|
||||
p.setReplyTo(QString::fromStdString(message.replyTo()));
|
||||
if (message.hasPriority())
|
||||
p.setPriority(message.priority());
|
||||
|
||||
rMsg->setProperties(p);
|
||||
|
||||
// Работа со свойствами Headers
|
||||
Headers h;
|
||||
AMQP::Table table = message.headers();
|
||||
vector<string> keys = table.keys();
|
||||
|
||||
string name;
|
||||
for(uint i = 0; i < keys.size(); i++) {
|
||||
name = keys[i];
|
||||
if (table.get(name).isInteger()) {
|
||||
int value = table.get(name);
|
||||
h.set(QString::fromStdString(name), value);
|
||||
}
|
||||
else if (table.get(name).isString()) {
|
||||
QString str = QString::fromStdString(table.get(name));
|
||||
h.set(QString::fromStdString(name), str);
|
||||
}
|
||||
else if (table.get(name).isBoolean()) {
|
||||
AMQP::Field &b = const_cast<AMQP::Field &>(table.get(name));
|
||||
AMQP::BooleanSet &b1 = dynamic_cast<AMQP::BooleanSet &>(b);
|
||||
bool value = b1.get(0);
|
||||
h.set(QString::fromStdString(name), value);
|
||||
}
|
||||
}
|
||||
|
||||
rMsg->setHeaders(h);
|
||||
emit onResultReady(rMsg, deliveryTag);
|
||||
|
||||
channel->ack(deliveryTag);
|
||||
};
|
||||
|
||||
// объявление точки обмена
|
||||
|
||||
if (!consumeOption.receivingExchange.name.isEmpty()) {
|
||||
string exchange = consumeOption.receivingExchange.name.toStdString();
|
||||
string type = consumeOption.receivingExchange.type.toStdString();
|
||||
|
||||
// преобразование типа точки обмена в формат AMQP
|
||||
AMQP::ExchangeType typeEx;
|
||||
if (type == "" || type == "direct")
|
||||
typeEx = AMQP::direct;
|
||||
else if (type == "topic")
|
||||
typeEx = AMQP::topic;
|
||||
else if (type == "headers")
|
||||
typeEx = AMQP::headers;
|
||||
else
|
||||
typeEx = AMQP::fanout;
|
||||
|
||||
// предобразование флагов точки обмена в формат AMQP
|
||||
int flagsExchange = 0;
|
||||
if (consumeOption.receivingExchange.durable)
|
||||
flagsExchange |= AMQP::durable;
|
||||
if (consumeOption.receivingExchange.auto_delete)
|
||||
flagsExchange |= AMQP::autodelete;
|
||||
if (consumeOption.receivingExchange.internal)
|
||||
flagsExchange |= AMQP::internal;
|
||||
|
||||
AMQP::Table tableExch;
|
||||
QString alt_e_name = "alternate-exchange";
|
||||
QString alt_e_value = "";
|
||||
if (consumeOption.receivingExchange.arguments.contains(alt_e_name)) {
|
||||
alt_e_value = consumeOption.receivingExchange.arguments[alt_e_name].value<QString>();
|
||||
tableExch.set(alt_e_name.toStdString(), alt_e_value.toStdString());
|
||||
}
|
||||
|
||||
// Для предопределенных точек обмена их обьявление не производим
|
||||
if ( exchange != "" && exchange != "amq.fanout" && exchange != "amq.direct" &&
|
||||
exchange != "amq.topic" && exchange != "amq.headers") {
|
||||
channel->declareExchange(exchange, typeEx, flagsExchange, tableExch)
|
||||
.onError([&](const char *description) {
|
||||
qDebug() << description;
|
||||
});
|
||||
}
|
||||
|
||||
QMultiMap<QString, QString>::iterator it = consumeOption.bindingArgs.begin();
|
||||
for(; it != consumeOption.bindingArgs.end(); ++it) {
|
||||
channel->bindExchange(it.key().toStdString(), exchange, it.value().toStdString()).onError([&](const char *description) {
|
||||
qDebug() << description;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// объявление очереди
|
||||
|
||||
QueueOption option = consumeOption.queueOption;
|
||||
|
||||
string exchange = consumeOption.exchange.toStdString();
|
||||
string queue = option.name.toStdString();
|
||||
|
||||
// Подготовка флагов для объявления очереди
|
||||
int flagsQueue = 0;
|
||||
if (option.durable)
|
||||
flagsQueue |= AMQP::durable;
|
||||
if (option.auto_delete)
|
||||
flagsQueue |= AMQP::autodelete;
|
||||
if (option.exclusive)
|
||||
flagsQueue |= AMQP::exclusive;
|
||||
|
||||
channel->declareQueue(queue, flagsQueue)
|
||||
.onSuccess( [&](const string &name, uint32_t messageCount, uint32_t consumerCount) {
|
||||
Q_UNUSED(messageCount)
|
||||
Q_UNUSED(consumerCount)
|
||||
queue = name;
|
||||
if (exchange != "")
|
||||
for (QString rk : consumeOption.bindingKeys) {
|
||||
channel->bindQueue(exchange, queue, rk.toStdString())
|
||||
.onError( [&](const char *description) {
|
||||
qDebug() << description;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Подготовка флагов потребления сообщений
|
||||
int flagsConsume = 0;
|
||||
if (consumeOption.nolocal)
|
||||
flagsConsume |= AMQP::nolocal;
|
||||
if (consumeOption.noack)
|
||||
flagsConsume |= AMQP::noack;
|
||||
if (consumeOption.exclusive)
|
||||
flagsConsume |= AMQP::exclusive;
|
||||
|
||||
|
||||
channel->consume(queue, flagsConsume).onReceived(messageCb)
|
||||
.onSuccess( [&](const string& tag) {
|
||||
nextTag = tag;
|
||||
})
|
||||
.onError( [&](const char *description) {
|
||||
emit onErrorConsume(description);
|
||||
markStop = true; // Останов потока
|
||||
});
|
||||
|
||||
//Цикл обработки событий
|
||||
while(!markStop) {
|
||||
|
||||
event_base_loop(evbase, EVLOOP_ONCE);
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
// Закроем канал и соединение
|
||||
channel->close();
|
||||
connection->close();
|
||||
|
||||
event_base_loopbreak(evbase);
|
||||
event_base_loopexit(evbase, 0);
|
||||
event_base_free(evbase);
|
||||
|
||||
delete channel;
|
||||
delete connection;
|
||||
|
||||
emit onWorkFinished(); // Посылаем сигнал о завершении работы
|
||||
}
|
||||
|
||||
|
||||
void CWorker::slotStop()
|
||||
{
|
||||
markStop = true;
|
||||
channel->cancel(nextTag); // Отменить потребление
|
||||
|
||||
channel->close();
|
||||
connection->close();
|
||||
|
||||
}
|
||||
|
||||
void CWorker::bind(QString exchange, QString key, bool ex)
|
||||
{
|
||||
if (ex) channel->bindExchange(exchange.toStdString(), consumeOption.exchange.toStdString(), key.toStdString());
|
||||
else channel->bindQueue(exchange.toStdString(), consumeOption.queueOption.name.toStdString(), key.toStdString());
|
||||
}
|
||||
|
||||
void CWorker::unbind(QString exchange, QString key, bool ex)
|
||||
{
|
||||
if (ex) channel->unbindExchange(exchange.toStdString(), consumeOption.exchange.toStdString(), key.toStdString());
|
||||
else channel->unbindQueue(exchange.toStdString(), consumeOption.queueOption.name.toStdString(), key.toStdString());
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
#ifndef CWORKER_H
|
||||
#define CWORKER_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <amqpcpp.h>
|
||||
#include <amqpcpp/libevent.h>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class CWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
ConsumeOption consumeOption;
|
||||
|
||||
bool markStop;
|
||||
|
||||
AMQP::TcpConnection *connection;
|
||||
AMQP::TcpChannel *channel;
|
||||
|
||||
string nextTag;
|
||||
|
||||
public:
|
||||
CWorker(ClientOption& clientOption, ConsumeOption& consumeOption);
|
||||
virtual ~CWorker();
|
||||
|
||||
public slots:
|
||||
void doWork();
|
||||
void slotStop();
|
||||
void bind(QString exchange, QString key, bool ex);
|
||||
void unbind(QString exchange, QString key, bool ex);
|
||||
|
||||
signals:
|
||||
void onResultReady(PtrProduceMessage msg, uint64_t deliveryTag);
|
||||
void onErrorConsume(const char *description);
|
||||
void onWorkFinished();
|
||||
};
|
||||
|
||||
|
||||
#endif // CWORKER_H
|
@ -1,40 +0,0 @@
|
||||
#include "headers.h"
|
||||
|
||||
Headers::Headers()
|
||||
{
|
||||
_headers.clear();
|
||||
}
|
||||
|
||||
Headers::Headers(const Headers& h)
|
||||
{
|
||||
this->_headers = h._headers;
|
||||
}
|
||||
|
||||
void Headers::operator=(const Headers& h)
|
||||
{
|
||||
this->_headers = h._headers;
|
||||
}
|
||||
|
||||
|
||||
QMap<QString,QVariant> Headers::getHeaders() const { return _headers; }
|
||||
|
||||
QList<QString> Headers::keys() const { return _headers.keys(); }
|
||||
QList<QVariant> Headers::values() const { return _headers.values(); }
|
||||
|
||||
int Headers::size() const { return _headers.size(); }
|
||||
|
||||
bool Headers::contains(const QString name) const { return _headers.contains(name); }
|
||||
|
||||
|
||||
void Headers::set(const QString name, bool value) { _headers.insert(name, value); }
|
||||
void Headers::set(const QString name, int value) { _headers.insert(name, value); }
|
||||
void Headers::set(const QString name, QString str) { _headers.insert(name, str); }
|
||||
|
||||
bool Headers::isBool(const QString name) const { return _headers[name].type() == QVariant::Bool; }
|
||||
bool Headers::isInteger(const QString name) const { return _headers[name].type() == QVariant::Int; }
|
||||
bool Headers::isString(const QString name) const { return _headers[name].type() == QVariant::String; }
|
||||
|
||||
bool Headers::getBool(const QString name) const { return _headers[name].value<bool>(); }
|
||||
int Headers::getInteger(const QString name) const { return _headers[name].value<int>(); }
|
||||
QString Headers::getString(const QString name) const { return _headers[name].value<QString>(); }
|
||||
|
@ -1,45 +0,0 @@
|
||||
#ifndef HEADERS_H
|
||||
#define HEADERS_H
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
class Headers
|
||||
{
|
||||
private:
|
||||
QMap<QString,QVariant> _headers;
|
||||
|
||||
public:
|
||||
Headers();
|
||||
Headers(const Headers& h); // Конструктор копирования
|
||||
~Headers() {}
|
||||
|
||||
void operator=(const Headers& h);
|
||||
|
||||
QMap<QString,QVariant> getHeaders() const;
|
||||
|
||||
QList<QString> keys() const;
|
||||
QList<QVariant> values() const;
|
||||
|
||||
int size() const;
|
||||
|
||||
bool contains(const QString name) const;
|
||||
|
||||
void set(const QString name, bool value);
|
||||
void set(const QString name, int value);
|
||||
void set(const QString name, QString str);
|
||||
|
||||
bool isBool(const QString name) const;
|
||||
bool isInteger(const QString name) const;
|
||||
bool isString(const QString name) const;
|
||||
|
||||
bool getBool(const QString name) const;
|
||||
int getInteger(const QString name) const;
|
||||
QString getString(const QString name) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // HEADERS_H
|
@ -1,45 +0,0 @@
|
||||
#ifndef CLIENTOPTION_H
|
||||
#define CLIENTOPTION_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
// Значения по умолчанию
|
||||
const QString DEFAULT_CPP_HOST = "localhost";
|
||||
const int DEFAULT_CPP_PORT = 5672;
|
||||
const QString DEFAULT_CPP_USER = "guest";
|
||||
const QString DEFAULT_CPP_PASSWORD = "guest";
|
||||
const QString DEFAULT_CPP_VHOST = "/";
|
||||
|
||||
|
||||
struct ClientOption {
|
||||
QString host;
|
||||
int port;
|
||||
QString user;
|
||||
QString password;
|
||||
QString vhost;
|
||||
|
||||
ClientOption() {
|
||||
host = DEFAULT_CPP_HOST;
|
||||
port = DEFAULT_CPP_PORT;
|
||||
user = DEFAULT_CPP_USER;
|
||||
password = DEFAULT_CPP_PASSWORD;
|
||||
vhost = DEFAULT_CPP_VHOST;
|
||||
}
|
||||
|
||||
~ClientOption() {}
|
||||
|
||||
ClientOption(const ClientOption& src) = default; // Конструктор копирования
|
||||
ClientOption(ClientOption&& src) = default; // Конструктор перемещения
|
||||
|
||||
ClientOption& operator=(const ClientOption rhs) // Оператор присваивания
|
||||
{
|
||||
host = rhs.host;
|
||||
port = rhs.port;
|
||||
user = rhs.user;
|
||||
password = rhs.password;
|
||||
vhost = rhs.vhost;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CLIENTOPTION_H
|
@ -1,52 +0,0 @@
|
||||
#ifndef CONSUMEOPTION_H
|
||||
#define CONSUMEOPTION_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
|
||||
#include "queueoption.h"
|
||||
#include "exchangeoption.h"
|
||||
|
||||
struct ConsumeOption
|
||||
{
|
||||
QString exchange; // Имя точки обмена для связывания
|
||||
QStringList bindingKeys; // ключи связи точки с очередью
|
||||
|
||||
bool nolocal;
|
||||
bool noack;
|
||||
bool exclusive;
|
||||
|
||||
QueueOption queueOption; // Параметры очереди
|
||||
ExchangeOption receivingExchange; // Параметры новой принимающей очереди (по умолчанию новой не создаётся)
|
||||
QMultiMap<QString, QString> bindingArgs; // список связей для точки обмена (если создаётся новая точка)
|
||||
|
||||
ConsumeOption() {
|
||||
exchange = "";
|
||||
receivingExchange.name = "";
|
||||
|
||||
nolocal = false;
|
||||
noack = false;
|
||||
exclusive = false;
|
||||
}
|
||||
|
||||
~ConsumeOption() {}
|
||||
|
||||
ConsumeOption(const ConsumeOption& src) = default; // Конструктор копирования
|
||||
ConsumeOption(ConsumeOption&& src) = default; // Конструктор перемещения
|
||||
|
||||
ConsumeOption& operator=(const ConsumeOption rhs) // Оператор присваивания
|
||||
{
|
||||
exchange = rhs.exchange;
|
||||
bindingKeys = rhs.bindingKeys;
|
||||
nolocal = rhs.nolocal;
|
||||
noack = rhs.noack;
|
||||
exclusive = rhs.exclusive;
|
||||
queueOption = rhs.queueOption;
|
||||
bindingArgs = rhs.bindingArgs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // CONSUMEOPTION_H
|
@ -1,55 +0,0 @@
|
||||
#ifndef EXCHANGEOPTION_H
|
||||
#define EXCHANGEOPTION_H
|
||||
|
||||
#include <QString>
|
||||
#include <QVariantMap>
|
||||
#include <QList>
|
||||
|
||||
struct ExchangeOption
|
||||
{
|
||||
QString name; // уникальное имя точки обмена
|
||||
QString type; // тип точки обмена (direct, topic,
|
||||
// fanout или headers)
|
||||
bool auto_delete; // автоматически удаляемая точка обмена
|
||||
bool durable; // долгоживущая точка обмена
|
||||
bool passive; // требуется информация о точке обмена
|
||||
bool internal; // нельзя вести публикацию из приложения
|
||||
|
||||
QVariantMap arguments; // необязательные аргументы
|
||||
QMap<QString, QString> bindingArgs; // список связей для точки обмена
|
||||
|
||||
bool ifunused; // можно удалять, только если точка обмена
|
||||
// не используется (не имеет потребителей)
|
||||
ExchangeOption() {
|
||||
name = "";
|
||||
type = "";
|
||||
auto_delete = false;
|
||||
durable = false;
|
||||
passive = false;
|
||||
internal = false;
|
||||
arguments.clear();
|
||||
|
||||
ifunused = false;
|
||||
}
|
||||
|
||||
~ExchangeOption() {}
|
||||
|
||||
ExchangeOption(const ExchangeOption& src) = default; // Конструктор копирования
|
||||
ExchangeOption(ExchangeOption&& src) = default; // Конструктор перемещения
|
||||
|
||||
ExchangeOption& operator=(const ExchangeOption rhs) // Оператор присваивания
|
||||
{
|
||||
name = rhs.name;
|
||||
type = rhs.type;
|
||||
auto_delete = rhs.auto_delete;
|
||||
durable = rhs.durable;
|
||||
passive = rhs.passive;
|
||||
internal = rhs.internal;
|
||||
arguments = rhs.arguments;
|
||||
|
||||
ifunused = rhs.ifunused;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EXCHANGEOPTION_H
|
@ -1,63 +0,0 @@
|
||||
#ifndef QUEUEOPTION_H
|
||||
#define QUEUEOPTION_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariantMap>
|
||||
|
||||
struct QueueOption
|
||||
{
|
||||
QString name; // Уникальное имя очереди
|
||||
|
||||
bool auto_delete; // Автоматически удаляемая очередь
|
||||
bool durable; // Долгоживущая очередь
|
||||
bool passive; // Требуется информация об очереди
|
||||
bool exclusive; // Исключительная очередь
|
||||
|
||||
QVariantMap arguments; // Необязательные аргументы очереди
|
||||
|
||||
bool ifunused; // Удалять, только если не используется
|
||||
bool ifempty; // Удалять, только если очередь пуста
|
||||
|
||||
int messageCount; // Число сообщений в очереди
|
||||
int consumerCount; // Число потребителей очереди
|
||||
|
||||
QueueOption() {
|
||||
name = "";
|
||||
|
||||
auto_delete = false;
|
||||
durable = false;
|
||||
passive = false;
|
||||
exclusive = false;
|
||||
|
||||
arguments.clear();
|
||||
|
||||
ifunused = false;
|
||||
ifempty = false;
|
||||
|
||||
messageCount = 0;
|
||||
consumerCount = 0;
|
||||
}
|
||||
|
||||
~QueueOption() {}
|
||||
|
||||
QueueOption(const QueueOption& src) = default; // Конструктор копирования
|
||||
QueueOption(QueueOption&& src) = default; // Конструктор перемещения
|
||||
|
||||
QueueOption& operator=(const QueueOption rhs) // Оператор присваивания
|
||||
{
|
||||
name = rhs.name;
|
||||
auto_delete = rhs.auto_delete;
|
||||
passive = rhs.passive;
|
||||
exclusive = rhs.exclusive;
|
||||
arguments = rhs.arguments;
|
||||
|
||||
ifunused = rhs.ifunused;
|
||||
ifempty = rhs.ifempty;
|
||||
messageCount = rhs.messageCount;
|
||||
consumerCount = rhs.consumerCount;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // QUEUEOPTION_H
|
@ -1,37 +0,0 @@
|
||||
#include "producemessage.h"
|
||||
|
||||
// Конструктор по умолчанию
|
||||
ProduceMessage::ProduceMessage()
|
||||
{
|
||||
_body.clear();
|
||||
}
|
||||
|
||||
// Конструктор копирования
|
||||
ProduceMessage::ProduceMessage(const ProduceMessage& msg)
|
||||
{
|
||||
this->_body = msg._body;
|
||||
this->_headers = msg._headers;
|
||||
this->_properties = msg._properties;
|
||||
}
|
||||
|
||||
ProduceMessage& ProduceMessage::operator=(const ProduceMessage& msg)
|
||||
{
|
||||
if (this != &msg) {
|
||||
this->_body = msg._body;
|
||||
this->_headers = msg._headers;
|
||||
this->_properties = msg._properties;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
QByteArray ProduceMessage::getBodyMsg() const { return _body; }
|
||||
void ProduceMessage::setBodyMsg(const QByteArray &ba) { _body = ba; }
|
||||
void ProduceMessage::setBodyMsg(const char *body, int size) { _body = QByteArray(body, size); }
|
||||
|
||||
Headers ProduceMessage::getHeaders() const { return _headers; }
|
||||
void ProduceMessage::setHeaders(const Headers &headers) { _headers = headers; }
|
||||
|
||||
Properties ProduceMessage::getProperties() const { return _properties; }
|
||||
void ProduceMessage::setProperties(const Properties &properties) { _properties = properties; }
|
||||
|
||||
|
@ -1,43 +0,0 @@
|
||||
#ifndef PRODUCEMESSAGE_H
|
||||
#define PRODUCEMESSAGE_H
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
#include "properties.h"
|
||||
#include "headers.h"
|
||||
|
||||
|
||||
class ProduceMessage
|
||||
{
|
||||
public:
|
||||
ProduceMessage();
|
||||
ProduceMessage(const ProduceMessage& msg);
|
||||
~ProduceMessage() {}
|
||||
|
||||
ProduceMessage& operator=(const ProduceMessage& msg);
|
||||
|
||||
QByteArray getBodyMsg() const;
|
||||
void setBodyMsg(const QByteArray &ba);
|
||||
void setBodyMsg(const char *body, int size);
|
||||
|
||||
Headers getHeaders() const;
|
||||
void setHeaders(const Headers &headers);
|
||||
|
||||
Properties getProperties() const;
|
||||
void setProperties(const Properties &properties);
|
||||
|
||||
private:
|
||||
QByteArray _body;
|
||||
|
||||
protected:
|
||||
Properties _properties;
|
||||
Headers _headers;
|
||||
};
|
||||
|
||||
|
||||
using PtrProduceMessage = ProduceMessage*;
|
||||
|
||||
Q_DECLARE_METATYPE(ProduceMessage)
|
||||
Q_DECLARE_METATYPE(PtrProduceMessage)
|
||||
|
||||
#endif // PRODUCEMESSAGE_H
|
@ -1,63 +0,0 @@
|
||||
#include "properties.h"
|
||||
|
||||
Properties::Properties()
|
||||
{
|
||||
_properties.clear();
|
||||
setDeliveryMode(1); // не оставлять сообщения
|
||||
}
|
||||
|
||||
// Конструктор копирования
|
||||
Properties::Properties(const Properties& p)
|
||||
{
|
||||
this->_properties = p._properties;
|
||||
}
|
||||
|
||||
|
||||
void Properties::operator=(const Properties& p)
|
||||
{
|
||||
this->_properties = p._properties;
|
||||
}
|
||||
|
||||
|
||||
const QMap<QString,QVariant> &Properties::getProperties() { return _properties; }
|
||||
|
||||
bool Properties::contains(const QString name) const { return _properties.contains(name); }
|
||||
|
||||
bool Properties::isContentType() const { return _properties.contains("content-type"); }
|
||||
bool Properties::isContentEncoding() const { return _properties.contains("content-encoding"); }
|
||||
bool Properties::isMessageID() const { return _properties.contains("message-id"); }
|
||||
bool Properties::isCorrelationID() const { return _properties.contains("correlation-id"); }
|
||||
bool Properties::isTimestamp() const { return _properties.contains("timestamp"); }
|
||||
bool Properties::isExpiration() const { return _properties.contains("expiration"); }
|
||||
bool Properties::isDeliveryMode() const { return _properties.contains("delivery-mode"); }
|
||||
bool Properties::isAppID() const { return _properties.contains("app-id"); }
|
||||
bool Properties::isUserID() const { return _properties.contains("user-id"); }
|
||||
bool Properties::isTypeName() const { return _properties.contains("type"); }
|
||||
bool Properties::isReplyTo() const { return _properties.contains("reply-to"); }
|
||||
bool Properties::isPriority() const { return _properties.contains("priority"); }
|
||||
|
||||
void Properties::setContentType(const QString &str) { _properties.insert("content-type", str); }
|
||||
void Properties::setContentEncoding(const QString &str) { _properties.insert("content-encoding", str); }
|
||||
void Properties::setMessageID(const QString &str) { _properties.insert("message-id", str); }
|
||||
void Properties::setCorrelationID(const QString &str) { _properties.insert("correlation-id", str); }
|
||||
void Properties::setTimestamp(const quint64 val) { _properties.insert("timestamp", val); }
|
||||
void Properties::setExpiration(const QString &str) { _properties.insert("expiration", str); }
|
||||
void Properties::setDeliveryMode(const quint8 val) { _properties.insert("delivery-mode", val); }
|
||||
void Properties::setAppID(const QString &str) { _properties.insert("app-id", str); }
|
||||
void Properties::setUserID(const QString &str) { _properties.insert("user-id", str); }
|
||||
void Properties::setTypeName(const QString &str) { _properties.insert("type", str); }
|
||||
void Properties::setReplyTo(const QString &str) { _properties.insert("reply-to", str); }
|
||||
void Properties::setPriority(const quint8 val) { _properties.insert("priority", val); }
|
||||
|
||||
QString Properties::getContentType() const { return _properties["content-type"].value<QString>(); }
|
||||
QString Properties::getContentEncoding() const { return _properties["content-encoding"].value<QString>(); }
|
||||
QString Properties::getMessageID() const { return _properties["message-id"].value<QString>(); }
|
||||
QString Properties::getCorrelationID() const { return _properties["correlation-id"].value<QString>(); }
|
||||
quint64 Properties::getTimestamp() const { return _properties["timestamp"].value<quint64>(); }
|
||||
QString Properties::getExpiration() const { return _properties["expiration"].value<QString>(); }
|
||||
quint8 Properties::getDeliveryMode() const { return _properties["delivery-mode"].value<quint8>(); }
|
||||
QString Properties::getAppID() const { return _properties["app-id"].value<QString>(); }
|
||||
QString Properties::getUserID() const { return _properties["user-id"].value<QString>(); }
|
||||
QString Properties::getTypeName() const { return _properties["type"].value<QString>(); }
|
||||
QString Properties::getReplyTo() const { return _properties["reply-to"].value<QString>(); }
|
||||
quint8 Properties::getPriority() const { return _properties["priority"].value<quint8>(); }
|
@ -1,73 +0,0 @@
|
||||
#ifndef PROPERTIES_H
|
||||
#define PROPERTIES_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
class Properties
|
||||
{
|
||||
private:
|
||||
QMap<QString,QVariant> _properties;
|
||||
|
||||
public:
|
||||
Properties();
|
||||
Properties(const Properties& p);
|
||||
~Properties() {}
|
||||
|
||||
void operator=(const Properties& p);
|
||||
|
||||
int size() {return _properties.size(); }
|
||||
|
||||
const QMap<QString,QVariant> &getProperties();
|
||||
|
||||
bool contains(const QString name) const;
|
||||
|
||||
bool isContentType() const;
|
||||
bool isContentEncoding() const;
|
||||
bool isMessageID() const;
|
||||
bool isCorrelationID() const;
|
||||
bool isTimestamp() const;
|
||||
bool isExpiration() const;
|
||||
bool isDeliveryMode() const;
|
||||
bool isAppID() const;
|
||||
bool isUserID() const;
|
||||
bool isTypeName() const;
|
||||
bool isReplyTo() const;
|
||||
bool isPriority() const;
|
||||
|
||||
void setContentType(const QString &str);
|
||||
void setContentEncoding(const QString &str);
|
||||
void setMessageID(const QString &str);
|
||||
void setCorrelationID(const QString &str);
|
||||
void setTimestamp(const quint64 val);
|
||||
void setExpiration(const QString &str);
|
||||
void setDeliveryMode(const quint8 val);
|
||||
void setAppID(const QString &str);
|
||||
void setUserID(const QString &str);
|
||||
void setTypeName(const QString &str);
|
||||
void setReplyTo(const QString &str);
|
||||
void setPriority(const quint8 val);
|
||||
|
||||
QString getContentType() const;
|
||||
QString getContentEncoding() const;
|
||||
QString getMessageID() const;
|
||||
QString getCorrelationID() const;
|
||||
quint64 getTimestamp() const;
|
||||
QString getExpiration() const;
|
||||
quint8 getDeliveryMode() const;
|
||||
QString getAppID() const;
|
||||
QString getUserID() const;
|
||||
QString getTypeName() const;
|
||||
QString getReplyTo() const;
|
||||
quint8 getPriority() const;
|
||||
};
|
||||
|
||||
#endif // PROPERTIES_H
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,330 +0,0 @@
|
||||
/**************************************************************************
|
||||
* PWorker - Publish Worker, - рабочий поток публикации сообщений *
|
||||
* редакция от 08.06.2022 *
|
||||
* Принадлежность: библиотека clientRBcpp *
|
||||
**************************************************************************/
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "_client_.h"
|
||||
#include "sender.h"
|
||||
#include "pworker.h"
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
PWorker::PWorker(ClientOption& clientOption, ExchangeOption& exchangeOption)
|
||||
: QObject(nullptr), markStop(false)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->exchangeOption = exchangeOption;
|
||||
|
||||
qu.clear();
|
||||
|
||||
// static const int idE2E = qRegisterMetaType<E2EStruct>();
|
||||
// Q_UNUSED(idE2E)
|
||||
|
||||
}
|
||||
|
||||
|
||||
PWorker::~PWorker()
|
||||
{
|
||||
// Освободим очередь сообщений
|
||||
mutex.lock();
|
||||
while (! qu.isEmpty()) {
|
||||
PublishPacket *packet = qu.dequeue();
|
||||
AMQP::Envelope *envelope = packet->envelope;
|
||||
delete envelope->body();
|
||||
delete envelope;
|
||||
delete packet;
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
// Здесь реализуется основная деятельность потока
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void PWorker::doWork()
|
||||
{
|
||||
string host = clientOption.host.toStdString();
|
||||
string port = QString::number(clientOption.port).toStdString();
|
||||
string user = clientOption.user.toStdString();
|
||||
string password = clientOption.password.toStdString();
|
||||
string vhost = clientOption.vhost.toStdString();
|
||||
|
||||
string address = "amqp://" + user + ":" + password + "@" + host + ":" + port + vhost;
|
||||
|
||||
// Обрабатываем аргументы на предмет альтернативной точки обмена
|
||||
AMQP::Table table;
|
||||
QString alt_e_name = "alternate-exchange";
|
||||
QString alt_e_value = "";
|
||||
if (exchangeOption.arguments.contains(alt_e_name)) {
|
||||
alt_e_value = exchangeOption.arguments[alt_e_name].value<QString>();
|
||||
table.set(alt_e_name.toStdString(), alt_e_value.toStdString());
|
||||
}
|
||||
|
||||
string alt_exchange = alt_e_value.toStdString(); // Имя альтернативной точки обмена
|
||||
AMQP::ExchangeType typeAltEx = AMQP::fanout; // Тип альтернативной точки обмена - всегда fanout
|
||||
int flagsAltEx = (AMQP::durable | AMQP::internal); // Точка долгоживущая и внутренняя
|
||||
|
||||
auto evbase = event_base_new();
|
||||
|
||||
AMQP::LibEventHandler handler(evbase);
|
||||
AMQP::TcpConnection connection(&handler, AMQP::Address(address));
|
||||
AMQP::TcpChannel channel(&connection);
|
||||
|
||||
channel.setQos(1);
|
||||
|
||||
channel.confirmSelect()
|
||||
.onAck([&](uint64_t deliveryTag, bool multiple) {
|
||||
emit onReceivedAckNack(deliveryTag, true, multiple);
|
||||
})
|
||||
.onNack([&](uint64_t deliveryTag, bool multiple, bool requeue) {
|
||||
Q_UNUSED(requeue)
|
||||
emit onReceivedAckNack(deliveryTag, false, multiple);
|
||||
});
|
||||
|
||||
// Объявляем альтернативную точку обмена
|
||||
//--------------------------------------
|
||||
if (alt_e_value != "") {
|
||||
channel.declareExchange(alt_exchange, typeAltEx, flagsAltEx)
|
||||
.onError( [&](const char *message) {
|
||||
string msg(message);
|
||||
emit onError(msg);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Обработка основной точки обмена
|
||||
//----------------------------------
|
||||
string exchange = exchangeOption.name.toStdString();
|
||||
string type = exchangeOption.type.toStdString();
|
||||
|
||||
// преобразование типа точки обмена в формат AMQP
|
||||
AMQP::ExchangeType typeEx;
|
||||
if (type == "" || type == "direct")
|
||||
typeEx = AMQP::direct;
|
||||
else if (type == "topic")
|
||||
typeEx = AMQP::topic;
|
||||
else if (type == "headers")
|
||||
typeEx = AMQP::headers;
|
||||
else
|
||||
typeEx = AMQP::fanout;
|
||||
|
||||
// предобразование флагов точки обмена в формат AMQP
|
||||
int flagsExchange = 0;
|
||||
if (exchangeOption.durable)
|
||||
flagsExchange |= AMQP::durable;
|
||||
if (exchangeOption.auto_delete)
|
||||
flagsExchange |= AMQP::autodelete;
|
||||
if (exchangeOption.internal)
|
||||
flagsExchange |= AMQP::internal;
|
||||
|
||||
// Для предопределенных точек обмена их обьявление не производим
|
||||
if ( exchange != "" && exchange != "amq.fanout" && exchange != "amq.direct" &&
|
||||
exchange != "amq.topic" && exchange != "amq.headers") {
|
||||
channel.declareExchange(exchange, typeEx, flagsExchange, table)
|
||||
.onError( [&](const char *message) {
|
||||
string msg(message);
|
||||
emit onError(msg);
|
||||
});
|
||||
}
|
||||
|
||||
// обработка mandatory
|
||||
|
||||
auto messageCb = [&](const AMQP::Message& message, int16_t code, const std::string &description)
|
||||
{
|
||||
Q_UNUSED(code)
|
||||
Q_UNUSED(description)
|
||||
|
||||
// Формируем принятое сообщениев формате ReceivedMessage
|
||||
ProduceMessage *rMsg = new ProduceMessage;
|
||||
rMsg->setBodyMsg(message.body(), message.bodySize());
|
||||
|
||||
// Формируем таблицу Properties свойств сообщения
|
||||
Properties p;
|
||||
if (message.hasContentType())
|
||||
p.setContentType(QString::fromStdString(message.contentType()));
|
||||
if (message.hasContentEncoding())
|
||||
p.setContentEncoding(QString::fromStdString(message.contentEncoding()));
|
||||
if (message.hasMessageID())
|
||||
p.setMessageID(QString::fromStdString(message.messageID()));
|
||||
if (message.hasCorrelationID())
|
||||
p.setCorrelationID(QString::fromStdString(message.correlationID()));
|
||||
if (message.timestamp())
|
||||
p.setTimestamp(message.timestamp());
|
||||
if (message.hasExpiration())
|
||||
p.setExpiration(QString::fromStdString(message.expiration()));
|
||||
if (message.hasDeliveryMode())
|
||||
p.setDeliveryMode(message.deliveryMode());
|
||||
if (message.hasAppID())
|
||||
p.setAppID(QString::fromStdString(message.appID()));
|
||||
if (message.hasUserID())
|
||||
p.setUserID(QString::fromStdString(message.userID()));
|
||||
if (message.hasTypeName())
|
||||
p.setTypeName(QString::fromStdString(message.typeName()));
|
||||
if (message.hasReplyTo())
|
||||
p.setReplyTo(QString::fromStdString(message.replyTo()));
|
||||
if (message.hasPriority())
|
||||
p.setPriority(message.priority());
|
||||
|
||||
rMsg->setProperties(p);
|
||||
|
||||
// Работа со свойствами Headers
|
||||
Headers h;
|
||||
AMQP::Table table = message.headers();
|
||||
vector<string> keys = table.keys();
|
||||
|
||||
string name;
|
||||
for(uint i = 0; i < keys.size(); i++) {
|
||||
name = keys[i];
|
||||
if (table.get(name).isInteger()) {
|
||||
int value = table.get(name);
|
||||
h.set(QString::fromStdString(name), value);
|
||||
}
|
||||
else if (table.get(name).isString()) {
|
||||
QString str = QString::fromStdString(table.get(name));
|
||||
h.set(QString::fromStdString(name), str);
|
||||
}
|
||||
else if (table.get(name).isBoolean()) {
|
||||
AMQP::Field &b = const_cast<AMQP::Field &>(table.get(name));
|
||||
AMQP::BooleanSet &b1 = dynamic_cast<AMQP::BooleanSet &>(b);
|
||||
bool value = b1.get(0);
|
||||
h.set(QString::fromStdString(name), value);
|
||||
}
|
||||
}
|
||||
|
||||
rMsg->setHeaders(h);
|
||||
emit onMessageBounced(rMsg);
|
||||
};
|
||||
|
||||
channel.recall().onReceived(messageCb);
|
||||
|
||||
// Цикл событий (event loop)
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
while (! markStop) {
|
||||
|
||||
// Обрабатываем очередь сообщений на передачу
|
||||
if (! qu.isEmpty()) {
|
||||
|
||||
mutex.lock();
|
||||
PublishPacket *packet = qu.dequeue();
|
||||
mutex.unlock();
|
||||
|
||||
AMQP::Envelope *envelope = packet->envelope;
|
||||
int publishFlags = packet->publishFlags;
|
||||
string routingKey = packet->routingKey;
|
||||
|
||||
if (envelope->hasAppID() && envelope->appID() == HEARBEATS)
|
||||
connection.heartbeat();
|
||||
else
|
||||
channel.publish(exchange, routingKey, *envelope, publishFlags);
|
||||
|
||||
delete envelope->body();
|
||||
delete envelope;
|
||||
delete packet;
|
||||
}
|
||||
|
||||
event_base_loop(evbase, EVLOOP_NONBLOCK);
|
||||
QCoreApplication::processEvents();
|
||||
QThread::msleep(0);
|
||||
} //while
|
||||
|
||||
// Закроем канал и соединение
|
||||
channel.close();
|
||||
connection.close();
|
||||
|
||||
event_base_loopbreak(evbase);
|
||||
event_base_loopexit(evbase, 0);
|
||||
event_base_free(evbase);
|
||||
|
||||
emit onWorkFinished(); // Посылаем сигнал о завершении работы
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Прием данных, предразование в формат передачи
|
||||
// и постановка в очередь на выдачу
|
||||
void PWorker::sending(ProduceMessage msg, QString routingKey, bool mandatory)
|
||||
{
|
||||
mutex.lock();
|
||||
|
||||
uint64_t size = msg.getBodyMsg().size();
|
||||
char *body = new char[size];
|
||||
memcpy(body, msg.getBodyMsg().data(), size);
|
||||
|
||||
AMQP::Envelope *env = new AMQP::Envelope(body, size);
|
||||
|
||||
// Готовим сообщение для отправки
|
||||
Properties p = msg.getProperties();
|
||||
if (p.contains("content-type"))
|
||||
env->setContentType(p.getContentType().toStdString().c_str());
|
||||
if (p.contains("content-encoding"))
|
||||
env->setContentEncoding(p.getContentEncoding().toStdString().c_str());
|
||||
if (p.contains("message-id"))
|
||||
env->setMessageID(p.getMessageID().toStdString().c_str());
|
||||
if (p.contains("correlation-id"))
|
||||
env->setCorrelationID(p.getCorrelationID().toStdString().c_str());
|
||||
if (p.contains("timestamp"))
|
||||
env->setTimestamp(p.getTimestamp());
|
||||
if (p.contains("expiration"))
|
||||
env->setExpiration(p.getExpiration().toStdString().c_str());
|
||||
if (p.contains("delivery-mode"))
|
||||
env->setDeliveryMode(p.getDeliveryMode());
|
||||
if (p.contains("app-id"))
|
||||
env->setAppID(p.getAppID().toStdString().c_str());
|
||||
if (p.contains("user-id"))
|
||||
env->setUserID(p.getUserID().toStdString().c_str());
|
||||
if (p.contains("type"))
|
||||
env->setTypeName(p.getTypeName().toStdString().c_str());
|
||||
if (p.contains("reply-to"))
|
||||
env->setReplyTo(p.getReplyTo().toStdString().c_str());
|
||||
if (p.contains("priority"))
|
||||
env->setPriority(p.getPriority());
|
||||
|
||||
AMQP::Table table;
|
||||
|
||||
Headers p2 = msg.getHeaders();
|
||||
QList<QString> k = p2.keys();
|
||||
QList<QVariant> v = p2.values();
|
||||
for (int i=0; i < p2.size(); i++) {
|
||||
QString name = k[i];
|
||||
QVariant val = v[i];
|
||||
if (val.type() == QVariant::Int) {
|
||||
AMQP::Long numb = val.value<int>();
|
||||
table.set(name.toStdString(), numb.value());
|
||||
}
|
||||
else if (val.type() == QVariant::String) {
|
||||
QString str = val.value<QString>();
|
||||
AMQP::ShortString s(str.toStdString());
|
||||
table.set(name.toStdString(), s.value());
|
||||
}
|
||||
else if (val.type() == QVariant::Bool) {
|
||||
bool numb = val.value<bool>();
|
||||
table.set(name.toStdString(), numb);
|
||||
}
|
||||
}
|
||||
env->setHeaders(table);
|
||||
|
||||
int flags = 0; // флаги - в формат AMQP
|
||||
if (mandatory)
|
||||
flags |= AMQP::mandatory;
|
||||
|
||||
string routing = routingKey.toStdString();
|
||||
|
||||
// формируем пакет для постановки в очередь
|
||||
PublishPacket *pp = new PublishPacket;
|
||||
pp->envelope = env;
|
||||
pp->publishFlags = flags;
|
||||
pp->routingKey = routing;
|
||||
|
||||
qu.enqueue(pp);
|
||||
mutex.unlock();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PWorker::stop()
|
||||
{
|
||||
markStop = true; // завершить цикл обработки сообщений
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
#ifndef PWORKER_H
|
||||
#define PWORKER_H
|
||||
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <amqpcpp.h>
|
||||
#include <amqpcpp/libevent.h>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
struct PublishPacket {
|
||||
AMQP::Envelope *envelope;
|
||||
string routingKey;
|
||||
int publishFlags;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class PWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
ExchangeOption exchangeOption;
|
||||
|
||||
bool markStop;
|
||||
QMutex mutex;
|
||||
QQueue<PublishPacket *> qu;
|
||||
|
||||
public:
|
||||
PWorker(ClientOption& clientOption, ExchangeOption& exchangeOption);
|
||||
virtual ~PWorker();
|
||||
|
||||
public slots:
|
||||
void doWork();
|
||||
void sending(ProduceMessage msg, QString routingKey, bool mandatory=false);
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
void onMessageBounced(PtrProduceMessage msg);
|
||||
void onError(string msg);
|
||||
void onReceivedAckNack(uint64_t deliveryTag, bool ack, bool multiple);
|
||||
void onWorkFinished();
|
||||
};
|
||||
|
||||
|
||||
#endif // PWORKER_H
|
@ -1,65 +0,0 @@
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
|
||||
|
||||
Receiver::Receiver(ClientOption &clientOption, ConsumeOption &consumeOption)
|
||||
: QObject(nullptr)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->consumeOption = consumeOption;
|
||||
this->consumeOption.receivingExchange = consumeOption.receivingExchange;
|
||||
this->consumeOption.bindingArgs = consumeOption.bindingArgs;
|
||||
|
||||
CWorker *worker = new CWorker(this->clientOption, this->consumeOption);
|
||||
worker->moveToThread(&workerThread);
|
||||
|
||||
connect(&workerThread, &QThread::started, worker, &CWorker::doWork);
|
||||
connect(&workerThread, &QThread::finished, worker, &CWorker::slotStop);
|
||||
|
||||
// Автоматическое удаление объектов PWorker и QThread по окончании работы
|
||||
connect(worker, &CWorker::onWorkFinished, worker, &CWorker::deleteLater);
|
||||
|
||||
// Посылаемые потоку сигналы
|
||||
connect(this, &Receiver::onStop, worker, &CWorker::slotStop, Qt::DirectConnection);
|
||||
connect(this, &Receiver::doBind, worker, &CWorker::bind, Qt::DirectConnection);
|
||||
connect(this, &Receiver::doUnbind, worker, &CWorker::unbind, Qt::DirectConnection);
|
||||
|
||||
// Сигналы, принимаемые от потока
|
||||
connect(worker, &CWorker::onWorkFinished, &workerThread, &QThread::quit, Qt::QueuedConnection);
|
||||
connect(worker, &CWorker::onResultReady, this, &Receiver::slotMsgReady, Qt::QueuedConnection);
|
||||
connect(worker, &CWorker::onErrorConsume, this, &Receiver::slotErrorMsg, Qt::QueuedConnection);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
}
|
||||
|
||||
|
||||
Receiver::~Receiver()
|
||||
{
|
||||
workerThread.quit();
|
||||
workerThread.wait();
|
||||
}
|
||||
|
||||
// При получении от потока сигнала о приеме сообщения
|
||||
// выпускаем сигнал дальше
|
||||
void Receiver::slotMsgReady(PtrProduceMessage msg, uint64_t deliveryTag)
|
||||
{
|
||||
ProduceMessage message = *msg;
|
||||
delete msg;
|
||||
emit onMessage(message, deliveryTag);
|
||||
}
|
||||
|
||||
// При получении сигнала об ошибке транслируем его
|
||||
void Receiver::slotErrorMsg(const char *description)
|
||||
{
|
||||
QString str(description);
|
||||
emit onError(str);
|
||||
}
|
||||
|
||||
|
||||
void Receiver::slotStop()
|
||||
{
|
||||
emit onStop();
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
#ifndef RECEIVER_H
|
||||
#define RECEIVER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
#include <QThread>
|
||||
#include <QVariant>
|
||||
|
||||
#include "_client_.h"
|
||||
#include "cworker.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class Receiver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
bool stop;
|
||||
|
||||
ClientOption clientOption;
|
||||
ConsumeOption consumeOption;
|
||||
QThread workerThread;
|
||||
|
||||
public:
|
||||
Receiver(ClientOption& clientOption, ConsumeOption& consumeOption);
|
||||
virtual ~Receiver();
|
||||
|
||||
public slots:
|
||||
void slotMsgReady(PtrProduceMessage msg, uint64_t deliveryTag);
|
||||
void slotErrorMsg(const char *description);
|
||||
void slotStop();
|
||||
|
||||
signals:
|
||||
void onMessage(ProduceMessage msg, uint64_t deliveryTag);
|
||||
void onError(QString description);
|
||||
void onStop();
|
||||
void doBind(QString exchange, QString key, bool ex);
|
||||
void doUnbind(QString exchange, QString key, bool ex);
|
||||
|
||||
};
|
||||
|
||||
#endif // RECEIVER_H
|
@ -1,106 +0,0 @@
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
|
||||
Sender::Sender(ClientOption& clientOption, ExchangeOption& exchangeOption)
|
||||
: QObject(nullptr)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->exchangeOption = exchangeOption;
|
||||
|
||||
PWorker *worker = new PWorker(this->clientOption, this->exchangeOption);
|
||||
worker->moveToThread(&workerThread);
|
||||
|
||||
connect(&workerThread, &QThread::started, worker, &PWorker::doWork);
|
||||
|
||||
// Автоматическое удаление объектов PWorker и QThread по окончании работы
|
||||
connect(worker, &PWorker::onWorkFinished, worker, &PWorker::deleteLater);
|
||||
|
||||
// Посылаемые потоку сигналы
|
||||
connect(this, &Sender::onSend, worker, &PWorker::sending, Qt::QueuedConnection);
|
||||
connect(this, &Sender::onStop, worker, &PWorker::stop, Qt::DirectConnection);
|
||||
|
||||
// Сигналы, принимаемые от потока
|
||||
connect(worker, &PWorker::onWorkFinished, &workerThread, &QThread::quit, Qt::QueuedConnection);
|
||||
connect(worker, &PWorker::onReceivedAckNack, this, &Sender::slotAckNack, Qt::QueuedConnection);
|
||||
connect(worker, &PWorker::onError, this, &Sender::slotError, Qt::QueuedConnection);
|
||||
connect(worker, &PWorker::onMessageBounced, this, &Sender::slotMsgBounced, Qt::QueuedConnection);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
// Запуск таймера для механизма сердцебиения
|
||||
tm.stop();
|
||||
tm.setInterval(30000); // 0,5 мин
|
||||
connect(&tm, &QTimer::timeout, this, &Sender::onTimer);
|
||||
tm.start();
|
||||
}
|
||||
|
||||
|
||||
Sender::~Sender()
|
||||
{
|
||||
tm.stop();
|
||||
|
||||
workerThread.quit();
|
||||
workerThread.wait();
|
||||
}
|
||||
|
||||
|
||||
// Периодическое подключение по таймеру (1 мин)
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void Sender::onTimer()
|
||||
{
|
||||
tm.stop();
|
||||
|
||||
// Формируем и отправляем служебное сообщение
|
||||
// на проверку соединения с экземпляром RabbitMQ
|
||||
|
||||
string str = "@@"; // содержимое не играет роли
|
||||
ProduceMessage msg;
|
||||
msg.setBodyMsg(str.c_str(), str.size());
|
||||
|
||||
Properties p;
|
||||
QString hearbeats(HEARBEATS);
|
||||
p.setAppID(hearbeats); // маркер служебного сообщения сердцебиения
|
||||
msg.setProperties(p);
|
||||
|
||||
QString routingKey = "";
|
||||
emit onSend(msg, routingKey); // сообщение передаем в поток для передачи серверу
|
||||
|
||||
tm.start();
|
||||
}
|
||||
|
||||
void Sender::slotMsgBounced(PtrProduceMessage msg)
|
||||
{
|
||||
ProduceMessage message = *msg;
|
||||
delete msg;
|
||||
emit onMsgBounced(message);
|
||||
}
|
||||
|
||||
// Передаем сообщение в поток для выдачи
|
||||
void Sender::send(ProduceMessage msg, QString routingKey, bool mandatory)
|
||||
{
|
||||
emit onSend(msg, routingKey, mandatory);
|
||||
}
|
||||
|
||||
|
||||
// Прием подтверждения от потока о выдаче (или невыдаче) сообщения
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-------~~~~~~~~~~~~~~------------
|
||||
void Sender::slotAckNack(uint64_t deliveryTag, bool ack, bool multiple)
|
||||
{
|
||||
emit onReceivedAckNack(deliveryTag, ack, multiple);
|
||||
}
|
||||
|
||||
|
||||
void Sender::slotError(string msg)
|
||||
{
|
||||
QString message = QString::fromStdString(msg);
|
||||
|
||||
emit onError(message);
|
||||
}
|
||||
|
||||
|
||||
void Sender::slotStop()
|
||||
{
|
||||
emit onStop();
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
#ifndef SENDER_H
|
||||
#define SENDER_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QMetaType>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Client;
|
||||
class PWorker;
|
||||
|
||||
|
||||
class Sender : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
ExchangeOption exchangeOption;
|
||||
QThread workerThread;
|
||||
QTimer tm;
|
||||
|
||||
public:
|
||||
Sender(ClientOption& clientOption, ExchangeOption& exchangeOption);
|
||||
virtual ~Sender();
|
||||
|
||||
|
||||
void send(ProduceMessage msg, QString routingKey, bool mandatory=false);
|
||||
|
||||
private slots:
|
||||
void onTimer();
|
||||
|
||||
public slots:
|
||||
void slotMsgBounced(PtrProduceMessage msg);
|
||||
void slotStop();
|
||||
void slotAckNack(uint64_t deliveryTag, bool ack, bool multiple);
|
||||
void slotError(string msg);
|
||||
|
||||
signals:
|
||||
void onMsgBounced(ProduceMessage msg);
|
||||
void onReceivedAckNack(uint64_t deliveryTag, bool ack, bool multiple);
|
||||
void onSend(ProduceMessage msg, QString routingKey, bool mandatory=false); // Отправка сообщения потоку
|
||||
void onError(QString &msg);
|
||||
void onStop();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // SENDER_H
|
@ -1,54 +0,0 @@
|
||||
#include "validator.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
Validator::Validator(ClientOption& clientOption, QList<ExchangeOption>& exchangeOptions)
|
||||
: QObject(nullptr)
|
||||
{
|
||||
// класс запускает поток с валидатором, который в течение 5 секунд должен проверить инфраструктуру.
|
||||
// любая ошибка приведёт к завершению работы программы. если ошибок не было перехвачено, через 5 секунд процесс завершается.
|
||||
|
||||
this->clientOption = clientOption;
|
||||
this->exchangeOptions = exchangeOptions;
|
||||
|
||||
VWorker *worker = new VWorker(this->clientOption, this->exchangeOptions);
|
||||
worker->moveToThread(&workerThread);
|
||||
|
||||
connect(&workerThread, &QThread::started, worker, &VWorker::doWork);
|
||||
|
||||
// Автоматическое удаление объектов VWorker и QThread по окончании работы
|
||||
connect(worker, &VWorker::onWorkFinished, worker, &VWorker::deleteLater);
|
||||
|
||||
// Сигналы, принимаемые от потока
|
||||
connect(worker, &VWorker::onWorkFinished, &workerThread, &QThread::quit, Qt::QueuedConnection);
|
||||
connect(worker, &VWorker::onError, this, &Validator::slotError, Qt::QueuedConnection);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
// Запуск таймера для механизма сердцебиения
|
||||
tm.stop();
|
||||
tm.setInterval(5000); // 5 сек
|
||||
connect(&tm, &QTimer::timeout, worker, &VWorker::slotStop);
|
||||
connect(&tm, &QTimer::timeout, this, &Validator::onTimer);
|
||||
tm.start();
|
||||
}
|
||||
|
||||
Validator::~Validator()
|
||||
{
|
||||
tm.stop();
|
||||
|
||||
workerThread.quit();
|
||||
}
|
||||
|
||||
void Validator::onTimer()
|
||||
{
|
||||
tm.stop();
|
||||
|
||||
workerThread.quit();
|
||||
}
|
||||
|
||||
void Validator::slotError(string msg)
|
||||
{
|
||||
QString message = QString::fromStdString(msg);
|
||||
emit onError(message);
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
#ifndef VALIDATOR_H
|
||||
#define VALIDATOR_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QMetaType>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
class Validator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Validator(ClientOption& clientOption, QList<ExchangeOption>& exchangeOptions);
|
||||
virtual ~Validator();
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
QList<ExchangeOption> exchangeOptions;
|
||||
QThread workerThread;
|
||||
QTimer tm;
|
||||
|
||||
private slots:
|
||||
void onTimer();
|
||||
|
||||
public slots:
|
||||
void slotError(string msg);
|
||||
|
||||
signals:
|
||||
void onError(QString &msg);
|
||||
void onStop();
|
||||
};
|
||||
|
||||
#endif // VALIDATOR_H
|
@ -1,123 +0,0 @@
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "_client_.h"
|
||||
#include "sender.h"
|
||||
#include "vworker.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
VWorker::VWorker(ClientOption &clientOption, QList<ExchangeOption>& exchangeOptions)
|
||||
: QObject(nullptr), markStop(false)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->exchangeOptions = exchangeOptions;
|
||||
}
|
||||
|
||||
VWorker::~VWorker()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void VWorker::doWork()
|
||||
{
|
||||
string host = clientOption.host.toStdString();
|
||||
string port = QString::number(clientOption.port).toStdString();
|
||||
string user = clientOption.user.toStdString();
|
||||
string password = clientOption.password.toStdString();
|
||||
string vhost = clientOption.vhost.toStdString();
|
||||
|
||||
string address = "amqp://" + user + ":" + password + "@" + host + ":" + port + vhost;
|
||||
|
||||
// Создаём подключение
|
||||
|
||||
auto evbase = event_base_new();
|
||||
|
||||
AMQP::LibEventHandler handler(evbase);
|
||||
AMQP::TcpConnection connection(&handler, AMQP::Address(address));
|
||||
AMQP::TcpChannel channel(&connection);
|
||||
|
||||
channel.setQos(1);
|
||||
|
||||
channel.confirmSelect()
|
||||
.onError([&](const char *message) {
|
||||
qDebug() << "validator - connecting error: " << message;
|
||||
});
|
||||
|
||||
// Обрабатываем список точек обмена
|
||||
|
||||
string exch;
|
||||
string exType;
|
||||
AMQP::ExchangeType typeExch;
|
||||
int flagsExch = 0;
|
||||
|
||||
QString ex_alt_e_name = "alternate-exchange";
|
||||
QString ex_alt_e_value = "";
|
||||
|
||||
for(ExchangeOption exOpt : exchangeOptions) {
|
||||
AMQP::Table exTable;
|
||||
exch = exOpt.name.toStdString();
|
||||
exType = exOpt.type.toStdString();
|
||||
|
||||
// преобразование типа точки обмена в формат AMQP
|
||||
if (exType == "" || exType == "direct")
|
||||
typeExch = AMQP::direct;
|
||||
else if (exType == "topic")
|
||||
typeExch = AMQP::topic;
|
||||
else if (exType == "headers")
|
||||
typeExch = AMQP::headers;
|
||||
else
|
||||
typeExch = AMQP::fanout;
|
||||
|
||||
// предобразование флагов точки обмена в формат AMQP
|
||||
if (exOpt.durable)
|
||||
flagsExch |= AMQP::durable;
|
||||
if (exOpt.auto_delete)
|
||||
flagsExch |= AMQP::autodelete;
|
||||
if (exOpt.internal)
|
||||
flagsExch |= AMQP::internal;
|
||||
|
||||
if (exOpt.arguments.contains(ex_alt_e_name)) {
|
||||
ex_alt_e_value = exOpt.arguments[ex_alt_e_name].value<QString>();
|
||||
exTable.set(ex_alt_e_name.toStdString(), ex_alt_e_value.toStdString());
|
||||
}
|
||||
|
||||
//Для предопределенных точек обмена их обьявление не производим
|
||||
|
||||
if ( exch != "" && exch != "amq.fanout" && exch != "amq.direct" &&
|
||||
exch != "amq.topic" && exch != "amq.headers") {
|
||||
channel.declareExchange(exch, typeExch, flagsExch, exTable)
|
||||
.onError( [&](const char *message) {
|
||||
qDebug() << "validator - declaring error: " << message;
|
||||
emit onError(message);
|
||||
});
|
||||
}
|
||||
|
||||
QMap<QString, QString>::iterator it = exOpt.bindingArgs.begin();
|
||||
for (; it != exOpt.bindingArgs.end(); ++it) {
|
||||
channel.bindExchange(exch, it.key().toStdString(), it.value().toStdString())
|
||||
.onError( [&](const char *message) {
|
||||
qDebug() << "validator - binding error: " << message;
|
||||
emit onError(message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
while (! markStop) {
|
||||
event_base_loop(evbase, EVLOOP_NONBLOCK);
|
||||
QCoreApplication::processEvents();
|
||||
QThread::msleep(0);
|
||||
}
|
||||
|
||||
// Закроем канал и соединение
|
||||
channel.close();
|
||||
connection.close();
|
||||
|
||||
event_base_loopbreak(evbase);
|
||||
event_base_loopexit(evbase, 0);
|
||||
event_base_free(evbase);
|
||||
}
|
||||
|
||||
void VWorker::slotStop()
|
||||
{
|
||||
markStop = true;
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
#ifndef VWORKER_H
|
||||
#define VWORKER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <amqpcpp.h>
|
||||
#include <amqpcpp/libevent.h>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class VWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
QList<ExchangeOption> exchangeOptions;
|
||||
|
||||
bool markStop;
|
||||
QMutex mutex;
|
||||
|
||||
public:
|
||||
VWorker(ClientOption& clientOption, QList<ExchangeOption>& exchangeOptions);
|
||||
virtual ~VWorker();
|
||||
|
||||
public slots:
|
||||
void doWork();
|
||||
void slotStop();
|
||||
|
||||
signals:
|
||||
void onError(string msg);
|
||||
void onWorkFinished();
|
||||
};
|
||||
|
||||
|
||||
#endif // VWORKER_H
|
@ -1,41 +0,0 @@
|
||||
QT += core gui widgets
|
||||
|
||||
LIBS += -L/usr/lib -lamqpcpp -L/usr/lib/x86_64-linux-gnu/ -levent -lpthread -ldl
|
||||
|
||||
SOURCES += \
|
||||
clientRBcpp/client.cpp \
|
||||
clientRBcpp/clientrbcpp.cpp \
|
||||
clientRBcpp/cworker.cpp \
|
||||
clientRBcpp/headers.cpp \
|
||||
clientRBcpp/producemessage.cpp \
|
||||
clientRBcpp/properties.cpp \
|
||||
clientRBcpp/pworker.cpp \
|
||||
clientRBcpp/receiver.cpp \
|
||||
clientRBcpp/sender.cpp \
|
||||
clientRBcpp/validator.cpp \
|
||||
clientRBcpp/vworker.cpp \
|
||||
main.cpp \
|
||||
mainwindow.cpp
|
||||
|
||||
HEADERS += \
|
||||
clientRBcpp/_client_.h \
|
||||
clientRBcpp/client_cpp.h \
|
||||
clientRBcpp/clientrbcpp.h \
|
||||
clientRBcpp/clientrbcpp_global.h \
|
||||
clientRBcpp/cworker.h \
|
||||
clientRBcpp/headers.h \
|
||||
clientRBcpp/options/clientoption.h \
|
||||
clientRBcpp/options/consumeoption.h \
|
||||
clientRBcpp/options/exchangeoption.h \
|
||||
clientRBcpp/options/queueoption.h \
|
||||
clientRBcpp/producemessage.h \
|
||||
clientRBcpp/properties.h \
|
||||
clientRBcpp/pworker.h \
|
||||
clientRBcpp/receiver.h \
|
||||
clientRBcpp/sender.h \
|
||||
clientRBcpp/validator.h \
|
||||
clientRBcpp/vworker.h \
|
||||
mainwindow.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui
|
@ -1,338 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.12.3, 2023-12-23T19:03:36. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{77607214-f3f8-45c8-bf65-1a310ea854a8}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="int">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
|
||||
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
|
||||
<value type="QString" key="ClangCodeModel.WarningConfigId">Builtin.Questionable</value>
|
||||
<valuemap type="QVariantMap" key="ClangTools">
|
||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||
<value type="int" key="ClangTools.ParallelJobs">0</value>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{fa463890-d98c-43fb-aee8-64b3da65bdfc}</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="bool">true</value>
|
||||
<value type="int" key="EnableQmlDebugging">0</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/build-consumer_fast-Desktop-Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/build-consumer_fast-Desktop-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Отладка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
|
||||
<value type="int" key="QtQuickCompiler">2</value>
|
||||
<value type="int" key="SeparateDebugInfo">2</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
|
||||
<value type="bool">true</value>
|
||||
<value type="int" key="EnableQmlDebugging">2</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/build-consumer_fast-Desktop-Release</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/build-consumer_fast-Desktop-Release</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Выпуск</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
|
||||
<value type="int" key="QtQuickCompiler">0</value>
|
||||
<value type="int" key="SeparateDebugInfo">2</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
|
||||
<value type="bool">true</value>
|
||||
<value type="int" key="EnableQmlDebugging">0</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/build-consumer_fast-Desktop-Profile</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/build-consumer_fast-Desktop-Profile</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Профилирование</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
|
||||
<value type="int" key="QtQuickCompiler">0</value>
|
||||
<value type="int" key="SeparateDebugInfo">0</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Perf.Events">
|
||||
<value type="QString">cpu-cycles</value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/>
|
||||
<value type="int" key="Analyzer.Perf.Frequency">250</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Perf.RecordArguments">
|
||||
<value type="QString">-e</value>
|
||||
<value type="QString">cpu-cycles</value>
|
||||
<value type="QString">--call-graph</value>
|
||||
<value type="QString">dwarf,4096</value>
|
||||
<value type="QString">-F</value>
|
||||
<value type="QString">250</value>
|
||||
</valuelist>
|
||||
<value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Perf.StackSize">4096</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
|
||||
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
|
||||
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value>
|
||||
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
|
||||
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
|
||||
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
|
||||
<value type="int">0</value>
|
||||
<value type="int">1</value>
|
||||
<value type="int">2</value>
|
||||
<value type="int">3</value>
|
||||
<value type="int">4</value>
|
||||
<value type="int">5</value>
|
||||
<value type="int">6</value>
|
||||
<value type="int">7</value>
|
||||
<value type="int">8</value>
|
||||
<value type="int">9</value>
|
||||
<value type="int">10</value>
|
||||
<value type="int">11</value>
|
||||
<value type="int">12</value>
|
||||
<value type="int">13</value>
|
||||
<value type="int">14</value>
|
||||
</valuelist>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/consumer_fast/consumer_fast.pro</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/consumer_fast/consumer_fast.pro</value>
|
||||
<value type="QString" key="RunConfiguration.Arguments"></value>
|
||||
<value type="bool" key="RunConfiguration.Arguments.multi">false</value>
|
||||
<value type="QString" key="RunConfiguration.OverrideDebuggerStartup"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory"></value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/build-consumer_fast-Desktop-Debug</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="int">1</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>Version</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
</qtcreator>
|
@ -1,11 +0,0 @@
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ClientOption clOpt;
|
||||
|
||||
ConsumeOption conOpt;
|
||||
conOpt.exchange = "publisher";
|
||||
conOpt.bindingKeys << "all";
|
||||
conOpt.queueOption.name = "queue_fast";
|
||||
conOpt.queueOption.auto_delete = true;
|
||||
|
||||
receiver = new Receiver(clOpt, conOpt);
|
||||
QObject::connect(receiver, &Receiver::onMessage, this, [&](ProduceMessage msg, uint64_t consumeTag) {
|
||||
Q_UNUSED(consumeTag)
|
||||
|
||||
QString msg_body = "got " + QString::fromLocal8Bit(msg.getBodyMsg());
|
||||
ui->listWidget->addItem(msg_body);
|
||||
});
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include "clientRBcpp/client_cpp.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class MainWindow; }
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
Receiver *receiver;
|
||||
int counter;
|
||||
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
@ -1,37 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QListWidget" name="listWidget"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
Binary file not shown.
@ -1,53 +0,0 @@
|
||||
#ifndef _CLIENT_H
|
||||
#define _CLIENT_H
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
#include "options/clientoption.h"
|
||||
#include "options/consumeoption.h"
|
||||
#include "options/exchangeoption.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define HEARBEATS "@@__Control__@@"
|
||||
|
||||
class Sender;
|
||||
class Receiver;
|
||||
|
||||
class Client : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
|
||||
QList<Sender *> *_senders;
|
||||
QList<Receiver *> *_receivers;
|
||||
|
||||
public:
|
||||
Client();
|
||||
Client(ClientOption option);
|
||||
virtual ~Client();
|
||||
|
||||
Client& operator=(Client client);
|
||||
QString getVersion() const;
|
||||
|
||||
ClientOption getClientOption() const { return clientOption; }
|
||||
|
||||
Sender *createSender(ExchangeOption& option);
|
||||
void removeSender(Sender *sender);
|
||||
|
||||
Receiver *createReceiver(ConsumeOption& option);
|
||||
void removeReceiver(Receiver *receiver);
|
||||
|
||||
signals:
|
||||
void onStop();
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(string)
|
||||
|
||||
#endif // _CLIENT_H
|
@ -1,124 +0,0 @@
|
||||
|
||||
#include "_client_.h"
|
||||
#include "sender.h"
|
||||
#include "receiver.h"
|
||||
|
||||
|
||||
// Конструктор для связи с локальным RabbitMQ
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Client::Client() : QObject(nullptr)
|
||||
{
|
||||
{
|
||||
static const int idMsg = qRegisterMetaType<ProduceMessage>();
|
||||
static const int idMsgPtr = qRegisterMetaType<PtrProduceMessage>();
|
||||
static const int idString = qRegisterMetaType<string>();
|
||||
|
||||
Q_UNUSED(idMsg)
|
||||
Q_UNUSED(idMsgPtr)
|
||||
Q_UNUSED(idString)
|
||||
}
|
||||
|
||||
_senders = new QList<Sender *>();
|
||||
_senders->clear();
|
||||
|
||||
_receivers = new QList<Receiver *>();
|
||||
_receivers->clear();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Client::Client(ClientOption option) : Client()
|
||||
{
|
||||
clientOption = option;
|
||||
}
|
||||
|
||||
|
||||
Client::~Client()
|
||||
{
|
||||
for (auto &sender : *_senders)
|
||||
delete sender;
|
||||
delete _senders;
|
||||
|
||||
for (auto &receiver : *_receivers)
|
||||
delete receiver;
|
||||
delete _receivers;
|
||||
}
|
||||
|
||||
|
||||
Client& Client::operator=(Client client)
|
||||
{
|
||||
if (this != &client) {
|
||||
this->clientOption = client.clientOption;
|
||||
|
||||
this->_senders = new QList<Sender *>();
|
||||
this->_senders->clear();
|
||||
|
||||
this->_receivers = new QList<Receiver *>();
|
||||
this->_receivers->clear();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
int majorVersion = 1;
|
||||
int minorVersion = 1;
|
||||
int releaseVersion = 1;
|
||||
|
||||
QString Client::getVersion() const
|
||||
{
|
||||
return QString::number(majorVersion) +
|
||||
"." + QString::number(minorVersion) +
|
||||
"." + QString::number(releaseVersion);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Создание публикатора (издателя) сообщений
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sender *Client::createSender(ExchangeOption& option)
|
||||
{
|
||||
Sender *sender = new Sender(clientOption, option);
|
||||
|
||||
connect(this, &Client::onStop, sender, &Sender::slotStop);
|
||||
connect(this, &Client::onStop, sender, &Sender::deleteLater);
|
||||
|
||||
_senders->append(sender);
|
||||
|
||||
return sender;
|
||||
}
|
||||
|
||||
void Client::removeSender(Sender *sender)
|
||||
{
|
||||
if ( !_senders->contains(sender))
|
||||
return;
|
||||
sender->slotStop();
|
||||
_senders->removeOne(sender);
|
||||
}
|
||||
|
||||
|
||||
// Создание потребителя сообщений
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Receiver *Client::createReceiver(ConsumeOption& option)
|
||||
{
|
||||
Receiver *receiver = new Receiver(clientOption, option);
|
||||
|
||||
connect(this, &Client::onStop, receiver, &Receiver::slotStop);
|
||||
connect(this, &Client::onStop, receiver, &Receiver::deleteLater);
|
||||
|
||||
_receivers->append(receiver);
|
||||
|
||||
return receiver;
|
||||
}
|
||||
|
||||
void Client::removeReceiver(Receiver *receiver)
|
||||
{
|
||||
if ( !_receivers->contains(receiver))
|
||||
return;
|
||||
receiver->slotStop();
|
||||
_receivers->removeOne(receiver);
|
||||
}
|
||||
|
||||
|
@ -1,22 +0,0 @@
|
||||
#ifndef CLIENT_CPP_H
|
||||
#define CLIENT_CPP_H
|
||||
|
||||
#include "clientrbcpp_global.h"
|
||||
#include "clientrbcpp.h"
|
||||
#include "_client_.h"
|
||||
#include "producemessage.h"
|
||||
#include "properties.h"
|
||||
#include "cworker.h"
|
||||
#include "headers.h"
|
||||
#include "pworker.h"
|
||||
#include "receiver.h"
|
||||
#include "sender.h"
|
||||
#include "validator.h"
|
||||
#include "vworker.h"
|
||||
|
||||
#include "options/clientoption.h"
|
||||
#include "options/consumeoption.h"
|
||||
#include "options/exchangeoption.h"
|
||||
#include "options/queueoption.h"
|
||||
|
||||
#endif // CLIENT_CPP_H
|
@ -1,6 +0,0 @@
|
||||
#include "clientrbcpp.h"
|
||||
|
||||
|
||||
ClientRBcpp::ClientRBcpp()
|
||||
{
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
#ifndef CLIENTRBCPP_H
|
||||
#define CLIENTRBCPP_H
|
||||
|
||||
#include "clientrbcpp_global.h"
|
||||
|
||||
class CLIENTRBCPPSHARED_EXPORT ClientRBcpp
|
||||
{
|
||||
|
||||
public:
|
||||
ClientRBcpp();
|
||||
};
|
||||
|
||||
#endif // CLIENTRBCPP_H
|
@ -1,12 +0,0 @@
|
||||
#ifndef CLIENTRBCPP_GLOBAL_H
|
||||
#define CLIENTRBCPP_GLOBAL_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#if defined(CLIENTRBCPP_LIBRARY)
|
||||
# define CLIENTRBCPPSHARED_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define CLIENTRBCPPSHARED_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif // CLIENTRBCPP_GLOBAL_H
|
@ -1,278 +0,0 @@
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
CWorker::CWorker(ClientOption& clientOption, ConsumeOption& consumeOption)
|
||||
: QObject(nullptr), markStop(false)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->consumeOption = consumeOption;
|
||||
this->consumeOption.receivingExchange = consumeOption.receivingExchange;
|
||||
|
||||
connection = nullptr;
|
||||
channel = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CWorker::~CWorker()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Здесь реализуется основная деятельность потока
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void CWorker::doWork()
|
||||
{
|
||||
|
||||
string host = clientOption.host.toStdString();
|
||||
string port = QString::number(clientOption.port).toStdString();
|
||||
string user = clientOption.user.toStdString();
|
||||
string password = clientOption.password.toStdString();
|
||||
string vhost = clientOption.vhost.toStdString();
|
||||
|
||||
string address = "amqp://" + user + ":" + password + "@" + host + ":" + port + vhost;
|
||||
|
||||
auto evbase = event_base_new();
|
||||
|
||||
AMQP::LibEventHandler handler(evbase);
|
||||
|
||||
// AMQP::TcpConnection connection(&handler, AMQP::Address(address));
|
||||
// AMQP::TcpChannel channel(&connection);
|
||||
|
||||
connection = new AMQP::TcpConnection(&handler, AMQP::Address(address));
|
||||
channel = new AMQP::TcpChannel(connection);
|
||||
|
||||
channel->setQos(1);
|
||||
|
||||
channel->onError([&](const char *message) {
|
||||
Q_UNUSED(message)
|
||||
emit onErrorConsume("Channel error!!!");
|
||||
});
|
||||
|
||||
QTimer tm;
|
||||
tm.stop();
|
||||
tm.setInterval(30000);
|
||||
connect(&tm, &QTimer::timeout, this, [&]() {
|
||||
tm.stop();
|
||||
connection->heartbeat();
|
||||
tm.start();
|
||||
});
|
||||
tm.start();
|
||||
|
||||
// Обработка принятого сообщения
|
||||
auto messageCb = [&](const AMQP::Message& message, uint64_t deliveryTag, bool redelivered)
|
||||
{
|
||||
Q_UNUSED(redelivered)
|
||||
|
||||
// Формируем принятое сообщениев формате ReceivedMessage
|
||||
ProduceMessage *rMsg = new ProduceMessage;
|
||||
rMsg->setBodyMsg(message.body(), message.bodySize());
|
||||
|
||||
// Формируем таблицу Properties свойств сообщения
|
||||
Properties p;
|
||||
if (message.hasContentType())
|
||||
p.setContentType(QString::fromStdString(message.contentType()));
|
||||
if (message.hasContentEncoding())
|
||||
p.setContentEncoding(QString::fromStdString(message.contentEncoding()));
|
||||
if (message.hasMessageID())
|
||||
p.setMessageID(QString::fromStdString(message.messageID()));
|
||||
if (message.hasCorrelationID())
|
||||
p.setCorrelationID(QString::fromStdString(message.correlationID()));
|
||||
if (message.timestamp())
|
||||
p.setTimestamp(message.timestamp());
|
||||
if (message.hasExpiration())
|
||||
p.setExpiration(QString::fromStdString(message.expiration()));
|
||||
if (message.hasDeliveryMode())
|
||||
p.setDeliveryMode(message.deliveryMode());
|
||||
if (message.hasAppID())
|
||||
p.setAppID(QString::fromStdString(message.appID()));
|
||||
if (message.hasUserID())
|
||||
p.setUserID(QString::fromStdString(message.userID()));
|
||||
if (message.hasTypeName())
|
||||
p.setTypeName(QString::fromStdString(message.typeName()));
|
||||
if (message.hasReplyTo())
|
||||
p.setReplyTo(QString::fromStdString(message.replyTo()));
|
||||
if (message.hasPriority())
|
||||
p.setPriority(message.priority());
|
||||
|
||||
rMsg->setProperties(p);
|
||||
|
||||
// Работа со свойствами Headers
|
||||
Headers h;
|
||||
AMQP::Table table = message.headers();
|
||||
vector<string> keys = table.keys();
|
||||
|
||||
string name;
|
||||
for(uint i = 0; i < keys.size(); i++) {
|
||||
name = keys[i];
|
||||
if (table.get(name).isInteger()) {
|
||||
int value = table.get(name);
|
||||
h.set(QString::fromStdString(name), value);
|
||||
}
|
||||
else if (table.get(name).isString()) {
|
||||
QString str = QString::fromStdString(table.get(name));
|
||||
h.set(QString::fromStdString(name), str);
|
||||
}
|
||||
else if (table.get(name).isBoolean()) {
|
||||
AMQP::Field &b = const_cast<AMQP::Field &>(table.get(name));
|
||||
AMQP::BooleanSet &b1 = dynamic_cast<AMQP::BooleanSet &>(b);
|
||||
bool value = b1.get(0);
|
||||
h.set(QString::fromStdString(name), value);
|
||||
}
|
||||
}
|
||||
|
||||
rMsg->setHeaders(h);
|
||||
|
||||
QThread::sleep(3);
|
||||
emit onResultReady(rMsg, deliveryTag);
|
||||
|
||||
channel->ack(deliveryTag);
|
||||
};
|
||||
|
||||
// объявление точки обмена
|
||||
|
||||
if (!consumeOption.receivingExchange.name.isEmpty()) {
|
||||
string exchange = consumeOption.receivingExchange.name.toStdString();
|
||||
string type = consumeOption.receivingExchange.type.toStdString();
|
||||
|
||||
// преобразование типа точки обмена в формат AMQP
|
||||
AMQP::ExchangeType typeEx;
|
||||
if (type == "" || type == "direct")
|
||||
typeEx = AMQP::direct;
|
||||
else if (type == "topic")
|
||||
typeEx = AMQP::topic;
|
||||
else if (type == "headers")
|
||||
typeEx = AMQP::headers;
|
||||
else
|
||||
typeEx = AMQP::fanout;
|
||||
|
||||
// предобразование флагов точки обмена в формат AMQP
|
||||
int flagsExchange = 0;
|
||||
if (consumeOption.receivingExchange.durable)
|
||||
flagsExchange |= AMQP::durable;
|
||||
if (consumeOption.receivingExchange.auto_delete)
|
||||
flagsExchange |= AMQP::autodelete;
|
||||
if (consumeOption.receivingExchange.internal)
|
||||
flagsExchange |= AMQP::internal;
|
||||
|
||||
AMQP::Table tableExch;
|
||||
QString alt_e_name = "alternate-exchange";
|
||||
QString alt_e_value = "";
|
||||
if (consumeOption.receivingExchange.arguments.contains(alt_e_name)) {
|
||||
alt_e_value = consumeOption.receivingExchange.arguments[alt_e_name].value<QString>();
|
||||
tableExch.set(alt_e_name.toStdString(), alt_e_value.toStdString());
|
||||
}
|
||||
|
||||
// Для предопределенных точек обмена их обьявление не производим
|
||||
if ( exchange != "" && exchange != "amq.fanout" && exchange != "amq.direct" &&
|
||||
exchange != "amq.topic" && exchange != "amq.headers") {
|
||||
channel->declareExchange(exchange, typeEx, flagsExchange, tableExch)
|
||||
.onError([&](const char *description) {
|
||||
qDebug() << description;
|
||||
});
|
||||
}
|
||||
|
||||
QMultiMap<QString, QString>::iterator it = consumeOption.bindingArgs.begin();
|
||||
for(; it != consumeOption.bindingArgs.end(); ++it) {
|
||||
channel->bindExchange(it.key().toStdString(), exchange, it.value().toStdString()).onError([&](const char *description) {
|
||||
qDebug() << description;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// объявление очереди
|
||||
|
||||
QueueOption option = consumeOption.queueOption;
|
||||
|
||||
string exchange = consumeOption.exchange.toStdString();
|
||||
string queue = option.name.toStdString();
|
||||
|
||||
// Подготовка флагов для объявления очереди
|
||||
int flagsQueue = 0;
|
||||
if (option.durable)
|
||||
flagsQueue |= AMQP::durable;
|
||||
if (option.auto_delete)
|
||||
flagsQueue |= AMQP::autodelete;
|
||||
if (option.exclusive)
|
||||
flagsQueue |= AMQP::exclusive;
|
||||
|
||||
channel->declareQueue(queue, flagsQueue)
|
||||
.onSuccess( [&](const string &name, uint32_t messageCount, uint32_t consumerCount) {
|
||||
Q_UNUSED(messageCount)
|
||||
Q_UNUSED(consumerCount)
|
||||
queue = name;
|
||||
if (exchange != "")
|
||||
for (QString rk : consumeOption.bindingKeys) {
|
||||
channel->bindQueue(exchange, queue, rk.toStdString())
|
||||
.onError( [&](const char *description) {
|
||||
qDebug() << description;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Подготовка флагов потребления сообщений
|
||||
int flagsConsume = 0;
|
||||
if (consumeOption.nolocal)
|
||||
flagsConsume |= AMQP::nolocal;
|
||||
if (consumeOption.noack)
|
||||
flagsConsume |= AMQP::noack;
|
||||
if (consumeOption.exclusive)
|
||||
flagsConsume |= AMQP::exclusive;
|
||||
|
||||
|
||||
channel->consume(queue, flagsConsume).onReceived(messageCb)
|
||||
.onSuccess( [&](const string& tag) {
|
||||
nextTag = tag;
|
||||
})
|
||||
.onError( [&](const char *description) {
|
||||
emit onErrorConsume(description);
|
||||
markStop = true; // Останов потока
|
||||
});
|
||||
|
||||
//Цикл обработки событий
|
||||
while(!markStop) {
|
||||
|
||||
event_base_loop(evbase, EVLOOP_ONCE);
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
// Закроем канал и соединение
|
||||
channel->close();
|
||||
connection->close();
|
||||
|
||||
event_base_loopbreak(evbase);
|
||||
event_base_loopexit(evbase, 0);
|
||||
event_base_free(evbase);
|
||||
|
||||
delete channel;
|
||||
delete connection;
|
||||
|
||||
emit onWorkFinished(); // Посылаем сигнал о завершении работы
|
||||
}
|
||||
|
||||
|
||||
void CWorker::slotStop()
|
||||
{
|
||||
markStop = true;
|
||||
channel->cancel(nextTag); // Отменить потребление
|
||||
|
||||
channel->close();
|
||||
connection->close();
|
||||
|
||||
}
|
||||
|
||||
void CWorker::bind(QString exchange, QString key, bool ex)
|
||||
{
|
||||
if (ex) channel->bindExchange(exchange.toStdString(), consumeOption.exchange.toStdString(), key.toStdString());
|
||||
else channel->bindQueue(exchange.toStdString(), consumeOption.queueOption.name.toStdString(), key.toStdString());
|
||||
}
|
||||
|
||||
void CWorker::unbind(QString exchange, QString key, bool ex)
|
||||
{
|
||||
if (ex) channel->unbindExchange(exchange.toStdString(), consumeOption.exchange.toStdString(), key.toStdString());
|
||||
else channel->unbindQueue(exchange.toStdString(), consumeOption.queueOption.name.toStdString(), key.toStdString());
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
#ifndef CWORKER_H
|
||||
#define CWORKER_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <amqpcpp.h>
|
||||
#include <amqpcpp/libevent.h>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class CWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
ConsumeOption consumeOption;
|
||||
|
||||
bool markStop;
|
||||
|
||||
AMQP::TcpConnection *connection;
|
||||
AMQP::TcpChannel *channel;
|
||||
|
||||
string nextTag;
|
||||
|
||||
public:
|
||||
CWorker(ClientOption& clientOption, ConsumeOption& consumeOption);
|
||||
virtual ~CWorker();
|
||||
|
||||
public slots:
|
||||
void doWork();
|
||||
void slotStop();
|
||||
void bind(QString exchange, QString key, bool ex);
|
||||
void unbind(QString exchange, QString key, bool ex);
|
||||
|
||||
signals:
|
||||
void onResultReady(PtrProduceMessage msg, uint64_t deliveryTag);
|
||||
void onErrorConsume(const char *description);
|
||||
void onWorkFinished();
|
||||
};
|
||||
|
||||
|
||||
#endif // CWORKER_H
|
@ -1,40 +0,0 @@
|
||||
#include "headers.h"
|
||||
|
||||
Headers::Headers()
|
||||
{
|
||||
_headers.clear();
|
||||
}
|
||||
|
||||
Headers::Headers(const Headers& h)
|
||||
{
|
||||
this->_headers = h._headers;
|
||||
}
|
||||
|
||||
void Headers::operator=(const Headers& h)
|
||||
{
|
||||
this->_headers = h._headers;
|
||||
}
|
||||
|
||||
|
||||
QMap<QString,QVariant> Headers::getHeaders() const { return _headers; }
|
||||
|
||||
QList<QString> Headers::keys() const { return _headers.keys(); }
|
||||
QList<QVariant> Headers::values() const { return _headers.values(); }
|
||||
|
||||
int Headers::size() const { return _headers.size(); }
|
||||
|
||||
bool Headers::contains(const QString name) const { return _headers.contains(name); }
|
||||
|
||||
|
||||
void Headers::set(const QString name, bool value) { _headers.insert(name, value); }
|
||||
void Headers::set(const QString name, int value) { _headers.insert(name, value); }
|
||||
void Headers::set(const QString name, QString str) { _headers.insert(name, str); }
|
||||
|
||||
bool Headers::isBool(const QString name) const { return _headers[name].type() == QVariant::Bool; }
|
||||
bool Headers::isInteger(const QString name) const { return _headers[name].type() == QVariant::Int; }
|
||||
bool Headers::isString(const QString name) const { return _headers[name].type() == QVariant::String; }
|
||||
|
||||
bool Headers::getBool(const QString name) const { return _headers[name].value<bool>(); }
|
||||
int Headers::getInteger(const QString name) const { return _headers[name].value<int>(); }
|
||||
QString Headers::getString(const QString name) const { return _headers[name].value<QString>(); }
|
||||
|
@ -1,45 +0,0 @@
|
||||
#ifndef HEADERS_H
|
||||
#define HEADERS_H
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
class Headers
|
||||
{
|
||||
private:
|
||||
QMap<QString,QVariant> _headers;
|
||||
|
||||
public:
|
||||
Headers();
|
||||
Headers(const Headers& h); // Конструктор копирования
|
||||
~Headers() {}
|
||||
|
||||
void operator=(const Headers& h);
|
||||
|
||||
QMap<QString,QVariant> getHeaders() const;
|
||||
|
||||
QList<QString> keys() const;
|
||||
QList<QVariant> values() const;
|
||||
|
||||
int size() const;
|
||||
|
||||
bool contains(const QString name) const;
|
||||
|
||||
void set(const QString name, bool value);
|
||||
void set(const QString name, int value);
|
||||
void set(const QString name, QString str);
|
||||
|
||||
bool isBool(const QString name) const;
|
||||
bool isInteger(const QString name) const;
|
||||
bool isString(const QString name) const;
|
||||
|
||||
bool getBool(const QString name) const;
|
||||
int getInteger(const QString name) const;
|
||||
QString getString(const QString name) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // HEADERS_H
|
@ -1,45 +0,0 @@
|
||||
#ifndef CLIENTOPTION_H
|
||||
#define CLIENTOPTION_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
// Значения по умолчанию
|
||||
const QString DEFAULT_CPP_HOST = "localhost";
|
||||
const int DEFAULT_CPP_PORT = 5672;
|
||||
const QString DEFAULT_CPP_USER = "guest";
|
||||
const QString DEFAULT_CPP_PASSWORD = "guest";
|
||||
const QString DEFAULT_CPP_VHOST = "/";
|
||||
|
||||
|
||||
struct ClientOption {
|
||||
QString host;
|
||||
int port;
|
||||
QString user;
|
||||
QString password;
|
||||
QString vhost;
|
||||
|
||||
ClientOption() {
|
||||
host = DEFAULT_CPP_HOST;
|
||||
port = DEFAULT_CPP_PORT;
|
||||
user = DEFAULT_CPP_USER;
|
||||
password = DEFAULT_CPP_PASSWORD;
|
||||
vhost = DEFAULT_CPP_VHOST;
|
||||
}
|
||||
|
||||
~ClientOption() {}
|
||||
|
||||
ClientOption(const ClientOption& src) = default; // Конструктор копирования
|
||||
ClientOption(ClientOption&& src) = default; // Конструктор перемещения
|
||||
|
||||
ClientOption& operator=(const ClientOption rhs) // Оператор присваивания
|
||||
{
|
||||
host = rhs.host;
|
||||
port = rhs.port;
|
||||
user = rhs.user;
|
||||
password = rhs.password;
|
||||
vhost = rhs.vhost;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CLIENTOPTION_H
|
@ -1,52 +0,0 @@
|
||||
#ifndef CONSUMEOPTION_H
|
||||
#define CONSUMEOPTION_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
|
||||
#include "queueoption.h"
|
||||
#include "exchangeoption.h"
|
||||
|
||||
struct ConsumeOption
|
||||
{
|
||||
QString exchange; // Имя точки обмена для связывания
|
||||
QStringList bindingKeys; // ключи связи точки с очередью
|
||||
|
||||
bool nolocal;
|
||||
bool noack;
|
||||
bool exclusive;
|
||||
|
||||
QueueOption queueOption; // Параметры очереди
|
||||
ExchangeOption receivingExchange; // Параметры новой принимающей очереди (по умолчанию новой не создаётся)
|
||||
QMultiMap<QString, QString> bindingArgs; // список связей для точки обмена (если создаётся новая точка)
|
||||
|
||||
ConsumeOption() {
|
||||
exchange = "";
|
||||
receivingExchange.name = "";
|
||||
|
||||
nolocal = false;
|
||||
noack = false;
|
||||
exclusive = false;
|
||||
}
|
||||
|
||||
~ConsumeOption() {}
|
||||
|
||||
ConsumeOption(const ConsumeOption& src) = default; // Конструктор копирования
|
||||
ConsumeOption(ConsumeOption&& src) = default; // Конструктор перемещения
|
||||
|
||||
ConsumeOption& operator=(const ConsumeOption rhs) // Оператор присваивания
|
||||
{
|
||||
exchange = rhs.exchange;
|
||||
bindingKeys = rhs.bindingKeys;
|
||||
nolocal = rhs.nolocal;
|
||||
noack = rhs.noack;
|
||||
exclusive = rhs.exclusive;
|
||||
queueOption = rhs.queueOption;
|
||||
bindingArgs = rhs.bindingArgs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // CONSUMEOPTION_H
|
@ -1,55 +0,0 @@
|
||||
#ifndef EXCHANGEOPTION_H
|
||||
#define EXCHANGEOPTION_H
|
||||
|
||||
#include <QString>
|
||||
#include <QVariantMap>
|
||||
#include <QList>
|
||||
|
||||
struct ExchangeOption
|
||||
{
|
||||
QString name; // уникальное имя точки обмена
|
||||
QString type; // тип точки обмена (direct, topic,
|
||||
// fanout или headers)
|
||||
bool auto_delete; // автоматически удаляемая точка обмена
|
||||
bool durable; // долгоживущая точка обмена
|
||||
bool passive; // требуется информация о точке обмена
|
||||
bool internal; // нельзя вести публикацию из приложения
|
||||
|
||||
QVariantMap arguments; // необязательные аргументы
|
||||
QMap<QString, QString> bindingArgs; // список связей для точки обмена
|
||||
|
||||
bool ifunused; // можно удалять, только если точка обмена
|
||||
// не используется (не имеет потребителей)
|
||||
ExchangeOption() {
|
||||
name = "";
|
||||
type = "";
|
||||
auto_delete = false;
|
||||
durable = false;
|
||||
passive = false;
|
||||
internal = false;
|
||||
arguments.clear();
|
||||
|
||||
ifunused = false;
|
||||
}
|
||||
|
||||
~ExchangeOption() {}
|
||||
|
||||
ExchangeOption(const ExchangeOption& src) = default; // Конструктор копирования
|
||||
ExchangeOption(ExchangeOption&& src) = default; // Конструктор перемещения
|
||||
|
||||
ExchangeOption& operator=(const ExchangeOption rhs) // Оператор присваивания
|
||||
{
|
||||
name = rhs.name;
|
||||
type = rhs.type;
|
||||
auto_delete = rhs.auto_delete;
|
||||
durable = rhs.durable;
|
||||
passive = rhs.passive;
|
||||
internal = rhs.internal;
|
||||
arguments = rhs.arguments;
|
||||
|
||||
ifunused = rhs.ifunused;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EXCHANGEOPTION_H
|
@ -1,63 +0,0 @@
|
||||
#ifndef QUEUEOPTION_H
|
||||
#define QUEUEOPTION_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariantMap>
|
||||
|
||||
struct QueueOption
|
||||
{
|
||||
QString name; // Уникальное имя очереди
|
||||
|
||||
bool auto_delete; // Автоматически удаляемая очередь
|
||||
bool durable; // Долгоживущая очередь
|
||||
bool passive; // Требуется информация об очереди
|
||||
bool exclusive; // Исключительная очередь
|
||||
|
||||
QVariantMap arguments; // Необязательные аргументы очереди
|
||||
|
||||
bool ifunused; // Удалять, только если не используется
|
||||
bool ifempty; // Удалять, только если очередь пуста
|
||||
|
||||
int messageCount; // Число сообщений в очереди
|
||||
int consumerCount; // Число потребителей очереди
|
||||
|
||||
QueueOption() {
|
||||
name = "";
|
||||
|
||||
auto_delete = false;
|
||||
durable = false;
|
||||
passive = false;
|
||||
exclusive = false;
|
||||
|
||||
arguments.clear();
|
||||
|
||||
ifunused = false;
|
||||
ifempty = false;
|
||||
|
||||
messageCount = 0;
|
||||
consumerCount = 0;
|
||||
}
|
||||
|
||||
~QueueOption() {}
|
||||
|
||||
QueueOption(const QueueOption& src) = default; // Конструктор копирования
|
||||
QueueOption(QueueOption&& src) = default; // Конструктор перемещения
|
||||
|
||||
QueueOption& operator=(const QueueOption rhs) // Оператор присваивания
|
||||
{
|
||||
name = rhs.name;
|
||||
auto_delete = rhs.auto_delete;
|
||||
passive = rhs.passive;
|
||||
exclusive = rhs.exclusive;
|
||||
arguments = rhs.arguments;
|
||||
|
||||
ifunused = rhs.ifunused;
|
||||
ifempty = rhs.ifempty;
|
||||
messageCount = rhs.messageCount;
|
||||
consumerCount = rhs.consumerCount;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // QUEUEOPTION_H
|
@ -1,37 +0,0 @@
|
||||
#include "producemessage.h"
|
||||
|
||||
// Конструктор по умолчанию
|
||||
ProduceMessage::ProduceMessage()
|
||||
{
|
||||
_body.clear();
|
||||
}
|
||||
|
||||
// Конструктор копирования
|
||||
ProduceMessage::ProduceMessage(const ProduceMessage& msg)
|
||||
{
|
||||
this->_body = msg._body;
|
||||
this->_headers = msg._headers;
|
||||
this->_properties = msg._properties;
|
||||
}
|
||||
|
||||
ProduceMessage& ProduceMessage::operator=(const ProduceMessage& msg)
|
||||
{
|
||||
if (this != &msg) {
|
||||
this->_body = msg._body;
|
||||
this->_headers = msg._headers;
|
||||
this->_properties = msg._properties;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
QByteArray ProduceMessage::getBodyMsg() const { return _body; }
|
||||
void ProduceMessage::setBodyMsg(const QByteArray &ba) { _body = ba; }
|
||||
void ProduceMessage::setBodyMsg(const char *body, int size) { _body = QByteArray(body, size); }
|
||||
|
||||
Headers ProduceMessage::getHeaders() const { return _headers; }
|
||||
void ProduceMessage::setHeaders(const Headers &headers) { _headers = headers; }
|
||||
|
||||
Properties ProduceMessage::getProperties() const { return _properties; }
|
||||
void ProduceMessage::setProperties(const Properties &properties) { _properties = properties; }
|
||||
|
||||
|
@ -1,43 +0,0 @@
|
||||
#ifndef PRODUCEMESSAGE_H
|
||||
#define PRODUCEMESSAGE_H
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
#include "properties.h"
|
||||
#include "headers.h"
|
||||
|
||||
|
||||
class ProduceMessage
|
||||
{
|
||||
public:
|
||||
ProduceMessage();
|
||||
ProduceMessage(const ProduceMessage& msg);
|
||||
~ProduceMessage() {}
|
||||
|
||||
ProduceMessage& operator=(const ProduceMessage& msg);
|
||||
|
||||
QByteArray getBodyMsg() const;
|
||||
void setBodyMsg(const QByteArray &ba);
|
||||
void setBodyMsg(const char *body, int size);
|
||||
|
||||
Headers getHeaders() const;
|
||||
void setHeaders(const Headers &headers);
|
||||
|
||||
Properties getProperties() const;
|
||||
void setProperties(const Properties &properties);
|
||||
|
||||
private:
|
||||
QByteArray _body;
|
||||
|
||||
protected:
|
||||
Properties _properties;
|
||||
Headers _headers;
|
||||
};
|
||||
|
||||
|
||||
using PtrProduceMessage = ProduceMessage*;
|
||||
|
||||
Q_DECLARE_METATYPE(ProduceMessage)
|
||||
Q_DECLARE_METATYPE(PtrProduceMessage)
|
||||
|
||||
#endif // PRODUCEMESSAGE_H
|
@ -1,63 +0,0 @@
|
||||
#include "properties.h"
|
||||
|
||||
Properties::Properties()
|
||||
{
|
||||
_properties.clear();
|
||||
setDeliveryMode(1); // не оставлять сообщения
|
||||
}
|
||||
|
||||
// Конструктор копирования
|
||||
Properties::Properties(const Properties& p)
|
||||
{
|
||||
this->_properties = p._properties;
|
||||
}
|
||||
|
||||
|
||||
void Properties::operator=(const Properties& p)
|
||||
{
|
||||
this->_properties = p._properties;
|
||||
}
|
||||
|
||||
|
||||
const QMap<QString,QVariant> &Properties::getProperties() { return _properties; }
|
||||
|
||||
bool Properties::contains(const QString name) const { return _properties.contains(name); }
|
||||
|
||||
bool Properties::isContentType() const { return _properties.contains("content-type"); }
|
||||
bool Properties::isContentEncoding() const { return _properties.contains("content-encoding"); }
|
||||
bool Properties::isMessageID() const { return _properties.contains("message-id"); }
|
||||
bool Properties::isCorrelationID() const { return _properties.contains("correlation-id"); }
|
||||
bool Properties::isTimestamp() const { return _properties.contains("timestamp"); }
|
||||
bool Properties::isExpiration() const { return _properties.contains("expiration"); }
|
||||
bool Properties::isDeliveryMode() const { return _properties.contains("delivery-mode"); }
|
||||
bool Properties::isAppID() const { return _properties.contains("app-id"); }
|
||||
bool Properties::isUserID() const { return _properties.contains("user-id"); }
|
||||
bool Properties::isTypeName() const { return _properties.contains("type"); }
|
||||
bool Properties::isReplyTo() const { return _properties.contains("reply-to"); }
|
||||
bool Properties::isPriority() const { return _properties.contains("priority"); }
|
||||
|
||||
void Properties::setContentType(const QString &str) { _properties.insert("content-type", str); }
|
||||
void Properties::setContentEncoding(const QString &str) { _properties.insert("content-encoding", str); }
|
||||
void Properties::setMessageID(const QString &str) { _properties.insert("message-id", str); }
|
||||
void Properties::setCorrelationID(const QString &str) { _properties.insert("correlation-id", str); }
|
||||
void Properties::setTimestamp(const quint64 val) { _properties.insert("timestamp", val); }
|
||||
void Properties::setExpiration(const QString &str) { _properties.insert("expiration", str); }
|
||||
void Properties::setDeliveryMode(const quint8 val) { _properties.insert("delivery-mode", val); }
|
||||
void Properties::setAppID(const QString &str) { _properties.insert("app-id", str); }
|
||||
void Properties::setUserID(const QString &str) { _properties.insert("user-id", str); }
|
||||
void Properties::setTypeName(const QString &str) { _properties.insert("type", str); }
|
||||
void Properties::setReplyTo(const QString &str) { _properties.insert("reply-to", str); }
|
||||
void Properties::setPriority(const quint8 val) { _properties.insert("priority", val); }
|
||||
|
||||
QString Properties::getContentType() const { return _properties["content-type"].value<QString>(); }
|
||||
QString Properties::getContentEncoding() const { return _properties["content-encoding"].value<QString>(); }
|
||||
QString Properties::getMessageID() const { return _properties["message-id"].value<QString>(); }
|
||||
QString Properties::getCorrelationID() const { return _properties["correlation-id"].value<QString>(); }
|
||||
quint64 Properties::getTimestamp() const { return _properties["timestamp"].value<quint64>(); }
|
||||
QString Properties::getExpiration() const { return _properties["expiration"].value<QString>(); }
|
||||
quint8 Properties::getDeliveryMode() const { return _properties["delivery-mode"].value<quint8>(); }
|
||||
QString Properties::getAppID() const { return _properties["app-id"].value<QString>(); }
|
||||
QString Properties::getUserID() const { return _properties["user-id"].value<QString>(); }
|
||||
QString Properties::getTypeName() const { return _properties["type"].value<QString>(); }
|
||||
QString Properties::getReplyTo() const { return _properties["reply-to"].value<QString>(); }
|
||||
quint8 Properties::getPriority() const { return _properties["priority"].value<quint8>(); }
|
@ -1,73 +0,0 @@
|
||||
#ifndef PROPERTIES_H
|
||||
#define PROPERTIES_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
class Properties
|
||||
{
|
||||
private:
|
||||
QMap<QString,QVariant> _properties;
|
||||
|
||||
public:
|
||||
Properties();
|
||||
Properties(const Properties& p);
|
||||
~Properties() {}
|
||||
|
||||
void operator=(const Properties& p);
|
||||
|
||||
int size() {return _properties.size(); }
|
||||
|
||||
const QMap<QString,QVariant> &getProperties();
|
||||
|
||||
bool contains(const QString name) const;
|
||||
|
||||
bool isContentType() const;
|
||||
bool isContentEncoding() const;
|
||||
bool isMessageID() const;
|
||||
bool isCorrelationID() const;
|
||||
bool isTimestamp() const;
|
||||
bool isExpiration() const;
|
||||
bool isDeliveryMode() const;
|
||||
bool isAppID() const;
|
||||
bool isUserID() const;
|
||||
bool isTypeName() const;
|
||||
bool isReplyTo() const;
|
||||
bool isPriority() const;
|
||||
|
||||
void setContentType(const QString &str);
|
||||
void setContentEncoding(const QString &str);
|
||||
void setMessageID(const QString &str);
|
||||
void setCorrelationID(const QString &str);
|
||||
void setTimestamp(const quint64 val);
|
||||
void setExpiration(const QString &str);
|
||||
void setDeliveryMode(const quint8 val);
|
||||
void setAppID(const QString &str);
|
||||
void setUserID(const QString &str);
|
||||
void setTypeName(const QString &str);
|
||||
void setReplyTo(const QString &str);
|
||||
void setPriority(const quint8 val);
|
||||
|
||||
QString getContentType() const;
|
||||
QString getContentEncoding() const;
|
||||
QString getMessageID() const;
|
||||
QString getCorrelationID() const;
|
||||
quint64 getTimestamp() const;
|
||||
QString getExpiration() const;
|
||||
quint8 getDeliveryMode() const;
|
||||
QString getAppID() const;
|
||||
QString getUserID() const;
|
||||
QString getTypeName() const;
|
||||
QString getReplyTo() const;
|
||||
quint8 getPriority() const;
|
||||
};
|
||||
|
||||
#endif // PROPERTIES_H
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,330 +0,0 @@
|
||||
/**************************************************************************
|
||||
* PWorker - Publish Worker, - рабочий поток публикации сообщений *
|
||||
* редакция от 08.06.2022 *
|
||||
* Принадлежность: библиотека clientRBcpp *
|
||||
**************************************************************************/
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "_client_.h"
|
||||
#include "sender.h"
|
||||
#include "pworker.h"
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
PWorker::PWorker(ClientOption& clientOption, ExchangeOption& exchangeOption)
|
||||
: QObject(nullptr), markStop(false)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->exchangeOption = exchangeOption;
|
||||
|
||||
qu.clear();
|
||||
|
||||
// static const int idE2E = qRegisterMetaType<E2EStruct>();
|
||||
// Q_UNUSED(idE2E)
|
||||
|
||||
}
|
||||
|
||||
|
||||
PWorker::~PWorker()
|
||||
{
|
||||
// Освободим очередь сообщений
|
||||
mutex.lock();
|
||||
while (! qu.isEmpty()) {
|
||||
PublishPacket *packet = qu.dequeue();
|
||||
AMQP::Envelope *envelope = packet->envelope;
|
||||
delete envelope->body();
|
||||
delete envelope;
|
||||
delete packet;
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
// Здесь реализуется основная деятельность потока
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void PWorker::doWork()
|
||||
{
|
||||
string host = clientOption.host.toStdString();
|
||||
string port = QString::number(clientOption.port).toStdString();
|
||||
string user = clientOption.user.toStdString();
|
||||
string password = clientOption.password.toStdString();
|
||||
string vhost = clientOption.vhost.toStdString();
|
||||
|
||||
string address = "amqp://" + user + ":" + password + "@" + host + ":" + port + vhost;
|
||||
|
||||
// Обрабатываем аргументы на предмет альтернативной точки обмена
|
||||
AMQP::Table table;
|
||||
QString alt_e_name = "alternate-exchange";
|
||||
QString alt_e_value = "";
|
||||
if (exchangeOption.arguments.contains(alt_e_name)) {
|
||||
alt_e_value = exchangeOption.arguments[alt_e_name].value<QString>();
|
||||
table.set(alt_e_name.toStdString(), alt_e_value.toStdString());
|
||||
}
|
||||
|
||||
string alt_exchange = alt_e_value.toStdString(); // Имя альтернативной точки обмена
|
||||
AMQP::ExchangeType typeAltEx = AMQP::fanout; // Тип альтернативной точки обмена - всегда fanout
|
||||
int flagsAltEx = (AMQP::durable | AMQP::internal); // Точка долгоживущая и внутренняя
|
||||
|
||||
auto evbase = event_base_new();
|
||||
|
||||
AMQP::LibEventHandler handler(evbase);
|
||||
AMQP::TcpConnection connection(&handler, AMQP::Address(address));
|
||||
AMQP::TcpChannel channel(&connection);
|
||||
|
||||
channel.setQos(1);
|
||||
|
||||
channel.confirmSelect()
|
||||
.onAck([&](uint64_t deliveryTag, bool multiple) {
|
||||
emit onReceivedAckNack(deliveryTag, true, multiple);
|
||||
})
|
||||
.onNack([&](uint64_t deliveryTag, bool multiple, bool requeue) {
|
||||
Q_UNUSED(requeue)
|
||||
emit onReceivedAckNack(deliveryTag, false, multiple);
|
||||
});
|
||||
|
||||
// Объявляем альтернативную точку обмена
|
||||
//--------------------------------------
|
||||
if (alt_e_value != "") {
|
||||
channel.declareExchange(alt_exchange, typeAltEx, flagsAltEx)
|
||||
.onError( [&](const char *message) {
|
||||
string msg(message);
|
||||
emit onError(msg);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Обработка основной точки обмена
|
||||
//----------------------------------
|
||||
string exchange = exchangeOption.name.toStdString();
|
||||
string type = exchangeOption.type.toStdString();
|
||||
|
||||
// преобразование типа точки обмена в формат AMQP
|
||||
AMQP::ExchangeType typeEx;
|
||||
if (type == "" || type == "direct")
|
||||
typeEx = AMQP::direct;
|
||||
else if (type == "topic")
|
||||
typeEx = AMQP::topic;
|
||||
else if (type == "headers")
|
||||
typeEx = AMQP::headers;
|
||||
else
|
||||
typeEx = AMQP::fanout;
|
||||
|
||||
// предобразование флагов точки обмена в формат AMQP
|
||||
int flagsExchange = 0;
|
||||
if (exchangeOption.durable)
|
||||
flagsExchange |= AMQP::durable;
|
||||
if (exchangeOption.auto_delete)
|
||||
flagsExchange |= AMQP::autodelete;
|
||||
if (exchangeOption.internal)
|
||||
flagsExchange |= AMQP::internal;
|
||||
|
||||
// Для предопределенных точек обмена их обьявление не производим
|
||||
if ( exchange != "" && exchange != "amq.fanout" && exchange != "amq.direct" &&
|
||||
exchange != "amq.topic" && exchange != "amq.headers") {
|
||||
channel.declareExchange(exchange, typeEx, flagsExchange, table)
|
||||
.onError( [&](const char *message) {
|
||||
string msg(message);
|
||||
emit onError(msg);
|
||||
});
|
||||
}
|
||||
|
||||
// обработка mandatory
|
||||
|
||||
auto messageCb = [&](const AMQP::Message& message, int16_t code, const std::string &description)
|
||||
{
|
||||
Q_UNUSED(code)
|
||||
Q_UNUSED(description)
|
||||
|
||||
// Формируем принятое сообщениев формате ReceivedMessage
|
||||
ProduceMessage *rMsg = new ProduceMessage;
|
||||
rMsg->setBodyMsg(message.body(), message.bodySize());
|
||||
|
||||
// Формируем таблицу Properties свойств сообщения
|
||||
Properties p;
|
||||
if (message.hasContentType())
|
||||
p.setContentType(QString::fromStdString(message.contentType()));
|
||||
if (message.hasContentEncoding())
|
||||
p.setContentEncoding(QString::fromStdString(message.contentEncoding()));
|
||||
if (message.hasMessageID())
|
||||
p.setMessageID(QString::fromStdString(message.messageID()));
|
||||
if (message.hasCorrelationID())
|
||||
p.setCorrelationID(QString::fromStdString(message.correlationID()));
|
||||
if (message.timestamp())
|
||||
p.setTimestamp(message.timestamp());
|
||||
if (message.hasExpiration())
|
||||
p.setExpiration(QString::fromStdString(message.expiration()));
|
||||
if (message.hasDeliveryMode())
|
||||
p.setDeliveryMode(message.deliveryMode());
|
||||
if (message.hasAppID())
|
||||
p.setAppID(QString::fromStdString(message.appID()));
|
||||
if (message.hasUserID())
|
||||
p.setUserID(QString::fromStdString(message.userID()));
|
||||
if (message.hasTypeName())
|
||||
p.setTypeName(QString::fromStdString(message.typeName()));
|
||||
if (message.hasReplyTo())
|
||||
p.setReplyTo(QString::fromStdString(message.replyTo()));
|
||||
if (message.hasPriority())
|
||||
p.setPriority(message.priority());
|
||||
|
||||
rMsg->setProperties(p);
|
||||
|
||||
// Работа со свойствами Headers
|
||||
Headers h;
|
||||
AMQP::Table table = message.headers();
|
||||
vector<string> keys = table.keys();
|
||||
|
||||
string name;
|
||||
for(uint i = 0; i < keys.size(); i++) {
|
||||
name = keys[i];
|
||||
if (table.get(name).isInteger()) {
|
||||
int value = table.get(name);
|
||||
h.set(QString::fromStdString(name), value);
|
||||
}
|
||||
else if (table.get(name).isString()) {
|
||||
QString str = QString::fromStdString(table.get(name));
|
||||
h.set(QString::fromStdString(name), str);
|
||||
}
|
||||
else if (table.get(name).isBoolean()) {
|
||||
AMQP::Field &b = const_cast<AMQP::Field &>(table.get(name));
|
||||
AMQP::BooleanSet &b1 = dynamic_cast<AMQP::BooleanSet &>(b);
|
||||
bool value = b1.get(0);
|
||||
h.set(QString::fromStdString(name), value);
|
||||
}
|
||||
}
|
||||
|
||||
rMsg->setHeaders(h);
|
||||
emit onMessageBounced(rMsg);
|
||||
};
|
||||
|
||||
channel.recall().onReceived(messageCb);
|
||||
|
||||
// Цикл событий (event loop)
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
while (! markStop) {
|
||||
|
||||
// Обрабатываем очередь сообщений на передачу
|
||||
if (! qu.isEmpty()) {
|
||||
|
||||
mutex.lock();
|
||||
PublishPacket *packet = qu.dequeue();
|
||||
mutex.unlock();
|
||||
|
||||
AMQP::Envelope *envelope = packet->envelope;
|
||||
int publishFlags = packet->publishFlags;
|
||||
string routingKey = packet->routingKey;
|
||||
|
||||
if (envelope->hasAppID() && envelope->appID() == HEARBEATS)
|
||||
connection.heartbeat();
|
||||
else
|
||||
channel.publish(exchange, routingKey, *envelope, publishFlags);
|
||||
|
||||
delete envelope->body();
|
||||
delete envelope;
|
||||
delete packet;
|
||||
}
|
||||
|
||||
event_base_loop(evbase, EVLOOP_NONBLOCK);
|
||||
QCoreApplication::processEvents();
|
||||
QThread::msleep(0);
|
||||
} //while
|
||||
|
||||
// Закроем канал и соединение
|
||||
channel.close();
|
||||
connection.close();
|
||||
|
||||
event_base_loopbreak(evbase);
|
||||
event_base_loopexit(evbase, 0);
|
||||
event_base_free(evbase);
|
||||
|
||||
emit onWorkFinished(); // Посылаем сигнал о завершении работы
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Прием данных, предразование в формат передачи
|
||||
// и постановка в очередь на выдачу
|
||||
void PWorker::sending(ProduceMessage msg, QString routingKey, bool mandatory)
|
||||
{
|
||||
mutex.lock();
|
||||
|
||||
uint64_t size = msg.getBodyMsg().size();
|
||||
char *body = new char[size];
|
||||
memcpy(body, msg.getBodyMsg().data(), size);
|
||||
|
||||
AMQP::Envelope *env = new AMQP::Envelope(body, size);
|
||||
|
||||
// Готовим сообщение для отправки
|
||||
Properties p = msg.getProperties();
|
||||
if (p.contains("content-type"))
|
||||
env->setContentType(p.getContentType().toStdString().c_str());
|
||||
if (p.contains("content-encoding"))
|
||||
env->setContentEncoding(p.getContentEncoding().toStdString().c_str());
|
||||
if (p.contains("message-id"))
|
||||
env->setMessageID(p.getMessageID().toStdString().c_str());
|
||||
if (p.contains("correlation-id"))
|
||||
env->setCorrelationID(p.getCorrelationID().toStdString().c_str());
|
||||
if (p.contains("timestamp"))
|
||||
env->setTimestamp(p.getTimestamp());
|
||||
if (p.contains("expiration"))
|
||||
env->setExpiration(p.getExpiration().toStdString().c_str());
|
||||
if (p.contains("delivery-mode"))
|
||||
env->setDeliveryMode(p.getDeliveryMode());
|
||||
if (p.contains("app-id"))
|
||||
env->setAppID(p.getAppID().toStdString().c_str());
|
||||
if (p.contains("user-id"))
|
||||
env->setUserID(p.getUserID().toStdString().c_str());
|
||||
if (p.contains("type"))
|
||||
env->setTypeName(p.getTypeName().toStdString().c_str());
|
||||
if (p.contains("reply-to"))
|
||||
env->setReplyTo(p.getReplyTo().toStdString().c_str());
|
||||
if (p.contains("priority"))
|
||||
env->setPriority(p.getPriority());
|
||||
|
||||
AMQP::Table table;
|
||||
|
||||
Headers p2 = msg.getHeaders();
|
||||
QList<QString> k = p2.keys();
|
||||
QList<QVariant> v = p2.values();
|
||||
for (int i=0; i < p2.size(); i++) {
|
||||
QString name = k[i];
|
||||
QVariant val = v[i];
|
||||
if (val.type() == QVariant::Int) {
|
||||
AMQP::Long numb = val.value<int>();
|
||||
table.set(name.toStdString(), numb.value());
|
||||
}
|
||||
else if (val.type() == QVariant::String) {
|
||||
QString str = val.value<QString>();
|
||||
AMQP::ShortString s(str.toStdString());
|
||||
table.set(name.toStdString(), s.value());
|
||||
}
|
||||
else if (val.type() == QVariant::Bool) {
|
||||
bool numb = val.value<bool>();
|
||||
table.set(name.toStdString(), numb);
|
||||
}
|
||||
}
|
||||
env->setHeaders(table);
|
||||
|
||||
int flags = 0; // флаги - в формат AMQP
|
||||
if (mandatory)
|
||||
flags |= AMQP::mandatory;
|
||||
|
||||
string routing = routingKey.toStdString();
|
||||
|
||||
// формируем пакет для постановки в очередь
|
||||
PublishPacket *pp = new PublishPacket;
|
||||
pp->envelope = env;
|
||||
pp->publishFlags = flags;
|
||||
pp->routingKey = routing;
|
||||
|
||||
qu.enqueue(pp);
|
||||
mutex.unlock();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PWorker::stop()
|
||||
{
|
||||
markStop = true; // завершить цикл обработки сообщений
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
#ifndef PWORKER_H
|
||||
#define PWORKER_H
|
||||
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <amqpcpp.h>
|
||||
#include <amqpcpp/libevent.h>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
struct PublishPacket {
|
||||
AMQP::Envelope *envelope;
|
||||
string routingKey;
|
||||
int publishFlags;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class PWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
ExchangeOption exchangeOption;
|
||||
|
||||
bool markStop;
|
||||
QMutex mutex;
|
||||
QQueue<PublishPacket *> qu;
|
||||
|
||||
public:
|
||||
PWorker(ClientOption& clientOption, ExchangeOption& exchangeOption);
|
||||
virtual ~PWorker();
|
||||
|
||||
public slots:
|
||||
void doWork();
|
||||
void sending(ProduceMessage msg, QString routingKey, bool mandatory=false);
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
void onMessageBounced(PtrProduceMessage msg);
|
||||
void onError(string msg);
|
||||
void onReceivedAckNack(uint64_t deliveryTag, bool ack, bool multiple);
|
||||
void onWorkFinished();
|
||||
};
|
||||
|
||||
|
||||
#endif // PWORKER_H
|
@ -1,65 +0,0 @@
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
|
||||
|
||||
Receiver::Receiver(ClientOption &clientOption, ConsumeOption &consumeOption)
|
||||
: QObject(nullptr)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->consumeOption = consumeOption;
|
||||
this->consumeOption.receivingExchange = consumeOption.receivingExchange;
|
||||
this->consumeOption.bindingArgs = consumeOption.bindingArgs;
|
||||
|
||||
CWorker *worker = new CWorker(this->clientOption, this->consumeOption);
|
||||
worker->moveToThread(&workerThread);
|
||||
|
||||
connect(&workerThread, &QThread::started, worker, &CWorker::doWork);
|
||||
connect(&workerThread, &QThread::finished, worker, &CWorker::slotStop);
|
||||
|
||||
// Автоматическое удаление объектов PWorker и QThread по окончании работы
|
||||
connect(worker, &CWorker::onWorkFinished, worker, &CWorker::deleteLater);
|
||||
|
||||
// Посылаемые потоку сигналы
|
||||
connect(this, &Receiver::onStop, worker, &CWorker::slotStop, Qt::DirectConnection);
|
||||
connect(this, &Receiver::doBind, worker, &CWorker::bind, Qt::DirectConnection);
|
||||
connect(this, &Receiver::doUnbind, worker, &CWorker::unbind, Qt::DirectConnection);
|
||||
|
||||
// Сигналы, принимаемые от потока
|
||||
connect(worker, &CWorker::onWorkFinished, &workerThread, &QThread::quit, Qt::QueuedConnection);
|
||||
connect(worker, &CWorker::onResultReady, this, &Receiver::slotMsgReady, Qt::QueuedConnection);
|
||||
connect(worker, &CWorker::onErrorConsume, this, &Receiver::slotErrorMsg, Qt::QueuedConnection);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
}
|
||||
|
||||
|
||||
Receiver::~Receiver()
|
||||
{
|
||||
workerThread.quit();
|
||||
workerThread.wait();
|
||||
}
|
||||
|
||||
// При получении от потока сигнала о приеме сообщения
|
||||
// выпускаем сигнал дальше
|
||||
void Receiver::slotMsgReady(PtrProduceMessage msg, uint64_t deliveryTag)
|
||||
{
|
||||
ProduceMessage message = *msg;
|
||||
delete msg;
|
||||
emit onMessage(message, deliveryTag);
|
||||
}
|
||||
|
||||
// При получении сигнала об ошибке транслируем его
|
||||
void Receiver::slotErrorMsg(const char *description)
|
||||
{
|
||||
QString str(description);
|
||||
emit onError(str);
|
||||
}
|
||||
|
||||
|
||||
void Receiver::slotStop()
|
||||
{
|
||||
emit onStop();
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
#ifndef RECEIVER_H
|
||||
#define RECEIVER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
#include <QThread>
|
||||
#include <QVariant>
|
||||
|
||||
#include "_client_.h"
|
||||
#include "cworker.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class Receiver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
bool stop;
|
||||
|
||||
ClientOption clientOption;
|
||||
ConsumeOption consumeOption;
|
||||
QThread workerThread;
|
||||
|
||||
public:
|
||||
Receiver(ClientOption& clientOption, ConsumeOption& consumeOption);
|
||||
virtual ~Receiver();
|
||||
|
||||
public slots:
|
||||
void slotMsgReady(PtrProduceMessage msg, uint64_t deliveryTag);
|
||||
void slotErrorMsg(const char *description);
|
||||
void slotStop();
|
||||
|
||||
signals:
|
||||
void onMessage(ProduceMessage msg, uint64_t deliveryTag);
|
||||
void onError(QString description);
|
||||
void onStop();
|
||||
void doBind(QString exchange, QString key, bool ex);
|
||||
void doUnbind(QString exchange, QString key, bool ex);
|
||||
|
||||
};
|
||||
|
||||
#endif // RECEIVER_H
|
@ -1,106 +0,0 @@
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
|
||||
Sender::Sender(ClientOption& clientOption, ExchangeOption& exchangeOption)
|
||||
: QObject(nullptr)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->exchangeOption = exchangeOption;
|
||||
|
||||
PWorker *worker = new PWorker(this->clientOption, this->exchangeOption);
|
||||
worker->moveToThread(&workerThread);
|
||||
|
||||
connect(&workerThread, &QThread::started, worker, &PWorker::doWork);
|
||||
|
||||
// Автоматическое удаление объектов PWorker и QThread по окончании работы
|
||||
connect(worker, &PWorker::onWorkFinished, worker, &PWorker::deleteLater);
|
||||
|
||||
// Посылаемые потоку сигналы
|
||||
connect(this, &Sender::onSend, worker, &PWorker::sending, Qt::QueuedConnection);
|
||||
connect(this, &Sender::onStop, worker, &PWorker::stop, Qt::DirectConnection);
|
||||
|
||||
// Сигналы, принимаемые от потока
|
||||
connect(worker, &PWorker::onWorkFinished, &workerThread, &QThread::quit, Qt::QueuedConnection);
|
||||
connect(worker, &PWorker::onReceivedAckNack, this, &Sender::slotAckNack, Qt::QueuedConnection);
|
||||
connect(worker, &PWorker::onError, this, &Sender::slotError, Qt::QueuedConnection);
|
||||
connect(worker, &PWorker::onMessageBounced, this, &Sender::slotMsgBounced, Qt::QueuedConnection);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
// Запуск таймера для механизма сердцебиения
|
||||
tm.stop();
|
||||
tm.setInterval(30000); // 0,5 мин
|
||||
connect(&tm, &QTimer::timeout, this, &Sender::onTimer);
|
||||
tm.start();
|
||||
}
|
||||
|
||||
|
||||
Sender::~Sender()
|
||||
{
|
||||
tm.stop();
|
||||
|
||||
workerThread.quit();
|
||||
workerThread.wait();
|
||||
}
|
||||
|
||||
|
||||
// Периодическое подключение по таймеру (1 мин)
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void Sender::onTimer()
|
||||
{
|
||||
tm.stop();
|
||||
|
||||
// Формируем и отправляем служебное сообщение
|
||||
// на проверку соединения с экземпляром RabbitMQ
|
||||
|
||||
string str = "@@"; // содержимое не играет роли
|
||||
ProduceMessage msg;
|
||||
msg.setBodyMsg(str.c_str(), str.size());
|
||||
|
||||
Properties p;
|
||||
QString hearbeats(HEARBEATS);
|
||||
p.setAppID(hearbeats); // маркер служебного сообщения сердцебиения
|
||||
msg.setProperties(p);
|
||||
|
||||
QString routingKey = "";
|
||||
emit onSend(msg, routingKey); // сообщение передаем в поток для передачи серверу
|
||||
|
||||
tm.start();
|
||||
}
|
||||
|
||||
void Sender::slotMsgBounced(PtrProduceMessage msg)
|
||||
{
|
||||
ProduceMessage message = *msg;
|
||||
delete msg;
|
||||
emit onMsgBounced(message);
|
||||
}
|
||||
|
||||
// Передаем сообщение в поток для выдачи
|
||||
void Sender::send(ProduceMessage msg, QString routingKey, bool mandatory)
|
||||
{
|
||||
emit onSend(msg, routingKey, mandatory);
|
||||
}
|
||||
|
||||
|
||||
// Прием подтверждения от потока о выдаче (или невыдаче) сообщения
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-------~~~~~~~~~~~~~~------------
|
||||
void Sender::slotAckNack(uint64_t deliveryTag, bool ack, bool multiple)
|
||||
{
|
||||
emit onReceivedAckNack(deliveryTag, ack, multiple);
|
||||
}
|
||||
|
||||
|
||||
void Sender::slotError(string msg)
|
||||
{
|
||||
QString message = QString::fromStdString(msg);
|
||||
|
||||
emit onError(message);
|
||||
}
|
||||
|
||||
|
||||
void Sender::slotStop()
|
||||
{
|
||||
emit onStop();
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
#ifndef SENDER_H
|
||||
#define SENDER_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QMetaType>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Client;
|
||||
class PWorker;
|
||||
|
||||
|
||||
class Sender : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
ExchangeOption exchangeOption;
|
||||
QThread workerThread;
|
||||
QTimer tm;
|
||||
|
||||
public:
|
||||
Sender(ClientOption& clientOption, ExchangeOption& exchangeOption);
|
||||
virtual ~Sender();
|
||||
|
||||
|
||||
void send(ProduceMessage msg, QString routingKey, bool mandatory=false);
|
||||
|
||||
private slots:
|
||||
void onTimer();
|
||||
|
||||
public slots:
|
||||
void slotMsgBounced(PtrProduceMessage msg);
|
||||
void slotStop();
|
||||
void slotAckNack(uint64_t deliveryTag, bool ack, bool multiple);
|
||||
void slotError(string msg);
|
||||
|
||||
signals:
|
||||
void onMsgBounced(ProduceMessage msg);
|
||||
void onReceivedAckNack(uint64_t deliveryTag, bool ack, bool multiple);
|
||||
void onSend(ProduceMessage msg, QString routingKey, bool mandatory=false); // Отправка сообщения потоку
|
||||
void onError(QString &msg);
|
||||
void onStop();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // SENDER_H
|
@ -1,54 +0,0 @@
|
||||
#include "validator.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
Validator::Validator(ClientOption& clientOption, QList<ExchangeOption>& exchangeOptions)
|
||||
: QObject(nullptr)
|
||||
{
|
||||
// класс запускает поток с валидатором, который в течение 5 секунд должен проверить инфраструктуру.
|
||||
// любая ошибка приведёт к завершению работы программы. если ошибок не было перехвачено, через 5 секунд процесс завершается.
|
||||
|
||||
this->clientOption = clientOption;
|
||||
this->exchangeOptions = exchangeOptions;
|
||||
|
||||
VWorker *worker = new VWorker(this->clientOption, this->exchangeOptions);
|
||||
worker->moveToThread(&workerThread);
|
||||
|
||||
connect(&workerThread, &QThread::started, worker, &VWorker::doWork);
|
||||
|
||||
// Автоматическое удаление объектов VWorker и QThread по окончании работы
|
||||
connect(worker, &VWorker::onWorkFinished, worker, &VWorker::deleteLater);
|
||||
|
||||
// Сигналы, принимаемые от потока
|
||||
connect(worker, &VWorker::onWorkFinished, &workerThread, &QThread::quit, Qt::QueuedConnection);
|
||||
connect(worker, &VWorker::onError, this, &Validator::slotError, Qt::QueuedConnection);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
// Запуск таймера для механизма сердцебиения
|
||||
tm.stop();
|
||||
tm.setInterval(5000); // 5 сек
|
||||
connect(&tm, &QTimer::timeout, worker, &VWorker::slotStop);
|
||||
connect(&tm, &QTimer::timeout, this, &Validator::onTimer);
|
||||
tm.start();
|
||||
}
|
||||
|
||||
Validator::~Validator()
|
||||
{
|
||||
tm.stop();
|
||||
|
||||
workerThread.quit();
|
||||
}
|
||||
|
||||
void Validator::onTimer()
|
||||
{
|
||||
tm.stop();
|
||||
|
||||
workerThread.quit();
|
||||
}
|
||||
|
||||
void Validator::slotError(string msg)
|
||||
{
|
||||
QString message = QString::fromStdString(msg);
|
||||
emit onError(message);
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
#ifndef VALIDATOR_H
|
||||
#define VALIDATOR_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QMetaType>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
class Validator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Validator(ClientOption& clientOption, QList<ExchangeOption>& exchangeOptions);
|
||||
virtual ~Validator();
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
QList<ExchangeOption> exchangeOptions;
|
||||
QThread workerThread;
|
||||
QTimer tm;
|
||||
|
||||
private slots:
|
||||
void onTimer();
|
||||
|
||||
public slots:
|
||||
void slotError(string msg);
|
||||
|
||||
signals:
|
||||
void onError(QString &msg);
|
||||
void onStop();
|
||||
};
|
||||
|
||||
#endif // VALIDATOR_H
|
@ -1,123 +0,0 @@
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "_client_.h"
|
||||
#include "sender.h"
|
||||
#include "vworker.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
VWorker::VWorker(ClientOption &clientOption, QList<ExchangeOption>& exchangeOptions)
|
||||
: QObject(nullptr), markStop(false)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->exchangeOptions = exchangeOptions;
|
||||
}
|
||||
|
||||
VWorker::~VWorker()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void VWorker::doWork()
|
||||
{
|
||||
string host = clientOption.host.toStdString();
|
||||
string port = QString::number(clientOption.port).toStdString();
|
||||
string user = clientOption.user.toStdString();
|
||||
string password = clientOption.password.toStdString();
|
||||
string vhost = clientOption.vhost.toStdString();
|
||||
|
||||
string address = "amqp://" + user + ":" + password + "@" + host + ":" + port + vhost;
|
||||
|
||||
// Создаём подключение
|
||||
|
||||
auto evbase = event_base_new();
|
||||
|
||||
AMQP::LibEventHandler handler(evbase);
|
||||
AMQP::TcpConnection connection(&handler, AMQP::Address(address));
|
||||
AMQP::TcpChannel channel(&connection);
|
||||
|
||||
channel.setQos(1);
|
||||
|
||||
channel.confirmSelect()
|
||||
.onError([&](const char *message) {
|
||||
qDebug() << "validator - connecting error: " << message;
|
||||
});
|
||||
|
||||
// Обрабатываем список точек обмена
|
||||
|
||||
string exch;
|
||||
string exType;
|
||||
AMQP::ExchangeType typeExch;
|
||||
int flagsExch = 0;
|
||||
|
||||
QString ex_alt_e_name = "alternate-exchange";
|
||||
QString ex_alt_e_value = "";
|
||||
|
||||
for(ExchangeOption exOpt : exchangeOptions) {
|
||||
AMQP::Table exTable;
|
||||
exch = exOpt.name.toStdString();
|
||||
exType = exOpt.type.toStdString();
|
||||
|
||||
// преобразование типа точки обмена в формат AMQP
|
||||
if (exType == "" || exType == "direct")
|
||||
typeExch = AMQP::direct;
|
||||
else if (exType == "topic")
|
||||
typeExch = AMQP::topic;
|
||||
else if (exType == "headers")
|
||||
typeExch = AMQP::headers;
|
||||
else
|
||||
typeExch = AMQP::fanout;
|
||||
|
||||
// предобразование флагов точки обмена в формат AMQP
|
||||
if (exOpt.durable)
|
||||
flagsExch |= AMQP::durable;
|
||||
if (exOpt.auto_delete)
|
||||
flagsExch |= AMQP::autodelete;
|
||||
if (exOpt.internal)
|
||||
flagsExch |= AMQP::internal;
|
||||
|
||||
if (exOpt.arguments.contains(ex_alt_e_name)) {
|
||||
ex_alt_e_value = exOpt.arguments[ex_alt_e_name].value<QString>();
|
||||
exTable.set(ex_alt_e_name.toStdString(), ex_alt_e_value.toStdString());
|
||||
}
|
||||
|
||||
//Для предопределенных точек обмена их обьявление не производим
|
||||
|
||||
if ( exch != "" && exch != "amq.fanout" && exch != "amq.direct" &&
|
||||
exch != "amq.topic" && exch != "amq.headers") {
|
||||
channel.declareExchange(exch, typeExch, flagsExch, exTable)
|
||||
.onError( [&](const char *message) {
|
||||
qDebug() << "validator - declaring error: " << message;
|
||||
emit onError(message);
|
||||
});
|
||||
}
|
||||
|
||||
QMap<QString, QString>::iterator it = exOpt.bindingArgs.begin();
|
||||
for (; it != exOpt.bindingArgs.end(); ++it) {
|
||||
channel.bindExchange(exch, it.key().toStdString(), it.value().toStdString())
|
||||
.onError( [&](const char *message) {
|
||||
qDebug() << "validator - binding error: " << message;
|
||||
emit onError(message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
while (! markStop) {
|
||||
event_base_loop(evbase, EVLOOP_NONBLOCK);
|
||||
QCoreApplication::processEvents();
|
||||
QThread::msleep(0);
|
||||
}
|
||||
|
||||
// Закроем канал и соединение
|
||||
channel.close();
|
||||
connection.close();
|
||||
|
||||
event_base_loopbreak(evbase);
|
||||
event_base_loopexit(evbase, 0);
|
||||
event_base_free(evbase);
|
||||
}
|
||||
|
||||
void VWorker::slotStop()
|
||||
{
|
||||
markStop = true;
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
#ifndef VWORKER_H
|
||||
#define VWORKER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <amqpcpp.h>
|
||||
#include <amqpcpp/libevent.h>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class VWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
QList<ExchangeOption> exchangeOptions;
|
||||
|
||||
bool markStop;
|
||||
QMutex mutex;
|
||||
|
||||
public:
|
||||
VWorker(ClientOption& clientOption, QList<ExchangeOption>& exchangeOptions);
|
||||
virtual ~VWorker();
|
||||
|
||||
public slots:
|
||||
void doWork();
|
||||
void slotStop();
|
||||
|
||||
signals:
|
||||
void onError(string msg);
|
||||
void onWorkFinished();
|
||||
};
|
||||
|
||||
|
||||
#endif // VWORKER_H
|
@ -1,41 +0,0 @@
|
||||
QT += core gui widgets
|
||||
|
||||
LIBS += -L/usr/lib -lamqpcpp -L/usr/lib/x86_64-linux-gnu/ -levent -lpthread -ldl
|
||||
|
||||
SOURCES += \
|
||||
clientRBcpp/client.cpp \
|
||||
clientRBcpp/clientrbcpp.cpp \
|
||||
clientRBcpp/cworker.cpp \
|
||||
clientRBcpp/headers.cpp \
|
||||
clientRBcpp/producemessage.cpp \
|
||||
clientRBcpp/properties.cpp \
|
||||
clientRBcpp/pworker.cpp \
|
||||
clientRBcpp/receiver.cpp \
|
||||
clientRBcpp/sender.cpp \
|
||||
clientRBcpp/validator.cpp \
|
||||
clientRBcpp/vworker.cpp \
|
||||
main.cpp \
|
||||
mainwindow.cpp
|
||||
|
||||
HEADERS += \
|
||||
clientRBcpp/_client_.h \
|
||||
clientRBcpp/client_cpp.h \
|
||||
clientRBcpp/clientrbcpp.h \
|
||||
clientRBcpp/clientrbcpp_global.h \
|
||||
clientRBcpp/cworker.h \
|
||||
clientRBcpp/headers.h \
|
||||
clientRBcpp/options/clientoption.h \
|
||||
clientRBcpp/options/consumeoption.h \
|
||||
clientRBcpp/options/exchangeoption.h \
|
||||
clientRBcpp/options/queueoption.h \
|
||||
clientRBcpp/producemessage.h \
|
||||
clientRBcpp/properties.h \
|
||||
clientRBcpp/pworker.h \
|
||||
clientRBcpp/receiver.h \
|
||||
clientRBcpp/sender.h \
|
||||
clientRBcpp/validator.h \
|
||||
clientRBcpp/vworker.h \
|
||||
mainwindow.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui
|
@ -1,338 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.12.3, 2023-12-23T19:03:36. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{77607214-f3f8-45c8-bf65-1a310ea854a8}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="int">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
|
||||
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
|
||||
<value type="QString" key="ClangCodeModel.WarningConfigId">Builtin.Questionable</value>
|
||||
<valuemap type="QVariantMap" key="ClangTools">
|
||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||
<value type="int" key="ClangTools.ParallelJobs">0</value>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{fa463890-d98c-43fb-aee8-64b3da65bdfc}</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="bool">true</value>
|
||||
<value type="int" key="EnableQmlDebugging">0</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/build-consumer_slow-Desktop-Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/build-consumer_slow-Desktop-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Отладка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
|
||||
<value type="int" key="QtQuickCompiler">2</value>
|
||||
<value type="int" key="SeparateDebugInfo">2</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
|
||||
<value type="bool">true</value>
|
||||
<value type="int" key="EnableQmlDebugging">2</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/build-consumer_slow-Desktop-Release</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/build-consumer_slow-Desktop-Release</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Выпуск</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
|
||||
<value type="int" key="QtQuickCompiler">0</value>
|
||||
<value type="int" key="SeparateDebugInfo">2</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
|
||||
<value type="bool">true</value>
|
||||
<value type="int" key="EnableQmlDebugging">0</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/build-consumer_slow-Desktop-Profile</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/build-consumer_slow-Desktop-Profile</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Профилирование</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
|
||||
<value type="int" key="QtQuickCompiler">0</value>
|
||||
<value type="int" key="SeparateDebugInfo">0</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Perf.Events">
|
||||
<value type="QString">cpu-cycles</value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/>
|
||||
<value type="int" key="Analyzer.Perf.Frequency">250</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Perf.RecordArguments">
|
||||
<value type="QString">-e</value>
|
||||
<value type="QString">cpu-cycles</value>
|
||||
<value type="QString">--call-graph</value>
|
||||
<value type="QString">dwarf,4096</value>
|
||||
<value type="QString">-F</value>
|
||||
<value type="QString">250</value>
|
||||
</valuelist>
|
||||
<value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Perf.StackSize">4096</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
|
||||
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
|
||||
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value>
|
||||
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
|
||||
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
|
||||
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
|
||||
<value type="int">0</value>
|
||||
<value type="int">1</value>
|
||||
<value type="int">2</value>
|
||||
<value type="int">3</value>
|
||||
<value type="int">4</value>
|
||||
<value type="int">5</value>
|
||||
<value type="int">6</value>
|
||||
<value type="int">7</value>
|
||||
<value type="int">8</value>
|
||||
<value type="int">9</value>
|
||||
<value type="int">10</value>
|
||||
<value type="int">11</value>
|
||||
<value type="int">12</value>
|
||||
<value type="int">13</value>
|
||||
<value type="int">14</value>
|
||||
</valuelist>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/consumer_slow/consumer_slow.pro</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/consumer_slow/consumer_slow.pro</value>
|
||||
<value type="QString" key="RunConfiguration.Arguments"></value>
|
||||
<value type="bool" key="RunConfiguration.Arguments.multi">false</value>
|
||||
<value type="QString" key="RunConfiguration.OverrideDebuggerStartup"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory"></value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/user/work/DAS_2023_1/alexandrov_dmitrii_lab_4/build-consumer_slow-Desktop-Debug</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="int">1</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>Version</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
</qtcreator>
|
@ -1,11 +0,0 @@
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
#include <QUuid>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ClientOption clOpt;
|
||||
|
||||
ConsumeOption conOpt;
|
||||
conOpt.exchange = "publisher";
|
||||
conOpt.bindingKeys << "all";
|
||||
conOpt.queueOption.name = "queue_slow";
|
||||
conOpt.queueOption.auto_delete = true;
|
||||
|
||||
receiver = new Receiver(clOpt, conOpt);
|
||||
QObject::connect(receiver, &Receiver::onMessage, this, [&](ProduceMessage msg, uint64_t consumeTag) {
|
||||
Q_UNUSED(consumeTag)
|
||||
|
||||
QString msg_body = "got " + QString::fromLocal8Bit(msg.getBodyMsg());
|
||||
ui->listWidget->addItem(msg_body);
|
||||
});
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include "clientRBcpp/client_cpp.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class MainWindow; }
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
Receiver *receiver;
|
||||
int counter;
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
@ -1,37 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QListWidget" name="listWidget"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
Binary file not shown.
@ -1,53 +0,0 @@
|
||||
#ifndef _CLIENT_H
|
||||
#define _CLIENT_H
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
#include "options/clientoption.h"
|
||||
#include "options/consumeoption.h"
|
||||
#include "options/exchangeoption.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define HEARBEATS "@@__Control__@@"
|
||||
|
||||
class Sender;
|
||||
class Receiver;
|
||||
|
||||
class Client : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
|
||||
QList<Sender *> *_senders;
|
||||
QList<Receiver *> *_receivers;
|
||||
|
||||
public:
|
||||
Client();
|
||||
Client(ClientOption option);
|
||||
virtual ~Client();
|
||||
|
||||
Client& operator=(Client client);
|
||||
QString getVersion() const;
|
||||
|
||||
ClientOption getClientOption() const { return clientOption; }
|
||||
|
||||
Sender *createSender(ExchangeOption& option);
|
||||
void removeSender(Sender *sender);
|
||||
|
||||
Receiver *createReceiver(ConsumeOption& option);
|
||||
void removeReceiver(Receiver *receiver);
|
||||
|
||||
signals:
|
||||
void onStop();
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(string)
|
||||
|
||||
#endif // _CLIENT_H
|
@ -1,124 +0,0 @@
|
||||
|
||||
#include "_client_.h"
|
||||
#include "sender.h"
|
||||
#include "receiver.h"
|
||||
|
||||
|
||||
// Конструктор для связи с локальным RabbitMQ
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Client::Client() : QObject(nullptr)
|
||||
{
|
||||
{
|
||||
static const int idMsg = qRegisterMetaType<ProduceMessage>();
|
||||
static const int idMsgPtr = qRegisterMetaType<PtrProduceMessage>();
|
||||
static const int idString = qRegisterMetaType<string>();
|
||||
|
||||
Q_UNUSED(idMsg)
|
||||
Q_UNUSED(idMsgPtr)
|
||||
Q_UNUSED(idString)
|
||||
}
|
||||
|
||||
_senders = new QList<Sender *>();
|
||||
_senders->clear();
|
||||
|
||||
_receivers = new QList<Receiver *>();
|
||||
_receivers->clear();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Client::Client(ClientOption option) : Client()
|
||||
{
|
||||
clientOption = option;
|
||||
}
|
||||
|
||||
|
||||
Client::~Client()
|
||||
{
|
||||
for (auto &sender : *_senders)
|
||||
delete sender;
|
||||
delete _senders;
|
||||
|
||||
for (auto &receiver : *_receivers)
|
||||
delete receiver;
|
||||
delete _receivers;
|
||||
}
|
||||
|
||||
|
||||
Client& Client::operator=(Client client)
|
||||
{
|
||||
if (this != &client) {
|
||||
this->clientOption = client.clientOption;
|
||||
|
||||
this->_senders = new QList<Sender *>();
|
||||
this->_senders->clear();
|
||||
|
||||
this->_receivers = new QList<Receiver *>();
|
||||
this->_receivers->clear();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
int majorVersion = 1;
|
||||
int minorVersion = 1;
|
||||
int releaseVersion = 1;
|
||||
|
||||
QString Client::getVersion() const
|
||||
{
|
||||
return QString::number(majorVersion) +
|
||||
"." + QString::number(minorVersion) +
|
||||
"." + QString::number(releaseVersion);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Создание публикатора (издателя) сообщений
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sender *Client::createSender(ExchangeOption& option)
|
||||
{
|
||||
Sender *sender = new Sender(clientOption, option);
|
||||
|
||||
connect(this, &Client::onStop, sender, &Sender::slotStop);
|
||||
connect(this, &Client::onStop, sender, &Sender::deleteLater);
|
||||
|
||||
_senders->append(sender);
|
||||
|
||||
return sender;
|
||||
}
|
||||
|
||||
void Client::removeSender(Sender *sender)
|
||||
{
|
||||
if ( !_senders->contains(sender))
|
||||
return;
|
||||
sender->slotStop();
|
||||
_senders->removeOne(sender);
|
||||
}
|
||||
|
||||
|
||||
// Создание потребителя сообщений
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Receiver *Client::createReceiver(ConsumeOption& option)
|
||||
{
|
||||
Receiver *receiver = new Receiver(clientOption, option);
|
||||
|
||||
connect(this, &Client::onStop, receiver, &Receiver::slotStop);
|
||||
connect(this, &Client::onStop, receiver, &Receiver::deleteLater);
|
||||
|
||||
_receivers->append(receiver);
|
||||
|
||||
return receiver;
|
||||
}
|
||||
|
||||
void Client::removeReceiver(Receiver *receiver)
|
||||
{
|
||||
if ( !_receivers->contains(receiver))
|
||||
return;
|
||||
receiver->slotStop();
|
||||
_receivers->removeOne(receiver);
|
||||
}
|
||||
|
||||
|
@ -1,22 +0,0 @@
|
||||
#ifndef CLIENT_CPP_H
|
||||
#define CLIENT_CPP_H
|
||||
|
||||
#include "clientrbcpp_global.h"
|
||||
#include "clientrbcpp.h"
|
||||
#include "_client_.h"
|
||||
#include "producemessage.h"
|
||||
#include "properties.h"
|
||||
#include "cworker.h"
|
||||
#include "headers.h"
|
||||
#include "pworker.h"
|
||||
#include "receiver.h"
|
||||
#include "sender.h"
|
||||
#include "validator.h"
|
||||
#include "vworker.h"
|
||||
|
||||
#include "options/clientoption.h"
|
||||
#include "options/consumeoption.h"
|
||||
#include "options/exchangeoption.h"
|
||||
#include "options/queueoption.h"
|
||||
|
||||
#endif // CLIENT_CPP_H
|
@ -1,6 +0,0 @@
|
||||
#include "clientrbcpp.h"
|
||||
|
||||
|
||||
ClientRBcpp::ClientRBcpp()
|
||||
{
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
#ifndef CLIENTRBCPP_H
|
||||
#define CLIENTRBCPP_H
|
||||
|
||||
#include "clientrbcpp_global.h"
|
||||
|
||||
class CLIENTRBCPPSHARED_EXPORT ClientRBcpp
|
||||
{
|
||||
|
||||
public:
|
||||
ClientRBcpp();
|
||||
};
|
||||
|
||||
#endif // CLIENTRBCPP_H
|
@ -1,12 +0,0 @@
|
||||
#ifndef CLIENTRBCPP_GLOBAL_H
|
||||
#define CLIENTRBCPP_GLOBAL_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#if defined(CLIENTRBCPP_LIBRARY)
|
||||
# define CLIENTRBCPPSHARED_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define CLIENTRBCPPSHARED_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif // CLIENTRBCPP_GLOBAL_H
|
@ -1,276 +0,0 @@
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
CWorker::CWorker(ClientOption& clientOption, ConsumeOption& consumeOption)
|
||||
: QObject(nullptr), markStop(false)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->consumeOption = consumeOption;
|
||||
this->consumeOption.receivingExchange = consumeOption.receivingExchange;
|
||||
|
||||
connection = nullptr;
|
||||
channel = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CWorker::~CWorker()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Здесь реализуется основная деятельность потока
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void CWorker::doWork()
|
||||
{
|
||||
|
||||
string host = clientOption.host.toStdString();
|
||||
string port = QString::number(clientOption.port).toStdString();
|
||||
string user = clientOption.user.toStdString();
|
||||
string password = clientOption.password.toStdString();
|
||||
string vhost = clientOption.vhost.toStdString();
|
||||
|
||||
string address = "amqp://" + user + ":" + password + "@" + host + ":" + port + vhost;
|
||||
|
||||
auto evbase = event_base_new();
|
||||
|
||||
AMQP::LibEventHandler handler(evbase);
|
||||
|
||||
// AMQP::TcpConnection connection(&handler, AMQP::Address(address));
|
||||
// AMQP::TcpChannel channel(&connection);
|
||||
|
||||
connection = new AMQP::TcpConnection(&handler, AMQP::Address(address));
|
||||
channel = new AMQP::TcpChannel(connection);
|
||||
|
||||
channel->setQos(1);
|
||||
|
||||
channel->onError([&](const char *message) {
|
||||
Q_UNUSED(message)
|
||||
emit onErrorConsume("Channel error!!!");
|
||||
});
|
||||
|
||||
QTimer tm;
|
||||
tm.stop();
|
||||
tm.setInterval(30000);
|
||||
connect(&tm, &QTimer::timeout, this, [&]() {
|
||||
tm.stop();
|
||||
connection->heartbeat();
|
||||
tm.start();
|
||||
});
|
||||
tm.start();
|
||||
|
||||
// Обработка принятого сообщения
|
||||
auto messageCb = [&](const AMQP::Message& message, uint64_t deliveryTag, bool redelivered)
|
||||
{
|
||||
Q_UNUSED(redelivered)
|
||||
|
||||
// Формируем принятое сообщениев формате ReceivedMessage
|
||||
ProduceMessage *rMsg = new ProduceMessage;
|
||||
rMsg->setBodyMsg(message.body(), message.bodySize());
|
||||
|
||||
// Формируем таблицу Properties свойств сообщения
|
||||
Properties p;
|
||||
if (message.hasContentType())
|
||||
p.setContentType(QString::fromStdString(message.contentType()));
|
||||
if (message.hasContentEncoding())
|
||||
p.setContentEncoding(QString::fromStdString(message.contentEncoding()));
|
||||
if (message.hasMessageID())
|
||||
p.setMessageID(QString::fromStdString(message.messageID()));
|
||||
if (message.hasCorrelationID())
|
||||
p.setCorrelationID(QString::fromStdString(message.correlationID()));
|
||||
if (message.timestamp())
|
||||
p.setTimestamp(message.timestamp());
|
||||
if (message.hasExpiration())
|
||||
p.setExpiration(QString::fromStdString(message.expiration()));
|
||||
if (message.hasDeliveryMode())
|
||||
p.setDeliveryMode(message.deliveryMode());
|
||||
if (message.hasAppID())
|
||||
p.setAppID(QString::fromStdString(message.appID()));
|
||||
if (message.hasUserID())
|
||||
p.setUserID(QString::fromStdString(message.userID()));
|
||||
if (message.hasTypeName())
|
||||
p.setTypeName(QString::fromStdString(message.typeName()));
|
||||
if (message.hasReplyTo())
|
||||
p.setReplyTo(QString::fromStdString(message.replyTo()));
|
||||
if (message.hasPriority())
|
||||
p.setPriority(message.priority());
|
||||
|
||||
rMsg->setProperties(p);
|
||||
|
||||
// Работа со свойствами Headers
|
||||
Headers h;
|
||||
AMQP::Table table = message.headers();
|
||||
vector<string> keys = table.keys();
|
||||
|
||||
string name;
|
||||
for(uint i = 0; i < keys.size(); i++) {
|
||||
name = keys[i];
|
||||
if (table.get(name).isInteger()) {
|
||||
int value = table.get(name);
|
||||
h.set(QString::fromStdString(name), value);
|
||||
}
|
||||
else if (table.get(name).isString()) {
|
||||
QString str = QString::fromStdString(table.get(name));
|
||||
h.set(QString::fromStdString(name), str);
|
||||
}
|
||||
else if (table.get(name).isBoolean()) {
|
||||
AMQP::Field &b = const_cast<AMQP::Field &>(table.get(name));
|
||||
AMQP::BooleanSet &b1 = dynamic_cast<AMQP::BooleanSet &>(b);
|
||||
bool value = b1.get(0);
|
||||
h.set(QString::fromStdString(name), value);
|
||||
}
|
||||
}
|
||||
|
||||
rMsg->setHeaders(h);
|
||||
emit onResultReady(rMsg, deliveryTag);
|
||||
|
||||
channel->ack(deliveryTag);
|
||||
};
|
||||
|
||||
// объявление точки обмена
|
||||
|
||||
if (!consumeOption.receivingExchange.name.isEmpty()) {
|
||||
string exchange = consumeOption.receivingExchange.name.toStdString();
|
||||
string type = consumeOption.receivingExchange.type.toStdString();
|
||||
|
||||
// преобразование типа точки обмена в формат AMQP
|
||||
AMQP::ExchangeType typeEx;
|
||||
if (type == "" || type == "direct")
|
||||
typeEx = AMQP::direct;
|
||||
else if (type == "topic")
|
||||
typeEx = AMQP::topic;
|
||||
else if (type == "headers")
|
||||
typeEx = AMQP::headers;
|
||||
else
|
||||
typeEx = AMQP::fanout;
|
||||
|
||||
// предобразование флагов точки обмена в формат AMQP
|
||||
int flagsExchange = 0;
|
||||
if (consumeOption.receivingExchange.durable)
|
||||
flagsExchange |= AMQP::durable;
|
||||
if (consumeOption.receivingExchange.auto_delete)
|
||||
flagsExchange |= AMQP::autodelete;
|
||||
if (consumeOption.receivingExchange.internal)
|
||||
flagsExchange |= AMQP::internal;
|
||||
|
||||
AMQP::Table tableExch;
|
||||
QString alt_e_name = "alternate-exchange";
|
||||
QString alt_e_value = "";
|
||||
if (consumeOption.receivingExchange.arguments.contains(alt_e_name)) {
|
||||
alt_e_value = consumeOption.receivingExchange.arguments[alt_e_name].value<QString>();
|
||||
tableExch.set(alt_e_name.toStdString(), alt_e_value.toStdString());
|
||||
}
|
||||
|
||||
// Для предопределенных точек обмена их обьявление не производим
|
||||
if ( exchange != "" && exchange != "amq.fanout" && exchange != "amq.direct" &&
|
||||
exchange != "amq.topic" && exchange != "amq.headers") {
|
||||
channel->declareExchange(exchange, typeEx, flagsExchange, tableExch)
|
||||
.onError([&](const char *description) {
|
||||
qDebug() << description;
|
||||
});
|
||||
}
|
||||
|
||||
QMultiMap<QString, QString>::iterator it = consumeOption.bindingArgs.begin();
|
||||
for(; it != consumeOption.bindingArgs.end(); ++it) {
|
||||
channel->bindExchange(it.key().toStdString(), exchange, it.value().toStdString()).onError([&](const char *description) {
|
||||
qDebug() << description;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// объявление очереди
|
||||
|
||||
QueueOption option = consumeOption.queueOption;
|
||||
|
||||
string exchange = consumeOption.exchange.toStdString();
|
||||
string queue = option.name.toStdString();
|
||||
|
||||
// Подготовка флагов для объявления очереди
|
||||
int flagsQueue = 0;
|
||||
if (option.durable)
|
||||
flagsQueue |= AMQP::durable;
|
||||
if (option.auto_delete)
|
||||
flagsQueue |= AMQP::autodelete;
|
||||
if (option.exclusive)
|
||||
flagsQueue |= AMQP::exclusive;
|
||||
|
||||
channel->declareQueue(queue, flagsQueue)
|
||||
.onSuccess( [&](const string &name, uint32_t messageCount, uint32_t consumerCount) {
|
||||
Q_UNUSED(messageCount)
|
||||
Q_UNUSED(consumerCount)
|
||||
queue = name;
|
||||
if (exchange != "")
|
||||
for (QString rk : consumeOption.bindingKeys) {
|
||||
channel->bindQueue(exchange, queue, rk.toStdString())
|
||||
.onError( [&](const char *description) {
|
||||
qDebug() << description;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Подготовка флагов потребления сообщений
|
||||
int flagsConsume = 0;
|
||||
if (consumeOption.nolocal)
|
||||
flagsConsume |= AMQP::nolocal;
|
||||
if (consumeOption.noack)
|
||||
flagsConsume |= AMQP::noack;
|
||||
if (consumeOption.exclusive)
|
||||
flagsConsume |= AMQP::exclusive;
|
||||
|
||||
|
||||
channel->consume(queue, flagsConsume).onReceived(messageCb)
|
||||
.onSuccess( [&](const string& tag) {
|
||||
nextTag = tag;
|
||||
})
|
||||
.onError( [&](const char *description) {
|
||||
emit onErrorConsume(description);
|
||||
markStop = true; // Останов потока
|
||||
});
|
||||
|
||||
//Цикл обработки событий
|
||||
while(!markStop) {
|
||||
|
||||
event_base_loop(evbase, EVLOOP_ONCE);
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
// Закроем канал и соединение
|
||||
channel->close();
|
||||
connection->close();
|
||||
|
||||
event_base_loopbreak(evbase);
|
||||
event_base_loopexit(evbase, 0);
|
||||
event_base_free(evbase);
|
||||
|
||||
delete channel;
|
||||
delete connection;
|
||||
|
||||
emit onWorkFinished(); // Посылаем сигнал о завершении работы
|
||||
}
|
||||
|
||||
|
||||
void CWorker::slotStop()
|
||||
{
|
||||
markStop = true;
|
||||
channel->cancel(nextTag); // Отменить потребление
|
||||
|
||||
channel->close();
|
||||
connection->close();
|
||||
|
||||
}
|
||||
|
||||
void CWorker::bind(QString exchange, QString key, bool ex)
|
||||
{
|
||||
if (ex) channel->bindExchange(exchange.toStdString(), consumeOption.exchange.toStdString(), key.toStdString());
|
||||
else channel->bindQueue(exchange.toStdString(), consumeOption.queueOption.name.toStdString(), key.toStdString());
|
||||
}
|
||||
|
||||
void CWorker::unbind(QString exchange, QString key, bool ex)
|
||||
{
|
||||
if (ex) channel->unbindExchange(exchange.toStdString(), consumeOption.exchange.toStdString(), key.toStdString());
|
||||
else channel->unbindQueue(exchange.toStdString(), consumeOption.queueOption.name.toStdString(), key.toStdString());
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
#ifndef CWORKER_H
|
||||
#define CWORKER_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <amqpcpp.h>
|
||||
#include <amqpcpp/libevent.h>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class CWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
ConsumeOption consumeOption;
|
||||
|
||||
bool markStop;
|
||||
|
||||
AMQP::TcpConnection *connection;
|
||||
AMQP::TcpChannel *channel;
|
||||
|
||||
string nextTag;
|
||||
|
||||
public:
|
||||
CWorker(ClientOption& clientOption, ConsumeOption& consumeOption);
|
||||
virtual ~CWorker();
|
||||
|
||||
public slots:
|
||||
void doWork();
|
||||
void slotStop();
|
||||
void bind(QString exchange, QString key, bool ex);
|
||||
void unbind(QString exchange, QString key, bool ex);
|
||||
|
||||
signals:
|
||||
void onResultReady(PtrProduceMessage msg, uint64_t deliveryTag);
|
||||
void onErrorConsume(const char *description);
|
||||
void onWorkFinished();
|
||||
};
|
||||
|
||||
|
||||
#endif // CWORKER_H
|
@ -1,40 +0,0 @@
|
||||
#include "headers.h"
|
||||
|
||||
Headers::Headers()
|
||||
{
|
||||
_headers.clear();
|
||||
}
|
||||
|
||||
Headers::Headers(const Headers& h)
|
||||
{
|
||||
this->_headers = h._headers;
|
||||
}
|
||||
|
||||
void Headers::operator=(const Headers& h)
|
||||
{
|
||||
this->_headers = h._headers;
|
||||
}
|
||||
|
||||
|
||||
QMap<QString,QVariant> Headers::getHeaders() const { return _headers; }
|
||||
|
||||
QList<QString> Headers::keys() const { return _headers.keys(); }
|
||||
QList<QVariant> Headers::values() const { return _headers.values(); }
|
||||
|
||||
int Headers::size() const { return _headers.size(); }
|
||||
|
||||
bool Headers::contains(const QString name) const { return _headers.contains(name); }
|
||||
|
||||
|
||||
void Headers::set(const QString name, bool value) { _headers.insert(name, value); }
|
||||
void Headers::set(const QString name, int value) { _headers.insert(name, value); }
|
||||
void Headers::set(const QString name, QString str) { _headers.insert(name, str); }
|
||||
|
||||
bool Headers::isBool(const QString name) const { return _headers[name].type() == QVariant::Bool; }
|
||||
bool Headers::isInteger(const QString name) const { return _headers[name].type() == QVariant::Int; }
|
||||
bool Headers::isString(const QString name) const { return _headers[name].type() == QVariant::String; }
|
||||
|
||||
bool Headers::getBool(const QString name) const { return _headers[name].value<bool>(); }
|
||||
int Headers::getInteger(const QString name) const { return _headers[name].value<int>(); }
|
||||
QString Headers::getString(const QString name) const { return _headers[name].value<QString>(); }
|
||||
|
@ -1,45 +0,0 @@
|
||||
#ifndef HEADERS_H
|
||||
#define HEADERS_H
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
class Headers
|
||||
{
|
||||
private:
|
||||
QMap<QString,QVariant> _headers;
|
||||
|
||||
public:
|
||||
Headers();
|
||||
Headers(const Headers& h); // Конструктор копирования
|
||||
~Headers() {}
|
||||
|
||||
void operator=(const Headers& h);
|
||||
|
||||
QMap<QString,QVariant> getHeaders() const;
|
||||
|
||||
QList<QString> keys() const;
|
||||
QList<QVariant> values() const;
|
||||
|
||||
int size() const;
|
||||
|
||||
bool contains(const QString name) const;
|
||||
|
||||
void set(const QString name, bool value);
|
||||
void set(const QString name, int value);
|
||||
void set(const QString name, QString str);
|
||||
|
||||
bool isBool(const QString name) const;
|
||||
bool isInteger(const QString name) const;
|
||||
bool isString(const QString name) const;
|
||||
|
||||
bool getBool(const QString name) const;
|
||||
int getInteger(const QString name) const;
|
||||
QString getString(const QString name) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // HEADERS_H
|
@ -1,45 +0,0 @@
|
||||
#ifndef CLIENTOPTION_H
|
||||
#define CLIENTOPTION_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
// Значения по умолчанию
|
||||
const QString DEFAULT_CPP_HOST = "localhost";
|
||||
const int DEFAULT_CPP_PORT = 5672;
|
||||
const QString DEFAULT_CPP_USER = "guest";
|
||||
const QString DEFAULT_CPP_PASSWORD = "guest";
|
||||
const QString DEFAULT_CPP_VHOST = "/";
|
||||
|
||||
|
||||
struct ClientOption {
|
||||
QString host;
|
||||
int port;
|
||||
QString user;
|
||||
QString password;
|
||||
QString vhost;
|
||||
|
||||
ClientOption() {
|
||||
host = DEFAULT_CPP_HOST;
|
||||
port = DEFAULT_CPP_PORT;
|
||||
user = DEFAULT_CPP_USER;
|
||||
password = DEFAULT_CPP_PASSWORD;
|
||||
vhost = DEFAULT_CPP_VHOST;
|
||||
}
|
||||
|
||||
~ClientOption() {}
|
||||
|
||||
ClientOption(const ClientOption& src) = default; // Конструктор копирования
|
||||
ClientOption(ClientOption&& src) = default; // Конструктор перемещения
|
||||
|
||||
ClientOption& operator=(const ClientOption rhs) // Оператор присваивания
|
||||
{
|
||||
host = rhs.host;
|
||||
port = rhs.port;
|
||||
user = rhs.user;
|
||||
password = rhs.password;
|
||||
vhost = rhs.vhost;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CLIENTOPTION_H
|
@ -1,52 +0,0 @@
|
||||
#ifndef CONSUMEOPTION_H
|
||||
#define CONSUMEOPTION_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
|
||||
#include "queueoption.h"
|
||||
#include "exchangeoption.h"
|
||||
|
||||
struct ConsumeOption
|
||||
{
|
||||
QString exchange; // Имя точки обмена для связывания
|
||||
QStringList bindingKeys; // ключи связи точки с очередью
|
||||
|
||||
bool nolocal;
|
||||
bool noack;
|
||||
bool exclusive;
|
||||
|
||||
QueueOption queueOption; // Параметры очереди
|
||||
ExchangeOption receivingExchange; // Параметры новой принимающей очереди (по умолчанию новой не создаётся)
|
||||
QMultiMap<QString, QString> bindingArgs; // список связей для точки обмена (если создаётся новая точка)
|
||||
|
||||
ConsumeOption() {
|
||||
exchange = "";
|
||||
receivingExchange.name = "";
|
||||
|
||||
nolocal = false;
|
||||
noack = false;
|
||||
exclusive = false;
|
||||
}
|
||||
|
||||
~ConsumeOption() {}
|
||||
|
||||
ConsumeOption(const ConsumeOption& src) = default; // Конструктор копирования
|
||||
ConsumeOption(ConsumeOption&& src) = default; // Конструктор перемещения
|
||||
|
||||
ConsumeOption& operator=(const ConsumeOption rhs) // Оператор присваивания
|
||||
{
|
||||
exchange = rhs.exchange;
|
||||
bindingKeys = rhs.bindingKeys;
|
||||
nolocal = rhs.nolocal;
|
||||
noack = rhs.noack;
|
||||
exclusive = rhs.exclusive;
|
||||
queueOption = rhs.queueOption;
|
||||
bindingArgs = rhs.bindingArgs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // CONSUMEOPTION_H
|
@ -1,55 +0,0 @@
|
||||
#ifndef EXCHANGEOPTION_H
|
||||
#define EXCHANGEOPTION_H
|
||||
|
||||
#include <QString>
|
||||
#include <QVariantMap>
|
||||
#include <QList>
|
||||
|
||||
struct ExchangeOption
|
||||
{
|
||||
QString name; // уникальное имя точки обмена
|
||||
QString type; // тип точки обмена (direct, topic,
|
||||
// fanout или headers)
|
||||
bool auto_delete; // автоматически удаляемая точка обмена
|
||||
bool durable; // долгоживущая точка обмена
|
||||
bool passive; // требуется информация о точке обмена
|
||||
bool internal; // нельзя вести публикацию из приложения
|
||||
|
||||
QVariantMap arguments; // необязательные аргументы
|
||||
QMap<QString, QString> bindingArgs; // список связей для точки обмена
|
||||
|
||||
bool ifunused; // можно удалять, только если точка обмена
|
||||
// не используется (не имеет потребителей)
|
||||
ExchangeOption() {
|
||||
name = "";
|
||||
type = "";
|
||||
auto_delete = false;
|
||||
durable = false;
|
||||
passive = false;
|
||||
internal = false;
|
||||
arguments.clear();
|
||||
|
||||
ifunused = false;
|
||||
}
|
||||
|
||||
~ExchangeOption() {}
|
||||
|
||||
ExchangeOption(const ExchangeOption& src) = default; // Конструктор копирования
|
||||
ExchangeOption(ExchangeOption&& src) = default; // Конструктор перемещения
|
||||
|
||||
ExchangeOption& operator=(const ExchangeOption rhs) // Оператор присваивания
|
||||
{
|
||||
name = rhs.name;
|
||||
type = rhs.type;
|
||||
auto_delete = rhs.auto_delete;
|
||||
durable = rhs.durable;
|
||||
passive = rhs.passive;
|
||||
internal = rhs.internal;
|
||||
arguments = rhs.arguments;
|
||||
|
||||
ifunused = rhs.ifunused;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EXCHANGEOPTION_H
|
@ -1,63 +0,0 @@
|
||||
#ifndef QUEUEOPTION_H
|
||||
#define QUEUEOPTION_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariantMap>
|
||||
|
||||
struct QueueOption
|
||||
{
|
||||
QString name; // Уникальное имя очереди
|
||||
|
||||
bool auto_delete; // Автоматически удаляемая очередь
|
||||
bool durable; // Долгоживущая очередь
|
||||
bool passive; // Требуется информация об очереди
|
||||
bool exclusive; // Исключительная очередь
|
||||
|
||||
QVariantMap arguments; // Необязательные аргументы очереди
|
||||
|
||||
bool ifunused; // Удалять, только если не используется
|
||||
bool ifempty; // Удалять, только если очередь пуста
|
||||
|
||||
int messageCount; // Число сообщений в очереди
|
||||
int consumerCount; // Число потребителей очереди
|
||||
|
||||
QueueOption() {
|
||||
name = "";
|
||||
|
||||
auto_delete = false;
|
||||
durable = false;
|
||||
passive = false;
|
||||
exclusive = false;
|
||||
|
||||
arguments.clear();
|
||||
|
||||
ifunused = false;
|
||||
ifempty = false;
|
||||
|
||||
messageCount = 0;
|
||||
consumerCount = 0;
|
||||
}
|
||||
|
||||
~QueueOption() {}
|
||||
|
||||
QueueOption(const QueueOption& src) = default; // Конструктор копирования
|
||||
QueueOption(QueueOption&& src) = default; // Конструктор перемещения
|
||||
|
||||
QueueOption& operator=(const QueueOption rhs) // Оператор присваивания
|
||||
{
|
||||
name = rhs.name;
|
||||
auto_delete = rhs.auto_delete;
|
||||
passive = rhs.passive;
|
||||
exclusive = rhs.exclusive;
|
||||
arguments = rhs.arguments;
|
||||
|
||||
ifunused = rhs.ifunused;
|
||||
ifempty = rhs.ifempty;
|
||||
messageCount = rhs.messageCount;
|
||||
consumerCount = rhs.consumerCount;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // QUEUEOPTION_H
|
@ -1,37 +0,0 @@
|
||||
#include "producemessage.h"
|
||||
|
||||
// Конструктор по умолчанию
|
||||
ProduceMessage::ProduceMessage()
|
||||
{
|
||||
_body.clear();
|
||||
}
|
||||
|
||||
// Конструктор копирования
|
||||
ProduceMessage::ProduceMessage(const ProduceMessage& msg)
|
||||
{
|
||||
this->_body = msg._body;
|
||||
this->_headers = msg._headers;
|
||||
this->_properties = msg._properties;
|
||||
}
|
||||
|
||||
ProduceMessage& ProduceMessage::operator=(const ProduceMessage& msg)
|
||||
{
|
||||
if (this != &msg) {
|
||||
this->_body = msg._body;
|
||||
this->_headers = msg._headers;
|
||||
this->_properties = msg._properties;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
QByteArray ProduceMessage::getBodyMsg() const { return _body; }
|
||||
void ProduceMessage::setBodyMsg(const QByteArray &ba) { _body = ba; }
|
||||
void ProduceMessage::setBodyMsg(const char *body, int size) { _body = QByteArray(body, size); }
|
||||
|
||||
Headers ProduceMessage::getHeaders() const { return _headers; }
|
||||
void ProduceMessage::setHeaders(const Headers &headers) { _headers = headers; }
|
||||
|
||||
Properties ProduceMessage::getProperties() const { return _properties; }
|
||||
void ProduceMessage::setProperties(const Properties &properties) { _properties = properties; }
|
||||
|
||||
|
@ -1,43 +0,0 @@
|
||||
#ifndef PRODUCEMESSAGE_H
|
||||
#define PRODUCEMESSAGE_H
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
#include "properties.h"
|
||||
#include "headers.h"
|
||||
|
||||
|
||||
class ProduceMessage
|
||||
{
|
||||
public:
|
||||
ProduceMessage();
|
||||
ProduceMessage(const ProduceMessage& msg);
|
||||
~ProduceMessage() {}
|
||||
|
||||
ProduceMessage& operator=(const ProduceMessage& msg);
|
||||
|
||||
QByteArray getBodyMsg() const;
|
||||
void setBodyMsg(const QByteArray &ba);
|
||||
void setBodyMsg(const char *body, int size);
|
||||
|
||||
Headers getHeaders() const;
|
||||
void setHeaders(const Headers &headers);
|
||||
|
||||
Properties getProperties() const;
|
||||
void setProperties(const Properties &properties);
|
||||
|
||||
private:
|
||||
QByteArray _body;
|
||||
|
||||
protected:
|
||||
Properties _properties;
|
||||
Headers _headers;
|
||||
};
|
||||
|
||||
|
||||
using PtrProduceMessage = ProduceMessage*;
|
||||
|
||||
Q_DECLARE_METATYPE(ProduceMessage)
|
||||
Q_DECLARE_METATYPE(PtrProduceMessage)
|
||||
|
||||
#endif // PRODUCEMESSAGE_H
|
@ -1,63 +0,0 @@
|
||||
#include "properties.h"
|
||||
|
||||
Properties::Properties()
|
||||
{
|
||||
_properties.clear();
|
||||
setDeliveryMode(1); // не оставлять сообщения
|
||||
}
|
||||
|
||||
// Конструктор копирования
|
||||
Properties::Properties(const Properties& p)
|
||||
{
|
||||
this->_properties = p._properties;
|
||||
}
|
||||
|
||||
|
||||
void Properties::operator=(const Properties& p)
|
||||
{
|
||||
this->_properties = p._properties;
|
||||
}
|
||||
|
||||
|
||||
const QMap<QString,QVariant> &Properties::getProperties() { return _properties; }
|
||||
|
||||
bool Properties::contains(const QString name) const { return _properties.contains(name); }
|
||||
|
||||
bool Properties::isContentType() const { return _properties.contains("content-type"); }
|
||||
bool Properties::isContentEncoding() const { return _properties.contains("content-encoding"); }
|
||||
bool Properties::isMessageID() const { return _properties.contains("message-id"); }
|
||||
bool Properties::isCorrelationID() const { return _properties.contains("correlation-id"); }
|
||||
bool Properties::isTimestamp() const { return _properties.contains("timestamp"); }
|
||||
bool Properties::isExpiration() const { return _properties.contains("expiration"); }
|
||||
bool Properties::isDeliveryMode() const { return _properties.contains("delivery-mode"); }
|
||||
bool Properties::isAppID() const { return _properties.contains("app-id"); }
|
||||
bool Properties::isUserID() const { return _properties.contains("user-id"); }
|
||||
bool Properties::isTypeName() const { return _properties.contains("type"); }
|
||||
bool Properties::isReplyTo() const { return _properties.contains("reply-to"); }
|
||||
bool Properties::isPriority() const { return _properties.contains("priority"); }
|
||||
|
||||
void Properties::setContentType(const QString &str) { _properties.insert("content-type", str); }
|
||||
void Properties::setContentEncoding(const QString &str) { _properties.insert("content-encoding", str); }
|
||||
void Properties::setMessageID(const QString &str) { _properties.insert("message-id", str); }
|
||||
void Properties::setCorrelationID(const QString &str) { _properties.insert("correlation-id", str); }
|
||||
void Properties::setTimestamp(const quint64 val) { _properties.insert("timestamp", val); }
|
||||
void Properties::setExpiration(const QString &str) { _properties.insert("expiration", str); }
|
||||
void Properties::setDeliveryMode(const quint8 val) { _properties.insert("delivery-mode", val); }
|
||||
void Properties::setAppID(const QString &str) { _properties.insert("app-id", str); }
|
||||
void Properties::setUserID(const QString &str) { _properties.insert("user-id", str); }
|
||||
void Properties::setTypeName(const QString &str) { _properties.insert("type", str); }
|
||||
void Properties::setReplyTo(const QString &str) { _properties.insert("reply-to", str); }
|
||||
void Properties::setPriority(const quint8 val) { _properties.insert("priority", val); }
|
||||
|
||||
QString Properties::getContentType() const { return _properties["content-type"].value<QString>(); }
|
||||
QString Properties::getContentEncoding() const { return _properties["content-encoding"].value<QString>(); }
|
||||
QString Properties::getMessageID() const { return _properties["message-id"].value<QString>(); }
|
||||
QString Properties::getCorrelationID() const { return _properties["correlation-id"].value<QString>(); }
|
||||
quint64 Properties::getTimestamp() const { return _properties["timestamp"].value<quint64>(); }
|
||||
QString Properties::getExpiration() const { return _properties["expiration"].value<QString>(); }
|
||||
quint8 Properties::getDeliveryMode() const { return _properties["delivery-mode"].value<quint8>(); }
|
||||
QString Properties::getAppID() const { return _properties["app-id"].value<QString>(); }
|
||||
QString Properties::getUserID() const { return _properties["user-id"].value<QString>(); }
|
||||
QString Properties::getTypeName() const { return _properties["type"].value<QString>(); }
|
||||
QString Properties::getReplyTo() const { return _properties["reply-to"].value<QString>(); }
|
||||
quint8 Properties::getPriority() const { return _properties["priority"].value<quint8>(); }
|
@ -1,73 +0,0 @@
|
||||
#ifndef PROPERTIES_H
|
||||
#define PROPERTIES_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
class Properties
|
||||
{
|
||||
private:
|
||||
QMap<QString,QVariant> _properties;
|
||||
|
||||
public:
|
||||
Properties();
|
||||
Properties(const Properties& p);
|
||||
~Properties() {}
|
||||
|
||||
void operator=(const Properties& p);
|
||||
|
||||
int size() {return _properties.size(); }
|
||||
|
||||
const QMap<QString,QVariant> &getProperties();
|
||||
|
||||
bool contains(const QString name) const;
|
||||
|
||||
bool isContentType() const;
|
||||
bool isContentEncoding() const;
|
||||
bool isMessageID() const;
|
||||
bool isCorrelationID() const;
|
||||
bool isTimestamp() const;
|
||||
bool isExpiration() const;
|
||||
bool isDeliveryMode() const;
|
||||
bool isAppID() const;
|
||||
bool isUserID() const;
|
||||
bool isTypeName() const;
|
||||
bool isReplyTo() const;
|
||||
bool isPriority() const;
|
||||
|
||||
void setContentType(const QString &str);
|
||||
void setContentEncoding(const QString &str);
|
||||
void setMessageID(const QString &str);
|
||||
void setCorrelationID(const QString &str);
|
||||
void setTimestamp(const quint64 val);
|
||||
void setExpiration(const QString &str);
|
||||
void setDeliveryMode(const quint8 val);
|
||||
void setAppID(const QString &str);
|
||||
void setUserID(const QString &str);
|
||||
void setTypeName(const QString &str);
|
||||
void setReplyTo(const QString &str);
|
||||
void setPriority(const quint8 val);
|
||||
|
||||
QString getContentType() const;
|
||||
QString getContentEncoding() const;
|
||||
QString getMessageID() const;
|
||||
QString getCorrelationID() const;
|
||||
quint64 getTimestamp() const;
|
||||
QString getExpiration() const;
|
||||
quint8 getDeliveryMode() const;
|
||||
QString getAppID() const;
|
||||
QString getUserID() const;
|
||||
QString getTypeName() const;
|
||||
QString getReplyTo() const;
|
||||
quint8 getPriority() const;
|
||||
};
|
||||
|
||||
#endif // PROPERTIES_H
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,330 +0,0 @@
|
||||
/**************************************************************************
|
||||
* PWorker - Publish Worker, - рабочий поток публикации сообщений *
|
||||
* редакция от 08.06.2022 *
|
||||
* Принадлежность: библиотека clientRBcpp *
|
||||
**************************************************************************/
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "_client_.h"
|
||||
#include "sender.h"
|
||||
#include "pworker.h"
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
PWorker::PWorker(ClientOption& clientOption, ExchangeOption& exchangeOption)
|
||||
: QObject(nullptr), markStop(false)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->exchangeOption = exchangeOption;
|
||||
|
||||
qu.clear();
|
||||
|
||||
// static const int idE2E = qRegisterMetaType<E2EStruct>();
|
||||
// Q_UNUSED(idE2E)
|
||||
|
||||
}
|
||||
|
||||
|
||||
PWorker::~PWorker()
|
||||
{
|
||||
// Освободим очередь сообщений
|
||||
mutex.lock();
|
||||
while (! qu.isEmpty()) {
|
||||
PublishPacket *packet = qu.dequeue();
|
||||
AMQP::Envelope *envelope = packet->envelope;
|
||||
delete envelope->body();
|
||||
delete envelope;
|
||||
delete packet;
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
// Здесь реализуется основная деятельность потока
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void PWorker::doWork()
|
||||
{
|
||||
string host = clientOption.host.toStdString();
|
||||
string port = QString::number(clientOption.port).toStdString();
|
||||
string user = clientOption.user.toStdString();
|
||||
string password = clientOption.password.toStdString();
|
||||
string vhost = clientOption.vhost.toStdString();
|
||||
|
||||
string address = "amqp://" + user + ":" + password + "@" + host + ":" + port + vhost;
|
||||
|
||||
// Обрабатываем аргументы на предмет альтернативной точки обмена
|
||||
AMQP::Table table;
|
||||
QString alt_e_name = "alternate-exchange";
|
||||
QString alt_e_value = "";
|
||||
if (exchangeOption.arguments.contains(alt_e_name)) {
|
||||
alt_e_value = exchangeOption.arguments[alt_e_name].value<QString>();
|
||||
table.set(alt_e_name.toStdString(), alt_e_value.toStdString());
|
||||
}
|
||||
|
||||
string alt_exchange = alt_e_value.toStdString(); // Имя альтернативной точки обмена
|
||||
AMQP::ExchangeType typeAltEx = AMQP::fanout; // Тип альтернативной точки обмена - всегда fanout
|
||||
int flagsAltEx = (AMQP::durable | AMQP::internal); // Точка долгоживущая и внутренняя
|
||||
|
||||
auto evbase = event_base_new();
|
||||
|
||||
AMQP::LibEventHandler handler(evbase);
|
||||
AMQP::TcpConnection connection(&handler, AMQP::Address(address));
|
||||
AMQP::TcpChannel channel(&connection);
|
||||
|
||||
channel.setQos(1);
|
||||
|
||||
channel.confirmSelect()
|
||||
.onAck([&](uint64_t deliveryTag, bool multiple) {
|
||||
emit onReceivedAckNack(deliveryTag, true, multiple);
|
||||
})
|
||||
.onNack([&](uint64_t deliveryTag, bool multiple, bool requeue) {
|
||||
Q_UNUSED(requeue)
|
||||
emit onReceivedAckNack(deliveryTag, false, multiple);
|
||||
});
|
||||
|
||||
// Объявляем альтернативную точку обмена
|
||||
//--------------------------------------
|
||||
if (alt_e_value != "") {
|
||||
channel.declareExchange(alt_exchange, typeAltEx, flagsAltEx)
|
||||
.onError( [&](const char *message) {
|
||||
string msg(message);
|
||||
emit onError(msg);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Обработка основной точки обмена
|
||||
//----------------------------------
|
||||
string exchange = exchangeOption.name.toStdString();
|
||||
string type = exchangeOption.type.toStdString();
|
||||
|
||||
// преобразование типа точки обмена в формат AMQP
|
||||
AMQP::ExchangeType typeEx;
|
||||
if (type == "" || type == "direct")
|
||||
typeEx = AMQP::direct;
|
||||
else if (type == "topic")
|
||||
typeEx = AMQP::topic;
|
||||
else if (type == "headers")
|
||||
typeEx = AMQP::headers;
|
||||
else
|
||||
typeEx = AMQP::fanout;
|
||||
|
||||
// предобразование флагов точки обмена в формат AMQP
|
||||
int flagsExchange = 0;
|
||||
if (exchangeOption.durable)
|
||||
flagsExchange |= AMQP::durable;
|
||||
if (exchangeOption.auto_delete)
|
||||
flagsExchange |= AMQP::autodelete;
|
||||
if (exchangeOption.internal)
|
||||
flagsExchange |= AMQP::internal;
|
||||
|
||||
// Для предопределенных точек обмена их обьявление не производим
|
||||
if ( exchange != "" && exchange != "amq.fanout" && exchange != "amq.direct" &&
|
||||
exchange != "amq.topic" && exchange != "amq.headers") {
|
||||
channel.declareExchange(exchange, typeEx, flagsExchange, table)
|
||||
.onError( [&](const char *message) {
|
||||
string msg(message);
|
||||
emit onError(msg);
|
||||
});
|
||||
}
|
||||
|
||||
// обработка mandatory
|
||||
|
||||
auto messageCb = [&](const AMQP::Message& message, int16_t code, const std::string &description)
|
||||
{
|
||||
Q_UNUSED(code)
|
||||
Q_UNUSED(description)
|
||||
|
||||
// Формируем принятое сообщениев формате ReceivedMessage
|
||||
ProduceMessage *rMsg = new ProduceMessage;
|
||||
rMsg->setBodyMsg(message.body(), message.bodySize());
|
||||
|
||||
// Формируем таблицу Properties свойств сообщения
|
||||
Properties p;
|
||||
if (message.hasContentType())
|
||||
p.setContentType(QString::fromStdString(message.contentType()));
|
||||
if (message.hasContentEncoding())
|
||||
p.setContentEncoding(QString::fromStdString(message.contentEncoding()));
|
||||
if (message.hasMessageID())
|
||||
p.setMessageID(QString::fromStdString(message.messageID()));
|
||||
if (message.hasCorrelationID())
|
||||
p.setCorrelationID(QString::fromStdString(message.correlationID()));
|
||||
if (message.timestamp())
|
||||
p.setTimestamp(message.timestamp());
|
||||
if (message.hasExpiration())
|
||||
p.setExpiration(QString::fromStdString(message.expiration()));
|
||||
if (message.hasDeliveryMode())
|
||||
p.setDeliveryMode(message.deliveryMode());
|
||||
if (message.hasAppID())
|
||||
p.setAppID(QString::fromStdString(message.appID()));
|
||||
if (message.hasUserID())
|
||||
p.setUserID(QString::fromStdString(message.userID()));
|
||||
if (message.hasTypeName())
|
||||
p.setTypeName(QString::fromStdString(message.typeName()));
|
||||
if (message.hasReplyTo())
|
||||
p.setReplyTo(QString::fromStdString(message.replyTo()));
|
||||
if (message.hasPriority())
|
||||
p.setPriority(message.priority());
|
||||
|
||||
rMsg->setProperties(p);
|
||||
|
||||
// Работа со свойствами Headers
|
||||
Headers h;
|
||||
AMQP::Table table = message.headers();
|
||||
vector<string> keys = table.keys();
|
||||
|
||||
string name;
|
||||
for(uint i = 0; i < keys.size(); i++) {
|
||||
name = keys[i];
|
||||
if (table.get(name).isInteger()) {
|
||||
int value = table.get(name);
|
||||
h.set(QString::fromStdString(name), value);
|
||||
}
|
||||
else if (table.get(name).isString()) {
|
||||
QString str = QString::fromStdString(table.get(name));
|
||||
h.set(QString::fromStdString(name), str);
|
||||
}
|
||||
else if (table.get(name).isBoolean()) {
|
||||
AMQP::Field &b = const_cast<AMQP::Field &>(table.get(name));
|
||||
AMQP::BooleanSet &b1 = dynamic_cast<AMQP::BooleanSet &>(b);
|
||||
bool value = b1.get(0);
|
||||
h.set(QString::fromStdString(name), value);
|
||||
}
|
||||
}
|
||||
|
||||
rMsg->setHeaders(h);
|
||||
emit onMessageBounced(rMsg);
|
||||
};
|
||||
|
||||
channel.recall().onReceived(messageCb);
|
||||
|
||||
// Цикл событий (event loop)
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
while (! markStop) {
|
||||
|
||||
// Обрабатываем очередь сообщений на передачу
|
||||
if (! qu.isEmpty()) {
|
||||
|
||||
mutex.lock();
|
||||
PublishPacket *packet = qu.dequeue();
|
||||
mutex.unlock();
|
||||
|
||||
AMQP::Envelope *envelope = packet->envelope;
|
||||
int publishFlags = packet->publishFlags;
|
||||
string routingKey = packet->routingKey;
|
||||
|
||||
if (envelope->hasAppID() && envelope->appID() == HEARBEATS)
|
||||
connection.heartbeat();
|
||||
else
|
||||
channel.publish(exchange, routingKey, *envelope, publishFlags);
|
||||
|
||||
delete envelope->body();
|
||||
delete envelope;
|
||||
delete packet;
|
||||
}
|
||||
|
||||
event_base_loop(evbase, EVLOOP_NONBLOCK);
|
||||
QCoreApplication::processEvents();
|
||||
QThread::msleep(0);
|
||||
} //while
|
||||
|
||||
// Закроем канал и соединение
|
||||
channel.close();
|
||||
connection.close();
|
||||
|
||||
event_base_loopbreak(evbase);
|
||||
event_base_loopexit(evbase, 0);
|
||||
event_base_free(evbase);
|
||||
|
||||
emit onWorkFinished(); // Посылаем сигнал о завершении работы
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Прием данных, предразование в формат передачи
|
||||
// и постановка в очередь на выдачу
|
||||
void PWorker::sending(ProduceMessage msg, QString routingKey, bool mandatory)
|
||||
{
|
||||
mutex.lock();
|
||||
|
||||
uint64_t size = msg.getBodyMsg().size();
|
||||
char *body = new char[size];
|
||||
memcpy(body, msg.getBodyMsg().data(), size);
|
||||
|
||||
AMQP::Envelope *env = new AMQP::Envelope(body, size);
|
||||
|
||||
// Готовим сообщение для отправки
|
||||
Properties p = msg.getProperties();
|
||||
if (p.contains("content-type"))
|
||||
env->setContentType(p.getContentType().toStdString().c_str());
|
||||
if (p.contains("content-encoding"))
|
||||
env->setContentEncoding(p.getContentEncoding().toStdString().c_str());
|
||||
if (p.contains("message-id"))
|
||||
env->setMessageID(p.getMessageID().toStdString().c_str());
|
||||
if (p.contains("correlation-id"))
|
||||
env->setCorrelationID(p.getCorrelationID().toStdString().c_str());
|
||||
if (p.contains("timestamp"))
|
||||
env->setTimestamp(p.getTimestamp());
|
||||
if (p.contains("expiration"))
|
||||
env->setExpiration(p.getExpiration().toStdString().c_str());
|
||||
if (p.contains("delivery-mode"))
|
||||
env->setDeliveryMode(p.getDeliveryMode());
|
||||
if (p.contains("app-id"))
|
||||
env->setAppID(p.getAppID().toStdString().c_str());
|
||||
if (p.contains("user-id"))
|
||||
env->setUserID(p.getUserID().toStdString().c_str());
|
||||
if (p.contains("type"))
|
||||
env->setTypeName(p.getTypeName().toStdString().c_str());
|
||||
if (p.contains("reply-to"))
|
||||
env->setReplyTo(p.getReplyTo().toStdString().c_str());
|
||||
if (p.contains("priority"))
|
||||
env->setPriority(p.getPriority());
|
||||
|
||||
AMQP::Table table;
|
||||
|
||||
Headers p2 = msg.getHeaders();
|
||||
QList<QString> k = p2.keys();
|
||||
QList<QVariant> v = p2.values();
|
||||
for (int i=0; i < p2.size(); i++) {
|
||||
QString name = k[i];
|
||||
QVariant val = v[i];
|
||||
if (val.type() == QVariant::Int) {
|
||||
AMQP::Long numb = val.value<int>();
|
||||
table.set(name.toStdString(), numb.value());
|
||||
}
|
||||
else if (val.type() == QVariant::String) {
|
||||
QString str = val.value<QString>();
|
||||
AMQP::ShortString s(str.toStdString());
|
||||
table.set(name.toStdString(), s.value());
|
||||
}
|
||||
else if (val.type() == QVariant::Bool) {
|
||||
bool numb = val.value<bool>();
|
||||
table.set(name.toStdString(), numb);
|
||||
}
|
||||
}
|
||||
env->setHeaders(table);
|
||||
|
||||
int flags = 0; // флаги - в формат AMQP
|
||||
if (mandatory)
|
||||
flags |= AMQP::mandatory;
|
||||
|
||||
string routing = routingKey.toStdString();
|
||||
|
||||
// формируем пакет для постановки в очередь
|
||||
PublishPacket *pp = new PublishPacket;
|
||||
pp->envelope = env;
|
||||
pp->publishFlags = flags;
|
||||
pp->routingKey = routing;
|
||||
|
||||
qu.enqueue(pp);
|
||||
mutex.unlock();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PWorker::stop()
|
||||
{
|
||||
markStop = true; // завершить цикл обработки сообщений
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
#ifndef PWORKER_H
|
||||
#define PWORKER_H
|
||||
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <amqpcpp.h>
|
||||
#include <amqpcpp/libevent.h>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
struct PublishPacket {
|
||||
AMQP::Envelope *envelope;
|
||||
string routingKey;
|
||||
int publishFlags;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class PWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
ExchangeOption exchangeOption;
|
||||
|
||||
bool markStop;
|
||||
QMutex mutex;
|
||||
QQueue<PublishPacket *> qu;
|
||||
|
||||
public:
|
||||
PWorker(ClientOption& clientOption, ExchangeOption& exchangeOption);
|
||||
virtual ~PWorker();
|
||||
|
||||
public slots:
|
||||
void doWork();
|
||||
void sending(ProduceMessage msg, QString routingKey, bool mandatory=false);
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
void onMessageBounced(PtrProduceMessage msg);
|
||||
void onError(string msg);
|
||||
void onReceivedAckNack(uint64_t deliveryTag, bool ack, bool multiple);
|
||||
void onWorkFinished();
|
||||
};
|
||||
|
||||
|
||||
#endif // PWORKER_H
|
@ -1,65 +0,0 @@
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
|
||||
|
||||
Receiver::Receiver(ClientOption &clientOption, ConsumeOption &consumeOption)
|
||||
: QObject(nullptr)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->consumeOption = consumeOption;
|
||||
this->consumeOption.receivingExchange = consumeOption.receivingExchange;
|
||||
this->consumeOption.bindingArgs = consumeOption.bindingArgs;
|
||||
|
||||
CWorker *worker = new CWorker(this->clientOption, this->consumeOption);
|
||||
worker->moveToThread(&workerThread);
|
||||
|
||||
connect(&workerThread, &QThread::started, worker, &CWorker::doWork);
|
||||
connect(&workerThread, &QThread::finished, worker, &CWorker::slotStop);
|
||||
|
||||
// Автоматическое удаление объектов PWorker и QThread по окончании работы
|
||||
connect(worker, &CWorker::onWorkFinished, worker, &CWorker::deleteLater);
|
||||
|
||||
// Посылаемые потоку сигналы
|
||||
connect(this, &Receiver::onStop, worker, &CWorker::slotStop, Qt::DirectConnection);
|
||||
connect(this, &Receiver::doBind, worker, &CWorker::bind, Qt::DirectConnection);
|
||||
connect(this, &Receiver::doUnbind, worker, &CWorker::unbind, Qt::DirectConnection);
|
||||
|
||||
// Сигналы, принимаемые от потока
|
||||
connect(worker, &CWorker::onWorkFinished, &workerThread, &QThread::quit, Qt::QueuedConnection);
|
||||
connect(worker, &CWorker::onResultReady, this, &Receiver::slotMsgReady, Qt::QueuedConnection);
|
||||
connect(worker, &CWorker::onErrorConsume, this, &Receiver::slotErrorMsg, Qt::QueuedConnection);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
}
|
||||
|
||||
|
||||
Receiver::~Receiver()
|
||||
{
|
||||
workerThread.quit();
|
||||
workerThread.wait();
|
||||
}
|
||||
|
||||
// При получении от потока сигнала о приеме сообщения
|
||||
// выпускаем сигнал дальше
|
||||
void Receiver::slotMsgReady(PtrProduceMessage msg, uint64_t deliveryTag)
|
||||
{
|
||||
ProduceMessage message = *msg;
|
||||
delete msg;
|
||||
emit onMessage(message, deliveryTag);
|
||||
}
|
||||
|
||||
// При получении сигнала об ошибке транслируем его
|
||||
void Receiver::slotErrorMsg(const char *description)
|
||||
{
|
||||
QString str(description);
|
||||
emit onError(str);
|
||||
}
|
||||
|
||||
|
||||
void Receiver::slotStop()
|
||||
{
|
||||
emit onStop();
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
#ifndef RECEIVER_H
|
||||
#define RECEIVER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
#include <QThread>
|
||||
#include <QVariant>
|
||||
|
||||
#include "_client_.h"
|
||||
#include "cworker.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class Receiver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
bool stop;
|
||||
|
||||
ClientOption clientOption;
|
||||
ConsumeOption consumeOption;
|
||||
QThread workerThread;
|
||||
|
||||
public:
|
||||
Receiver(ClientOption& clientOption, ConsumeOption& consumeOption);
|
||||
virtual ~Receiver();
|
||||
|
||||
public slots:
|
||||
void slotMsgReady(PtrProduceMessage msg, uint64_t deliveryTag);
|
||||
void slotErrorMsg(const char *description);
|
||||
void slotStop();
|
||||
|
||||
signals:
|
||||
void onMessage(ProduceMessage msg, uint64_t deliveryTag);
|
||||
void onError(QString description);
|
||||
void onStop();
|
||||
void doBind(QString exchange, QString key, bool ex);
|
||||
void doUnbind(QString exchange, QString key, bool ex);
|
||||
|
||||
};
|
||||
|
||||
#endif // RECEIVER_H
|
@ -1,106 +0,0 @@
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
|
||||
Sender::Sender(ClientOption& clientOption, ExchangeOption& exchangeOption)
|
||||
: QObject(nullptr)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->exchangeOption = exchangeOption;
|
||||
|
||||
PWorker *worker = new PWorker(this->clientOption, this->exchangeOption);
|
||||
worker->moveToThread(&workerThread);
|
||||
|
||||
connect(&workerThread, &QThread::started, worker, &PWorker::doWork);
|
||||
|
||||
// Автоматическое удаление объектов PWorker и QThread по окончании работы
|
||||
connect(worker, &PWorker::onWorkFinished, worker, &PWorker::deleteLater);
|
||||
|
||||
// Посылаемые потоку сигналы
|
||||
connect(this, &Sender::onSend, worker, &PWorker::sending, Qt::QueuedConnection);
|
||||
connect(this, &Sender::onStop, worker, &PWorker::stop, Qt::DirectConnection);
|
||||
|
||||
// Сигналы, принимаемые от потока
|
||||
connect(worker, &PWorker::onWorkFinished, &workerThread, &QThread::quit, Qt::QueuedConnection);
|
||||
connect(worker, &PWorker::onReceivedAckNack, this, &Sender::slotAckNack, Qt::QueuedConnection);
|
||||
connect(worker, &PWorker::onError, this, &Sender::slotError, Qt::QueuedConnection);
|
||||
connect(worker, &PWorker::onMessageBounced, this, &Sender::slotMsgBounced, Qt::QueuedConnection);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
// Запуск таймера для механизма сердцебиения
|
||||
tm.stop();
|
||||
tm.setInterval(30000); // 0,5 мин
|
||||
connect(&tm, &QTimer::timeout, this, &Sender::onTimer);
|
||||
tm.start();
|
||||
}
|
||||
|
||||
|
||||
Sender::~Sender()
|
||||
{
|
||||
tm.stop();
|
||||
|
||||
workerThread.quit();
|
||||
workerThread.wait();
|
||||
}
|
||||
|
||||
|
||||
// Периодическое подключение по таймеру (1 мин)
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void Sender::onTimer()
|
||||
{
|
||||
tm.stop();
|
||||
|
||||
// Формируем и отправляем служебное сообщение
|
||||
// на проверку соединения с экземпляром RabbitMQ
|
||||
|
||||
string str = "@@"; // содержимое не играет роли
|
||||
ProduceMessage msg;
|
||||
msg.setBodyMsg(str.c_str(), str.size());
|
||||
|
||||
Properties p;
|
||||
QString hearbeats(HEARBEATS);
|
||||
p.setAppID(hearbeats); // маркер служебного сообщения сердцебиения
|
||||
msg.setProperties(p);
|
||||
|
||||
QString routingKey = "";
|
||||
emit onSend(msg, routingKey); // сообщение передаем в поток для передачи серверу
|
||||
|
||||
tm.start();
|
||||
}
|
||||
|
||||
void Sender::slotMsgBounced(PtrProduceMessage msg)
|
||||
{
|
||||
ProduceMessage message = *msg;
|
||||
delete msg;
|
||||
emit onMsgBounced(message);
|
||||
}
|
||||
|
||||
// Передаем сообщение в поток для выдачи
|
||||
void Sender::send(ProduceMessage msg, QString routingKey, bool mandatory)
|
||||
{
|
||||
emit onSend(msg, routingKey, mandatory);
|
||||
}
|
||||
|
||||
|
||||
// Прием подтверждения от потока о выдаче (или невыдаче) сообщения
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-------~~~~~~~~~~~~~~------------
|
||||
void Sender::slotAckNack(uint64_t deliveryTag, bool ack, bool multiple)
|
||||
{
|
||||
emit onReceivedAckNack(deliveryTag, ack, multiple);
|
||||
}
|
||||
|
||||
|
||||
void Sender::slotError(string msg)
|
||||
{
|
||||
QString message = QString::fromStdString(msg);
|
||||
|
||||
emit onError(message);
|
||||
}
|
||||
|
||||
|
||||
void Sender::slotStop()
|
||||
{
|
||||
emit onStop();
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
#ifndef SENDER_H
|
||||
#define SENDER_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QMetaType>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Client;
|
||||
class PWorker;
|
||||
|
||||
|
||||
class Sender : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
ExchangeOption exchangeOption;
|
||||
QThread workerThread;
|
||||
QTimer tm;
|
||||
|
||||
public:
|
||||
Sender(ClientOption& clientOption, ExchangeOption& exchangeOption);
|
||||
virtual ~Sender();
|
||||
|
||||
|
||||
void send(ProduceMessage msg, QString routingKey, bool mandatory=false);
|
||||
|
||||
private slots:
|
||||
void onTimer();
|
||||
|
||||
public slots:
|
||||
void slotMsgBounced(PtrProduceMessage msg);
|
||||
void slotStop();
|
||||
void slotAckNack(uint64_t deliveryTag, bool ack, bool multiple);
|
||||
void slotError(string msg);
|
||||
|
||||
signals:
|
||||
void onMsgBounced(ProduceMessage msg);
|
||||
void onReceivedAckNack(uint64_t deliveryTag, bool ack, bool multiple);
|
||||
void onSend(ProduceMessage msg, QString routingKey, bool mandatory=false); // Отправка сообщения потоку
|
||||
void onError(QString &msg);
|
||||
void onStop();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // SENDER_H
|
@ -1,54 +0,0 @@
|
||||
#include "validator.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
Validator::Validator(ClientOption& clientOption, QList<ExchangeOption>& exchangeOptions)
|
||||
: QObject(nullptr)
|
||||
{
|
||||
// класс запускает поток с валидатором, который в течение 5 секунд должен проверить инфраструктуру.
|
||||
// любая ошибка приведёт к завершению работы программы. если ошибок не было перехвачено, через 5 секунд процесс завершается.
|
||||
|
||||
this->clientOption = clientOption;
|
||||
this->exchangeOptions = exchangeOptions;
|
||||
|
||||
VWorker *worker = new VWorker(this->clientOption, this->exchangeOptions);
|
||||
worker->moveToThread(&workerThread);
|
||||
|
||||
connect(&workerThread, &QThread::started, worker, &VWorker::doWork);
|
||||
|
||||
// Автоматическое удаление объектов VWorker и QThread по окончании работы
|
||||
connect(worker, &VWorker::onWorkFinished, worker, &VWorker::deleteLater);
|
||||
|
||||
// Сигналы, принимаемые от потока
|
||||
connect(worker, &VWorker::onWorkFinished, &workerThread, &QThread::quit, Qt::QueuedConnection);
|
||||
connect(worker, &VWorker::onError, this, &Validator::slotError, Qt::QueuedConnection);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
// Запуск таймера для механизма сердцебиения
|
||||
tm.stop();
|
||||
tm.setInterval(5000); // 5 сек
|
||||
connect(&tm, &QTimer::timeout, worker, &VWorker::slotStop);
|
||||
connect(&tm, &QTimer::timeout, this, &Validator::onTimer);
|
||||
tm.start();
|
||||
}
|
||||
|
||||
Validator::~Validator()
|
||||
{
|
||||
tm.stop();
|
||||
|
||||
workerThread.quit();
|
||||
}
|
||||
|
||||
void Validator::onTimer()
|
||||
{
|
||||
tm.stop();
|
||||
|
||||
workerThread.quit();
|
||||
}
|
||||
|
||||
void Validator::slotError(string msg)
|
||||
{
|
||||
QString message = QString::fromStdString(msg);
|
||||
emit onError(message);
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
#ifndef VALIDATOR_H
|
||||
#define VALIDATOR_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QMetaType>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
class Validator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Validator(ClientOption& clientOption, QList<ExchangeOption>& exchangeOptions);
|
||||
virtual ~Validator();
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
QList<ExchangeOption> exchangeOptions;
|
||||
QThread workerThread;
|
||||
QTimer tm;
|
||||
|
||||
private slots:
|
||||
void onTimer();
|
||||
|
||||
public slots:
|
||||
void slotError(string msg);
|
||||
|
||||
signals:
|
||||
void onError(QString &msg);
|
||||
void onStop();
|
||||
};
|
||||
|
||||
#endif // VALIDATOR_H
|
@ -1,123 +0,0 @@
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "_client_.h"
|
||||
#include "sender.h"
|
||||
#include "vworker.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
VWorker::VWorker(ClientOption &clientOption, QList<ExchangeOption>& exchangeOptions)
|
||||
: QObject(nullptr), markStop(false)
|
||||
{
|
||||
this->clientOption = clientOption;
|
||||
this->exchangeOptions = exchangeOptions;
|
||||
}
|
||||
|
||||
VWorker::~VWorker()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void VWorker::doWork()
|
||||
{
|
||||
string host = clientOption.host.toStdString();
|
||||
string port = QString::number(clientOption.port).toStdString();
|
||||
string user = clientOption.user.toStdString();
|
||||
string password = clientOption.password.toStdString();
|
||||
string vhost = clientOption.vhost.toStdString();
|
||||
|
||||
string address = "amqp://" + user + ":" + password + "@" + host + ":" + port + vhost;
|
||||
|
||||
// Создаём подключение
|
||||
|
||||
auto evbase = event_base_new();
|
||||
|
||||
AMQP::LibEventHandler handler(evbase);
|
||||
AMQP::TcpConnection connection(&handler, AMQP::Address(address));
|
||||
AMQP::TcpChannel channel(&connection);
|
||||
|
||||
channel.setQos(1);
|
||||
|
||||
channel.confirmSelect()
|
||||
.onError([&](const char *message) {
|
||||
qDebug() << "validator - connecting error: " << message;
|
||||
});
|
||||
|
||||
// Обрабатываем список точек обмена
|
||||
|
||||
string exch;
|
||||
string exType;
|
||||
AMQP::ExchangeType typeExch;
|
||||
int flagsExch = 0;
|
||||
|
||||
QString ex_alt_e_name = "alternate-exchange";
|
||||
QString ex_alt_e_value = "";
|
||||
|
||||
for(ExchangeOption exOpt : exchangeOptions) {
|
||||
AMQP::Table exTable;
|
||||
exch = exOpt.name.toStdString();
|
||||
exType = exOpt.type.toStdString();
|
||||
|
||||
// преобразование типа точки обмена в формат AMQP
|
||||
if (exType == "" || exType == "direct")
|
||||
typeExch = AMQP::direct;
|
||||
else if (exType == "topic")
|
||||
typeExch = AMQP::topic;
|
||||
else if (exType == "headers")
|
||||
typeExch = AMQP::headers;
|
||||
else
|
||||
typeExch = AMQP::fanout;
|
||||
|
||||
// предобразование флагов точки обмена в формат AMQP
|
||||
if (exOpt.durable)
|
||||
flagsExch |= AMQP::durable;
|
||||
if (exOpt.auto_delete)
|
||||
flagsExch |= AMQP::autodelete;
|
||||
if (exOpt.internal)
|
||||
flagsExch |= AMQP::internal;
|
||||
|
||||
if (exOpt.arguments.contains(ex_alt_e_name)) {
|
||||
ex_alt_e_value = exOpt.arguments[ex_alt_e_name].value<QString>();
|
||||
exTable.set(ex_alt_e_name.toStdString(), ex_alt_e_value.toStdString());
|
||||
}
|
||||
|
||||
//Для предопределенных точек обмена их обьявление не производим
|
||||
|
||||
if ( exch != "" && exch != "amq.fanout" && exch != "amq.direct" &&
|
||||
exch != "amq.topic" && exch != "amq.headers") {
|
||||
channel.declareExchange(exch, typeExch, flagsExch, exTable)
|
||||
.onError( [&](const char *message) {
|
||||
qDebug() << "validator - declaring error: " << message;
|
||||
emit onError(message);
|
||||
});
|
||||
}
|
||||
|
||||
QMap<QString, QString>::iterator it = exOpt.bindingArgs.begin();
|
||||
for (; it != exOpt.bindingArgs.end(); ++it) {
|
||||
channel.bindExchange(exch, it.key().toStdString(), it.value().toStdString())
|
||||
.onError( [&](const char *message) {
|
||||
qDebug() << "validator - binding error: " << message;
|
||||
emit onError(message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
while (! markStop) {
|
||||
event_base_loop(evbase, EVLOOP_NONBLOCK);
|
||||
QCoreApplication::processEvents();
|
||||
QThread::msleep(0);
|
||||
}
|
||||
|
||||
// Закроем канал и соединение
|
||||
channel.close();
|
||||
connection.close();
|
||||
|
||||
event_base_loopbreak(evbase);
|
||||
event_base_loopexit(evbase, 0);
|
||||
event_base_free(evbase);
|
||||
}
|
||||
|
||||
void VWorker::slotStop()
|
||||
{
|
||||
markStop = true;
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
#ifndef VWORKER_H
|
||||
#define VWORKER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <amqpcpp.h>
|
||||
#include <amqpcpp/libevent.h>
|
||||
|
||||
#include "client_cpp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class VWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ClientOption clientOption;
|
||||
QList<ExchangeOption> exchangeOptions;
|
||||
|
||||
bool markStop;
|
||||
QMutex mutex;
|
||||
|
||||
public:
|
||||
VWorker(ClientOption& clientOption, QList<ExchangeOption>& exchangeOptions);
|
||||
virtual ~VWorker();
|
||||
|
||||
public slots:
|
||||
void doWork();
|
||||
void slotStop();
|
||||
|
||||
signals:
|
||||
void onError(string msg);
|
||||
void onWorkFinished();
|
||||
};
|
||||
|
||||
|
||||
#endif // VWORKER_H
|
@ -1,11 +0,0 @@
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ClientOption clOpt;
|
||||
|
||||
clOpt.host = "localhost";
|
||||
clOpt.port = 5672;
|
||||
clOpt.user = "user";
|
||||
clOpt.password = "12345678";
|
||||
|
||||
Properties props;
|
||||
props.setAppID("ClientApp");
|
||||
props.setDeliveryMode(1);
|
||||
|
||||
pm.setProperties(props);
|
||||
|
||||
ExchangeOption exOpt;
|
||||
exOpt.name = "publisher";
|
||||
exOpt.type = "fanout";
|
||||
|
||||
sender = new Sender(clOpt, exOpt);
|
||||
|
||||
tm = new QTimer(this);
|
||||
connect(tm, SIGNAL(timeout()), this, SLOT(send_msg()));
|
||||
tm->start(1000);
|
||||
|
||||
counter = 1;
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
tm->stop();
|
||||
delete tm;
|
||||
sender->slotStop();
|
||||
QThread::msleep(150);
|
||||
delete sender;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::send_msg()
|
||||
{
|
||||
QString str = "message " + QString::number(counter);
|
||||
ui->listWidget->addItem("sent " + str);
|
||||
pm.setBodyMsg(QByteArray::fromStdString(str.toStdString()));
|
||||
sender->send(pm, "");
|
||||
counter++;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user