mm_os 2.1.9 → 2.2.1

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.
@@ -1,3 +1,8 @@
1
+ const MQTT_client = require('mqtt');
2
+ const {
3
+ v4
4
+ } = require('uuid');
5
+
1
6
  const Index = require('mm_machine').Index;
2
7
  const Drive = require('./drive');
3
8
 
@@ -17,19 +22,64 @@ class MQTT extends Index {
17
22
  super(scope, __dirname);
18
23
  this.Drive = Drive;
19
24
  this.type = "mqtt";
20
- this.dict = {};
21
25
  this.title = title;
26
+ this.dict = {};
22
27
 
23
28
  this.config = {
24
- host: "127.0.0.1",
29
+ hostname: "127.0.0.1",
25
30
  port: "1883",
26
31
  protocol: "mqtt",
27
- clientId: "test123",
28
- username: "admin",
32
+ clientId: "server",
33
+ subscribe_qos: 0,
34
+ publish_qos: 1,
35
+ username: "server",
29
36
  password: "asd123",
30
- clean: false
37
+ clean: false,
38
+ longtime: 15000,
39
+ // maxInflight: 20,
40
+ // 重连间隔
41
+ interval: 6000
31
42
  }
43
+
44
+ // mqtt客户端服务器
32
45
  this.client = null;
46
+ /**
47
+ * message queue
48
+ */
49
+ this.list_msg = [
50
+ /*
51
+ {
52
+ // information ID
53
+ id: "",
54
+ // request method
55
+ method: "",
56
+ // message parameters
57
+ params: {},
58
+ // Callback
59
+ func: function(res){}
60
+ }
61
+ */
62
+ ];
63
+
64
+ /**
65
+ * 订阅集合 (主题 => 函数列表)
66
+ */
67
+ this.dict_subscribe = {};
68
+
69
+ /**
70
+ * method collection
71
+ */
72
+ this.methods = {
73
+ /**
74
+ * Provide to the server to see how many open functions there are
75
+ */
76
+ get_method: function() {
77
+ return Object.keys(_this.methods)
78
+ }
79
+ };
80
+
81
+ this.retryTimes = 0;
82
+ this.connecting = false;
33
83
  }
34
84
  }
35
85
 
