@platform-x/hep-message-broker-client 1.0.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/src/Util/commonUtil.js.map +1 -0
- package/dist/src/Util/constants.js +8 -0
- package/dist/src/Util/constants.js.map +1 -0
- package/dist/src/Util/logger.js.map +1 -0
- package/dist/src/Util/requestTracer.js.map +1 -0
- package/dist/src/config/ConfigManager.js.map +1 -0
- package/dist/src/config/index.js.map +1 -0
- package/dist/src/index.js +22 -1
- package/dist/src/index.js.map +1 -0
- package/dist/src/messageBroker/BaseRabbitMQClient.js.map +1 -0
- package/dist/src/messageBroker/ConnectionManager.js.map +1 -0
- package/dist/src/messageBroker/MessageBrokerClient.js.map +1 -0
- package/dist/src/messageBroker/MessageConsumer.js.map +1 -0
- package/dist/src/messageBroker/MessageProducer.js.map +1 -0
- package/dist/src/messageBroker/RabbitMQClient.js.map +1 -0
- package/dist/src/messageBroker/RetryManager.js.map +1 -0
- package/dist/src/messageBroker/interface/ConnectionWrapper.js.map +1 -0
- package/dist/src/messageBroker/interface/IMessageBrokerClient.js.map +1 -0
- package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js +90 -53
- package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.js.map +1 -0
- package/dist/src/messageBroker/types/ActionType.js.map +1 -0
- package/dist/src/messageBroker/types/PublishMessageInputType.js.map +1 -0
- package/dist/src/models/MessageModel.js.map +1 -0
- package/dist/src/models/NotificationMessageModel.js.map +1 -0
- package/package.json +43 -40
- package/src/Util/commonUtil.ts +41 -0
- package/src/Util/constants.ts +4 -0
- package/src/Util/logger.ts +219 -0
- package/src/Util/requestTracer.ts +28 -0
- package/src/config/ConfigManager.ts +35 -0
- package/src/config/index.ts +31 -0
- package/src/index.ts +73 -0
- package/src/messageBroker/BaseRabbitMQClient.ts +30 -0
- package/src/messageBroker/ConnectionManager.ts +182 -0
- package/src/messageBroker/MessageBrokerClient.ts +88 -0
- package/src/messageBroker/MessageConsumer.ts +85 -0
- package/src/messageBroker/MessageProducer.ts +142 -0
- package/src/messageBroker/RabbitMQClient.ts +47 -0
- package/src/messageBroker/RetryManager.ts +64 -0
- package/src/messageBroker/interface/ConnectionWrapper.ts +7 -0
- package/src/messageBroker/interface/IMessageBrokerClient.ts +11 -0
- package/src/messageBroker/rabbitmq/MessageBrokerClient.ts +680 -0
- package/src/messageBroker/types/ActionType.ts +1 -0
- package/src/messageBroker/types/PublishMessageInputType.ts +8 -0
- package/src/models/MessageModel.ts +14 -0
- package/tsconfig.json +73 -0
- package/dist/src/Util/commonUtil.d.ts +0 -16
- package/dist/src/Util/logger.d.ts +0 -68
- package/dist/src/Util/requestTracer.d.ts +0 -7
- package/dist/src/config/ConfigManager.d.ts +0 -9
- package/dist/src/config/index.d.ts +0 -29
- package/dist/src/index.d.ts +0 -2
- package/dist/src/messageBroker/BaseRabbitMQClient.d.ts +0 -16
- package/dist/src/messageBroker/ConnectionManager.d.ts +0 -60
- package/dist/src/messageBroker/MessageBrokerClient.d.ts +0 -34
- package/dist/src/messageBroker/MessageConsumer.d.ts +0 -26
- package/dist/src/messageBroker/MessageProducer.d.ts +0 -29
- package/dist/src/messageBroker/RabbitMQClient.d.ts +0 -12
- package/dist/src/messageBroker/RetryManager.d.ts +0 -23
- package/dist/src/messageBroker/interface/ConnectionWrapper.d.ts +0 -6
- package/dist/src/messageBroker/interface/IMessageBrokerClient.d.ts +0 -7
- package/dist/src/messageBroker/rabbitmq/MessageBrokerClient.d.ts +0 -114
- package/dist/src/messageBroker/types/ActionType.d.ts +0 -1
- package/dist/src/messageBroker/types/PublishMessageInputType.d.ts +0 -7
- package/dist/src/models/MessageModel.d.ts +0 -5
- /package/{dist/src/models/NotificationMessageModel.d.ts → src/models/NotificationMessageModel.ts} +0 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import bunyan from 'bunyan';
|
|
2
|
+
import config from '../config/index';
|
|
3
|
+
import bformat from 'bunyan-format';
|
|
4
|
+
import { getTraceId, getSpanId } from './requestTracer';
|
|
5
|
+
import _ from 'lodash';
|
|
6
|
+
export interface payLoadInterface {
|
|
7
|
+
statusCode?: number;
|
|
8
|
+
data?: any;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface LoggerInterface {
|
|
12
|
+
info(message: string, method: string): void;
|
|
13
|
+
warn(message: string, method: string, payload?: object): void;
|
|
14
|
+
error(message: string, method: string, payload?: object): void;
|
|
15
|
+
debug(message: string, method: string, payload?: object): void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class LoggerClass implements LoggerInterface {
|
|
19
|
+
private logger: bunyan;
|
|
20
|
+
private infoLevel: boolean = false;
|
|
21
|
+
private debugLevel: boolean = false;
|
|
22
|
+
private errorLevel: boolean = false;
|
|
23
|
+
private warnLevel: boolean = false;
|
|
24
|
+
private blockedKeywords = ['currentPassword', 'clientSecret', 'newPassword'];
|
|
25
|
+
|
|
26
|
+
constructor() {
|
|
27
|
+
this.mapLogLevels();
|
|
28
|
+
this.logger = bunyan.createLogger({
|
|
29
|
+
name: config.APP_NAME,
|
|
30
|
+
level: 'trace', // by default enabling all levels, controlled through env separately
|
|
31
|
+
stream: bformat({
|
|
32
|
+
outputMode: config.NODE_ENV === 'development' ? 'short' : 'bunyan',
|
|
33
|
+
levelInString: true,
|
|
34
|
+
color: true,
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* It's written to handle JSON.circular error
|
|
40
|
+
* @param obj
|
|
41
|
+
* @returns
|
|
42
|
+
*/
|
|
43
|
+
public customstringify(obj: any) {
|
|
44
|
+
let cache: any = [];
|
|
45
|
+
let str = JSON.stringify(obj, (key, value) => {
|
|
46
|
+
{
|
|
47
|
+
this.info(`Logger customstringify ${key}`, 'customstringify');
|
|
48
|
+
if (typeof value === 'object' && value !== null) {
|
|
49
|
+
if (cache.indexOf(value) !== -1) {
|
|
50
|
+
// Circular reference found, discard key
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// Store value in our collection
|
|
54
|
+
cache.push(value);
|
|
55
|
+
}
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
cache = null; // reset the cache
|
|
60
|
+
return str;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* for info log
|
|
64
|
+
* @param message
|
|
65
|
+
* @param payload
|
|
66
|
+
* @param method
|
|
67
|
+
* @returns
|
|
68
|
+
*/
|
|
69
|
+
public info(message: string, method: string) {
|
|
70
|
+
if (!this.infoLevel) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
let loggerParams = {
|
|
74
|
+
message,
|
|
75
|
+
method,
|
|
76
|
+
traceId: getTraceId(),
|
|
77
|
+
};
|
|
78
|
+
this.logger.info(` start ${JSON.stringify(loggerParams)}==end`);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* for warn log
|
|
82
|
+
* @param message
|
|
83
|
+
* @param payload
|
|
84
|
+
* @param method
|
|
85
|
+
* @returns
|
|
86
|
+
*/
|
|
87
|
+
public warn(message: string, method: string, payload?: any) {
|
|
88
|
+
if (!this.warnLevel) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
let loggerParams = {
|
|
92
|
+
message,
|
|
93
|
+
method,
|
|
94
|
+
traceId: getTraceId(),
|
|
95
|
+
statusCode: payload?.statusCode,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
let finalPayload = payload?.length ? payload : {};
|
|
99
|
+
this.logger.warn(
|
|
100
|
+
` start ${JSON.stringify(loggerParams)} payload: ${this.customstringify(
|
|
101
|
+
this.sanitizeLog(finalPayload)
|
|
102
|
+
)}==end`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* for error log
|
|
107
|
+
* @param message
|
|
108
|
+
* @param payload
|
|
109
|
+
* @param method
|
|
110
|
+
* @returns
|
|
111
|
+
*/
|
|
112
|
+
public error(message: string, method: string, payload?: any) {
|
|
113
|
+
if (!this.errorLevel) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (payload instanceof Error) {
|
|
118
|
+
payload = {
|
|
119
|
+
message,
|
|
120
|
+
method,
|
|
121
|
+
traceId: getTraceId(),
|
|
122
|
+
stack: payload?.stack,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
let loggerParams = {
|
|
126
|
+
message,
|
|
127
|
+
method,
|
|
128
|
+
traceId: getTraceId(),
|
|
129
|
+
spanId: getSpanId(),
|
|
130
|
+
statusCode: payload?.statusCode,
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
let finalPayload = payload?.length ? payload : {};
|
|
134
|
+
this.logger.error(
|
|
135
|
+
` start ${JSON.stringify(loggerParams)} payload: ${this.customstringify(
|
|
136
|
+
this.sanitizeLog(finalPayload)
|
|
137
|
+
)}==end`
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* for debug log
|
|
142
|
+
* @param message
|
|
143
|
+
* @param payload
|
|
144
|
+
* @param method
|
|
145
|
+
* @returns
|
|
146
|
+
*/
|
|
147
|
+
public debug(message: string, method: string, payload?: any) {
|
|
148
|
+
if (!this.debugLevel) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let loggerParams = {
|
|
153
|
+
message,
|
|
154
|
+
method,
|
|
155
|
+
traceId: getTraceId(),
|
|
156
|
+
statusCode: payload?.statusCode,
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
let finalPayload = payload?.length ? payload : {};
|
|
160
|
+
this.logger.debug(
|
|
161
|
+
` start ${JSON.stringify(loggerParams)} payload: ${this.customstringify(
|
|
162
|
+
this.sanitizeLog(finalPayload)
|
|
163
|
+
)}==end`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* to map log levels and handle from config
|
|
168
|
+
*/
|
|
169
|
+
private mapLogLevels() {
|
|
170
|
+
if (config.LOG_LEVELS.length) {
|
|
171
|
+
config.LOG_LEVELS.forEach((element: string) => {
|
|
172
|
+
const logLevel = element.trim();
|
|
173
|
+
if (logLevel === 'info') {
|
|
174
|
+
this.infoLevel = true;
|
|
175
|
+
} else if (logLevel === 'debug') {
|
|
176
|
+
this.debugLevel = true;
|
|
177
|
+
} else if (logLevel === 'error') {
|
|
178
|
+
this.errorLevel = true;
|
|
179
|
+
} else if (logLevel === 'warn') {
|
|
180
|
+
this.warnLevel = true;
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* to sanitize logs from unwanted fields to be shown
|
|
187
|
+
* @param request
|
|
188
|
+
* @returns
|
|
189
|
+
*/
|
|
190
|
+
private sanitizeLog(request: any) {
|
|
191
|
+
try {
|
|
192
|
+
if (request) {
|
|
193
|
+
// let obj: any = {};
|
|
194
|
+
Object.keys(request).forEach((key) => {
|
|
195
|
+
let value = request[key];
|
|
196
|
+
if (request[key] === 'options') {
|
|
197
|
+
delete request.options;
|
|
198
|
+
} else {
|
|
199
|
+
if (
|
|
200
|
+
this.blockedKeywords.find(
|
|
201
|
+
(blockedKey: any) =>
|
|
202
|
+
key.toLowerCase() === blockedKey.toLowerCase()
|
|
203
|
+
)
|
|
204
|
+
) {
|
|
205
|
+
request[key] = 'XXXXXXXXXX';
|
|
206
|
+
} else {
|
|
207
|
+
request[key] = value;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
return request;
|
|
212
|
+
}
|
|
213
|
+
} catch (err: any) {
|
|
214
|
+
this.error('Logger sanitize error', err);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export const Logger = new LoggerClass();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { NextFunction, Request, Response } from 'express';
|
|
2
|
+
import cls from 'cls-hooked';
|
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
|
|
5
|
+
const TRACE_ID_HEADER_NAME = 'Platform-X-Trace-Id';
|
|
6
|
+
const nsid = `rtracer:${uuidv4()}`;
|
|
7
|
+
const ns = cls.createNamespace(nsid);
|
|
8
|
+
const traceIdKey = 'traceId';
|
|
9
|
+
const spanIdKey = 'spanId';
|
|
10
|
+
/**
|
|
11
|
+
* setTracers - to set the request tracers on the request
|
|
12
|
+
*/
|
|
13
|
+
export const setTracers = (req: Request, res: Response, next: NextFunction) => {
|
|
14
|
+
const headerName = TRACE_ID_HEADER_NAME.toLocaleLowerCase();
|
|
15
|
+
ns.bindEmitter(req);
|
|
16
|
+
ns.bindEmitter(res);
|
|
17
|
+
const traceId = req.headers[headerName] || uuidv4(); // to be passed in headers
|
|
18
|
+
const spanId = uuidv4(); // will be unique for services
|
|
19
|
+
|
|
20
|
+
ns.run(() => {
|
|
21
|
+
ns.set(traceIdKey, traceId);
|
|
22
|
+
ns.set(spanIdKey, spanId);
|
|
23
|
+
next();
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const getTraceId = () => ns.get(traceIdKey);
|
|
28
|
+
export const getSpanId = () => ns.get(spanIdKey);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import config from "./index";
|
|
3
|
+
import { Logger } from '../Util/logger';
|
|
4
|
+
|
|
5
|
+
class ConfigManager {
|
|
6
|
+
private static instance: ConfigManager;
|
|
7
|
+
private config: any;
|
|
8
|
+
private constructor() {
|
|
9
|
+
this.config = {};
|
|
10
|
+
this.loadConfig(config.RABBITMQ.CONFIG_PATH);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public static getInstance(): ConfigManager {
|
|
14
|
+
if (!ConfigManager.instance) {
|
|
15
|
+
ConfigManager.instance = new ConfigManager();
|
|
16
|
+
}
|
|
17
|
+
return ConfigManager.instance;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public loadConfig(configPath: string): void {
|
|
21
|
+
if (fs.existsSync(configPath)) {
|
|
22
|
+
// Do something
|
|
23
|
+
this.config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
24
|
+
}else{
|
|
25
|
+
Logger.error("Config file missing!", "loadConfig")
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public getConfig(): any {
|
|
31
|
+
return this.config;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default ConfigManager;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import dotenv from 'dotenv';
|
|
2
|
+
dotenv.config();
|
|
3
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
LOG_LEVELS: ['info', 'error', 'warn', 'debug'],
|
|
7
|
+
NODE_ENV: 'development',
|
|
8
|
+
APP_NAME: 'hep-message-broker-client',
|
|
9
|
+
RABBITMQ: {
|
|
10
|
+
USER: process.env.RABBITMQ_USER??'root',
|
|
11
|
+
PASS: process.env.RABBITMQ_PASS??'root',
|
|
12
|
+
HOST: process.env.RABBITMQ_HOST??'127.0.0.1',
|
|
13
|
+
PORT: process.env.RABBITMQ_PORT??'5672',
|
|
14
|
+
MAIN_QUEUE: 'main_queue',
|
|
15
|
+
MAIN_EXCHANGE: 'assets_metadata_generate_exchange',
|
|
16
|
+
DLX_QUEUE: 'dead_letter_queue',
|
|
17
|
+
DLX_EXCHANGE: 'assets_dlx_exchange',
|
|
18
|
+
RETRY_QUEUE: 'retry_queue',
|
|
19
|
+
RETRY_EXCHANGE: 'assets_metadata_generate_retry_exchange',
|
|
20
|
+
MAX_RETRIES: Number(process.env.RABBITMQ_MAX_RETRIES?.trim() ?? 1),
|
|
21
|
+
HEARTBEAT: Number(process.env.RABBITMQ_HEARTBEAT?.trim() ?? 5),
|
|
22
|
+
TTL:process.env.RABBITMQ_TTL??"3000|6000|9000",
|
|
23
|
+
BACKOFF_TIME:Number(process.env.BACKOFF_TIME?.trim() ?? 1000),
|
|
24
|
+
IS_ENABLED: process.env.RABBITMQ_IS_ENABLED ?? 'true',
|
|
25
|
+
RABBITMQ_CONFIG: process.env.RABBITMQ_CONFIG ?? '',
|
|
26
|
+
PREFETCH_COUNT: Number(process.env.RABBITMQ_PREFETCH ?? 50),
|
|
27
|
+
CONNECTION_ERROR:process.env.RABBITMQ_CONNECTION_ERROR ?? false,
|
|
28
|
+
PUBLISHER_ERROR:process.env.RABBITMQ_PUBLISHER_ERROR ?? false,
|
|
29
|
+
CONSUMER_ERROR:process.env.RABBITMQ_CONSUMER_ERROR ?? false,
|
|
30
|
+
CONFIG_PATH: process.env.CONFIG_PATH ?? '/etc/rabbitmq/rabbitMQConfig.json',
|
|
31
|
+
}}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
|
|
2
|
+
import { MessageBrokerClient } from "./messageBroker/rabbitmq/MessageBrokerClient";
|
|
3
|
+
// const messageBrokerClient = new MessageBrokerClient();
|
|
4
|
+
// let initial_message = {
|
|
5
|
+
// message: {
|
|
6
|
+
// 'queue_name': 'image_thumbnail_request_queue',
|
|
7
|
+
// 'body': {
|
|
8
|
+
// 'url': 'https://dev.dam.hcl-x.com/server/api/core/bitstreams/43817aff-ebb7-47d2-be0e-fb4db1ab267a/content',
|
|
9
|
+
// 'file_name': 'Kudos (1)',
|
|
10
|
+
// 'destination_path': '1721365841379/public/png',
|
|
11
|
+
// 'visibility': 'public',
|
|
12
|
+
// 'urgency': 0,
|
|
13
|
+
// 'folder_name': '',
|
|
14
|
+
// 'bitstream_id': '43817aff-ebb7-47d2-be0e-fb4db1ab267a',
|
|
15
|
+
// 'ext': 'png',
|
|
16
|
+
// 'asset_type': 'Image',
|
|
17
|
+
// 'item_id': 'b1ff157e-a04f-4f8c-83b5-3a2ead732101',
|
|
18
|
+
// },
|
|
19
|
+
// 'item_id': 'b1ff157e-a04f-4f8c-83b5-3a2ead732101',
|
|
20
|
+
// "language": "en",
|
|
21
|
+
// 'retries': 0,
|
|
22
|
+
// },
|
|
23
|
+
// corelationId: 'lgkdkfgkkfd',
|
|
24
|
+
// version: 0,
|
|
25
|
+
// trace: '',
|
|
26
|
+
// };
|
|
27
|
+
|
|
28
|
+
// let initial_message = {
|
|
29
|
+
// "message":{
|
|
30
|
+
// "queue_name":"summary_request_queue",
|
|
31
|
+
// "body":{
|
|
32
|
+
// "input": "€ !~!@#$%^&*()_++_<><?:{}[];,./ Hi everyone, good afternoon. Hope you all are doing good. Myself Akshima, Daitishin from Hetzial Healthcare. So today I am going to discuss about weight loss platy. We all must be aware about what is a weight loss platy. This is a term which we all come across when we are focusing on our weight loss journey. ",
|
|
33
|
+
// "language": "hi",
|
|
34
|
+
// "max_length": 20,
|
|
35
|
+
// "min_length": 10
|
|
36
|
+
// },
|
|
37
|
+
// "language": "en",
|
|
38
|
+
// "correlationId":"",
|
|
39
|
+
// "retries": 0
|
|
40
|
+
// }
|
|
41
|
+
// };
|
|
42
|
+
|
|
43
|
+
// console.log(initial_message)
|
|
44
|
+
// async function testConnection() {
|
|
45
|
+
// await messageBrokerClient.initialize().then(async () => {
|
|
46
|
+
// return '';
|
|
47
|
+
// setInterval(() => {
|
|
48
|
+
// messageBrokerClient.initializeConsumers();
|
|
49
|
+
// messageBrokerClient.publishMessage( { queueName: 'summary_request_queue', exchangeName:"assets_metadata_generate_exchange", message: initial_message })
|
|
50
|
+
|
|
51
|
+
// }, 1);
|
|
52
|
+
// });
|
|
53
|
+
// }
|
|
54
|
+
|
|
55
|
+
// testConnection();
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
export { MessageBrokerClient };
|
|
64
|
+
let injectedSecretService: any = null;
|
|
65
|
+
export const initIAMSecretsMessageBroker = (secretServiceIns: any) =>{
|
|
66
|
+
injectedSecretService = secretServiceIns;
|
|
67
|
+
}
|
|
68
|
+
export const getIAMSecrets = async() =>{
|
|
69
|
+
if (!injectedSecretService) {
|
|
70
|
+
throw new Error("IAM secrets not initialized");
|
|
71
|
+
}
|
|
72
|
+
return await injectedSecretService.getSecretKeys(); // returns cached data
|
|
73
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as amqp from 'amqplib';
|
|
2
|
+
import ConfigManager from '../config/ConfigManager';
|
|
3
|
+
import config from '../config';
|
|
4
|
+
import ConnectionManager from './ConnectionManager';
|
|
5
|
+
|
|
6
|
+
class BaseRabbitMQClient{
|
|
7
|
+
public readonly configManager: ConfigManager;
|
|
8
|
+
public readonly connectionManager: ConnectionManager = new ConnectionManager();
|
|
9
|
+
protected connection: amqp.Connection | undefined;
|
|
10
|
+
protected channel: amqp.Channel | undefined;
|
|
11
|
+
protected configData: any = {};
|
|
12
|
+
constructor() {
|
|
13
|
+
this.configManager = ConfigManager.getInstance();
|
|
14
|
+
this.configData = this.configManager.getConfig();
|
|
15
|
+
this.channel = this.connectionManager.getChannel();
|
|
16
|
+
this.connection = this.connectionManager.getConnection();
|
|
17
|
+
this.init();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Function for load the config data
|
|
22
|
+
*/
|
|
23
|
+
private init() {
|
|
24
|
+
this.configManager.loadConfig(config?.RABBITMQ?.CONFIG_PATH);
|
|
25
|
+
this.configData = this.configManager.getConfig();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default BaseRabbitMQClient;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// Import the amqplib library for RabbitMQ
|
|
2
|
+
import * as amqp from 'amqplib';
|
|
3
|
+
import { Logger } from '../Util/logger';
|
|
4
|
+
import ConfigManager from '../config/ConfigManager';
|
|
5
|
+
import config from '../config';
|
|
6
|
+
let isConnectionOpen = false;
|
|
7
|
+
let MAX_RETRIES: number = 1;
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
interface ConnectionWrapper {
|
|
11
|
+
connection: amqp.Connection,
|
|
12
|
+
channel: amqp.Channel
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class ConnectionManager {
|
|
16
|
+
private static instance: ConnectionManager;
|
|
17
|
+
private readonly configManager: ConfigManager;
|
|
18
|
+
protected connection: amqp.Connection | undefined;
|
|
19
|
+
protected channel: amqp.Channel | undefined;
|
|
20
|
+
protected configData: any = {};
|
|
21
|
+
constructor() {
|
|
22
|
+
this.configManager = ConfigManager.getInstance();
|
|
23
|
+
this.init();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Function for get channel
|
|
28
|
+
*/
|
|
29
|
+
public getChannel():amqp.Channel | undefined{
|
|
30
|
+
return this.channel;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Function for get channel
|
|
35
|
+
*/
|
|
36
|
+
public getConnection():amqp.Connection | undefined{
|
|
37
|
+
return this.connection;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Function for create and return intance
|
|
42
|
+
* @returns
|
|
43
|
+
*/
|
|
44
|
+
public static async getInstance(): Promise<ConnectionManager> {
|
|
45
|
+
if (!ConnectionManager.instance) {
|
|
46
|
+
ConnectionManager.instance = new ConnectionManager();
|
|
47
|
+
}
|
|
48
|
+
return ConnectionManager.instance;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Function to connect create to RabbitMQ
|
|
53
|
+
*/
|
|
54
|
+
public async createConnection(): Promise<ConnectionWrapper> {
|
|
55
|
+
try {
|
|
56
|
+
Logger.info('Reached to createConnection', 'createConnection');
|
|
57
|
+
this.configManager.loadConfig(config?.RABBITMQ?.CONFIG_PATH);
|
|
58
|
+
let url: string = `amqp://${this.configData?.username}:${this.configData?.password}@${this.configData?.host}`;
|
|
59
|
+
// Create a connection to RabbitMQ server
|
|
60
|
+
this.connection = await amqp.connect(url, { heartbeat: this.configData?.heartbeat });
|
|
61
|
+
isConnectionOpen = true;
|
|
62
|
+
// check the connection status
|
|
63
|
+
this.bindConnectionEventHandler();
|
|
64
|
+
// create channel
|
|
65
|
+
this.channel = await this.connection.createConfirmChannel();
|
|
66
|
+
Logger.info('RabbitMQ connected successfully! ', 'createConnection');
|
|
67
|
+
// create exchange and queue and bind with exchange
|
|
68
|
+
await this.setupQueuesAndExchanges();
|
|
69
|
+
const connectionWrapper: ConnectionWrapper = { connection: this.connection, channel: this.channel }
|
|
70
|
+
return connectionWrapper;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
// Log and rethrow any errors that occur during connection
|
|
73
|
+
Logger.error('Failed to connect to RabbitMQ', 'connection', (error as Error)?.message);
|
|
74
|
+
return { connection: null, channel: null } as unknown as ConnectionWrapper;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Function for bind connection event handler on close and error setupQueuesAndExchanges
|
|
80
|
+
* @returns
|
|
81
|
+
*/
|
|
82
|
+
private bindConnectionEventHandler():boolean {
|
|
83
|
+
try {
|
|
84
|
+
this.connection?.on('close', (err: any) => {
|
|
85
|
+
Logger.error(`RabbitMQ: bindConnectionEventHandler:close`, `Connection closed`, err);
|
|
86
|
+
isConnectionOpen = false;
|
|
87
|
+
});
|
|
88
|
+
this.connection?.on('error', (err: any) => {
|
|
89
|
+
Logger.error(`RabbitMQ: bindConnectionEventHandler:error`, `Connection error`, err);
|
|
90
|
+
isConnectionOpen = false;
|
|
91
|
+
});
|
|
92
|
+
return isConnectionOpen;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
isConnectionOpen = false;
|
|
95
|
+
return isConnectionOpen;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Function to check the status of the connection
|
|
102
|
+
* @returns boolean
|
|
103
|
+
*/
|
|
104
|
+
public async isConnected(): Promise<boolean> {
|
|
105
|
+
return isConnectionOpen;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Function to initialize the connection, channel and setup the queues and exchanges
|
|
111
|
+
* @param reqData
|
|
112
|
+
* @returns
|
|
113
|
+
*/
|
|
114
|
+
public async initialize() {
|
|
115
|
+
Logger.info('Reached to initialize', 'initialize');
|
|
116
|
+
let retries: number = 0;
|
|
117
|
+
MAX_RETRIES = this.configData?.max_retries;
|
|
118
|
+
// Retrie times connection
|
|
119
|
+
while (retries < MAX_RETRIES) {
|
|
120
|
+
try {
|
|
121
|
+
await this.createConnection();
|
|
122
|
+
return { connection:this.connection, channel:this.channel };
|
|
123
|
+
} catch (err) {
|
|
124
|
+
retries++;
|
|
125
|
+
Logger.error('initialize:Failed to connect to RabbitMQ', `Attempt ${retries} of ${MAX_RETRIES}.`);
|
|
126
|
+
if (retries >= MAX_RETRIES) {
|
|
127
|
+
Logger.error('Max retries reached, cannot connect to RabbitMQ.', 'initialize');
|
|
128
|
+
return { connection:this.connection, channel:this.channel };
|
|
129
|
+
}
|
|
130
|
+
// Wait before retrying (e.g., 10 seconds)
|
|
131
|
+
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Function to setup the queues and exchanges
|
|
138
|
+
* @params array
|
|
139
|
+
* @rtrun
|
|
140
|
+
*/
|
|
141
|
+
private async setupQueuesAndExchanges():Promise<void> {
|
|
142
|
+
Logger.info('Reached to setupQueuesAndExchanges', 'setupQueuesAndExchanges');
|
|
143
|
+
try {
|
|
144
|
+
let exchanges: any = this.configData.exchanges;
|
|
145
|
+
let queues: any = this.configData.queues;
|
|
146
|
+
let bindings: any = this.configData.bindings;
|
|
147
|
+
// Declare the exchange with dlx
|
|
148
|
+
for (let data of exchanges) {
|
|
149
|
+
await this.channel?.assertExchange(data?.name, data.type, { durable: data.durable, autoDelete: data.autoDelete });
|
|
150
|
+
Logger.info(`${data?.name} exchange created`, 'setupQueuesAndExchanges');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Declare the queues with dlx
|
|
154
|
+
for (let data of queues) {
|
|
155
|
+
await this.channel?.assertQueue(data?.name, { durable: data.durable, exclusive: data.exclusive, autoDelete: data.autoDelete, arguments: data.arguments });
|
|
156
|
+
Logger.info(`${data?.name} queue created `, 'setupQueuesAndExchanges');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Declare the bindings for queues and exchanges with routing keys
|
|
160
|
+
for (let obj in bindings) {
|
|
161
|
+
bindings[obj]?.forEach(async (key: any) => {
|
|
162
|
+
await this.channel?.bindQueue(key?.queue, obj, key?.routingKey);
|
|
163
|
+
Logger.info(`${key?.queue} bind with exchange name ${obj} and routing key ${key?.routingKey}`, 'setupQueuesAndExchanges');
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
} catch (error) {
|
|
167
|
+
Logger.error("Error on setup queues, exchanges and binding", 'setupQueuesAndExchanges', (error as Error).message);
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Function for load the config data
|
|
174
|
+
*/
|
|
175
|
+
private init() {
|
|
176
|
+
this.configManager.loadConfig(config?.RABBITMQ?.CONFIG_PATH);
|
|
177
|
+
this.configData = this.configManager.getConfig();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export default ConnectionManager;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import config from '../config';
|
|
2
|
+
import ConfigManager from '../config/ConfigManager';
|
|
3
|
+
import ConnectionManager from './ConnectionManager';
|
|
4
|
+
import { IMessageBrokerClient } from './interface/IMessageBrokerClient';
|
|
5
|
+
import MessageProducer from './MessageProducer';
|
|
6
|
+
import { RabbitMQClient } from './RabbitMQClient';
|
|
7
|
+
import RetryManager from './RetryManager';
|
|
8
|
+
import { PublishMessageInputType } from './types/PublishMessageInputType';
|
|
9
|
+
const connectionManager = ConnectionManager.getInstance();
|
|
10
|
+
export class MessageBrokerClient implements IMessageBrokerClient {
|
|
11
|
+
private readonly rabbitMQClient: RabbitMQClient;
|
|
12
|
+
private readonly messageProducer: MessageProducer;
|
|
13
|
+
private readonly configManager: ConfigManager;
|
|
14
|
+
// private readonly retryManager: RetryManager<T>;
|
|
15
|
+
private readonly isEnabledRabbitMQ: boolean = false;
|
|
16
|
+
private readonly configData: any = {};
|
|
17
|
+
constructor() {
|
|
18
|
+
this.rabbitMQClient = new RabbitMQClient();
|
|
19
|
+
this.messageProducer = new MessageProducer();
|
|
20
|
+
this.isEnabledRabbitMQ = config?.RABBITMQ?.IS_ENABLED === 'true';
|
|
21
|
+
this.configManager = ConfigManager.getInstance();
|
|
22
|
+
this.configData = this.configManager.getConfig();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Function to initialize the RabbitMQ connection
|
|
27
|
+
*/
|
|
28
|
+
async initialize(): Promise<void> {
|
|
29
|
+
if(this.isEnabledRabbitMQ){
|
|
30
|
+
this.rabbitMQClient.initialize();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Function to close the connection and channel
|
|
36
|
+
*/
|
|
37
|
+
disconnect(): void {
|
|
38
|
+
if(this.isEnabledRabbitMQ){
|
|
39
|
+
this.rabbitMQClient.disconnect();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Function to publish a message with retry
|
|
45
|
+
* @param request
|
|
46
|
+
* @returns
|
|
47
|
+
*/
|
|
48
|
+
publishMessage(request:PublishMessageInputType): Promise<boolean> {
|
|
49
|
+
if(this.isEnabledRabbitMQ){
|
|
50
|
+
const boundPublishMessage = this.messageProducer.publishMessage.bind(this);
|
|
51
|
+
const boundConsumerHandler = this.messageProducer.messageHandler.bind(this);
|
|
52
|
+
let retry_delay = this.configData?.retry_delay;
|
|
53
|
+
let max_retries = this.configData?.max_retries;
|
|
54
|
+
// Instantiate RetryManager
|
|
55
|
+
const retryManager = RetryManager.getInstance<PublishMessageInputType>(max_retries, retry_delay);
|
|
56
|
+
retryManager.performActionWithRetry(boundPublishMessage, request, boundConsumerHandler)
|
|
57
|
+
}
|
|
58
|
+
return Promise.resolve(false);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Function to publish a message with retry to exchange
|
|
63
|
+
* @param request
|
|
64
|
+
* @returns
|
|
65
|
+
*/
|
|
66
|
+
publishMessageToExchange(request:PublishMessageInputType): Promise<boolean> {
|
|
67
|
+
if(this.isEnabledRabbitMQ){
|
|
68
|
+
const boundPublishMessage = this.messageProducer.publishMessageToExchange.bind(this);
|
|
69
|
+
const boundConsumerHandler = this.messageProducer.messageHandler.bind(this);
|
|
70
|
+
let retry_delay = this.configData?.retry_delay;
|
|
71
|
+
let max_retries = this.configData?.max_retries;
|
|
72
|
+
// Instantiate RetryManager
|
|
73
|
+
const retryManager = RetryManager.getInstance<PublishMessageInputType>(max_retries, retry_delay);
|
|
74
|
+
retryManager.performActionWithRetry(boundPublishMessage, request, boundConsumerHandler)
|
|
75
|
+
}
|
|
76
|
+
return Promise.resolve(false);
|
|
77
|
+
}
|
|
78
|
+
/***
|
|
79
|
+
* Function to check if the connection is established
|
|
80
|
+
*/
|
|
81
|
+
async isConnected(): Promise<boolean> {
|
|
82
|
+
if(this.isEnabledRabbitMQ){
|
|
83
|
+
return (await connectionManager) ? (await connectionManager).isConnected() : Promise.resolve(false);
|
|
84
|
+
}
|
|
85
|
+
return Promise.resolve(false);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
}
|