@modernlock/common 1.0.63 → 1.0.65
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/build/events/base-consumer.d.ts +4 -1
- package/build/events/base-consumer.js +36 -6
- package/build/events/rabbitmq-wrapper.d.ts +1 -0
- package/build/events/rabbitmq-wrapper.js +13 -0
- package/build/index.d.ts +1 -0
- package/build/index.js +1 -0
- package/build/mqtt/mqtt-wrapper.d.ts +15 -0
- package/build/mqtt/mqtt-wrapper.js +140 -0
- package/build/mqtt/topics.d.ts +3 -1
- package/build/mqtt/topics.js +2 -0
- package/package.json +2 -1
|
@@ -8,8 +8,11 @@ export declare abstract class Consumer {
|
|
|
8
8
|
abstract exchangeType: ExchangeTypes;
|
|
9
9
|
abstract routingKey: RoutingKeys;
|
|
10
10
|
abstract queue: Queues;
|
|
11
|
-
abstract onMessage(msg: amqp.Message, data: any, channel
|
|
11
|
+
abstract onMessage(msg: amqp.Message, data: any, channel?: amqp.Channel): Promise<void>;
|
|
12
12
|
private channel;
|
|
13
|
+
private dlx;
|
|
14
|
+
private dlxType;
|
|
15
|
+
private dlRoutingKey;
|
|
13
16
|
constructor(channel: amqp.Channel);
|
|
14
17
|
listen(): Promise<void>;
|
|
15
18
|
parseMessage(msg: amqp.Message): any;
|
|
@@ -12,21 +12,51 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.Consumer = void 0;
|
|
13
13
|
class Consumer {
|
|
14
14
|
constructor(channel) {
|
|
15
|
+
// We define standard names for our Dead letter queu
|
|
16
|
+
this.dlx = 'dead_letter_exchange';
|
|
17
|
+
this.dlxType = 'direct';
|
|
18
|
+
this.dlRoutingKey = 'dead_letter';
|
|
15
19
|
this.channel = channel;
|
|
16
20
|
}
|
|
17
21
|
;
|
|
18
22
|
listen() {
|
|
19
23
|
return __awaiter(this, void 0, void 0, function* () {
|
|
20
24
|
try {
|
|
25
|
+
// Assert the Dead Letter Exchange
|
|
26
|
+
yield this.channel.assertExchange(this.dlx, this.dlxType);
|
|
27
|
+
// Assert the Dead Letter Queue
|
|
28
|
+
const dlQueueName = `${this.queue}.dlq`; // e.g., "update-calendar.dlq"
|
|
29
|
+
yield this.channel.assertQueue(dlQueueName, { durable: true });
|
|
30
|
+
// Bind them so failed messages go into the DLQ
|
|
31
|
+
yield this.channel.bindQueue(dlQueueName, this.dlx, this.dlRoutingKey);
|
|
21
32
|
yield this.channel.assertExchange(this.exchange, this.exchangeType);
|
|
22
|
-
|
|
33
|
+
// Assert the Main Queue with special arguments linking to DLQ
|
|
34
|
+
const q = yield this.channel.assertQueue(this.queue, {
|
|
35
|
+
durable: true,
|
|
36
|
+
arguments: {
|
|
37
|
+
// If message is Nack'ed (rejected), send to this exchange:
|
|
38
|
+
'x-dead-letter-exchange': this.dlx,
|
|
39
|
+
// With this routing key:
|
|
40
|
+
'x-dead-letter-routing-key': this.dlRoutingKey
|
|
41
|
+
// Optional: Time to Live (TTL) before moving to DLQ
|
|
42
|
+
// 'x-message-ttl': 60000
|
|
43
|
+
}
|
|
44
|
+
});
|
|
23
45
|
yield this.channel.bindQueue(q.queue, this.exchange, this.routingKey);
|
|
24
|
-
this.channel.
|
|
46
|
+
yield this.channel.prefetch(1);
|
|
47
|
+
this.channel.consume(q.queue, (msg) => __awaiter(this, void 0, void 0, function* () {
|
|
25
48
|
if (!msg)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
49
|
+
return;
|
|
50
|
+
try {
|
|
51
|
+
const data = this.parseMessage(msg);
|
|
52
|
+
yield this.onMessage(data, msg);
|
|
53
|
+
this.channel.ack(msg);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
console.error(`Error processing message in ${this.queue}:`, error);
|
|
57
|
+
this.channel.nack(msg, false, false);
|
|
58
|
+
}
|
|
59
|
+
}));
|
|
30
60
|
}
|
|
31
61
|
catch (error) {
|
|
32
62
|
console.error('Failed to publish message:', error);
|
|
@@ -115,6 +115,19 @@ class RabbitmqWrapper {
|
|
|
115
115
|
}
|
|
116
116
|
});
|
|
117
117
|
}
|
|
118
|
+
close() {
|
|
119
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
120
|
+
try {
|
|
121
|
+
if (this.channel)
|
|
122
|
+
yield this.channel.close();
|
|
123
|
+
if (this.connection)
|
|
124
|
+
yield this.connection.close();
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
console.error("Error closing RabbitMQ connection", err);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
118
131
|
}
|
|
119
132
|
exports.RabbitmqWrapper = RabbitmqWrapper;
|
|
120
133
|
;
|
package/build/index.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ export * from "./config/elasticsearchConnection";
|
|
|
38
38
|
export * from "./interfaces/reservation";
|
|
39
39
|
export * from "./things/events";
|
|
40
40
|
export * from "./mqtt/topics";
|
|
41
|
+
export * from "./mqtt/mqtt-wrapper";
|
|
41
42
|
export * from "./things/commands";
|
|
42
43
|
export * from "./@types/notification";
|
|
43
44
|
export * from "./@types/express";
|
package/build/index.js
CHANGED
|
@@ -54,6 +54,7 @@ __exportStar(require("./config/elasticsearchConnection"), exports);
|
|
|
54
54
|
__exportStar(require("./interfaces/reservation"), exports);
|
|
55
55
|
__exportStar(require("./things/events"), exports);
|
|
56
56
|
__exportStar(require("./mqtt/topics"), exports);
|
|
57
|
+
__exportStar(require("./mqtt/mqtt-wrapper"), exports);
|
|
57
58
|
__exportStar(require("./things/commands"), exports);
|
|
58
59
|
__exportStar(require("./@types/notification"), exports);
|
|
59
60
|
__exportStar(require("./@types/express"), exports);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as mqtt from 'mqtt';
|
|
2
|
+
type MqttMessageHandler = (message: string, topic: string) => void;
|
|
3
|
+
declare class MqttWrapper {
|
|
4
|
+
private client?;
|
|
5
|
+
private handlers;
|
|
6
|
+
constructor();
|
|
7
|
+
connect(options: mqtt.IClientOptions): Promise<void>;
|
|
8
|
+
private routeMessage;
|
|
9
|
+
private topicMatches;
|
|
10
|
+
publish(topic: string, message: string, options?: mqtt.IClientPublishOptions): Promise<void>;
|
|
11
|
+
subscribe(topic: string, callback: MqttMessageHandler): Promise<void>;
|
|
12
|
+
disconnect(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export declare const mqttWrapper: MqttWrapper;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
exports.mqttWrapper = void 0;
|
|
36
|
+
const mqtt = __importStar(require("mqtt"));
|
|
37
|
+
class MqttWrapper {
|
|
38
|
+
constructor() {
|
|
39
|
+
this.handlers = new Map();
|
|
40
|
+
}
|
|
41
|
+
// 1. Connect Method (Async & Explicit)
|
|
42
|
+
connect(options) {
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
this.client = mqtt.connect(options);
|
|
45
|
+
this.client.on('connect', () => {
|
|
46
|
+
console.log('✅ Connected to MQTT broker');
|
|
47
|
+
resolve();
|
|
48
|
+
});
|
|
49
|
+
this.client.on('error', (err) => {
|
|
50
|
+
console.error('❌ MQTT error:', err);
|
|
51
|
+
// Only reject if we are still trying to connect initially
|
|
52
|
+
// If already connected, this is just a runtime error log
|
|
53
|
+
});
|
|
54
|
+
this.client.on('message', (topic, message) => {
|
|
55
|
+
this.routeMessage(topic, message.toString('utf8'));
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
routeMessage(topic, message) {
|
|
60
|
+
// Optimization: If no handlers, don't loop
|
|
61
|
+
if (this.handlers.size === 0)
|
|
62
|
+
return;
|
|
63
|
+
for (const [filter, handler] of this.handlers.entries()) {
|
|
64
|
+
if (this.topicMatches(filter, topic)) {
|
|
65
|
+
handler(message, topic);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
topicMatches(filter, topic) {
|
|
70
|
+
const filterParts = filter.split('/');
|
|
71
|
+
const topicParts = topic.split('/');
|
|
72
|
+
for (let i = 0; i < filterParts.length; i++) {
|
|
73
|
+
const filterPart = filterParts[i];
|
|
74
|
+
const topicPart = topicParts[i];
|
|
75
|
+
if (filterPart === '#')
|
|
76
|
+
return true;
|
|
77
|
+
if (filterPart === '+') {
|
|
78
|
+
if (!topicPart)
|
|
79
|
+
return false;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (filterPart !== topicPart)
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return filterParts.length === topicParts.length;
|
|
86
|
+
}
|
|
87
|
+
publish(topic, message, options = { qos: 0 }) {
|
|
88
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
89
|
+
if (!this.client)
|
|
90
|
+
throw new Error("Cannot publish before connecting");
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
this.client.publish(topic, message, options, (err) => {
|
|
93
|
+
if (err)
|
|
94
|
+
reject(err);
|
|
95
|
+
else
|
|
96
|
+
resolve();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
subscribe(topic, callback) {
|
|
102
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
103
|
+
if (!this.client)
|
|
104
|
+
throw new Error("Cannot subscribe before connecting");
|
|
105
|
+
return new Promise((resolve, reject) => {
|
|
106
|
+
if (this.handlers.has(topic)) {
|
|
107
|
+
this.handlers.set(topic, callback);
|
|
108
|
+
return resolve();
|
|
109
|
+
}
|
|
110
|
+
this.client.subscribe(topic, { qos: 1 }, (err) => {
|
|
111
|
+
if (err) {
|
|
112
|
+
reject(err);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
console.log(`Subscribed to MQTT topic: ${topic}`);
|
|
116
|
+
this.handlers.set(topic, callback);
|
|
117
|
+
resolve();
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
// 2. Graceful Shutdown
|
|
124
|
+
disconnect() {
|
|
125
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
126
|
+
return new Promise((resolve) => {
|
|
127
|
+
if (this.client) {
|
|
128
|
+
this.client.end(false, () => {
|
|
129
|
+
console.log("MQTT Disconnected");
|
|
130
|
+
resolve();
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
resolve();
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.mqttWrapper = new MqttWrapper();
|
package/build/mqtt/topics.d.ts
CHANGED
|
@@ -3,7 +3,9 @@ export declare enum MqttTopics {
|
|
|
3
3
|
connectionJoiningReply = "m@dernl0ck/connection-joining-reply/#",
|
|
4
4
|
database = "m@dernl0ck/database/#",
|
|
5
5
|
databaseInquiry = "m@dernl0ck/database-inquiry/#",
|
|
6
|
-
thingsNotification = "m@dernl0ck/devices/#"
|
|
6
|
+
thingsNotification = "m@dernl0ck/devices/#",
|
|
7
|
+
factoryDevicesDetected = "factory/devices/detected",
|
|
8
|
+
factoryDevicesRegistered = "factory/devices/registered"
|
|
7
9
|
}
|
|
8
10
|
export declare const mqttCallTopics: {
|
|
9
11
|
getConnectionJoiningTopic: (coordinatorId: string) => string;
|
package/build/mqtt/topics.js
CHANGED
|
@@ -8,6 +8,8 @@ var MqttTopics;
|
|
|
8
8
|
MqttTopics["database"] = "m@dernl0ck/database/#";
|
|
9
9
|
MqttTopics["databaseInquiry"] = "m@dernl0ck/database-inquiry/#";
|
|
10
10
|
MqttTopics["thingsNotification"] = "m@dernl0ck/devices/#";
|
|
11
|
+
MqttTopics["factoryDevicesDetected"] = "factory/devices/detected";
|
|
12
|
+
MqttTopics["factoryDevicesRegistered"] = "factory/devices/registered";
|
|
11
13
|
})(MqttTopics = exports.MqttTopics || (exports.MqttTopics = {}));
|
|
12
14
|
exports.mqttCallTopics = {
|
|
13
15
|
getConnectionJoiningTopic: (coordinatorId) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modernlock/common",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.65",
|
|
4
4
|
"main": "./build/index.js",
|
|
5
5
|
"types": "./build/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"cookie-session": "^2.0.0",
|
|
28
28
|
"express": "4.18.2",
|
|
29
29
|
"jsonwebtoken": "9.0.0",
|
|
30
|
+
"mqtt": "^5.14.1",
|
|
30
31
|
"winston": "^3.12.0",
|
|
31
32
|
"winston-elasticsearch": "^0.18.0"
|
|
32
33
|
},
|