@@ -56,57 +106,290 @@ MQTT.prototype.match = function(topic, top) {
56
106
  /**
57
107
  * 初始化
58
108
  */
59
- MQTT.prototype.init_after = function() {
60
- this.client.on("message", (topic, msg) => {
61
- var db = $.sql.db();
62
- var list = this.list;
63
- for (var i = 0, o; o = list[i++];) {
64
- if (this.match(topic, o.config.topic)) {
65
- o.run(topic, msg);
109
+ MQTT.prototype.update_after = function() {
110
+ var _this = this;
111
+ var list = this.list;
112
+ for (var i = 0, o; o = list[i++];) {
113
+ o.send = function(topic, msg, qos = 0, retain = false) {
114
+ if (topic) {
115
+ _this.send(topic, msg, qos, retain);
116
+ }
117
+ };
118
+
119
+ o.run('init');
120
+ var topics = o.config.topic;
121
+ if (topics) {
122
+ for (var i = 0; i < topics.length; i++) {
123
+ var tc = topics[i];
124
+ var retain = o.config.retain || false;
125
+ var qos = o.config.qos || 0;
126
+ if (tc.indexOf("heartbeat") !== -1) {
127
+ retain = false;
128
+ qos = 0;
129
+ }
130
+ this.subscribe(tc, null, qos, retain);
66
131
  }
67
132
  }
133
+ }
134
+ }
135
+
136
+
137
+ /**
138
+ * 重新连接
139
+ */
140
+ MQTT.prototype.reconnect = function() {
141
+ this.retryTimes += 1;
142
+ if (this.retryTimes > 5) {
143
+ try {
144
+ this.client.end();
145
+ $.sleep(this.config.interval);
146
+ this.init();
147
+ } catch (error) {
148
+ this.$message.error(error.toString());
149
+ }
150
+ }
151
+ }
152
+
153
+ /**
154
+ * 初始化
155
+ * @param {Object} config 配置参数
156
+ */
157
+ MQTT.prototype.init = function(config) {
158
+ this.config = Object.assign(this.config, config);
159
+ this.client = {
160
+ connected: false
161
+ };
162
+ this.retryTimes = 0;
163
+ this.connecting = false;
164
+ };
165
+
166
+ /**
167
+ * 运行MQTT
168
+ * @param {Object} config 配置参数
169
+ */
170
+ MQTT.prototype.start = function() {
171
+ this.connecting = true;
172
+ var err;
173
+ try {
174
+ var cg = this.config;
175
+ if (cg.host) {
176
+ delete cg.hostname;
177
+ delete cg.port;
178
+ this.client = MQTT_client.connect(cg.host, cg);
179
+ } else {
180
+ this.client = MQTT_client.connect(cg);
181
+ }
182
+ if (this.client.on) {
183
+ return new Promise((resolve, reject) => {
184
+ this.client.on('connect', (packet, err) => {
185
+ this.connecting = false;
186
+ if (err) {
187
+ resolve(null);
188
+ reject(err);
189
+ } else {
190
+ this.client.on('message', async (topic, message) => {
191
+ await this.receive(topic, message.toString());
192
+ });
193
+ resolve(packet);
194
+ }
195
+ });
196
+ this.client.on("reconnect", this.reconnect);
197
+ this.client.on("error", (error) => {
198
+ console.error("Connection failed", error);
199
+ });
200
+ });
201
+ }
202
+ } catch (error) {
203
+ this.connecting = false;
204
+ err = error;
205
+ }
206
+ return new Promise((resolve, reject) => {
207
+ resolve(null);
208
+ reject(err);
68
209
  });
210
+ };
211
+
212
+ /**
213
+ * 监听事件
214
+ * @param {String} topic 事件名称
215
+ * @param {Function} func 回调函数
216
+ */
217
+ MQTT.prototype.on = function(topic, func) {
218
+ this.client.on(topic, func);
219
+ }
220
+
221
+ /**
222
+ * 接收消息
223
+ * @param {String} topic 订阅板块
224
+ * @param {Object} msg 消息主体
225
+ */
226
+ MQTT.prototype.message = async function(topic, msg) {
227
+ if (this.dict_subscribe[topic]) {
228
+ var list = this.dict_subscribe[topic];
229
+ try {
230
+ for (var key in list) {
231
+ list[key](msg);
232
+ }
233
+ } catch (err) {
234
+ console.error(err);
235
+ }
236
+ }
69
237
  }
70
238
 
71
239
  /**
72
- * 处理mqtt请求
73
- * @param {Object} conn 通讯连接器
240
+ * 接收消息
241
+ * @param {String} push_topic 推送过来的主题
242
+ * @param {Object} msg 消息主体
74
243
  */
75
- MQTT.prototype.run = async function(conn) {
244
+ MQTT.prototype.receive = async function(push_topic, msg) {
245
+ if (msg && (msg.indexOf('[') === 0) || msg.indexOf('{') === 0) {
246
+ try {
247
+ msg = JSON.parse(msg);
248
+ } catch {}
249
+ }
250
+ var ret;
76
251
  var list = this.list;
77
252
  for (var i = 0, o; o = list[i++];) {
78
- client.subscribe(o.config.topic);
253
+ var topics = o.config.topic;
254
+ if (topics) {
255
+ for (var i = 0; i < topics.length; i++) {
256
+ var topic = topics[i];
257
+ if (this.match(push_topic, topic)) {
258
+ try {
259
+ ret = await o.run("main", push_topic, msg, topic, i);
260
+ } catch (error) {
261
+ $.log.error("mqtt处理程序错误", error);
262
+ return
263
+ }
264
+ }
265
+ }
266
+ }
267
+ }
268
+ try {
269
+ await this.message(topic, msg);
270
+ } catch (error) {
271
+ $.log.error("mqtt处理程序错误", error);
272
+ return
273
+ }
274
+ };
275
+
276
+ /**
277
+ * 订阅
278
+ * @param {String} topic 主题
279
+ * @param {Function} func 回调函数
280
+ * @param {Number} qos 推送方式 0
281
+ * @param {Boolean} retain 保持
282
+ */
283
+ MQTT.prototype.subscribe = function(topic, func, qos = null, retain = false) {
284
+ if (qos === null || qos === undefined) {
285
+ qos = this.config.subscribe_qos || 0;
286
+ }
287
+ this.client.subscribe(topic, {
288
+ // 订阅消息方式,0为保留 , 1为确认收到1次
289
+ qos,
290
+ retain
291
+ });
292
+ if (func) {
293
+ if (!this.dict_subscribe[topic]) {
294
+ this.dict_subscribe[topic] = {};
295
+ }
296
+ var key = this.key_num + 1;
297
+ this.dict_subscribe[topic][key] = func;
298
+ return key;
299
+ }
300
+ }
301
+
302
+ /**
303
+ * 取消订阅
304
+ * @param {String} topic 主题
305
+ * @param {String} key 主键
306
+ */
307
+ MQTT.prototype.unsubscribe = function(topic, key) {
308
+ this.client.unsubscribe(topic);
309
+ if (this.dict_subscribe[topic]) {
310
+ delete this.dict_subscribe[topic][key];
311
+ }
312
+ }
313
+
314
+ /**
315
+ * 结束客户端
316
+ */
317
+ MQTT.prototype.end = function() {
318
+ this.client.end();
319
+ };
320
+
321
+ /**
322
+ * 发布主题
323
+ * @param {String} topic 主题
324
+ * @param {Object} message 消息对象
325
+ * @param {Number} qos 推送方式 0
326
+ * @param {Boolean} retain 保持
327
+ */
328
+ MQTT.prototype.publish = function(topic, message, qos = null, retain = false) {
329
+ if (qos === null || qos === undefined) {
330
+ qos = this.config.publish_qos || 0;
79
331
  }
332
+ // console.log("发布", qos, topic);
333
+ this.client.publish(topic, message, {
334
+ qos,
335
+ retain
336
+ });
337
+ };
338
+
339
+ /**
340
+ * 主题推送
341
+ * @param {String} topic 主题
342
+ * @param {Object} msgObj 消息对象
343
+ * @param {Number} qos 推送方式 0
344
+ * @param {Boolean} retain 保持
345
+ */
346
+ MQTT.prototype.send = function(topic, msgObj, qos = null, retain = false) {
347
+ this.publish(topic, JSON.stringify(msgObj), qos, retain);
80
348
  };
81
349
 
82
350
  /**
83
- * 加载插件
84
- * @param {String} path 检索路径
85
- * @param {Boolean} isApp 是否APP
351
+ * 请求
352
+ * @param {String} topic 主题
353
+ * @param {String} method 请求方法
354
+ * @param {Object} params 请求参数
355
+ * @param {Function} func 回调函数
86
356
  */
87
- MQTT.prototype.load = function(path) {
88
- if (!path) {
89
- path = "./mqtt/";
357
+ MQTT.prototype.req = function(topic, method, params, func) {
358
+ var data = {
359
+ id: this.client.options.clientId + "_" + Date.parse(new Date()),
360
+ method,
361
+ params
362
+ };
363
+
364
+ if (func) {
365
+ data.func = func;
366
+ this.list_msg.push(data);
90
367
  }
91
- // 获取所有应用路径
92
- var list_scope = $.dir.getAll(path, "mqtt");
368
+ this.send(topic, data);
369
+ };
93
370
 
94
- // 遍历目录路径
371
+ /**
372
+ * 同步请求 - 可及时取回消息
373
+ * @param {String} method 请求方法
374
+ * @param {Object} params 传递参数
375
+ * @returns {Object} 返回响应结果
376
+ */
377
+ MQTT.prototype.reqASync = function(topic, method, params) {
95
378
  var _this = this;
96
- list_scope.map(async function(f) {
97
- var list_file = $.file.getAll(f, "*" + _this.type + ".json");
98
- list_file.map(async (file) => {
99
- var dir = file.dirname();
100
- if (file.hasFile()) {
101
- var obj = new Drive(dir);
102
- obj.load(file);
103
- if (obj.config.name) {
104
- _this.list.push(obj);
105
- }
106
- }
379
+ return new Promise((resolve, reject) => {
380
+ var hasMsg;
381
+ _this.req(topic, method, params, (res) => {
382
+ hasMsg = true;
383
+ resolve(res);
107
384
  });
385
+ setTimeout(function() {
386
+ if (!hasMsg) {
387
+ resolve(null);
388
+ reject("request timeout!");
389
+ }
390
+ }, 3000);
108
391
  });
109
- }
392
+ };
110
393
 
111
394
  module.exports = MQTT;
112
395
 
@@ -136,5 +419,4 @@ function mqtt_admin(scope, title) {
136
419
  * @param {string} title 标题
137
420
  * @return {Object} 返回一个缓存类
138
421
  */
139
- $.mqtt_admin = mqtt_admin;
140
-
422
+ $.mqtt_admin = mqtt_admin;
@@ -0,0 +1,327 @@
1
+ const MQTT = require('mqtt');
2
+ const {
3
+ v4
4
+ } = require('uuid');
5
+
6
+
7
+ class MM_mqtt {
8
+ /**
9
+ * 构造函数
10
+ * @param {Object} config 配置参数
11
+ */
12
+ constructor(config) {
13
+ var clientId = v4();
14
+ this.config = Object.assign({
15
+ hostname: "127.0.0.1",
16
+ port: "",
17
+ protocol: "ws",
18
+ clientId,
19
+ subscribe_qos: 0,
20
+ publish_qos: 1,
21
+ username: "demo",
22
+ password: "asd123",
23
+ clean: false,
24
+ topic_receive: "client/message/",
25
+ longtime: 15000,
26
+ // maxInflight: 20,
27
+ // 重连间隔
28
+ interval: 6000
29
+ }, config);
30
+
31
+ // mqtt客户端服务器
32
+ this.client = null;
33
+
34
+ /**
35
+ * message queue
36
+ */
37
+ this.list_msg = [
38
+ /*
39
+ {
40
+ // information ID
41
+ id: "",
42
+ // request method
43
+ method: "",
44
+ // message parameters
45
+ params: {},
46
+ // Callback
47
+ func: function(res){}
48
+ }
49
+ */
50
+ ];
51
+
52
+ /**
53
+ * 订阅集合 (主题 => 函数列表)
54
+ */
55
+ this.dict_subscribe = {};
56
+
57
+ /**
58
+ * method collection
59
+ */
60
+ this.methods = {
61
+ /**
62
+ * Provide to the server to see how many open functions there are
63
+ */
64
+ get_method: function() {
65
+ return Object.keys(_this.methods)
66
+ }
67
+ };
68
+
69
+ this.retryTimes = 0;
70
+ this.connecting = false;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * 重新连接
76
+ */
77
+ MM_mqtt.prototype.reconnect = function() {
78
+ this.retryTimes += 1;
79
+ if (this.retryTimes > 5) {
80
+ try {
81
+ this.client.end();
82
+ $.sleep(this.config.interval);
83
+ this.init();
84
+ } catch (error) {
85
+ this.$message.error(error.toString());
86
+ }
87
+ }
88
+ }
89
+
90
+ /**
91
+ * 初始化
92
+ * @param {Object} config 配置参数
93
+ */
94
+ MM_mqtt.prototype.init = function(config) {
95
+ this.config = Object.assign(this.config, config);
96
+ this.client = {
97
+ connected: false,
98
+ };
99
+ this.retryTimes = 0;
100
+ this.connecting = false;
101
+ };
102
+
103
+ /**
104
+ * 运行MQTT
105
+ */
106
+ MM_mqtt.prototype.run = function(config) {
107
+ this.connecting = true;
108
+ var err;
109
+ try {
110
+ var cg = Object.assign(this.config, config);
111
+ if (cg.host) {
112
+ delete cg.hostname;
113
+ delete cg.port;
114
+ this.client = MQTT.connect(cg.host, cg);
115
+ } else {
116
+ this.client = MQTT.connect(cg);
117
+ }
118
+ if (this.client.on) {
119
+ return new Promise((resolve, reject) => {
120
+ this.client.on('connect', (packet, err) => {
121
+ this.connecting = false;
122
+ if (err) {
123
+ resolve(null);
124
+ reject(err);
125
+ } else {
126
+ this.client.on('message', async(topic, message) => {
127
+ await this.receive(topic, message.toString());
128
+ });
129
+ resolve(packet);
130
+ }
131
+ });
132
+ this.client.on("reconnect", this.reconnect);
133
+ this.client.on("error", (error) => {
134
+ console.error("Connection failed", error);
135
+ });
136
+ });
137
+ }
138
+ } catch (error) {
139
+ this.connecting = false;
140
+ err = error;
141
+ }
142
+ return new Promise((resolve, reject) => {
143
+ resolve(null);
144
+ reject(err);
145
+ });
146
+ };
147
+
148
+ /**
149
+ * 监听事件
150
+ * @param {String} eventName
151
+ * @param {Function} func
152
+ */
153
+ MM_mqtt.prototype.on = function(eventName, func) {
154
+ this.client.on(eventName, func);
155
+ };
156
+
157
+ /**
158
+ * 接收消息
159
+ * @param {String} topic 订阅板块
160
+ * @param {Object} msg 消息主体
161
+ */
162
+ MM_mqtt.prototype.message = async function(topic, msg) {
163
+ if (this.dict_subscribe[topic]) {
164
+ var list = this.dict_subscribe[topic];
165
+ try {
166
+ for (var key in list) {
167
+ list[key](msg);
168
+ }
169
+ } catch (err) {
170
+ console.error(err);
171
+ }
172
+ }
173
+ }
174
+
175
+
176
+ /**
177
+ * 接收消息
178
+ * @param {String} topic 订阅
179
+ * @param {Object} bodyStr 消息主体
180
+ */
181
+ MM_mqtt.prototype.receive = async function(topic, bodyStr) {
182
+ var json;
183
+ if (bodyStr && (bodyStr.indexOf('[') === 0) || bodyStr.indexOf('{') === 0) {
184
+ try {
185
+ json = JSON.parse(bodyStr);
186
+ } catch {}
187
+ }
188
+ if (json) {
189
+ var id = json.id;
190
+ if (json.result && id) {
191
+ var lt = this.list_msg;
192
+ var len = lt.length;
193
+ var has = false;
194
+ for (var i = 0; i < len; i++) {
195
+ var o = lt[i];
196
+ if (id === o.id) {
197
+ o.func(json.result);
198
+ lt.splice(i, 1);
199
+ has = true;
200
+ break;
201
+ }
202
+ }
203
+ if (has) {
204
+ return;
205
+ }
206
+ } else if (json.method) {
207
+ var func;
208
+ var methods = this.methods;
209
+ var arr = json.method.split('.');
210
+ for (var i = 0; i < arr.length; i++) {
211
+ var m = methods[arr[i]];
212
+ if (m) {
213
+ methods = m;
214
+ }
215
+ }
216
+ if (methods && typeof(methods) == 'function') {
217
+ func = methods;
218
+ }
219
+ if (func) {
220
+ var params = json.params;
221
+ var from = params.from;
222
+ var ret = func(params);
223
+ if (ret) {
224
+ var obj = {};
225
+ if (id) {
226
+ obj.id = id
227
+ }
228
+ obj.result = ret;
229
+ if (from) {
230
+ var topic_receive = this.config.topic_receive + from;
231
+ this.send(topic_receive, obj);
232
+ }
233
+ }
234
+ return;
235
+ }
236
+ }
237
+ await this.message(topic, json);
238
+ return
239
+ }
240
+ await this.message(topic, bodyStr);
241
+ };
242
+
243
+
244
+ MM_mqtt.prototype.subscribe = function(topic, func, qos = null, retain = false) {
245
+ if (qos === null || qos === undefined) {
246
+ qos = this.config.subscribe_qos || 0;
247
+ }
248
+ // console.log("订阅", qos);
249
+ this.client.subscribe(topic, {
250
+ // 订阅消息方式,0为保留 , 1为确认收到1次
251
+ qos,
252
+ retain
253
+ });
254
+ if (func) {
255
+ if (!this.dict_subscribe[topic]) {
256
+ this.dict_subscribe[topic] = {};
257
+ }
258
+ var key = this.key_num + 1;
259
+ this.dict_subscribe[topic][key] = func;
260
+ return key;
261
+ }
262
+ }
263
+
264
+ MM_mqtt.prototype.unsubscribe = function(topic, key) {
265
+ this.client.unsubscribe(topic);
266
+ if (this.dict_subscribe[topic]) {
267
+ delete this.dict_subscribe[topic][key];
268
+ }
269
+ }
270
+
271
+ MM_mqtt.prototype.end = function() {
272
+ this.client.end();
273
+ };
274
+
275
+ MM_mqtt.prototype.publish = function(topic, message, qos = null, retain = false) {
276
+ if (qos === null || qos === undefined) {
277
+ qos = this.config.publish_qos || 0;
278
+ }
279
+ // console.log("发布", qos, topic);
280
+ this.client.publish(topic, message, {
281
+ qos,
282
+ retain
283
+ });
284
+ };
285
+
286
+ MM_mqtt.prototype.send = function(topic, msgObj) {
287
+ this.publish(topic, JSON.stringify(msgObj));
288
+ };
289
+
290
+ MM_mqtt.prototype.req = function(topic, method, params, func) {
291
+ var data = {
292
+ id: this.client.options.clientId + "_" + Date.parse(new Date()),
293
+ method,
294
+ params
295
+ };
296
+
297
+ if (func) {
298
+ data.func = func;
299
+ this.list_msg.push(data);
300
+ }
301
+ this.send(topic, data);
302
+ };
303
+
304
+ /**
305
+ * 同步请求 - 可及时取回消息
306
+ * @param {String} method 请求方法
307
+ * @param {Object} params 传递参数
308
+ * @returns {Object} 返回响应结果
309
+ */
310
+ MM_mqtt.prototype.reqASync = function(topic, method, params) {
311
+ var _this = this;
312
+ return new Promise((resolve, reject) => {
313
+ var hasMsg;
314
+ _this.req(topic, method, params, (res) => {
315
+ hasMsg = true;
316
+ resolve(res);
317
+ });
318
+ setTimeout(function() {
319
+ if (!hasMsg) {
320
+ resolve(null);
321
+ reject("request timeout!");
322
+ }
323
+ }, 3000);
324
+ });
325
+ };
326
+
327
+ module.exports = MM_mqtt;