mm_os 2.1.8 → 2.2.0

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.
@@ -250,6 +250,7 @@ Event.prototype.after = async function(target, ctx, db) {
250
250
  * @return {Object} 执行结果
251
251
  */
252
252
  Event.prototype.run = async function(target, ctx, db) {
253
+ console.log("运行了", target, ctx, db);
253
254
  if (!db) {
254
255
  db = {
255
256
  ret: null
@@ -11,17 +11,25 @@ class Eventer {
11
11
  this.dict = {};
12
12
  this.list_add = [];
13
13
  this.list_del = [];
14
+ // 模式,0为执行完不重载程序,1为执行完后重载程序。
15
+ this.mode = 0;
16
+ // 自增ID,用于添加事件处理程序后可控更新和卸载。
14
17
  this.autoId = 1;
15
18
  }
16
19
  }
17
20
 
18
21
  /**
19
- * 模型
22
+ * 事件模型
23
+ * @param {String|Number} id ID,用于标识查找事件,方便调用、更替和删除
20
24
  */
21
- Eventer.prototype.model = function() {
25
+ Eventer.prototype.model = function(id = "") {
26
+ if (!id) {
27
+ id = this.autoId;
28
+ this.autoId++;
29
+ }
22
30
  return {
23
- // 定时器ID
24
- id: 0,
31
+ // 事件ID
32
+ id,
25
33
  // 消息类型
26
34
  type: "发动攻击时",
27
35
  // 时态
@@ -46,21 +54,37 @@ Eventer.prototype.model = function() {
46
54
  * @param {Object} param 回调附加参数
47
55
  * @param {String} tense 时态 before执行前|check确认是否执行|main执行|after执行后
48
56
  * @param {Number} count 执行次数
57
+ * @param {String|Number} id ID,用于标识查找事件,方便调用、更替和删除
49
58
  */
50
- Eventer.prototype.add = function(type, func, param, tense, count = -1) {
51
- var id = this.autoId;
52
- var info = {
53
- id,
54
- type,
55
- tense: tense || "main",
56
- num: 0,
57
- state: 1,
58
- count,
59
- param,
60
- func
61
- };
59
+ Eventer.prototype.add = function(type, func, param, tense, count = -1, id = "") {
60
+ var info;
61
+ if (typeof(type) === "object") {
62
+ info = type;
63
+ if (!info.id) {
64
+ if (!id) {
65
+ id = this.autoId;
66
+ this.autoId++;
67
+ }
68
+ info.id = id;
69
+ }
70
+ } else {
71
+ if (!id) {
72
+ id = this.autoId;
73
+ this.autoId++;
74
+ }
75
+
76
+ info = {
77
+ id,
78
+ type,
79
+ tense: tense || "main",
80
+ num: 0,
81
+ state: 1,
82
+ count,
83
+ param,
84
+ func
85
+ };
86
+ }
62
87
  this.list_add.push(info);
63
- this.autoId++;
64
88
  return id;
65
89
  }
66
90
 
@@ -1,12 +1,36 @@
1
1
  {
2
- // mqtt订阅的主题
3
- "topic": "{1}",
4
- // 名称
2
+ // 名称, 由中英文和下“_”组成, 用于修改或卸载 例如: demo
5
3
  "name": "{0}",
6
- // mqtt标题
7
- "title": "示例订阅",
8
- // 描述,用来介绍该mqtt程序是做什么用的
9
- "description": "用来测试",
10
- // mqtt调用的脚本文件
11
- "func_file": "./index.js"
12
- }
4
+ // mqtt 服务标题
5
+ "title": "",
6
+ // mqtt 服务介绍
7
+ "description": "",
8
+ // 状态 0未启用,1启用
9
+ "state": 1,
10
+ // 订阅的主题
11
+ "topic": ["mqtt/server/sn/#", "mqtt/face/sn/#"],
12
+ // 主题回复
13
+ "topic_receive": ["mqtt/client/", "mqtt/face/"],
14
+ // 给客户端推送的主题
15
+ "topic_push": "mqtt/client/${clientid}",
16
+ // 接收方式
17
+ "qos": 1,
18
+ // 保持接收
19
+ "retain": true,
20
+ // 超时反馈
21
+ "longtime": 60000,
22
+ // 调用的脚本
23
+ "func_file": "./index.js",
24
+ // 客户端ID
25
+ "clientid": "clientid",
26
+ // 消息ID
27
+ "msgid": "msgid",
28
+ // 请求方法
29
+ "method": "operator",
30
+ // 参数
31
+ "params": "info",
32
+ // 结果
33
+ "result": "result",
34
+ // 回复方法
35
+ "method_receive": "${method}-Ack"
36
+ }
@@ -1,5 +1,8 @@
1
+ const os = require('os');
2
+ const util = require('util');
1
3
  const Item = require('mm_machine').Item;
2
4
 
5
+
3
6
  /**
4
7
  * mqtt驱动类
5
8
  * @extends {Item}
@@ -22,41 +25,49 @@ class Drive extends Item {
22
25
  this.config = {
23
26
  // 名称, 由中英文和下“_”组成, 用于修改或卸载 例如: demo
24
27
  "name": "",
25
- // 状态 0未启用,1启用
26
- "state": 1,
27
- // 订阅的主题
28
- "topic": "",
29
28
  // mqtt 服务标题
30
29
  "title": "",
31
30
  // mqtt 服务介绍
32
31
  "description": "",
32
+ // 状态 0未启用,1启用
33
+ "state": 1,
34
+ // 订阅的主题
35
+ "topic": [],
36
+ // 主题回复
37
+ "topic_receive": [],
38
+ // 给客户端推送的主题
39
+ "topic_push": "mqtt/client/${clientid}",
40
+ // 接收方式
41
+ "qos": 1,
42
+ // 推送方式
43
+ "qos_push": 1,
44
+ // 保持接收
45
+ "retain": true,
46
+ // 超时反馈
47
+ "longtime": 10000,
33
48
  // 调用的脚本
34
- "func_file": "./index.js"
49
+ "func_file": "./index.js",
50
+ // 消息ID
51
+ "clientid": "clientid",
52
+ // 消息ID
53
+ "msgid": "msgid",
54
+ // 请求方法
55
+ "method": "method",
56
+ // 参数
57
+ "params": "params",
58
+ // 结果
59
+ "result": "result",
60
+ // 回复方法
61
+ "method_receive": "${method}-Ack"
35
62
  };
36
63
 
37
64
  // 开放给前端调用的函数
38
65
  this.methods = Object.assign({}, $.methods);
39
- }
40
- }
41
66
 
42
- /**
43
- * 新建脚本
44
- * @param {String} 文件
45
- */
46
- Drive.prototype.new_script = function(file) {
47
- var fl = __dirname + "/script.js";
48
- if (fl.hasFile()) {
49
- var text = fl.loadText();
50
- if (text) {
51
- var l = $.slash;
52
- if (file.indexOf('mqtt' + l) !== -1) {
53
- var name = file.between('mqtt' + l, l);
54
- text = text.replaceAll("{0}", name);
55
- }
56
- file.saveText(text);
57
- }
67
+ // 消息字典
68
+ this.drives = {};
58
69
  }
59
- };
70
+ }
60
71
 
61
72
  /**
62
73
  * 配置示例
@@ -71,17 +82,41 @@ Drive.prototype.model = function() {
71
82
  // "topic": "$SYS/mm/service/state"
72
83
  return {
73
84
  // 名称, 由中英文和下“_”组成, 用于修改或卸载 例如: demo
74
- "name": "demo",
85
+ "name": "demo_test",
86
+ // mqtt 服务标题
87
+ "title": "示例MQTT",
88
+ // mqtt 服务介绍
89
+ "description": "",
75
90
  // 状态 0未启用,1启用
76
91
  "state": 1,
77
92
  // 订阅的主题
78
- "topic": "$SYS/mm/service/user/state",
79
- // mqtt 服务标题
80
- "title": "用户状态",
81
- // mqtt 服务介绍
82
- "description": "用于用户登录状态改变时,如1登录、2隐身、3高调、4离线",
93
+ "topic": ["mqtt/server/sn/#", "mqtt/face/sn/#"],
94
+ // 回复订阅主题
95
+ "topic_receive": ["mqtt/client/", "mqtt/face/"],
96
+ // 给客户端推送的主题
97
+ "topic_push": "mqtt/client/${clientid}",
98
+ // 接收方式
99
+ "qos": 1,
100
+ // 推送方式
101
+ "qos_push": 1,
102
+ // 保持接收
103
+ "retain": true,
104
+ // 超时反馈
105
+ "longtime": 10000,
83
106
  // 调用的脚本
84
- "func_file": "./index.js"
107
+ "func_file": "./index.js",
108
+ // 消息ID
109
+ "clientid": "clientid",
110
+ // 消息ID
111
+ "msgid": "msgid",
112
+ // 请求方法
113
+ "method": "method",
114
+ // 参数
115
+ "params": "params",
116
+ // 结果
117
+ "result": "result",
118
+ // 回复方法
119
+ "method_receive": "${method}-Ack"
85
120
  }
86
121
  }
87
122
 
@@ -105,35 +140,372 @@ Drive.prototype.new_config = function(file) {
105
140
  };
106
141
 
107
142
  /**
108
- * 发送消息 —— 会发送给所有目标
109
- * @param {String} topic 推送的主题
110
- * @param {Object} msg 消息正文
143
+ * 获取IP
144
+ * @returns {String} 返回IP地址
111
145
  */
112
- Drive.prototype.send = async function(topic, msg) {
146
+ Drive.prototype.get_ip = function() {
147
+ const interfaces = os.networkInterfaces();
148
+ for (const iface of Object.values(interfaces)) {
149
+ for (const config of iface) {
150
+ if (config.family === 'IPv4' && !config.internal) {
151
+ return config.address;
152
+ }
153
+ }
154
+ }
155
+ return '127.0.0.1'; // 如果没有找到,返回本地回环地址
156
+ }
113
157
 
114
- };
158
+ /**
159
+ * 新建消息ID
160
+ * @param {String} method 方法
161
+ * @param {String} terminal 终端
162
+ */
163
+ Drive.prototype.get_msgid = function(method, terminal = 'server') {
164
+ var time = new Date().getTime();
165
+ var ip = this.get_ip();
166
+ // var msgid = "ID:localhost-" + clientid + "-" + time;
167
+ var msgid = `${terminal}:${ip}-${time}-${method}`;
168
+ return msgid;
169
+ }
115
170
 
116
171
  /**
117
- * 接收订阅消息
118
- * @param {String} topic 推送的主题
119
- * @param {Object} msg 消息正文
172
+ * 回复的方法格式
173
+ * @param {String} method 方法
174
+ * @param {String} terminal 终端
120
175
  */
121
- Drive.prototype.main = async function(topic, msg) {
122
- return null;
123
- };
176
+ Drive.prototype.get_method = function(method) {
177
+ var str = this.config.method_receive;
178
+ return str.replace("${method}", method);
179
+ }
180
+
181
+ /**
182
+ * 获取KEY
183
+ * @param {String} method 方法
184
+ * @param {String} clientid 客户端ID
185
+ * @param {String} msgid 消息ID
186
+ */
187
+ Drive.prototype.get_receive_key = function(method, clientid, msgid) {
188
+ return this.get_method(method) + "_" + clientid + "_" + msgid;
189
+ }
190
+
191
+ /**
192
+ * 获取KEY
193
+ * @param {String} method 方法
194
+ * @param {String} clientid 客户端ID
195
+ * @param {String} msgid 消息ID
196
+ */
197
+ Drive.prototype.get_key = function(method, clientid, msgid) {
198
+ return method + "_" + clientid + "_" + msgid;
199
+ }
200
+
201
+ /**
202
+ * 补全路径
203
+ * @param {String} src
204
+ * @returns {String} 返回完整的路径
205
+ */
206
+ Drive.prototype.fullUrl = function(src) {
207
+ if (!src) {
208
+ return ""
209
+ }
210
+ if (src.indexOf("http") !== 0) {
211
+ if (src.indexOf("~/") === 0) {
212
+ src = src.replace('~/', $.host);
213
+ } else if (src.indexOf("/") === 0) {
214
+ src = src.replace('/', $.host);
215
+ }
216
+ }
217
+ return src;
218
+ }
219
+
220
+ /**
221
+ * 推送消息
222
+ * @param {String} topic 推送主题
223
+ * @param {Object} msg 推送内容
224
+ * @param {Number} qos 接收方式
225
+ * @param {Boolean} retain 是否保持推送
226
+ */
227
+ Drive.prototype.send = function(topic, msg, qos = 0, retain = false) {
228
+
229
+ }
230
+
231
+ /**
232
+ * 收到消息
233
+ * @param {String} push_topic 推送过来的主题
234
+ * @param {Object} msg 原消息
235
+ * @param {Number} index 索引
236
+ * @param {String} topic 订阅的主题
237
+ */
238
+ Drive.prototype.message = async function(push_topic, msg, index, topic) {
239
+ // console.log("请求后", push_topic, msg, index, topic);
240
+ }
241
+
242
+ /**
243
+ * 推送消息到设备
244
+ * @param {String} clientid 客户端ID
245
+ * @param {Object} msg 消息主题
246
+ * @param {Function} func 回调函数
247
+ */
248
+ Drive.prototype.pushSync = function(clientid, msg, func, longtime = 0) {
249
+ var {
250
+ msgid,
251
+ method,
252
+ params,
253
+ topic_push,
254
+ qos_push
255
+ } = this.config;
256
+ var id = msg[msgid];
257
+ if (!id) {
258
+ msg[msgid] = this.get_msgid(msg[method], 'server');
259
+ id = msg[msgid];
260
+ }
261
+ var key = this.get_receive_key(msg[method], clientid, id);
262
+ if (func) {
263
+ if (!this.drives[clientid]) {
264
+ this.drives[clientid] = {}
265
+ }
266
+
267
+ this.drives[clientid][key] = {
268
+ clientid,
269
+ id,
270
+ func
271
+ };
272
+ }
273
+
274
+ var topic = this.get_topic(topic_push, clientid);
275
+ this.send(topic, msg, qos_push);
276
+ if (func) {
277
+ if (!longtime) {
278
+ longtime = this.config.longtime || 60000;
279
+ }
280
+ var timer = setTimeout(() => {
281
+ // 如果时间到了,回调函数还在队列中,则视为无回复
282
+ if (this.drives[clientid][key]) {
283
+ this.del_msg(clientid, key);
284
+ func(null);
285
+ }
286
+ }, longtime);
287
+ }
288
+ }
289
+
290
+ /**
291
+ * 推送消息
292
+ * @param {String} clientid 客户端ID
293
+ * @param {Object} msg 信息
294
+ * @param {Number} longtime 超时回馈
295
+ */
296
+ Drive.prototype.pushS = function(clientid, msg, longtime) {
297
+ var _this = this;
298
+ return new Promise(function(resolve, reject) {
299
+ _this.pushSync(clientid, msg, (res) => {
300
+ resolve(res);
301
+ }, longtime);
302
+ });
303
+ }
304
+
305
+ /**
306
+ * 推送消息
307
+ * @param {String} method 方法
308
+ * @param {String} clientid 客户端ID
309
+ * @param {Object} params 信息
310
+ * @param {Number} longtime 超时回馈
311
+ */
312
+ Drive.prototype.push = function(method, clientid, params, longtime = 0) {
313
+ var cg = this.config;
314
+ var msg = {};
315
+ cg[cg.msgid] = this.get_msgid(method);
316
+ cg[cg.method] = method;
317
+ cg[cg.params] = params;
318
+ return this.pushS(clientid, msg);
319
+ }
320
+
321
+ /**
322
+ * 删除消息
323
+ * @param {String} clientid 设备ID
324
+ * @param {String} key 消息键
325
+ */
326
+ Drive.prototype.del_msg = function(clientid, key) {
327
+ if (this.drives[clientid]) {
328
+ var dict = this.drives[clientid];
329
+ delete dict[key];
330
+ }
331
+ }
332
+
333
+ /**
334
+ * 处理事件
335
+ * @param {String} key 键
336
+ * @param {Object} json 信息
337
+ */
338
+ Drive.prototype.run_event = function(clientid, key, json) {
339
+ var method = key.left("_");
340
+ var func = this[method + "_event"];
341
+ if (func) {
342
+ func(clientid, json);
343
+ }
344
+ }
345
+
346
+ /**
347
+ * 执行响应
348
+ * @param {String} key 键
349
+ * @param {String} msgid 消息ID
350
+ * @param {Object} json 信息
351
+ */
352
+ Drive.prototype.exec = async function(clientid, key, json) {
353
+ var o;
354
+ if (this.drives[clientid]) {
355
+ o = this.drives[clientid][key];
356
+ }
357
+ if (o) {
358
+ delete this.drives[clientid][key];
359
+ await o.func(json);
360
+ } else {
361
+ await this.run_event(clientid, key, json);
362
+ }
363
+ return o;
364
+ }
124
365
 
125
366
  /**
126
- * 初始化函数, 用于定义开放给前端的函数
367
+ * 获取客户端ID
368
+ * @param {String} push_topic 推送过来的主题
369
+ * @param {Object} msg 消息
370
+ * @param {String} topic 订阅的主题
127
371
  */
128
- Drive.prototype.init = async function init() {
372
+ Drive.prototype.get_clientid = function(push_topic, msg, topic) {
373
+ var cg = this.config;
374
+ var str = topic.left("#");
375
+ var clientid = push_topic.between(str, "/");
376
+ return clientid;
377
+ }
378
+
379
+ /**
380
+ * 数据格式转换-转入
381
+ * @param {String} push_topic 推送过来的主题
382
+ * @param {Object} msg 消息主体
383
+ * @param {Number} index 索引
384
+ * @param {String} topic 订阅的主题
385
+ */
386
+ Drive.prototype.convert_in = function(push_topic, msg, topic, index) {
387
+ var cg = this.config;
388
+ var clientid = msg[cg.clientid] || this.get_clientid(push_topic, msg, topic);
389
+ var method = msg[cg.method];
390
+ var json = {
391
+ clientid,
392
+ id: msg[cg.msgid] || this.get_msgid(method, 'client'),
393
+ method
394
+ };
395
+
396
+ if (msg[cg.params]) {
397
+ json.params = msg[cg.params]
398
+ }
399
+ if (msg[cg.result]) {
400
+ json.result = msg[cg.result]
401
+ }
402
+ return json;
403
+ }
404
+
405
+ /**
406
+ * 数据格式转换-转出
407
+ * @param {String} push_topic 推送过来的主题
408
+ * @param {Object} msg 消息主体
409
+ * @param {Number} index 索引
410
+ * @param {String} topic 订阅的主题
411
+ */
412
+ Drive.prototype.convert_out = function(push_topic, msg, topic, index) {
413
+ return msg;
414
+ }
415
+
416
+ /**
417
+ * 获取回复主题
418
+ * @param {String} topic_tpl 主题模板
419
+ * @param {String} clientid 客户端ID
420
+ * @param {Object} params 消息
421
+ * @returns 返回主题
422
+ */
423
+ Drive.prototype.get_topic = function(topic_tpl, clientid, params) {
424
+ return (topic_tpl || "").replace("${clientid}", clientid);
425
+ }
426
+
427
+ /**
428
+ * 处理函数, 用于处理订阅内容
429
+ * @param {String} push_topic 推送过来的主题
430
+ * @param {Object} body 消息格式
431
+ * @param {String} topic 订阅的主题
432
+ * @param {Number} index 索引
433
+ * @return {Object} 返回执行结果
434
+ */
435
+ Drive.prototype.handle = async function(push_topic, msg, topic, index) {
436
+ var json = this.convert_in(push_topic, msg, topic, index);
437
+ var id = json.id;
438
+ if (json.result && id) {
439
+ var key = this.get_key(json.method, json.clientid, id);
440
+ var o = await this.exec(json.clientid, key, json.result);
441
+ if (o) {
442
+ return
443
+ }
444
+ }
129
445
 
446
+ if (json.method) {
447
+ var func;
448
+ var methods = this.methods;
449
+ var arr = json.method.split('.');
450
+ for (var i = 0; i < arr.length; i++) {
451
+ var key = arr[i];
452
+ var m = methods[key];
453
+ if (m) {
454
+ methods = m;
455
+ }
456
+ }
457
+ if (methods && typeof(methods) == 'function') {
458
+ func = methods;
459
+ }
460
+ if (func) {
461
+ var id = json.id;
462
+ var params = json.params;
463
+ var ret = func(json.clientid, params, msg, id);
464
+ if (ret) {
465
+ if (util.types.isPromise(ret)) {
466
+ ret = await ret;
467
+ }
468
+ if (ret) {
469
+ var arr_tc = this.config.topic_receive;
470
+ if (arr_tc.length > index) {
471
+ var obj = {};
472
+ var cg = this.config;
473
+ if (id) {
474
+ obj[cg.msgid] = id;
475
+ }
476
+ obj[cg.method] = this.get_method(json.method);
477
+ obj[cg.result] = ret;
478
+ var topic_receive = this.get_topic(arr_tc[index], json.clientid, params);
479
+ var reply_msg = this.convert_out(topic_receive, obj, topic, index);
480
+ this.send(topic_receive, reply_msg);
481
+ }
482
+ }
483
+ }
484
+ }
485
+ }
486
+ return
130
487
  };
131
488
 
132
489
  /**
133
- * 加载完成时
490
+ * 主函数, 用于接收并处理订阅内容
491
+ * @param {String} push_topic 推送过来的主题
492
+ * @param {Object} body 消息格式
493
+ * @param {String} topic 订阅的主题
494
+ * @param {Number} index 索引
495
+ * @return {Object} 返回执行结果
496
+ */
497
+ Drive.prototype.main = async function(push_topic, msg, index, topic) {
498
+ return this.handle(push_topic, msg, topic, index);
499
+ }
500
+
501
+ /**
502
+ * 接收订阅消息
503
+ * @param {Object} push_topic 主题
504
+ * @param {Object} msg 消息正文
134
505
  */
135
- Drive.prototype.load_after = function() {
136
- this.init();
506
+ Drive.prototype.main_after = async function(ret, push_topic, msg, topic, index) {
507
+ await this.message(push_topic, msg, topic, index);
137
508
  };
138
509
 
139
- module.exports = Drive;
510
+
511
+ module.exports = Drive;