Compare commits
No commits in common. "main" and "martysheva_tamara_lab_7" have entirely different histories.
main
...
martysheva
@ -1,27 +0,0 @@
|
|||||||
version: '3.8'
|
|
||||||
services:
|
|
||||||
usr_service:
|
|
||||||
build:
|
|
||||||
context: /user_service
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
depends_on:
|
|
||||||
- msg_service
|
|
||||||
expose:
|
|
||||||
- 8082
|
|
||||||
|
|
||||||
msg_service:
|
|
||||||
build:
|
|
||||||
context: /message_service
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
expose:
|
|
||||||
- 8081
|
|
||||||
|
|
||||||
nginx:
|
|
||||||
image: nginx
|
|
||||||
ports:
|
|
||||||
- 8086:8086
|
|
||||||
volumes:
|
|
||||||
- ./nginx.conf:/etc/nginx/nginx.conf
|
|
||||||
depends_on:
|
|
||||||
- msg_service
|
|
||||||
- usr_service
|
|
@ -1,11 +0,0 @@
|
|||||||
FROM python:3.9
|
|
||||||
|
|
||||||
EXPOSE 8081
|
|
||||||
|
|
||||||
RUN pip install Flask requests
|
|
||||||
|
|
||||||
WORKDIR /work
|
|
||||||
|
|
||||||
COPY msg_service.py ./
|
|
||||||
|
|
||||||
CMD ["python", "msg_service.py"]
|
|
@ -1,50 +0,0 @@
|
|||||||
from flask import Flask, jsonify, request, Response
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
|
|
||||||
msgs = {0: {'id': 0, 'from': 0, 'to': 1, 'body': 'qq', 'dt': datetime(2023, 12, 22, 8, 0)},
|
|
||||||
1: {'id': 1, 'from': 1, 'to': 0, 'body': 'qq', 'dt': datetime(2023, 12, 22, 8, 5)},
|
|
||||||
2: {'id': 2, 'from': 0, 'to': 1, 'body': 'bye', 'dt': datetime(2023, 12, 22, 8, 10)},
|
|
||||||
3: {'id': 3, 'from': 1, 'to': 1, 'body': 'bye', 'dt': datetime(2023, 12, 22, 8, 15)}}
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/', methods=['GET', 'POST'])
|
|
||||||
def get_all():
|
|
||||||
if request.method == 'POST':
|
|
||||||
dto = request.get_json()['dto']
|
|
||||||
new_id = max(msgs.keys()) + 1
|
|
||||||
msgs[new_id] = {
|
|
||||||
'id': new_id,
|
|
||||||
'from': dto['from'],
|
|
||||||
'to': dto['to'],
|
|
||||||
'body': dto['body'],
|
|
||||||
'dt': datetime.now()
|
|
||||||
}
|
|
||||||
return jsonify(msgs[new_id])
|
|
||||||
return jsonify(msgs)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/<int:msg_id>', methods=['GET', 'PUT', 'DELETE'])
|
|
||||||
def get_by_id(msg_id):
|
|
||||||
if msg_id not in msgs.keys():
|
|
||||||
return Response(status=404)
|
|
||||||
|
|
||||||
if request.method == 'PUT':
|
|
||||||
dto = request.get_json()['dto']
|
|
||||||
msgs[msg_id] = {
|
|
||||||
'from': dto['from'],
|
|
||||||
'to': dto['to'],
|
|
||||||
'body': dto['body'],
|
|
||||||
'dt': datetime.now()
|
|
||||||
}
|
|
||||||
return msgs[msg_id]
|
|
||||||
elif request.method == 'DELETE':
|
|
||||||
msgs.pop(msg_id)
|
|
||||||
return Response(status=200)
|
|
||||||
|
|
||||||
return jsonify(msgs[msg_id])
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app.run(host='0.0.0.0', use_reloader=False, port=8081)
|
|
@ -1,27 +0,0 @@
|
|||||||
events {
|
|
||||||
worker_connections 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
http {
|
|
||||||
server {
|
|
||||||
listen 8086;
|
|
||||||
listen [::]:8086;
|
|
||||||
server_name localhost;
|
|
||||||
|
|
||||||
location /msg_service/ {
|
|
||||||
proxy_pass http://msg_service:8081/;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-Proto $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Prefix $scheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /usr_service/ {
|
|
||||||
proxy_pass http://usr_service:8082/;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-Proto $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Prefix $scheme;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
## Задание
|
|
||||||
|
|
||||||
1. Создать 2 микросервиса, реализующих CRUD на связанных сущностях.
|
|
||||||
2. Реализовать механизм синхронного обмена сообщениями между микросервисами.
|
|
||||||
3. Реализовать шлюз на основе прозрачного прокси-сервера nginx.
|
|
||||||
|
|
||||||
Вариант: сообщения и пользователи
|
|
||||||
|
|
||||||
## Выполнение
|
|
||||||
Были написаны два сервиса на языке python с технологией flask:
|
|
||||||
* Сервис msg_service, хранящий данные о сообщениях и реализующий CRUD операции с ними через HTTP запросы.
|
|
||||||
* Сервис usr_service, хранящий данные о пользователях и реализующий CRUD операции с ними через HTTP запросы.
|
|
||||||
|
|
||||||
Сервисы синхронно сообщены - сервис пользователей запрашивает данные у сервиса сообщений для получения сообщений пользователя.
|
|
||||||
|
|
||||||
Для сервисов прописаны файлы Dockerfile, описывающие создание контейнеров:
|
|
||||||
* Для обоих контейнеров выбирается Python 3.9.
|
|
||||||
* Оба контейнера проявляют порты, на которых работает приложение: 8081 для сообщений и 8082 для пользователей.
|
|
||||||
* В оба контейнера устанавливаются пакеты Flask и requests.
|
|
||||||
* Выбирается рабочая директория /work и туда копируются файлы скриптов.
|
|
||||||
* Командой запускаются сами скрипты.
|
|
||||||
|
|
||||||
Общий yaml-файл развёртки был настроен следующим образом:
|
|
||||||
* блок services, где перечислены разворачиваемые сервисы.
|
|
||||||
* для каждого сервиса прописан build, где объявляется его папка и докерфайл создания и зависимости.
|
|
||||||
* для сервиса nginx прописан порт для отображения вовне.
|
|
||||||
|
|
||||||
## Результат
|
|
||||||
Демонстрация работы в видео.
|
|
||||||
|
|
||||||
## Ссылка на видео
|
|
||||||
https://drive.google.com/file/d/1gmZsbzMmC34Uidi4u_D3nFyPAG0MuPAf/view?usp=drive_link
|
|
@ -1,11 +0,0 @@
|
|||||||
FROM python:3.9
|
|
||||||
|
|
||||||
EXPOSE 8082
|
|
||||||
|
|
||||||
RUN pip install Flask requests
|
|
||||||
|
|
||||||
WORKDIR /work
|
|
||||||
|
|
||||||
COPY usr_service.py ./
|
|
||||||
|
|
||||||
CMD ["python", "usr_service.py"]
|
|
@ -1,56 +0,0 @@
|
|||||||
import requests
|
|
||||||
from flask import Flask, jsonify, request, Response
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
|
|
||||||
usrs = {0: {'id': 0, 'name': 'anton', 'role': 'admin', 'online': False, 'msgs_sent': [0, 2], 'msgs_got': [1, 3]},
|
|
||||||
1: {'id': 1, 'name': 'lioha', 'role': 'user', 'online': False, 'msgs_sent': [1, 3], 'msgs_got': [0, 2]}}
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/', methods=['GET', 'POST'])
|
|
||||||
def get_all():
|
|
||||||
if request.method == 'POST':
|
|
||||||
dto = request.get_json()['dto']
|
|
||||||
new_id = max(usrs.keys()) + 1
|
|
||||||
usrs[new_id] = {
|
|
||||||
'id': new_id,
|
|
||||||
'name': dto['name'],
|
|
||||||
'role': dto['role'],
|
|
||||||
'online': dto['online']
|
|
||||||
}
|
|
||||||
return jsonify(usrs[new_id])
|
|
||||||
return jsonify(usrs)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/<int:usr_id>', methods=['GET', 'PUT', 'DELETE'])
|
|
||||||
def get_by_id(usr_id):
|
|
||||||
if usr_id not in usrs.keys():
|
|
||||||
return Response(status=404)
|
|
||||||
|
|
||||||
if request.method == 'PUT':
|
|
||||||
dto = request.get_json()['dto']
|
|
||||||
usrs[usr_id] = {
|
|
||||||
'name': dto['name'],
|
|
||||||
'role': dto['role'],
|
|
||||||
'online': dto['online']
|
|
||||||
}
|
|
||||||
return usrs[usr_id]
|
|
||||||
elif request.method == 'DELETE':
|
|
||||||
usrs.pop(usr_id)
|
|
||||||
return Response(status=200)
|
|
||||||
|
|
||||||
usr = usrs[usr_id]
|
|
||||||
msgs = []
|
|
||||||
for msg_id in usr['msgs_sent']:
|
|
||||||
msgs.append(requests.get("http://msg_service:8081/"+str(msg_id)).json())
|
|
||||||
usr['msgs_sent'] = msgs
|
|
||||||
msgs.clear()
|
|
||||||
for msg_id in usr['msgs_got']:
|
|
||||||
msgs.append(requests.get("http://msg_service:8081/"+str(msg_id)).json())
|
|
||||||
usr['msgs_got'] = msgs
|
|
||||||
|
|
||||||
return jsonify(usr)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app.run(host='0.0.0.0', use_reloader=False, port=8082)
|
|
@ -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();
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user