Compare commits
263 Commits
gusev_vlad
...
main
Author | SHA1 | Date | |
---|---|---|---|
60ef5724cd | |||
6827a64c4d | |||
7de577eadc | |||
2690438508 | |||
e3677ed302 | |||
|
f5bc94c4ec | ||
f4ec46b14d | |||
ac085099f4 | |||
|
46f2a8da94 | ||
|
84bd5277a9 | ||
|
bb78e6823b | ||
|
ea990fd848 | ||
a284e473a9 | |||
c7ccb94de9 | |||
0a6ce933c7 | |||
d867909883 | |||
|
b9d3eb249b | ||
|
934dd837ac | ||
|
36c429cb4f | ||
|
61c94a9155 | ||
8496ba5b3e | |||
4e177372a9 | |||
a311037d8d | |||
6fea07c73d | |||
3f6234209a | |||
b3c9d6a471 | |||
080efc8a4c | |||
6e86bdcc1e | |||
51c5bfa80a | |||
a901a2b306 | |||
ffdf6c9ab9 | |||
a44eb5cb56 | |||
2270fa67e4 | |||
8ed344819f | |||
426dcca1ec | |||
e7ba5e4e23 | |||
5bca0d2e6f | |||
992635f9e5 | |||
ec6f254f98 | |||
e1be77f193 | |||
|
a8df36581d | ||
|
e3972e8932 | ||
|
e617f9ebbb | ||
5e2305d3ac | |||
89b987e416 | |||
2de04f60a9 | |||
a2cd0cf527 | |||
219ce2acfe | |||
cf88b559cc | |||
8f7c563a25 | |||
259bcd07f0 | |||
e68c51b313 | |||
12523aabaf | |||
b0d3c4cc7a | |||
7205c6f8f0 | |||
82cab3fc1b | |||
a0e60b3699 | |||
993786b8ae | |||
|
66525b2d4b | ||
|
7328dcb134 | ||
08e44c25c3 | |||
2c61f815fa | |||
2bdf735b95 | |||
2ef1f65ed6 | |||
7dcce0138f | |||
427173d554 | |||
5104f74803 | |||
5341271f9e | |||
e582711076 | |||
|
0a5d8d6e02 | ||
|
4498245823 | ||
|
b06fb8f5c5 | ||
|
1ffed2075a | ||
|
f7b9e00012 | ||
|
6afc3b032f | ||
|
a07d49560a | ||
|
1cd0264117 | ||
a346187851 | |||
97f2f1e018 | |||
314d96b716 | |||
d45d516d4a | |||
7c877e803d | |||
e07dde810d | |||
46ae5b2736 | |||
55d384cf1b | |||
3cc0bb20fc | |||
d36865cc2b | |||
34ecd9c33e | |||
9e7b0fcc03 | |||
a3d495ad1a | |||
0c34abeb21 | |||
86d0303d8d | |||
a5f9016bb5 | |||
38717b004c | |||
d613c85a20 | |||
db6e3e1ba6 | |||
4c7875241f | |||
6cf3fb6eda | |||
073265a64b | |||
176dd95462 | |||
5f1bb5e2bd | |||
5a1e7cb698 | |||
0a2777cf55 | |||
aeee4e3f7e | |||
927816dc42 | |||
660bc2681c | |||
f03ae3e342 | |||
59e524f061 | |||
dc26a1f48c | |||
a8f49f7572 | |||
|
722b354fab | ||
|
256e916485 | ||
|
9160de5e51 | ||
|
3593a55226 | ||
|
89f2a30f71 | ||
|
7d25138f9d | ||
44925143c2 | |||
c4c4873091 | |||
42b2bd7a78 | |||
1555cb5642 | |||
de4b5c8584 | |||
27bde41368 | |||
8926cf25c0 | |||
fb2cd5836b | |||
48b78907cb | |||
33c9790fef | |||
f6b74ebd83 | |||
60c5417187 | |||
ac825f136b | |||
fa99584756 | |||
da4a529412 | |||
3a1de5ead0 | |||
3ca3be38d3 | |||
c80433f4ca | |||
1d7145da66 | |||
985bf1ba01 | |||
880d359158 | |||
7ae3de0e65 | |||
2690abc1d6 | |||
4ccd7b91ff | |||
fda332b761 | |||
d3154cdae0 | |||
cd51734f82 | |||
be23ab0a6e | |||
cfb17604eb | |||
13d5139b19 | |||
c3c07e870e | |||
0cf1b56fd2 | |||
f17187207a | |||
b7187c8f60 | |||
81f8116770 | |||
06de5e8246 | |||
c99644f2d4 | |||
d0d2bcf2db | |||
301f7ad941 | |||
711b7d275a | |||
|
60be16bdbc | ||
|
46001bf28b | ||
|
fadbd75718 | ||
38854734b5 | |||
|
3f98128517 | ||
|
9b69bb7feb | ||
|
7459415f70 | ||
|
6ddd513f75 | ||
ad6a4552db | |||
|
7bdeec66ba | ||
e35c9da7e0 | |||
c83f26573c | |||
01a4946295 | |||
ad12c8f3ac | |||
45b0dc6f0a | |||
71bc735b26 | |||
a1f814a584 | |||
5044e52972 | |||
d39df3e247 | |||
df28992456 | |||
f67d0375f9 | |||
977bdd56b2 | |||
063e631fc0 | |||
|
775bd41749 | ||
|
b75a601ab9 | ||
9022f7ad44 | |||
0eb56e61da | |||
04fc1cf183 | |||
170d671dff | |||
eaa28196ec | |||
f2adafe2e1 | |||
5f3397e313 | |||
b0c2b37252 | |||
aac23548d7 | |||
43ba1a2bb8 | |||
bc9fbb58dc | |||
1ca5dad17e | |||
79c62bdf6a | |||
49a6a252e3 | |||
|
5120eec932 | ||
bbeb924b57 | |||
39937db6ca | |||
6699354369 | |||
6bc7e4e9b0 | |||
1e39fba62c | |||
2fb2eac941 | |||
a9f710dd11 | |||
8a8414d202 | |||
afd81bb6c1 | |||
f4da09deb9 | |||
9f007f3c58 | |||
b03eaf85a3 | |||
9115693f3c | |||
849067494a | |||
716a0f8d01 | |||
6e6d80f6d1 | |||
c39ea36d29 | |||
ee89271e08 | |||
9268c9b075 | |||
8c1f9a15fd | |||
59a42a730f | |||
|
4f5586f9ac | ||
|
d3c914ad38 | ||
|
896ee1da9d | ||
|
325d6f9bbb | ||
380e99a4ea | |||
|
a4a35b5529 | ||
|
7cd2022236 | ||
|
266432cfda | ||
|
ca5364cb65 | ||
|
f279209740 | ||
|
60ff69f12d | ||
|
45d977f668 | ||
|
fe7928f10c | ||
0f9fb5d61a | |||
12bc9d0a08 | |||
8ebca9c409 | |||
fb11539f57 | |||
49095d8467 | |||
f3f4543fc3 | |||
1a73e12489 | |||
ca8c66d237 | |||
9e85fa9e0f | |||
7af5aaa299 | |||
84a3741b9a | |||
|
82b7b37f0f | ||
ad34d07492 | |||
02a13a395d | |||
5e85f5a315 | |||
22b163ed29 | |||
06eba2e084 | |||
d4007d8cc6 | |||
de2e3c4f33 | |||
83528356a1 | |||
e404748401 | |||
8ff2a44649 | |||
3a9b24d065 | |||
50f7253477 | |||
89c01268ca | |||
d45fcb79c1 | |||
ee72f8bb84 | |||
530632543f | |||
a0565f8b4c | |||
a8c0d980ba | |||
|
b166d347a9 | ||
|
23dfef9856 | ||
076820725d |
@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11" project-jdk-type="Python SDK" />
|
||||
</project>
|
@ -17,8 +17,8 @@
|
||||
1. [Знакомство с docker и docker-compose](http://student.git.athene.tech/Alexey/DAS_2023_1/src/branch/main/labs/lab_1.md)
|
||||
2. [Разработка простейшего распределённого приложения](http://student.git.athene.tech/Alexey/DAS_2023_1/src/branch/main/labs/lab_2.md)
|
||||
3. [REST API, Gateway и синхронный обмен между микросервисами](http://student.git.athene.tech/Alexey/DAS_2023_1/src/branch/main/labs/lab_3.md)
|
||||
4. TBD
|
||||
4. [Работа с брокером сообщений](http://student.git.athene.tech/Alexey/DAS_2023_1/src/branch/main/labs/lab_4.md)
|
||||
5. [Параллельное умножение матриц](http://student.git.athene.tech/Alexey/DAS_2023_1/src/branch/main/labs/lab_5.md)
|
||||
6. TBD
|
||||
7. TBD
|
||||
8. TBD
|
||||
6. [Параллельный поиск значения детерминанта матрицы](http://student.git.athene.tech/Alexey/DAS_2023_1/src/branch/main/labs/lab_6.md)
|
||||
7. [Балансировка нагрузки в распределённых системах при помощи открытых технологий на примерах](http://student.git.athene.tech/Alexey/DAS_2023_1/src/branch/main/labs/lab_7.md).
|
||||
8. [Про устройство распределенных систем](http://student.git.athene.tech/Alexey/DAS_2023_1/src/branch/main/labs/lab_8.md).
|
19
alexandrov_dmitrii_lab_2/docker-compose.yml
Normal file
19
alexandrov_dmitrii_lab_2/docker-compose.yml
Normal file
@ -0,0 +1,19 @@
|
||||
services:
|
||||
worker-1:
|
||||
build:
|
||||
context: /worker-1
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- 8081:8081
|
||||
volumes:
|
||||
- .\var\data:/var/data
|
||||
- .\var\result:/var/result
|
||||
|
||||
worker-2:
|
||||
build:
|
||||
context: /worker-2
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- 8082:8082
|
||||
volumes:
|
||||
- .\var\result:/var/result
|
37
alexandrov_dmitrii_lab_2/readme.md
Normal file
37
alexandrov_dmitrii_lab_2/readme.md
Normal file
@ -0,0 +1,37 @@
|
||||
## Задание
|
||||
Развернуть два взаимосвязанных сервиса по варианту:
|
||||
|
||||
Вариант 1:
|
||||
* Сервис 1 ищет в каталоге /var/data файл с наибольшим количеством строк и перекладывает его в /var/result/data.txt.
|
||||
* Сервис 2 ищет набольшее число из файла /var/data/data.txt и сохраняет его вторую степень в /var/result/result.txt.
|
||||
|
||||
## Выполнение
|
||||
Были написаны два сервиса на языке python с технологией flask. Они выводят на страницу кнопки, по которым происходило срабатывание скриптов по варианту.
|
||||
|
||||
Для сервисов прописаны файлы Dockerfile, описывающие создание контейнеров:
|
||||
* Для обоих контейнеров выбирается Python 9.
|
||||
* Оба контейнера проявляют порты, на которых работает приложение: 8081 для первого и 8082 для второго.
|
||||
* В контейнерах создаются папки /work для файлов скриптов, папки /var/result для обоих сервисов и /var/data для первого скрипта.
|
||||
* В оба контейнера устанавливается пакет Flask.
|
||||
* Выбирается рабочая директория /work и туда копируются файлы скриптов.
|
||||
* Командой запускаются сами скрипты.
|
||||
|
||||
Общий yaml-файл развёртки был настроен следующим образом:
|
||||
* блок services, где перечислены разворачиваемые сервисы.
|
||||
* для каждого сервиса прописан build, где объявляется его папка и докерфайл создания.
|
||||
* для каждого сервиса прописано отображение портов на такие же хоста.
|
||||
* для каждого сервиса прописано монтирование нужных папок хостовой системы как соответствующих папок внутри контейнеров.
|
||||
|
||||
## Результат
|
||||
Пример выполнения:
|
||||
|
||||
Исходные данные: три файла в папке /var/data, средний файл имеет наибольшее количество строк и наибольшее число 40.
|
||||
|
||||
Ход работы: нажатие кнопок на странице первого сервиса, потом - второго.
|
||||
Запросы:
|
||||
![Запросы](screens/requests.png)
|
||||
Выходные данные: средний файл, перенесённый в /var/result/data.txt, файл result.txt там же с результатом вычислений - числом 1600. Результат выведен на страницу второго сервиса:
|
||||
![Результат](screens/res.png)
|
||||
|
||||
## Ссылка на видео
|
||||
https://drive.google.com/file/d/1ZI1FeQ8BqPR-e_dKnUlNW7V5A39ZlTYu/view?usp=drive_link
|
BIN
alexandrov_dmitrii_lab_2/screens/requests.png
Normal file
BIN
alexandrov_dmitrii_lab_2/screens/requests.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
BIN
alexandrov_dmitrii_lab_2/screens/res.png
Normal file
BIN
alexandrov_dmitrii_lab_2/screens/res.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
3
alexandrov_dmitrii_lab_2/var/data/file1.txt
Normal file
3
alexandrov_dmitrii_lab_2/var/data/file1.txt
Normal file
@ -0,0 +1,3 @@
|
||||
10
|
||||
20
|
||||
15
|
5
alexandrov_dmitrii_lab_2/var/data/file2.txt
Normal file
5
alexandrov_dmitrii_lab_2/var/data/file2.txt
Normal file
@ -0,0 +1,5 @@
|
||||
30
|
||||
40
|
||||
35
|
||||
15
|
||||
10
|
4
alexandrov_dmitrii_lab_2/var/data/file3.txt
Normal file
4
alexandrov_dmitrii_lab_2/var/data/file3.txt
Normal file
@ -0,0 +1,4 @@
|
||||
20
|
||||
30
|
||||
25
|
||||
40
|
5
alexandrov_dmitrii_lab_2/var/result/data.txt
Normal file
5
alexandrov_dmitrii_lab_2/var/result/data.txt
Normal file
@ -0,0 +1,5 @@
|
||||
30
|
||||
40
|
||||
35
|
||||
15
|
||||
10
|
1
alexandrov_dmitrii_lab_2/var/result/result.txt
Normal file
1
alexandrov_dmitrii_lab_2/var/result/result.txt
Normal file
@ -0,0 +1 @@
|
||||
1600
|
15
alexandrov_dmitrii_lab_2/worker-1/Dockerfile
Normal file
15
alexandrov_dmitrii_lab_2/worker-1/Dockerfile
Normal file
@ -0,0 +1,15 @@
|
||||
FROM python:3.9
|
||||
|
||||
ENV LISTEN_PORT=8081
|
||||
EXPOSE 8081
|
||||
|
||||
RUN ["mkdir", "/work"]
|
||||
RUN ["mkdir", "/var/data"]
|
||||
RUN ["mkdir", "/var/result"]
|
||||
RUN pip install Flask
|
||||
|
||||
WORKDIR /work
|
||||
|
||||
COPY template.html worker-1.py ./
|
||||
|
||||
CMD ["python", "worker-1.py"]
|
12
alexandrov_dmitrii_lab_2/worker-1/template.html
Normal file
12
alexandrov_dmitrii_lab_2/worker-1/template.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Worker 1</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="http://127.0.0.1:8081/do">
|
||||
<input type="submit" value="Выполнить"/>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
29
alexandrov_dmitrii_lab_2/worker-1/worker-1.py
Normal file
29
alexandrov_dmitrii_lab_2/worker-1/worker-1.py
Normal file
@ -0,0 +1,29 @@
|
||||
from flask import Flask, redirect, render_template
|
||||
import os
|
||||
|
||||
app = Flask(__name__, template_folder='')
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def home():
|
||||
return render_template("template.html")
|
||||
|
||||
|
||||
@app.route('/do')
|
||||
def do():
|
||||
data_dir = '/var/data'
|
||||
result_file = '/var/result/data.txt'
|
||||
text = []
|
||||
for filename in os.listdir(data_dir):
|
||||
with open(os.path.join(data_dir, filename), 'r') as file:
|
||||
txt = file.readlines()
|
||||
if len(text) < len(txt):
|
||||
text = txt
|
||||
|
||||
with open(result_file, 'w') as result:
|
||||
result.writelines(text)
|
||||
|
||||
return redirect("/")
|
||||
|
||||
|
||||
app.run(host='0.0.0.0', port=8081)
|
14
alexandrov_dmitrii_lab_2/worker-2/Dockerfile
Normal file
14
alexandrov_dmitrii_lab_2/worker-2/Dockerfile
Normal file
@ -0,0 +1,14 @@
|
||||
FROM python:3.9
|
||||
|
||||
ENV LISTEN_PORT=8082
|
||||
EXPOSE 8082
|
||||
|
||||
RUN ["mkdir", "/work"]
|
||||
RUN ["mkdir", "/var/result"]
|
||||
RUN pip install Flask
|
||||
|
||||
WORKDIR /work
|
||||
|
||||
COPY template.html result.html worker-2.py ./
|
||||
|
||||
CMD ["python", "worker-2.py"]
|
10
alexandrov_dmitrii_lab_2/worker-2/result.html
Normal file
10
alexandrov_dmitrii_lab_2/worker-2/result.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Worker 2</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Результат: {{res_num}}</h2>
|
||||
</body>
|
||||
</html>
|
12
alexandrov_dmitrii_lab_2/worker-2/template.html
Normal file
12
alexandrov_dmitrii_lab_2/worker-2/template.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Worker 2</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="http://127.0.0.1:8082/do">
|
||||
<input type="submit" value="Выполнить"/>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
34
alexandrov_dmitrii_lab_2/worker-2/worker-2.py
Normal file
34
alexandrov_dmitrii_lab_2/worker-2/worker-2.py
Normal file
@ -0,0 +1,34 @@
|
||||
from flask import Flask, render_template
|
||||
import re
|
||||
|
||||
app = Flask(__name__, template_folder='')
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def home():
|
||||
return render_template("template.html")
|
||||
|
||||
|
||||
@app.route('/do')
|
||||
def do():
|
||||
data_file = '/var/result/data.txt'
|
||||
result_file = '/var/result/result.txt'
|
||||
|
||||
numbers = []
|
||||
with open(data_file, 'r') as file:
|
||||
txt = file.read()
|
||||
numbers = map(int, re.findall(r'\d+', txt))
|
||||
|
||||
max_v = 0
|
||||
for val in numbers:
|
||||
if max_v < val:
|
||||
max_v = val
|
||||
max_v = max_v * max_v
|
||||
|
||||
with open(result_file, 'w') as result:
|
||||
result.write(str(max_v))
|
||||
|
||||
return render_template("result.html", res_num=max_v)
|
||||
|
||||
|
||||
app.run(host='0.0.0.0', port=8082)
|
27
alexandrov_dmitrii_lab_3/docker-compose.yml
Normal file
27
alexandrov_dmitrii_lab_3/docker-compose.yml
Normal file
@ -0,0 +1,27 @@
|
||||
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
|
11
alexandrov_dmitrii_lab_3/message_service/Dockerfile
Normal file
11
alexandrov_dmitrii_lab_3/message_service/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
||||
FROM python:3.9
|
||||
|
||||
EXPOSE 8081
|
||||
|
||||
RUN pip install Flask requests
|
||||
|
||||
WORKDIR /work
|
||||
|
||||
COPY msg_service.py ./
|
||||
|
||||
CMD ["python", "msg_service.py"]
|
50
alexandrov_dmitrii_lab_3/message_service/msg_service.py
Normal file
50
alexandrov_dmitrii_lab_3/message_service/msg_service.py
Normal file
@ -0,0 +1,50 @@
|
||||
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)
|
27
alexandrov_dmitrii_lab_3/nginx.conf
Normal file
27
alexandrov_dmitrii_lab_3/nginx.conf
Normal file
@ -0,0 +1,27 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
32
alexandrov_dmitrii_lab_3/readme.md
Normal file
32
alexandrov_dmitrii_lab_3/readme.md
Normal file
@ -0,0 +1,32 @@
|
||||
## Задание
|
||||
|
||||
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
|
11
alexandrov_dmitrii_lab_3/user_service/Dockerfile
Normal file
11
alexandrov_dmitrii_lab_3/user_service/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
||||
FROM python:3.9
|
||||
|
||||
EXPOSE 8082
|
||||
|
||||
RUN pip install Flask requests
|
||||
|
||||
WORKDIR /work
|
||||
|
||||
COPY usr_service.py ./
|
||||
|
||||
CMD ["python", "usr_service.py"]
|
56
alexandrov_dmitrii_lab_3/user_service/usr_service.py
Normal file
56
alexandrov_dmitrii_lab_3/user_service/usr_service.py
Normal file
@ -0,0 +1,56 @@
|
||||
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)
|
@ -0,0 +1,53 @@
|
||||
#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
|
124
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/client.cpp
Normal file
124
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/client.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
#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
|
@ -0,0 +1,6 @@
|
||||
#include "clientrbcpp.h"
|
||||
|
||||
|
||||
ClientRBcpp::ClientRBcpp()
|
||||
{
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
#ifndef CLIENTRBCPP_H
|
||||
#define CLIENTRBCPP_H
|
||||
|
||||
#include "clientrbcpp_global.h"
|
||||
|
||||
class CLIENTRBCPPSHARED_EXPORT ClientRBcpp
|
||||
{
|
||||
|
||||
public:
|
||||
ClientRBcpp();
|
||||
};
|
||||
|
||||
#endif // CLIENTRBCPP_H
|
@ -0,0 +1,12 @@
|
||||
#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
|
276
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/cworker.cpp
Normal file
276
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/cworker.cpp
Normal file
@ -0,0 +1,276 @@
|
||||
#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());
|
||||
}
|
54
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/cworker.h
Normal file
54
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/cworker.h
Normal file
@ -0,0 +1,54 @@
|
||||
#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
|
@ -0,0 +1,40 @@
|
||||
#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>(); }
|
||||
|
45
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/headers.h
Normal file
45
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/headers.h
Normal file
@ -0,0 +1,45 @@
|
||||
#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
|
@ -0,0 +1,45 @@
|
||||
#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
|
@ -0,0 +1,52 @@
|
||||
#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
|
@ -0,0 +1,55 @@
|
||||
#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
|
@ -0,0 +1,63 @@
|
||||
#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
|
@ -0,0 +1,37 @@
|
||||
#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; }
|
||||
|
||||
|
@ -0,0 +1,43 @@
|
||||
#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
|
@ -0,0 +1,63 @@
|
||||
#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>(); }
|
@ -0,0 +1,73 @@
|
||||
#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
|
||||
|
||||
|
||||
|
||||
|
||||
|
330
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/pworker.cpp
Normal file
330
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/pworker.cpp
Normal file
@ -0,0 +1,330 @@
|
||||
/**************************************************************************
|
||||
* 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; // завершить цикл обработки сообщений
|
||||
}
|
58
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/pworker.h
Normal file
58
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/pworker.h
Normal file
@ -0,0 +1,58 @@
|
||||
#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
|
@ -0,0 +1,65 @@
|
||||
#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();
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
#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
|
106
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/sender.cpp
Normal file
106
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/sender.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
#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();
|
||||
}
|
58
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/sender.h
Normal file
58
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/sender.h
Normal file
@ -0,0 +1,58 @@
|
||||
#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
|
@ -0,0 +1,54 @@
|
||||
#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);
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
#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
|
123
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/vworker.cpp
Normal file
123
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/vworker.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
#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;
|
||||
}
|
43
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/vworker.h
Normal file
43
alexandrov_dmitrii_lab_4/consumer_fast/clientRBcpp/vworker.h
Normal file
@ -0,0 +1,43 @@
|
||||
#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
|
41
alexandrov_dmitrii_lab_4/consumer_fast/consumer_fast.pro
Normal file
41
alexandrov_dmitrii_lab_4/consumer_fast/consumer_fast.pro
Normal file
@ -0,0 +1,41 @@
|
||||
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
|
338
alexandrov_dmitrii_lab_4/consumer_fast/consumer_fast.pro.user
Normal file
338
alexandrov_dmitrii_lab_4/consumer_fast/consumer_fast.pro.user
Normal file
@ -0,0 +1,338 @@
|
||||
<?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>
|
11
alexandrov_dmitrii_lab_4/consumer_fast/main.cpp
Normal file
11
alexandrov_dmitrii_lab_4/consumer_fast/main.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
31
alexandrov_dmitrii_lab_4/consumer_fast/mainwindow.cpp
Normal file
31
alexandrov_dmitrii_lab_4/consumer_fast/mainwindow.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#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;
|
||||
}
|
||||
|
26
alexandrov_dmitrii_lab_4/consumer_fast/mainwindow.h
Normal file
26
alexandrov_dmitrii_lab_4/consumer_fast/mainwindow.h
Normal file
@ -0,0 +1,26 @@
|
||||
#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
|
37
alexandrov_dmitrii_lab_4/consumer_fast/mainwindow.ui
Normal file
37
alexandrov_dmitrii_lab_4/consumer_fast/mainwindow.ui
Normal file
@ -0,0 +1,37 @@
|
||||
<?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>
|
BIN
alexandrov_dmitrii_lab_4/consumer_fast_service
Executable file
BIN
alexandrov_dmitrii_lab_4/consumer_fast_service
Executable file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
#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
|
124
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/client.cpp
Normal file
124
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/client.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
#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
|
@ -0,0 +1,6 @@
|
||||
#include "clientrbcpp.h"
|
||||
|
||||
|
||||
ClientRBcpp::ClientRBcpp()
|
||||
{
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
#ifndef CLIENTRBCPP_H
|
||||
#define CLIENTRBCPP_H
|
||||
|
||||
#include "clientrbcpp_global.h"
|
||||
|
||||
class CLIENTRBCPPSHARED_EXPORT ClientRBcpp
|
||||
{
|
||||
|
||||
public:
|
||||
ClientRBcpp();
|
||||
};
|
||||
|
||||
#endif // CLIENTRBCPP_H
|
@ -0,0 +1,12 @@
|
||||
#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
|
278
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/cworker.cpp
Normal file
278
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/cworker.cpp
Normal file
@ -0,0 +1,278 @@
|
||||
#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());
|
||||
}
|
54
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/cworker.h
Normal file
54
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/cworker.h
Normal file
@ -0,0 +1,54 @@
|
||||
#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
|
@ -0,0 +1,40 @@
|
||||
#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>(); }
|
||||
|
45
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/headers.h
Normal file
45
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/headers.h
Normal file
@ -0,0 +1,45 @@
|
||||
#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
|
@ -0,0 +1,45 @@
|
||||
#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
|
@ -0,0 +1,52 @@
|
||||
#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
|
@ -0,0 +1,55 @@
|
||||
#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
|
@ -0,0 +1,63 @@
|
||||
#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
|
@ -0,0 +1,37 @@
|
||||
#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; }
|
||||
|
||||
|
@ -0,0 +1,43 @@
|
||||
#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
|
@ -0,0 +1,63 @@
|
||||
#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>(); }
|
@ -0,0 +1,73 @@
|
||||
#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
|
||||
|
||||
|
||||
|
||||
|
||||
|
330
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/pworker.cpp
Normal file
330
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/pworker.cpp
Normal file
@ -0,0 +1,330 @@
|
||||
/**************************************************************************
|
||||
* 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; // завершить цикл обработки сообщений
|
||||
}
|
58
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/pworker.h
Normal file
58
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/pworker.h
Normal file
@ -0,0 +1,58 @@
|
||||
#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
|
@ -0,0 +1,65 @@
|
||||
#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();
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
#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
|
106
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/sender.cpp
Normal file
106
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/sender.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
#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();
|
||||
}
|
58
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/sender.h
Normal file
58
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/sender.h
Normal file
@ -0,0 +1,58 @@
|
||||
#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
|
@ -0,0 +1,54 @@
|
||||
#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);
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
#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
|
123
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/vworker.cpp
Normal file
123
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/vworker.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
#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;
|
||||
}
|
43
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/vworker.h
Normal file
43
alexandrov_dmitrii_lab_4/consumer_slow/clientRBcpp/vworker.h
Normal file
@ -0,0 +1,43 @@
|
||||
#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
|
41
alexandrov_dmitrii_lab_4/consumer_slow/consumer_slow.pro
Normal file
41
alexandrov_dmitrii_lab_4/consumer_slow/consumer_slow.pro
Normal file
@ -0,0 +1,41 @@
|
||||
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
|
338
alexandrov_dmitrii_lab_4/consumer_slow/consumer_slow.pro.user
Normal file
338
alexandrov_dmitrii_lab_4/consumer_slow/consumer_slow.pro.user
Normal file
@ -0,0 +1,338 @@
|
||||
<?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>
|
11
alexandrov_dmitrii_lab_4/consumer_slow/main.cpp
Normal file
11
alexandrov_dmitrii_lab_4/consumer_slow/main.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
33
alexandrov_dmitrii_lab_4/consumer_slow/mainwindow.cpp
Normal file
33
alexandrov_dmitrii_lab_4/consumer_slow/mainwindow.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#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;
|
||||
}
|
||||
|
25
alexandrov_dmitrii_lab_4/consumer_slow/mainwindow.h
Normal file
25
alexandrov_dmitrii_lab_4/consumer_slow/mainwindow.h
Normal file
@ -0,0 +1,25 @@
|
||||
#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
|
37
alexandrov_dmitrii_lab_4/consumer_slow/mainwindow.ui
Normal file
37
alexandrov_dmitrii_lab_4/consumer_slow/mainwindow.ui
Normal file
@ -0,0 +1,37 @@
|
||||
<?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>
|
BIN
alexandrov_dmitrii_lab_4/consumer_slow_service
Executable file
BIN
alexandrov_dmitrii_lab_4/consumer_slow_service
Executable file
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
#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
|
124
alexandrov_dmitrii_lab_4/publisher_app/clientRBcpp/client.cpp
Normal file
124
alexandrov_dmitrii_lab_4/publisher_app/clientRBcpp/client.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
#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
|
@ -0,0 +1,6 @@
|
||||
#include "clientrbcpp.h"
|
||||
|
||||
|
||||
ClientRBcpp::ClientRBcpp()
|
||||
{
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
#ifndef CLIENTRBCPP_H
|
||||
#define CLIENTRBCPP_H
|
||||
|
||||
#include "clientrbcpp_global.h"
|
||||
|
||||
class CLIENTRBCPPSHARED_EXPORT ClientRBcpp
|
||||
{
|
||||
|
||||
public:
|
||||
ClientRBcpp();
|
||||
};
|
||||
|
||||
#endif // CLIENTRBCPP_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user