@mango-power/node-kit 0.0.5 → 0.0.6

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 CHANGED
@@ -9,6 +9,8 @@ Shared node toolkit package for MP services.
9
9
  - `RedisClient`
10
10
  - `RmqService`
11
11
  - `SLSClient`
12
+ - `AwsMqttService`
13
+ - `AliMqttService`
12
14
  - `EmqxMqttService` / `EMQXMqttService`
13
15
 
14
16
  ## Build
@@ -34,6 +36,6 @@ registry=https://registry.npmjs.org/
34
36
  ## Install from other projects
35
37
 
36
38
  ```bash
37
- npm i @mango-power/node-kit@^0.0.5
39
+ npm i @mango-power/node-kit@^0.0.6
38
40
  ```
39
41
 
package/dist/index.d.ts CHANGED
@@ -4,4 +4,6 @@ export * from "./redis.service";
4
4
  export * from "./rmq.service";
5
5
  export * from "./sls.service";
6
6
  export * from "./mqtt/mqtt.type";
7
+ export * from "./mqtt/aws-mqtt.service";
8
+ export * from "./mqtt/ali-mqtt.service";
7
9
  export * from "./mqtt/emqx-mqtt.service";
package/dist/index.js CHANGED
@@ -20,4 +20,6 @@ __exportStar(require("./redis.service"), exports);
20
20
  __exportStar(require("./rmq.service"), exports);
21
21
  __exportStar(require("./sls.service"), exports);
22
22
  __exportStar(require("./mqtt/mqtt.type"), exports);
23
+ __exportStar(require("./mqtt/aws-mqtt.service"), exports);
24
+ __exportStar(require("./mqtt/ali-mqtt.service"), exports);
23
25
  __exportStar(require("./mqtt/emqx-mqtt.service"), exports);
@@ -0,0 +1,36 @@
1
+ import mqtt from "mqtt";
2
+ import { AliyunMqttConfig, MqttTopicRunner } from "./mqtt.type";
3
+ type MqttQos = 0 | 1 | 2;
4
+ interface MqttMessageContext {
5
+ topic: string;
6
+ payload: Buffer;
7
+ match?: string;
8
+ }
9
+ interface MqttHandlerRegistration {
10
+ id?: string;
11
+ topicPattern: string;
12
+ qos: MqttQos;
13
+ handler: (ctx: MqttMessageContext) => Promise<void> | void;
14
+ }
15
+ export declare class AliMqttService {
16
+ client: mqtt.MqttClient;
17
+ private handlerMap;
18
+ private topicHandlerMap;
19
+ private hasConnectedOnce;
20
+ private readonly logger;
21
+ init(config: AliyunMqttConfig): Promise<void>;
22
+ private onError;
23
+ private onMessage;
24
+ private onConnect;
25
+ private subscribe;
26
+ private isTopicMatch;
27
+ private isWildcardPattern;
28
+ private getMatchValue;
29
+ publish(topic: string, message: string | Buffer, opts: mqtt.IClientPublishOptions): Promise<void>;
30
+ registerService(service: MqttTopicRunner): Promise<string>;
31
+ unregisterService(id: string): Promise<void>;
32
+ subscribeHandler(registration: MqttHandlerRegistration): Promise<string>;
33
+ unsubscribeHandler(id: string): Promise<void>;
34
+ clearService(): Promise<void>;
35
+ }
36
+ export {};
@@ -0,0 +1,244 @@
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 () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.AliMqttService = void 0;
40
+ const crypto = __importStar(require("crypto"));
41
+ const crypto_1 = require("crypto");
42
+ const mqtt_1 = __importDefault(require("mqtt"));
43
+ const mqtt_pattern_1 = __importDefault(require("mqtt-pattern"));
44
+ const logger_1 = require("../logger");
45
+ function createAliyunMqttClientId(groupName, appName) {
46
+ return `${groupName}@@@${appName}_${(0, crypto_1.randomUUID)()}`;
47
+ }
48
+ function createAliyunMqttAuthInfo(clientId, instanceId, accessKeyId, accessKeySecret) {
49
+ const username = `Signature|${accessKeyId}|${instanceId}`;
50
+ const password = crypto.createHmac("sha1", accessKeySecret).update(clientId).digest("base64");
51
+ return { username, password };
52
+ }
53
+ class AliMqttService {
54
+ constructor() {
55
+ this.handlerMap = new Map();
56
+ this.topicHandlerMap = new Map();
57
+ this.hasConnectedOnce = false;
58
+ this.logger = (0, logger_1.createLogger)(AliMqttService.name);
59
+ }
60
+ async init(config) {
61
+ const clientId = createAliyunMqttClientId("GID_MP_SVC", "iot_svc_task");
62
+ const { username, password } = createAliyunMqttAuthInfo(clientId, config.instanceId, config.accessKeyId, config.accessKeySecret);
63
+ this.client = mqtt_1.default.connect(`mqtts://${config.host}:8883`, {
64
+ clientId,
65
+ username,
66
+ password,
67
+ reconnectPeriod: 1000,
68
+ connectTimeout: 30000,
69
+ keepalive: 120,
70
+ resubscribe: true,
71
+ });
72
+ this.client.on("message", async (topic, message) => {
73
+ await this.onMessage(topic, message);
74
+ });
75
+ this.client.on("connect", async () => {
76
+ await this.onConnect();
77
+ });
78
+ this.client.on("close", () => {
79
+ if (this.hasConnectedOnce) {
80
+ this.logger.warn("ali.mqtt.connection.closed");
81
+ }
82
+ else {
83
+ this.logger.info("ali.mqtt.connection.closed.startup");
84
+ }
85
+ });
86
+ this.client.on("offline", () => {
87
+ if (this.hasConnectedOnce) {
88
+ this.logger.warn("ali.mqtt.connection.offline");
89
+ }
90
+ else {
91
+ this.logger.info("ali.mqtt.connection.offline.startup");
92
+ }
93
+ });
94
+ this.client.on("reconnect", () => {
95
+ if (this.hasConnectedOnce) {
96
+ this.logger.warn("ali.mqtt.connection.reconnecting");
97
+ }
98
+ else {
99
+ this.logger.info("ali.mqtt.connection.reconnecting.startup");
100
+ }
101
+ });
102
+ this.client.on("end", () => {
103
+ this.logger.warn("ali.mqtt.connection.ended");
104
+ });
105
+ this.client.on("disconnect", (packet) => {
106
+ this.logger.warn({ packet }, "ali.mqtt.connection.disconnected");
107
+ });
108
+ this.client.on("error", async (e) => {
109
+ if (this.hasConnectedOnce) {
110
+ this.logger.error({ error: e }, "ali.mqtt.connection.error");
111
+ }
112
+ else {
113
+ this.logger.warn({ error: e }, "ali.mqtt.connection.error.startup");
114
+ }
115
+ await this.onError();
116
+ });
117
+ await new Promise((resolve, reject) => {
118
+ const timeoutMs = 90000;
119
+ const timer = setTimeout(() => reject(new Error(`ali.mqtt.init.timeout.${timeoutMs}ms`)), timeoutMs);
120
+ this.client.once("connect", () => {
121
+ clearTimeout(timer);
122
+ resolve(1);
123
+ });
124
+ });
125
+ }
126
+ async onError() {
127
+ this.logger.info("ali.mqtt.error.handled");
128
+ }
129
+ async onMessage(topic, message) {
130
+ for (const [pattern, groupMap] of this.topicHandlerMap.entries()) {
131
+ if (!this.isTopicMatch(pattern, topic)) {
132
+ continue;
133
+ }
134
+ const matchValue = this.getMatchValue(pattern, topic);
135
+ for (const registration of groupMap.values()) {
136
+ await registration.handler({ topic, payload: message, match: matchValue });
137
+ }
138
+ }
139
+ }
140
+ async onConnect() {
141
+ this.hasConnectedOnce = true;
142
+ this.logger.info("ali.mqtt.connection.connected");
143
+ const topicQosMap = new Map();
144
+ for (const [topicPattern, groupMap] of this.topicHandlerMap.entries()) {
145
+ let maxQos = 0;
146
+ for (const registration of groupMap.values()) {
147
+ maxQos = Math.max(maxQos, registration.qos);
148
+ }
149
+ topicQosMap.set(topicPattern, maxQos);
150
+ }
151
+ for (const [topic, qos] of topicQosMap.entries()) {
152
+ await this.subscribe(topic, { qos });
153
+ }
154
+ }
155
+ async subscribe(topic, opts) {
156
+ await new Promise((resolve, reject) => {
157
+ this.client.subscribe(topic, opts, (err) => {
158
+ if (err) {
159
+ reject(err);
160
+ return;
161
+ }
162
+ resolve();
163
+ });
164
+ });
165
+ }
166
+ isTopicMatch(pattern, topic) {
167
+ if (!this.isWildcardPattern(pattern)) {
168
+ return pattern === topic;
169
+ }
170
+ return mqtt_pattern_1.default.matches(pattern, topic);
171
+ }
172
+ isWildcardPattern(pattern) {
173
+ return pattern.includes("+") || pattern.includes("#");
174
+ }
175
+ getMatchValue(pattern, topic) {
176
+ if (!this.isWildcardPattern(pattern)) {
177
+ return topic;
178
+ }
179
+ const plusIdx = pattern.indexOf("+");
180
+ const hashIdx = pattern.indexOf("#");
181
+ const idxList = [plusIdx, hashIdx].filter((idx) => idx >= 0);
182
+ if (idxList.length === 0) {
183
+ return topic;
184
+ }
185
+ const firstWildcardIndex = Math.min(...idxList);
186
+ const prefix = pattern.slice(0, firstWildcardIndex);
187
+ return topic.startsWith(prefix) ? (topic.slice(prefix.length) || "") : topic;
188
+ }
189
+ async publish(topic, message, opts) {
190
+ await this.client.publish(topic, message, opts);
191
+ }
192
+ async registerService(service) {
193
+ return this.subscribeHandler({
194
+ id: service.id,
195
+ topicPattern: service.topic,
196
+ qos: service.qos,
197
+ handler: async ({ topic, payload, match }) => service.callback(topic, payload, match),
198
+ });
199
+ }
200
+ async unregisterService(id) {
201
+ await this.unsubscribeHandler(id);
202
+ }
203
+ async subscribeHandler(registration) {
204
+ registration.id = registration.id || (0, crypto_1.randomUUID)();
205
+ this.handlerMap.set(registration.id, registration);
206
+ const groupMap = this.topicHandlerMap.get(registration.topicPattern);
207
+ const isNewTopic = !groupMap;
208
+ if (groupMap) {
209
+ groupMap.set(registration.id, registration);
210
+ }
211
+ else {
212
+ const gMap = new Map();
213
+ gMap.set(registration.id, registration);
214
+ this.topicHandlerMap.set(registration.topicPattern, gMap);
215
+ }
216
+ if (isNewTopic) {
217
+ await this.subscribe(registration.topicPattern, { qos: registration.qos });
218
+ }
219
+ return registration.id;
220
+ }
221
+ async unsubscribeHandler(id) {
222
+ const registration = this.handlerMap.get(id);
223
+ if (!registration) {
224
+ return;
225
+ }
226
+ const groupMap = this.topicHandlerMap.get(registration.topicPattern);
227
+ if (groupMap) {
228
+ groupMap.delete(id);
229
+ if (groupMap.size === 0) {
230
+ this.topicHandlerMap.delete(registration.topicPattern);
231
+ this.client.unsubscribe(registration.topicPattern);
232
+ }
233
+ }
234
+ this.handlerMap.delete(id);
235
+ }
236
+ async clearService() {
237
+ for (const topic of this.topicHandlerMap.keys()) {
238
+ this.client.unsubscribe(topic);
239
+ }
240
+ this.handlerMap.clear();
241
+ this.topicHandlerMap.clear();
242
+ }
243
+ }
244
+ exports.AliMqttService = AliMqttService;
@@ -0,0 +1,37 @@
1
+ import * as aws from "aws-iot-device-sdk";
2
+ import mqtt from "mqtt";
3
+ import { AwsMqttConfig, MqttTopicRunner } from "./mqtt.type";
4
+ type MqttQos = 0 | 1 | 2;
5
+ interface MqttMessageContext {
6
+ topic: string;
7
+ payload: Buffer;
8
+ match?: string;
9
+ }
10
+ interface MqttHandlerRegistration {
11
+ id?: string;
12
+ topicPattern: string;
13
+ qos: MqttQos;
14
+ handler: (ctx: MqttMessageContext) => Promise<void> | void;
15
+ }
16
+ export declare class AwsMqttService {
17
+ client: aws.device;
18
+ private handlerMap;
19
+ private topicHandlerMap;
20
+ private hasConnectedOnce;
21
+ private readonly logger;
22
+ init(config: AwsMqttConfig): Promise<void>;
23
+ private onError;
24
+ private onMessage;
25
+ private onConnect;
26
+ private subscribe;
27
+ private isTopicMatch;
28
+ private isWildcardPattern;
29
+ private getMatchValue;
30
+ publish(topic: string, message: string | Buffer, opts: mqtt.IClientPublishOptions): Promise<void>;
31
+ registerService(service: MqttTopicRunner): Promise<string>;
32
+ unregisterService(id: string): Promise<void>;
33
+ subscribeHandler(registration: MqttHandlerRegistration): Promise<string>;
34
+ unsubscribeHandler(id: string): Promise<void>;
35
+ clearService(): Promise<void>;
36
+ }
37
+ export {};
@@ -0,0 +1,238 @@
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 () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.AwsMqttService = void 0;
40
+ const crypto_1 = require("crypto");
41
+ const aws = __importStar(require("aws-iot-device-sdk"));
42
+ const path = __importStar(require("path"));
43
+ const mqtt_pattern_1 = __importDefault(require("mqtt-pattern"));
44
+ const logger_1 = require("../logger");
45
+ class AwsMqttService {
46
+ constructor() {
47
+ this.handlerMap = new Map();
48
+ this.topicHandlerMap = new Map();
49
+ this.hasConnectedOnce = false;
50
+ this.logger = (0, logger_1.createLogger)(AwsMqttService.name);
51
+ }
52
+ async init(config) {
53
+ const pathPrefix = process.cwd();
54
+ this.client = new aws.device({
55
+ keyPath: path.resolve(pathPrefix, config.keyPath),
56
+ certPath: path.resolve(pathPrefix, config.certPath),
57
+ caPath: path.resolve(pathPrefix, config.caPath),
58
+ clientId: "mp-iot-service_" + (0, crypto_1.randomUUID)(),
59
+ host: config.host,
60
+ });
61
+ this.client.on("message", async (topic, message) => {
62
+ await this.onMessage(topic, message);
63
+ });
64
+ this.client.on("connect", async () => {
65
+ await this.onConnect();
66
+ });
67
+ this.client.on("close", () => {
68
+ if (this.hasConnectedOnce) {
69
+ this.logger.warn("aws.mqtt.connection.closed");
70
+ }
71
+ else {
72
+ this.logger.info("aws.mqtt.connection.closed.startup");
73
+ }
74
+ });
75
+ this.client.on("offline", () => {
76
+ if (this.hasConnectedOnce) {
77
+ this.logger.warn("aws.mqtt.connection.offline");
78
+ }
79
+ else {
80
+ this.logger.info("aws.mqtt.connection.offline.startup");
81
+ }
82
+ });
83
+ this.client.on("reconnect", () => {
84
+ if (this.hasConnectedOnce) {
85
+ this.logger.warn("aws.mqtt.connection.reconnecting");
86
+ }
87
+ else {
88
+ this.logger.info("aws.mqtt.connection.reconnecting.startup");
89
+ }
90
+ });
91
+ this.client.on("close", () => {
92
+ this.logger.warn("aws.mqtt.connection.ended");
93
+ });
94
+ this.client.on("error", async (e) => {
95
+ if (this.hasConnectedOnce) {
96
+ this.logger.error({ error: e }, "aws.mqtt.connection.error");
97
+ }
98
+ else {
99
+ this.logger.warn({ error: e }, "aws.mqtt.connection.error.startup");
100
+ }
101
+ await this.onError();
102
+ });
103
+ await new Promise((resolve, reject) => {
104
+ const timeoutMs = 90000;
105
+ const timer = setTimeout(() => reject(new Error(`aws.mqtt.init.timeout.${timeoutMs}ms`)), timeoutMs);
106
+ this.client.once("connect", () => {
107
+ clearTimeout(timer);
108
+ resolve(1);
109
+ });
110
+ });
111
+ }
112
+ async onError() {
113
+ this.logger.info("aws.mqtt.error.handled");
114
+ }
115
+ async onMessage(topic, message) {
116
+ for (const [pattern, groupMap] of this.topicHandlerMap.entries()) {
117
+ if (!this.isTopicMatch(pattern, topic)) {
118
+ continue;
119
+ }
120
+ const matchValue = this.getMatchValue(pattern, topic);
121
+ for (const registration of groupMap.values()) {
122
+ await registration.handler({ topic, payload: message, match: matchValue });
123
+ }
124
+ }
125
+ }
126
+ async onConnect() {
127
+ this.hasConnectedOnce = true;
128
+ this.logger.info("aws.mqtt.connection.connected");
129
+ const topicQosMap = new Map();
130
+ for (const [topicPattern, groupMap] of this.topicHandlerMap.entries()) {
131
+ let maxQos = 0;
132
+ for (const registration of groupMap.values()) {
133
+ maxQos = Math.max(maxQos, registration.qos);
134
+ }
135
+ topicQosMap.set(topicPattern, maxQos);
136
+ }
137
+ for (const [topic, qos] of topicQosMap.entries()) {
138
+ await this.subscribe(topic, { qos });
139
+ }
140
+ }
141
+ async subscribe(topic, opts) {
142
+ await new Promise((resolve, reject) => {
143
+ this.client.subscribe(topic, opts, (err) => {
144
+ if (err) {
145
+ reject(err);
146
+ return;
147
+ }
148
+ resolve();
149
+ });
150
+ });
151
+ }
152
+ isTopicMatch(pattern, topic) {
153
+ if (!this.isWildcardPattern(pattern)) {
154
+ return pattern === topic;
155
+ }
156
+ return mqtt_pattern_1.default.matches(pattern, topic);
157
+ }
158
+ isWildcardPattern(pattern) {
159
+ return pattern.includes("+") || pattern.includes("#");
160
+ }
161
+ getMatchValue(pattern, topic) {
162
+ if (!this.isWildcardPattern(pattern)) {
163
+ return topic;
164
+ }
165
+ const plusIdx = pattern.indexOf("+");
166
+ const hashIdx = pattern.indexOf("#");
167
+ const idxList = [plusIdx, hashIdx].filter((idx) => idx >= 0);
168
+ if (idxList.length === 0) {
169
+ return topic;
170
+ }
171
+ const firstWildcardIndex = Math.min(...idxList);
172
+ const prefix = pattern.slice(0, firstWildcardIndex);
173
+ return topic.startsWith(prefix) ? (topic.slice(prefix.length) || "") : topic;
174
+ }
175
+ async publish(topic, message, opts) {
176
+ await new Promise((resolve, reject) => {
177
+ this.client.publish(topic, message, opts, (err) => {
178
+ if (err) {
179
+ reject(err);
180
+ return;
181
+ }
182
+ resolve();
183
+ });
184
+ });
185
+ }
186
+ async registerService(service) {
187
+ return this.subscribeHandler({
188
+ id: service.id,
189
+ topicPattern: service.topic,
190
+ qos: service.qos,
191
+ handler: async ({ topic, payload, match }) => service.callback(topic, payload, match),
192
+ });
193
+ }
194
+ async unregisterService(id) {
195
+ await this.unsubscribeHandler(id);
196
+ }
197
+ async subscribeHandler(registration) {
198
+ registration.id = registration.id || (0, crypto_1.randomUUID)();
199
+ this.handlerMap.set(registration.id, registration);
200
+ const groupMap = this.topicHandlerMap.get(registration.topicPattern);
201
+ const isNewTopic = !groupMap;
202
+ if (groupMap) {
203
+ groupMap.set(registration.id, registration);
204
+ }
205
+ else {
206
+ const gMap = new Map();
207
+ gMap.set(registration.id, registration);
208
+ this.topicHandlerMap.set(registration.topicPattern, gMap);
209
+ }
210
+ if (isNewTopic) {
211
+ await this.subscribe(registration.topicPattern, { qos: registration.qos });
212
+ }
213
+ return registration.id;
214
+ }
215
+ async unsubscribeHandler(id) {
216
+ const registration = this.handlerMap.get(id);
217
+ if (!registration) {
218
+ return;
219
+ }
220
+ const groupMap = this.topicHandlerMap.get(registration.topicPattern);
221
+ if (groupMap) {
222
+ groupMap.delete(id);
223
+ if (groupMap.size === 0) {
224
+ this.topicHandlerMap.delete(registration.topicPattern);
225
+ this.client.unsubscribe(registration.topicPattern);
226
+ }
227
+ }
228
+ this.handlerMap.delete(id);
229
+ }
230
+ async clearService() {
231
+ for (const topic of this.topicHandlerMap.keys()) {
232
+ this.client.unsubscribe(topic);
233
+ }
234
+ this.handlerMap.clear();
235
+ this.topicHandlerMap.clear();
236
+ }
237
+ }
238
+ exports.AwsMqttService = AwsMqttService;
@@ -1,3 +1,15 @@
1
+ export interface AliyunMqttConfig {
2
+ host: string;
3
+ instanceId: string;
4
+ accessKeyId: string;
5
+ accessKeySecret: string;
6
+ }
7
+ export interface AwsMqttConfig {
8
+ host: string;
9
+ keyPath: string;
10
+ certPath: string;
11
+ caPath: string;
12
+ }
1
13
  export declare class MqttTopicRunner {
2
14
  id?: string;
3
15
  name?: string;
@@ -10,6 +10,7 @@ export declare class PGClientConfig {
10
10
  }
11
11
  export declare class PGClient {
12
12
  private pool;
13
+ private readonly logger;
13
14
  init(config: PGClientConfig): Promise<void>;
14
15
  query<T = any>(sql: string, params?: readonly unknown[]): Promise<T[]>;
15
16
  queryOne<T = any>(sql: string, params?: readonly unknown[]): Promise<T>;
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.PGClient = exports.PGClientConfig = void 0;
37
37
  const pg = __importStar(require("pg"));
38
38
  const humps_1 = require("humps");
39
+ const logger_1 = require("./logger");
39
40
  class PGClientConfig {
40
41
  constructor() {
41
42
  this.ssl = false;
@@ -44,6 +45,9 @@ class PGClientConfig {
44
45
  }
45
46
  exports.PGClientConfig = PGClientConfig;
46
47
  class PGClient {
48
+ constructor() {
49
+ this.logger = (0, logger_1.createLogger)("PGClient");
50
+ }
47
51
  async init(config) {
48
52
  const pgConfig = {
49
53
  host: config.host,
@@ -62,6 +66,7 @@ class PGClient {
62
66
  const client = await this.pool.connect();
63
67
  await client.query("select now()");
64
68
  await client.release();
69
+ this.logger.debug("pg.init.ping.ok");
65
70
  }
66
71
  async query(sql, params) {
67
72
  let result = [];
@@ -72,7 +77,7 @@ class PGClient {
72
77
  result = (0, humps_1.camelizeKeys)(rows);
73
78
  }
74
79
  catch (e) {
75
- console.error("db error.", e.stack);
80
+ this.logger.error({ error: e }, "pg.query.failed");
76
81
  error = e;
77
82
  }
78
83
  finally {
@@ -91,7 +96,7 @@ class PGClient {
91
96
  result = ((0, humps_1.camelizeKeys)(rows[0]) || {});
92
97
  }
93
98
  catch (e) {
94
- console.error("db error.", e);
99
+ this.logger.error({ error: e }, "pg.query_one.failed");
95
100
  throw new Error(String(e));
96
101
  }
97
102
  finally {
@@ -109,7 +114,7 @@ class PGClient {
109
114
  return result;
110
115
  }
111
116
  catch (e) {
112
- console.error("Transaction error.", e);
117
+ this.logger.error({ error: e }, "pg.transaction.failed");
113
118
  await client.query("ROLLBACK");
114
119
  await client.release();
115
120
  throw e;
@@ -12,6 +12,7 @@ export declare class RedisClientConfig {
12
12
  }
13
13
  export declare class RedisClient {
14
14
  client: Redis;
15
+ private readonly logger;
15
16
  init(config: RedisClientConfig): Promise<void>;
16
17
  set(key: string, value: string | number | Buffer, expire?: number): Promise<void>;
17
18
  get(key: string): Promise<string | null>;
@@ -5,10 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.RedisClient = exports.RedisClientConfig = void 0;
7
7
  const ioredis_1 = __importDefault(require("ioredis"));
8
+ const logger_1 = require("./logger");
8
9
  class RedisClientConfig {
9
10
  }
10
11
  exports.RedisClientConfig = RedisClientConfig;
11
12
  class RedisClient {
13
+ constructor() {
14
+ this.logger = (0, logger_1.createLogger)("RedisClient");
15
+ }
12
16
  async init(config) {
13
17
  try {
14
18
  const redisOptions = {
@@ -19,12 +23,12 @@ class RedisClient {
19
23
  password: config.password,
20
24
  disableClientInfo: true,
21
25
  reconnectOnError: (err) => {
22
- console.warn("Reconnect on error:", err);
26
+ this.logger.warn({ error: err }, "redis.reconnect_on_error");
23
27
  return true;
24
28
  },
25
29
  retryStrategy: (times) => {
26
30
  const delay = Math.min(times * 50, 2000);
27
- console.info(`Retrying connection in ${delay}ms`);
31
+ this.logger.info({ delayMs: delay, retryTimes: times }, "redis.retry_scheduled");
28
32
  return delay;
29
33
  },
30
34
  };
@@ -33,13 +37,13 @@ class RedisClient {
33
37
  }
34
38
  this.client = new ioredis_1.default(redisOptions);
35
39
  this.client.on("error", (err) => {
36
- console.error("Redis Error:", err);
40
+ this.logger.error({ error: err }, "redis.client.error");
37
41
  });
38
- const result = await this.client.ping();
39
- console.debug(result);
42
+ await this.client.ping();
43
+ this.logger.debug("redis.ping.ok");
40
44
  }
41
45
  catch (e) {
42
- console.error(e);
46
+ this.logger.error({ error: e }, "redis.init.failed");
43
47
  }
44
48
  }
45
49
  async set(key, value, expire) {
@@ -48,7 +52,7 @@ class RedisClient {
48
52
  await client.multi().set(key, value).expire(key, expire || 300).exec();
49
53
  }
50
54
  catch (e) {
51
- console.error(e);
55
+ this.logger.error({ error: e, key }, "redis.set.failed");
52
56
  }
53
57
  }
54
58
  async get(key) {
@@ -66,7 +70,7 @@ class RedisClient {
66
70
  return JSON.parse(s);
67
71
  }
68
72
  catch (e) {
69
- console.error(e);
73
+ this.logger.error({ error: e, key }, "redis.get_json.parse_failed");
70
74
  return null;
71
75
  }
72
76
  }
@@ -13,6 +13,8 @@ const index_1 = require("../index");
13
13
  const redis = new index_1.RedisClient();
14
14
  const rmq = new index_1.RmqService();
15
15
  const sls = new index_1.SLSClient();
16
+ const awsMqtt = new index_1.AwsMqttService();
17
+ const aliMqtt = new index_1.AliMqttService();
16
18
  const mqtt = new index_1.EmqxMqttService();
17
19
  const mqttCompat = new index_1.EMQXMqttService();
18
20
  const runner = new index_1.MqttTopicRunner();
@@ -20,6 +22,8 @@ const index_1 = require("../index");
20
22
  strict_1.default.ok(redis);
21
23
  strict_1.default.ok(rmq);
22
24
  strict_1.default.ok(sls);
25
+ strict_1.default.ok(awsMqtt);
26
+ strict_1.default.ok(aliMqtt);
23
27
  strict_1.default.ok(mqtt);
24
28
  strict_1.default.ok(mqttCompat);
25
29
  strict_1.default.ok(runner.id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mango-power/node-kit",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Shared node toolkit for mp services",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -27,6 +27,7 @@
27
27
  "dependencies": {
28
28
  "@alicloud/log": "^1.2.6",
29
29
  "amqplib": "^0.10.9",
30
+ "aws-iot-device-sdk": "^2.2.16",
30
31
  "humps": "^2.0.1",
31
32
  "ioredis": "^5.8.1",
32
33
  "mqtt": "^5.14.1",
@@ -35,6 +36,7 @@
35
36
  },
36
37
  "devDependencies": {
37
38
  "@types/amqplib": "^0.10.8",
39
+ "@types/aws-iot-device-sdk": "^2.2.8",
38
40
  "@types/humps": "^2.0.6",
39
41
  "@types/pg": "^8.15.6",
40
42
  "@types/node": "^24.11.0",