mm_os 4.3.6 → 5.0.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.
- package/README.md +101 -504
- package/index.js +26 -19
- package/lib/loader.js +787 -0
- package/lib/os.js +369 -0
- package/package.json +55 -80
- package/LICENSE +0 -21
- package/README_EN.md +0 -505
- package/adapter/adapter.js +0 -484
- package/adapter/custom_persistence.js +0 -661
- package/adapter/mqtt.js +0 -254
- package/adapter/socket.js +0 -244
- package/adapter/web.js +0 -92
- package/adapter/websocket.js +0 -43
- package/ai.js +0 -130
- package/com/api/README.md +0 -3
- package/com/api/com.json +0 -5
- package/com/api/config.tpl.json +0 -41
- package/com/api/drive.js +0 -732
- package/com/api/index.js +0 -201
- package/com/api/oauth.js +0 -200
- package/com/api/script.tpl.js +0 -32
- package/com/cmd/README.md +0 -11
- package/com/cmd/com.json +0 -5
- package/com/cmd/config.tpl.json +0 -48
- package/com/cmd/drive.js +0 -176
- package/com/cmd/index.js +0 -287
- package/com/cmd/job/config.json +0 -66
- package/com/cmd/job/index.js +0 -241
- package/com/cmd/job/test.js +0 -188
- package/com/cmd/msg.json +0 -48
- package/com/cmd/script.tpl.js +0 -12
- package/com/db/README.md +0 -3
- package/com/db/com.json +0 -5
- package/com/db/drive.js +0 -2206
- package/com/db/index.js +0 -241
- package/com/event/README.md +0 -4
- package/com/event/com.json +0 -5
- package/com/event/config.tpl.json +0 -20
- package/com/event/drive.js +0 -61
- package/com/event/index.js +0 -438
- package/com/event/script.tpl.js +0 -23
- package/com/mqtt/README.md +0 -47
- package/com/mqtt/com.json +0 -5
- package/com/mqtt/config.tpl.json +0 -42
- package/com/mqtt/drive.js +0 -696
- package/com/mqtt/index.js +0 -1017
- package/com/mqtt/index.test.js +0 -503
- package/com/mqtt/mm_mqtt.js +0 -446
- package/com/mqtt/script.tpl.js +0 -719
- package/com/nav/README.md +0 -2
- package/com/nav/com.json +0 -5
- package/com/nav/config.tpl.json +0 -84
- package/com/nav/drive.js +0 -702
- package/com/nav/index.js +0 -228
- package/com/nav/tpl/admin_pc/page_channel.vue +0 -305
- package/com/nav/tpl/admin_pc/page_config.vue +0 -280
- package/com/nav/tpl/admin_pc/page_config_form.vue +0 -194
- package/com/nav/tpl/admin_pc/page_default.vue +0 -247
- package/com/nav/tpl/admin_pc/page_form.vue +0 -180
- package/com/nav/tpl/admin_pc/page_lang.vue +0 -264
- package/com/nav/tpl/admin_pc/page_nav.vue +0 -321
- package/com/nav/tpl/admin_pc/page_table.vue +0 -296
- package/com/nav/tpl/admin_pc/page_type.vue +0 -321
- package/com/nav/tpl/admin_pc/page_view.vue +0 -124
- package/com/nav/tpl/dev_pc/page_channel.vue +0 -253
- package/com/nav/tpl/dev_pc/page_config.vue +0 -253
- package/com/nav/tpl/dev_pc/page_default.vue +0 -247
- package/com/nav/tpl/dev_pc/page_form.vue +0 -162
- package/com/nav/tpl/dev_pc/page_nav.vue +0 -253
- package/com/nav/tpl/dev_pc/page_table.vue +0 -247
- package/com/nav/tpl/dev_pc/page_type.vue +0 -313
- package/com/nav/tpl/home_pc/page_channel.vue +0 -234
- package/com/nav/tpl/home_pc/page_default.vue +0 -234
- package/com/nav/tpl/home_pc/page_form.vue +0 -137
- package/com/nav/tpl/home_pc/page_list.vue +0 -234
- package/com/nav/tpl/home_pc/page_nav.vue +0 -221
- package/com/nav/tpl/home_pc/page_type.vue +0 -234
- package/com/nav/tpl/home_pc/page_view.vue +0 -125
- package/com/nav/tpl/home_phone/page_channel.vue +0 -234
- package/com/nav/tpl/home_phone/page_default.vue +0 -234
- package/com/nav/tpl/home_phone/page_form.vue +0 -137
- package/com/nav/tpl/home_phone/page_list.vue +0 -234
- package/com/nav/tpl/home_phone/page_nav.vue +0 -237
- package/com/nav/tpl/home_phone/page_type.vue +0 -234
- package/com/nav/tpl/home_phone/page_view.vue +0 -125
- package/com/nav/viewmodel.js +0 -446
- package/com/param/README.md +0 -2
- package/com/param/com.json +0 -5
- package/com/param/config.tpl.json +0 -136
- package/com/param/drive.js +0 -502
- package/com/param/index.js +0 -158
- package/com/param/script.tpl.js +0 -12
- package/com/pendant/README.md +0 -3
- package/com/pendant/com.json +0 -5
- package/com/pendant/config.tpl.json +0 -32
- package/com/pendant/drive.js +0 -204
- package/com/pendant/index.js +0 -467
- package/com/pendant/pendant.html +0 -16
- package/com/pendant/script.tpl.js +0 -18
- package/com/socket/README.md +0 -47
- package/com/socket/com.json +0 -5
- package/com/socket/config.tpl.json +0 -12
- package/com/socket/drive.js +0 -679
- package/com/socket/index.js +0 -402
- package/com/socket/script.tpl.js +0 -41
- package/com/sql/README.md +0 -3
- package/com/sql/com.json +0 -5
- package/com/sql/config.tpl.json +0 -74
- package/com/sql/drive.js +0 -1283
- package/com/sql/index.js +0 -152
- package/com/sql/script.tpl.js +0 -47
- package/com/static/README.md +0 -2
- package/com/static/com.json +0 -5
- package/com/static/config.tpl.json +0 -24
- package/com/static/drive.js +0 -194
- package/com/static/index.js +0 -237
- package/com/static/script.tpl.js +0 -28
- package/com/task/README.md +0 -3
- package/com/task/com.json +0 -5
- package/com/task/config.tpl.json +0 -24
- package/com/task/drive.js +0 -428
- package/com/task/index.js +0 -159
- package/com/task/script.tpl.js +0 -40
- package/com/template/com.json +0 -5
- package/com/template/config.tpl.json +0 -16
- package/com/template/drive.js +0 -81
- package/com/template/index.js +0 -141
- package/com.js +0 -237
- package/common/README.md +0 -2
- package/common/middleware/web_after/index.js +0 -26
- package/common/middleware/web_after/middleware.json +0 -9
- package/common/middleware/web_base/index.js +0 -113
- package/common/middleware/web_base/middleware.json +0 -19
- package/common/middleware/web_before/index.js +0 -33
- package/common/middleware/web_before/middleware.json +0 -9
- package/common/middleware/web_cors/index.js +0 -87
- package/common/middleware/web_cors/middleware.json +0 -24
- package/common/middleware/web_error/index.js +0 -131
- package/common/middleware/web_error/middleware.json +0 -19
- package/common/middleware/web_ip/index.js +0 -15
- package/common/middleware/web_ip/middleware.json +0 -14
- package/common/middleware/web_logger/index.js +0 -156
- package/common/middleware/web_logger/middleware.json +0 -14
- package/common/middleware/web_main/index.js +0 -26
- package/common/middleware/web_main/middleware.json +0 -9
- package/common/middleware/web_static/index.js +0 -73
- package/common/middleware/web_static/middleware.json +0 -54
- package/common/middleware/web_waf/index.js +0 -385
- package/common/middleware/web_waf/middleware.json +0 -13
- package/core/app/config.tpl.json +0 -67
- package/core/app/index.js +0 -710
- package/core/app/script.tpl.js +0 -52
- package/core/channel/index.js +0 -899
- package/core/channel/matcher.js +0 -585
- package/core/com/config.tpl.json +0 -16
- package/core/com/index.js +0 -77
- package/core/com/script.tpl.js +0 -5
- package/core/component/component.js +0 -42
- package/core/component/config.tpl.json +0 -63
- package/core/component/index.js +0 -273
- package/core/component/script.tpl.js +0 -19
- package/core/controller/config.tpl.json +0 -14
- package/core/controller/index.js +0 -371
- package/core/controller/script.tpl.js +0 -27
- package/core/factory/config.tpl.json +0 -14
- package/core/factory/entity.js +0 -275
- package/core/factory/index.js +0 -241
- package/core/factory/script.tpl.js +0 -16
- package/core/game/bat/index.js +0 -137
- package/core/game/bat/world.js +0 -622
- package/core/game/config.tpl.json +0 -16
- package/core/game/entity_admin.js +0 -230
- package/core/game/index.js +0 -186
- package/core/handler/config.tpl.json +0 -22
- package/core/handler/index.js +0 -181
- package/core/handler/script.tpl.js +0 -23
- package/core/logic/config.tpl.json +0 -14
- package/core/logic/index.js +0 -59
- package/core/logic/script.tpl.js +0 -19
- package/core/middleware/config.tpl.json +0 -16
- package/core/middleware/index.js +0 -117
- package/core/middleware/script.tpl.js +0 -37
- package/core/mod/config.tpl.json +0 -22
- package/core/mod/index.js +0 -136
- package/core/mod/script.tpl.js +0 -34
- package/core/model/config.tpl.json +0 -219
- package/core/model/index.js +0 -272
- package/core/model/model.js +0 -27
- package/core/model/script.tpl.js +0 -20
- package/core/notifier/config.tpl.json +0 -14
- package/core/notifier/index.js +0 -77
- package/core/notifier/script.tpl.js +0 -20
- package/core/plugin/config.tpl.json +0 -36
- package/core/plugin/index.js +0 -297
- package/core/plugin/script.tpl.js +0 -51
- package/core/pusher/config.tpl.json +0 -14
- package/core/pusher/index.js +0 -158
- package/core/pusher/script.tpl.js +0 -20
- package/core/room/bat/index.js +0 -170
- package/core/room/bat/room.js +0 -524
- package/core/room/config.tpl.json +0 -20
- package/core/room/index.js +0 -249
- package/core/room/room.js +0 -61
- package/core/scene/config.tpl.json +0 -14
- package/core/scene/index.js +0 -467
- package/core/scene/loop.js +0 -1306
- package/core/scene/map.js +0 -28
- package/core/scene/script.tpl.js +0 -22
- package/core/sender/config.tpl.json +0 -14
- package/core/sender/index.js +0 -79
- package/core/sender/script.tpl.js +0 -20
- package/core/service/config.tpl.json +0 -14
- package/core/service/index.js +0 -100
- package/core/service/script.tpl.js +0 -25
- package/core/store/config.tpl.json +0 -26
- package/core/store/index.js +0 -1794
- package/core/store/script.tpl.js +0 -22
- package/core/store/sql.js +0 -1488
- package/core/system/config.tpl.json +0 -18
- package/core/system/index.js +0 -312
- package/core/system/script.tpl.js +0 -77
- package/core/view/config.tpl.json +0 -14
- package/core/view/index.js +0 -91
- package/core/view/script.tpl.js +0 -20
- package/core/zone/bat/index.js +0 -744
- package/core/zone/config.tpl.json +0 -54
- package/core/zone/index.js +0 -655
- package/core/zone/script.tpl.js +0 -10
- package/core/zone/zone_bat.js +0 -136
- package/core//345/237/272/347/261/273/346/250/241/345/235/227/346/270/205/345/215/225.md +0 -24
- package/os.js +0 -53
- package/server.js +0 -595
- package/ulits/id_gen.js +0 -134
- package/ulits/word.js +0 -206
package/com/mqtt/index.js
DELETED
|
@@ -1,1017 +0,0 @@
|
|
|
1
|
-
const Mqtt_client = require("mqtt");
|
|
2
|
-
const Manager = require("mm_machine").Manager;
|
|
3
|
-
const Drive = require("./drive");
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Mqtt通讯类
|
|
7
|
-
* @augments {Manager}
|
|
8
|
-
* @class
|
|
9
|
-
*/
|
|
10
|
-
class Mqtt extends Manager {
|
|
11
|
-
/**
|
|
12
|
-
* 配置参数
|
|
13
|
-
* @type {object}
|
|
14
|
-
*/
|
|
15
|
-
static config = {
|
|
16
|
-
/**
|
|
17
|
-
* 名称
|
|
18
|
-
* @type {string}
|
|
19
|
-
*/
|
|
20
|
-
name: "",
|
|
21
|
-
/**
|
|
22
|
-
* 标题
|
|
23
|
-
* @type {string}
|
|
24
|
-
*/
|
|
25
|
-
title: "Mqtt通讯类",
|
|
26
|
-
/**
|
|
27
|
-
* 描述
|
|
28
|
-
* @type {string}
|
|
29
|
-
*/
|
|
30
|
-
description: "这是Mqtt通讯类管理器",
|
|
31
|
-
/**
|
|
32
|
-
* 检索文件名
|
|
33
|
-
* @type {string}
|
|
34
|
-
*/
|
|
35
|
-
filename: "mqtt.json",
|
|
36
|
-
/**
|
|
37
|
-
* 模板目录
|
|
38
|
-
* @type {string}
|
|
39
|
-
*/
|
|
40
|
-
tpl_dir: __dirname,
|
|
41
|
-
/**
|
|
42
|
-
* 基础目录
|
|
43
|
-
* @type {string}
|
|
44
|
-
*/
|
|
45
|
-
base_dir: "../common/mqtt".fullname(__dirname),
|
|
46
|
-
/**
|
|
47
|
-
* 自定义目录,加载项目自定义资源
|
|
48
|
-
* @type {string}
|
|
49
|
-
*/
|
|
50
|
-
dir: "./app".fullname(),
|
|
51
|
-
/**
|
|
52
|
-
* 搜索模式 dir按目录搜索 | file按文件名搜索
|
|
53
|
-
* @type {string}
|
|
54
|
-
*/
|
|
55
|
-
search_way: "file",
|
|
56
|
-
/**
|
|
57
|
-
* 是否懒加载
|
|
58
|
-
* @type {boolean}
|
|
59
|
-
*/
|
|
60
|
-
lazy_load: false,
|
|
61
|
-
/**
|
|
62
|
-
* 模式
|
|
63
|
-
* 1.生产模式,改变文件不会重新加载
|
|
64
|
-
* 2.热更新模式,改变配置文件会重新加载配置,不重新加载脚本
|
|
65
|
-
* 3.热重载模式,改变配置文件都会加载配置和脚本
|
|
66
|
-
* 4.重载模式,执行完后重新加载脚本,避免变量污染
|
|
67
|
-
* 5.热更新+重载模式,改变配置文件重新加载配置和脚本,执行完后重新加载脚本
|
|
68
|
-
* @type {number}
|
|
69
|
-
*/
|
|
70
|
-
mode: process.env.NODE_ENV === "production" ? 1 : 3,
|
|
71
|
-
host: "",
|
|
72
|
-
hostname: "127.0.0.1",
|
|
73
|
-
port: "1883",
|
|
74
|
-
protocol: "mqtt",
|
|
75
|
-
// MQTT协议版本: 4表示MQTT 3.1.1(兼容aedes v1.x)
|
|
76
|
-
protocol_version: 4,
|
|
77
|
-
clientid: "server",
|
|
78
|
-
subscribe_qos: 2,
|
|
79
|
-
publish_qos: 2,
|
|
80
|
-
username: "server",
|
|
81
|
-
password: process.env.MQTT_PASSWORD || "",
|
|
82
|
-
table: "iot_device",
|
|
83
|
-
clean: false,
|
|
84
|
-
longtime: 15000,
|
|
85
|
-
request_timeout: 3000,
|
|
86
|
-
// 在线有效期时长判断 单位:毫秒,150000毫秒为2.5分钟
|
|
87
|
-
online_expires: 150000,
|
|
88
|
-
// 在线有效期检测间隔
|
|
89
|
-
online_interval: 10000,
|
|
90
|
-
// 连接超时
|
|
91
|
-
connect_timeout: 30000,
|
|
92
|
-
// maxInflight: 20,
|
|
93
|
-
// 重连间隔
|
|
94
|
-
reconnet_period: 6000, // 重连间隔1秒
|
|
95
|
-
/**
|
|
96
|
-
* 最大深度
|
|
97
|
-
* @type {number}
|
|
98
|
-
*/
|
|
99
|
-
max_depth: 6
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* 构造函数
|
|
104
|
-
* @param {object} config 配置参数
|
|
105
|
-
* @param {object} parent 父级模块
|
|
106
|
-
*/
|
|
107
|
-
constructor(config, parent) {
|
|
108
|
-
super({ ...Mqtt.config, ...config }, parent);
|
|
109
|
-
this.retryTimes = 0;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* 预置
|
|
115
|
-
*/
|
|
116
|
-
Mqtt.prototype._preset = function () {
|
|
117
|
-
this.dict = {};
|
|
118
|
-
// 缓存缺失记录, 用于宽容期判断幽灵在线
|
|
119
|
-
this.dict_lost = {};
|
|
120
|
-
// 定时器
|
|
121
|
-
this.timer = null;
|
|
122
|
-
// 关闭旧客户端
|
|
123
|
-
if (this.client && this.client.end) {
|
|
124
|
-
try {
|
|
125
|
-
this.client.end(true);
|
|
126
|
-
} catch {
|
|
127
|
-
// ignore close error
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
// mqtt客户端服务器
|
|
131
|
-
this.client = null;
|
|
132
|
-
/**
|
|
133
|
-
* message queue
|
|
134
|
-
*/
|
|
135
|
-
this.list_msg = [
|
|
136
|
-
/*
|
|
137
|
-
{
|
|
138
|
-
// information ID
|
|
139
|
-
id: "",
|
|
140
|
-
// request method
|
|
141
|
-
method: "",
|
|
142
|
-
// message parameters
|
|
143
|
-
params: {},
|
|
144
|
-
// Callback
|
|
145
|
-
func: function(res){}
|
|
146
|
-
}
|
|
147
|
-
*/
|
|
148
|
-
];
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* 消息ID索引 (id => message对象), 用于O(1)查找
|
|
152
|
-
*/
|
|
153
|
-
this.dict_msg = {};
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* 订阅集合 (主题 => 函数列表)
|
|
157
|
-
*/
|
|
158
|
-
this.dict_subscribe = {};
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* 正则表达式缓存 (模式字符串 => RegExp对象)
|
|
162
|
-
*/
|
|
163
|
-
this._regex_cache = {};
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* method collection
|
|
167
|
-
*/
|
|
168
|
-
var _this = this;
|
|
169
|
-
this.methods = {
|
|
170
|
-
/**
|
|
171
|
-
* 获取所有方法
|
|
172
|
-
* @returns {Array} 函数列表
|
|
173
|
-
*/
|
|
174
|
-
getMethod: function () {
|
|
175
|
-
return Object.keys(_this.methods);
|
|
176
|
-
},
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
this.retry_times = 0;
|
|
180
|
-
this.connecting = false;
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* mqtt驱动类
|
|
185
|
-
* @type {Drive}
|
|
186
|
-
*/
|
|
187
|
-
Mqtt.prototype.Drive = Drive;
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* 主题匹配
|
|
191
|
-
* @param {string} topic 接收到的主题
|
|
192
|
-
* @param {string} top 匹配用的主题
|
|
193
|
-
* @returns {boolean} 返回匹配结果,正确返回true,错误返回false
|
|
194
|
-
*/
|
|
195
|
-
Mqtt.prototype.match = function (topic, top) {
|
|
196
|
-
if (topic === top) {
|
|
197
|
-
return true;
|
|
198
|
-
}
|
|
199
|
-
var regex = this._regex_cache[top];
|
|
200
|
-
if (!regex) {
|
|
201
|
-
// 限制正则缓存大小,避免无限增长
|
|
202
|
-
if (Object.keys(this._regex_cache).length > 500) {
|
|
203
|
-
this._regex_cache = {};
|
|
204
|
-
}
|
|
205
|
-
var str =
|
|
206
|
-
"^" +
|
|
207
|
-
top
|
|
208
|
-
.replace("#", ".*")
|
|
209
|
-
.replace("+", "~~~")
|
|
210
|
-
.replace("~~~", "[a-zA-Z0-9_-]+")
|
|
211
|
-
.replace("$", "~~~")
|
|
212
|
-
.replace("~~~", "\\$");
|
|
213
|
-
var s = str.substring(str.length - 1, str.length);
|
|
214
|
-
if (s !== "#") {
|
|
215
|
-
str += "$";
|
|
216
|
-
}
|
|
217
|
-
regex = new RegExp(str);
|
|
218
|
-
this._regex_cache[top] = regex;
|
|
219
|
-
}
|
|
220
|
-
return regex.test(topic);
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* 初始化
|
|
225
|
-
*/
|
|
226
|
-
Mqtt.prototype.updateAfter = async function () {
|
|
227
|
-
var _this = this;
|
|
228
|
-
var infos = this.getInfos();
|
|
229
|
-
var promises = [];
|
|
230
|
-
|
|
231
|
-
for (var i = 0; i < infos.length; i++) {
|
|
232
|
-
var info = infos[i];
|
|
233
|
-
if (info.state === 1) {
|
|
234
|
-
var mod = this.getMod(info.name);
|
|
235
|
-
if (mod) {
|
|
236
|
-
mod.send = function (topic, msg, qos = 0, retain = false) {
|
|
237
|
-
if (topic) {
|
|
238
|
-
_this.send(topic, msg, qos, retain);
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
promises.push(
|
|
242
|
-
mod.do("init").catch((err) => {
|
|
243
|
-
console.error("MQTT mod初始化失败:", mod.config.name, err);
|
|
244
|
-
}),
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
await Promise.allSettled(promises);
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* 订阅所有已启用mod的主题
|
|
255
|
-
* 需在客户端连接成功后调用
|
|
256
|
-
* @private
|
|
257
|
-
*/
|
|
258
|
-
Mqtt.prototype._subscribeTopics = function () {
|
|
259
|
-
var mods = this.getMods();
|
|
260
|
-
for (var k in mods) {
|
|
261
|
-
var o = mods[k];
|
|
262
|
-
if (o.config.state !== 1) {
|
|
263
|
-
continue;
|
|
264
|
-
}
|
|
265
|
-
var topics = o.config.topic;
|
|
266
|
-
if (!topics) {
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
for (var n = 0; n < topics.length; n++) {
|
|
270
|
-
var tc = topics[n];
|
|
271
|
-
var retain = o.config.retain || false;
|
|
272
|
-
var qos = o.config.qos || 0;
|
|
273
|
-
if (tc.indexOf("heartbeat") !== -1) {
|
|
274
|
-
retain = false;
|
|
275
|
-
qos = 0;
|
|
276
|
-
}
|
|
277
|
-
this.subscribe(tc, null, qos, retain);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* 重新连接
|
|
284
|
-
*/
|
|
285
|
-
Mqtt.prototype.reconnect = async function () {
|
|
286
|
-
await $.sleep(this.config.reconnet_period);
|
|
287
|
-
this.retryTimes += 1;
|
|
288
|
-
if (this.retryTimes > 5) {
|
|
289
|
-
try {
|
|
290
|
-
// 保存当前订阅状态
|
|
291
|
-
var saved_subs = this.dict_subscribe;
|
|
292
|
-
this.dict_subscribe = {};
|
|
293
|
-
this.client.end();
|
|
294
|
-
this.client.removeAllListeners();
|
|
295
|
-
this.client = null;
|
|
296
|
-
// 重新初始化并启动
|
|
297
|
-
this.init();
|
|
298
|
-
await this.start();
|
|
299
|
-
// 恢复订阅
|
|
300
|
-
for (var k in saved_subs) {
|
|
301
|
-
var o = saved_subs[k];
|
|
302
|
-
var topics = o.topics || [];
|
|
303
|
-
for (var n = 0; n < topics.length; n++) {
|
|
304
|
-
var tc = topics[n];
|
|
305
|
-
this.subscribe(tc, null, o.config.qos || 0, o.config.retain || false);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
} catch (error) {
|
|
309
|
-
this.log("error", error.toString());
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* 运行Mqtt
|
|
316
|
-
* @returns {Promise} 连接结果
|
|
317
|
-
*/
|
|
318
|
-
Mqtt.prototype.start = async function () {
|
|
319
|
-
this.connecting = true;
|
|
320
|
-
|
|
321
|
-
try {
|
|
322
|
-
await this._createClient();
|
|
323
|
-
|
|
324
|
-
if (this.client && this.client.on) {
|
|
325
|
-
return await this._setupClientEvents();
|
|
326
|
-
}
|
|
327
|
-
} catch (error) {
|
|
328
|
-
this.connecting = false;
|
|
329
|
-
return await this._rejectPromise(error);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
return await this._rejectPromise();
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* 创建客户端
|
|
337
|
-
* @private
|
|
338
|
-
*/
|
|
339
|
-
Mqtt.prototype._createClient = async function () {
|
|
340
|
-
var cg = { ...this.config };
|
|
341
|
-
cg.clientId = cg.clientid;
|
|
342
|
-
if (cg.host) {
|
|
343
|
-
var broker_url = cg.host;
|
|
344
|
-
delete cg.hostname;
|
|
345
|
-
delete cg.port;
|
|
346
|
-
delete cg.host;
|
|
347
|
-
this.client = Mqtt_client.connect(broker_url, cg);
|
|
348
|
-
} else {
|
|
349
|
-
delete cg.host;
|
|
350
|
-
this.client = Mqtt_client.connect(cg);
|
|
351
|
-
}
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* 设置客户端事件
|
|
356
|
-
* @returns {Promise} 连接结果
|
|
357
|
-
* @private
|
|
358
|
-
*/
|
|
359
|
-
Mqtt.prototype._setupClientEvents = function () {
|
|
360
|
-
var _this = this;
|
|
361
|
-
var timeout_ms = _this.config.connect_timeout || 30000;
|
|
362
|
-
return new Promise((resolve, reject) => {
|
|
363
|
-
var timeout_timer = setTimeout(() => {
|
|
364
|
-
_this.connecting = false;
|
|
365
|
-
reject(new Error("MQTT连接超时"));
|
|
366
|
-
}, timeout_ms);
|
|
367
|
-
|
|
368
|
-
_this.client.on("connect", (connack) => {
|
|
369
|
-
clearTimeout(timeout_timer);
|
|
370
|
-
_this.connecting = false;
|
|
371
|
-
// 避免重连时重复绑定message事件
|
|
372
|
-
_this.client.removeAllListeners("message");
|
|
373
|
-
_this.client.on("message", (topic, message) => {
|
|
374
|
-
_this.receive(topic, message.toString()).catch((err) => {
|
|
375
|
-
console.error("MQTT消息处理错误:", err);
|
|
376
|
-
});
|
|
377
|
-
});
|
|
378
|
-
// 连接成功后订阅所有已启用mod的主题
|
|
379
|
-
_this._subscribeTopics();
|
|
380
|
-
// 启动在线状态定时器
|
|
381
|
-
_this.startTimer();
|
|
382
|
-
resolve(connack);
|
|
383
|
-
});
|
|
384
|
-
_this.client.on("error", (error) => {
|
|
385
|
-
clearTimeout(timeout_timer);
|
|
386
|
-
_this.connecting = false;
|
|
387
|
-
_this.log("error", "连接失败", error);
|
|
388
|
-
reject(error);
|
|
389
|
-
});
|
|
390
|
-
});
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
/**
|
|
394
|
-
* 创建被拒绝的Promise
|
|
395
|
-
* @param {Error} error 错误对象
|
|
396
|
-
* @returns {Promise} 被拒绝的Promise
|
|
397
|
-
* @private
|
|
398
|
-
*/
|
|
399
|
-
Mqtt.prototype._rejectPromise = function (error) {
|
|
400
|
-
return new Promise((resolve, reject) => {
|
|
401
|
-
if (error) {
|
|
402
|
-
reject(error);
|
|
403
|
-
} else {
|
|
404
|
-
reject(new Error("MQTT客户端连接失败"));
|
|
405
|
-
}
|
|
406
|
-
});
|
|
407
|
-
};
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* 监听事件
|
|
411
|
-
* @param {string} topic 事件名称
|
|
412
|
-
* @param {Function} func 回调函数
|
|
413
|
-
* @returns {object} 返回当前实例
|
|
414
|
-
*/
|
|
415
|
-
Mqtt.prototype.on = function (topic, func) {
|
|
416
|
-
if (!this.client) {
|
|
417
|
-
return this;
|
|
418
|
-
}
|
|
419
|
-
this.client.on(topic, func);
|
|
420
|
-
return this;
|
|
421
|
-
};
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* 接收消息
|
|
425
|
-
* @param {string} topic 订阅板块
|
|
426
|
-
* @param {object} msg 消息主体
|
|
427
|
-
*/
|
|
428
|
-
Mqtt.prototype.message = async function (topic, msg) {
|
|
429
|
-
if (this.dict_subscribe[topic]) {
|
|
430
|
-
var list = this.dict_subscribe[topic];
|
|
431
|
-
try {
|
|
432
|
-
for (var key in list) {
|
|
433
|
-
list[key](msg);
|
|
434
|
-
}
|
|
435
|
-
} catch (err) {
|
|
436
|
-
console.error(err);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
};
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* 接收消息
|
|
443
|
-
* @param {string} push_topic 推送过来的主题
|
|
444
|
-
* @param {object} message 消息主体
|
|
445
|
-
* @returns {object} 解析后的消息主体
|
|
446
|
-
*/
|
|
447
|
-
Mqtt.prototype.receive = async function (push_topic, message) {
|
|
448
|
-
var msg = this._parseMessage(message, push_topic);
|
|
449
|
-
if (msg === null) {
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
// 处理消息回复
|
|
454
|
-
this._handleResponse(msg);
|
|
455
|
-
|
|
456
|
-
var ret = await this._processTopics(push_topic, msg);
|
|
457
|
-
try {
|
|
458
|
-
await this.message(ret.topic, msg);
|
|
459
|
-
} catch (error) {
|
|
460
|
-
this.log("error", "mqtt处理程序错误", error);
|
|
461
|
-
return;
|
|
462
|
-
}
|
|
463
|
-
return ret.result;
|
|
464
|
-
};
|
|
465
|
-
|
|
466
|
-
/**
|
|
467
|
-
* 解析消息
|
|
468
|
-
* @param {object} message 消息主体
|
|
469
|
-
* @param {string} push_topic 推送过来的主题
|
|
470
|
-
* @returns {object|null} 解析后的消息
|
|
471
|
-
* @private
|
|
472
|
-
*/
|
|
473
|
-
Mqtt.prototype._parseMessage = function (message, push_topic) {
|
|
474
|
-
var msg = {};
|
|
475
|
-
if (message && (message.indexOf("[") === 0 || message.indexOf("{") === 0)) {
|
|
476
|
-
try {
|
|
477
|
-
msg = JSON.parse(message);
|
|
478
|
-
} catch (error) {
|
|
479
|
-
this.log("error", "消息结构体不对", push_topic, error);
|
|
480
|
-
return null;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
return msg;
|
|
484
|
-
};
|
|
485
|
-
|
|
486
|
-
/**
|
|
487
|
-
* 处理主题
|
|
488
|
-
* @param {string} push_topic 推送过来的主题
|
|
489
|
-
* @param {object} msg 消息主体
|
|
490
|
-
* @returns {object} 处理结果和主题
|
|
491
|
-
* @private
|
|
492
|
-
*/
|
|
493
|
-
Mqtt.prototype._processTopics = async function (push_topic, msg) {
|
|
494
|
-
var ret;
|
|
495
|
-
var collected = this._collectTopicPromises(push_topic, msg);
|
|
496
|
-
var promises = collected.promises;
|
|
497
|
-
var topic = collected.topic;
|
|
498
|
-
|
|
499
|
-
if (promises.length > 0) {
|
|
500
|
-
var results = await Promise.allSettled(promises);
|
|
501
|
-
// 取最后一个成功的结果作为返回值 (保持向后兼容)
|
|
502
|
-
for (var i = results.length - 1; i >= 0; i--) {
|
|
503
|
-
if (
|
|
504
|
-
results[i].status === "fulfilled" &&
|
|
505
|
-
results[i].value !== undefined &&
|
|
506
|
-
results[i].value !== null
|
|
507
|
-
) {
|
|
508
|
-
ret = results[i].value;
|
|
509
|
-
break;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
return { result: ret, topic };
|
|
515
|
-
};
|
|
516
|
-
|
|
517
|
-
/**
|
|
518
|
-
* 收集匹配主题的handler Promise
|
|
519
|
-
* @param {string} push_topic 推送过来的主题
|
|
520
|
-
* @param {object} msg 消息主体
|
|
521
|
-
* @returns {object} {promises: Array, topic: string} Promise数组和最后匹配的主题
|
|
522
|
-
* @private
|
|
523
|
-
*/
|
|
524
|
-
Mqtt.prototype._collectTopicPromises = function (push_topic, msg) {
|
|
525
|
-
var promises = [];
|
|
526
|
-
var topic = "";
|
|
527
|
-
var mods = this.getMods();
|
|
528
|
-
|
|
529
|
-
for (var k in mods) {
|
|
530
|
-
var o = mods[k];
|
|
531
|
-
if (o.config.state !== 1) {
|
|
532
|
-
continue;
|
|
533
|
-
}
|
|
534
|
-
var topics = o.config.topic;
|
|
535
|
-
if (!topics) {
|
|
536
|
-
continue;
|
|
537
|
-
}
|
|
538
|
-
for (var n = 0; n < topics.length; n++) {
|
|
539
|
-
topic = topics[n];
|
|
540
|
-
if (this.match(push_topic, topic)) {
|
|
541
|
-
promises.push(
|
|
542
|
-
o.call("handle", push_topic, msg, topic, n).catch((err) => {
|
|
543
|
-
console.error("MQTT handler执行错误:", err);
|
|
544
|
-
}),
|
|
545
|
-
);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
return { promises, topic };
|
|
551
|
-
};
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* 订阅主题
|
|
555
|
-
* @param {string} topic 主题
|
|
556
|
-
* @param {Function} func 回调函数
|
|
557
|
-
* @param {number} qos 推送方式 0
|
|
558
|
-
* @param {boolean} retain 保持
|
|
559
|
-
* @returns {string} 主键
|
|
560
|
-
*/
|
|
561
|
-
Mqtt.prototype.subscribe = function (topic, func, qos = null, retain = false) {
|
|
562
|
-
if (!this.client) {
|
|
563
|
-
return "";
|
|
564
|
-
}
|
|
565
|
-
this.client.subscribe(topic, {
|
|
566
|
-
// 订阅消息方式,0为保留 , 1为确认收到1次
|
|
567
|
-
qos: qos || this.config.subscribe_qos || 0,
|
|
568
|
-
retain,
|
|
569
|
-
});
|
|
570
|
-
if (func) {
|
|
571
|
-
if (!this.dict_subscribe[topic]) {
|
|
572
|
-
this.dict_subscribe[topic] = {};
|
|
573
|
-
}
|
|
574
|
-
var key = this.key_num + 1;
|
|
575
|
-
this.dict_subscribe[topic][key] = func;
|
|
576
|
-
return key;
|
|
577
|
-
}
|
|
578
|
-
return "";
|
|
579
|
-
};
|
|
580
|
-
|
|
581
|
-
/**
|
|
582
|
-
* 取消订阅
|
|
583
|
-
* @param {string} topic 主题
|
|
584
|
-
* @param {string} key 主键
|
|
585
|
-
*/
|
|
586
|
-
Mqtt.prototype.unsubscribe = function (topic, key) {
|
|
587
|
-
this.client.unsubscribe(topic);
|
|
588
|
-
if (this.dict_subscribe[topic]) {
|
|
589
|
-
delete this.dict_subscribe[topic][key];
|
|
590
|
-
}
|
|
591
|
-
};
|
|
592
|
-
|
|
593
|
-
/**
|
|
594
|
-
* 结束客户端
|
|
595
|
-
*/
|
|
596
|
-
Mqtt.prototype.end = function () {
|
|
597
|
-
if (this.client) {
|
|
598
|
-
this.client.removeAllListeners();
|
|
599
|
-
this.client.end();
|
|
600
|
-
this.client = null;
|
|
601
|
-
}
|
|
602
|
-
if (this.timer) {
|
|
603
|
-
clearInterval(this.timer);
|
|
604
|
-
this.timer = null;
|
|
605
|
-
}
|
|
606
|
-
// 清空运行时数据结构
|
|
607
|
-
this.list_msg = [];
|
|
608
|
-
this.dict_msg = {};
|
|
609
|
-
this.dict_subscribe = {};
|
|
610
|
-
this._regex_cache = {};
|
|
611
|
-
};
|
|
612
|
-
|
|
613
|
-
/**
|
|
614
|
-
* 发布主题
|
|
615
|
-
* @param {string} topic 主题
|
|
616
|
-
* @param {object} message 消息对象
|
|
617
|
-
* @param {number} qos 推送方式 0
|
|
618
|
-
* @param {boolean} retain 保持
|
|
619
|
-
*/
|
|
620
|
-
Mqtt.prototype.publish = function (topic, message, qos = null, retain = false) {
|
|
621
|
-
this.client.publish(topic, message, {
|
|
622
|
-
qos: qos || this.config.publish_qos || 0,
|
|
623
|
-
retain,
|
|
624
|
-
});
|
|
625
|
-
};
|
|
626
|
-
|
|
627
|
-
/**
|
|
628
|
-
* 主题推送
|
|
629
|
-
* @param {string} topic 主题
|
|
630
|
-
* @param {string} msg_obj 消息主体
|
|
631
|
-
* @param {number} qos 推送方式 0
|
|
632
|
-
* @param {boolean} retain 保持
|
|
633
|
-
*/
|
|
634
|
-
Mqtt.prototype.send = function (topic, msg_obj, qos = null, retain = false) {
|
|
635
|
-
this.publish(topic, JSON.stringify(msg_obj), qos, retain);
|
|
636
|
-
};
|
|
637
|
-
|
|
638
|
-
/**
|
|
639
|
-
* 生成ID
|
|
640
|
-
* @param {string} clientId 客户端ID
|
|
641
|
-
* @returns {string} ID
|
|
642
|
-
*/
|
|
643
|
-
Mqtt.prototype.genId = function (clientId) {
|
|
644
|
-
return clientId + "_" + Date.parse(new Date());
|
|
645
|
-
};
|
|
646
|
-
|
|
647
|
-
/**
|
|
648
|
-
* 请求
|
|
649
|
-
* @param {string} topic 主题
|
|
650
|
-
* @param {string} method 请求方法
|
|
651
|
-
* @param {object} params 请求参数
|
|
652
|
-
* @param {Function} func 回调函数
|
|
653
|
-
* @param {number} timeout 超时时间(毫秒)
|
|
654
|
-
*/
|
|
655
|
-
Mqtt.prototype.req = function (topic, method, params, func, timeout = 0) {
|
|
656
|
-
var data = {
|
|
657
|
-
id: this.genId(this.client.options.clientId),
|
|
658
|
-
method,
|
|
659
|
-
params,
|
|
660
|
-
};
|
|
661
|
-
|
|
662
|
-
if (func) {
|
|
663
|
-
data.func = func;
|
|
664
|
-
data.timestamp = Date.now();
|
|
665
|
-
data.timeout = timeout || this.config.request_timeout || 3000;
|
|
666
|
-
this.list_msg.push(data);
|
|
667
|
-
this.dict_msg[data.id] = data;
|
|
668
|
-
|
|
669
|
-
// 设置超时移除定时器
|
|
670
|
-
var _this = this;
|
|
671
|
-
data.timer = setTimeout(() => {
|
|
672
|
-
_this._delMsgById(data.id);
|
|
673
|
-
}, data.timeout);
|
|
674
|
-
}
|
|
675
|
-
this.send(topic, data);
|
|
676
|
-
};
|
|
677
|
-
|
|
678
|
-
/**
|
|
679
|
-
* 同步请求 - 可及时取回消息
|
|
680
|
-
* @param {string} topic 订阅板块
|
|
681
|
-
* @param {string} method 请求方法
|
|
682
|
-
* @param {object} params 传递参数
|
|
683
|
-
* @param {number} timeout 超时时间 0为默认值 10000ms
|
|
684
|
-
* @returns {object} 返回响应结果
|
|
685
|
-
*/
|
|
686
|
-
Mqtt.prototype.reqAsync = function (topic, method, params, timeout = 0) {
|
|
687
|
-
var _this = this;
|
|
688
|
-
return new Promise((resolve, reject) => {
|
|
689
|
-
_this.req(
|
|
690
|
-
topic,
|
|
691
|
-
method,
|
|
692
|
-
params,
|
|
693
|
-
(res) => {
|
|
694
|
-
resolve(res);
|
|
695
|
-
},
|
|
696
|
-
timeout,
|
|
697
|
-
);
|
|
698
|
-
});
|
|
699
|
-
};
|
|
700
|
-
|
|
701
|
-
/**
|
|
702
|
-
* 根据ID移除消息
|
|
703
|
-
* @param {string} msg_id 消息ID
|
|
704
|
-
* @private
|
|
705
|
-
*/
|
|
706
|
-
Mqtt.prototype._delMsgById = function (msg_id) {
|
|
707
|
-
var o = this.dict_msg[msg_id];
|
|
708
|
-
if (!o) {
|
|
709
|
-
return;
|
|
710
|
-
}
|
|
711
|
-
// 清除定时器
|
|
712
|
-
if (o.timer) {
|
|
713
|
-
clearTimeout(o.timer);
|
|
714
|
-
}
|
|
715
|
-
delete this.dict_msg[msg_id];
|
|
716
|
-
|
|
717
|
-
// 从数组中移除 (保持list_msg与dict_msg同步)
|
|
718
|
-
for (var i = 0; i < this.list_msg.length; i++) {
|
|
719
|
-
if (this.list_msg[i].id === msg_id) {
|
|
720
|
-
this.list_msg.splice(i, 1);
|
|
721
|
-
break;
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
};
|
|
725
|
-
|
|
726
|
-
/**
|
|
727
|
-
* 处理消息回复
|
|
728
|
-
* @param {object} msg 回复消息
|
|
729
|
-
* @private
|
|
730
|
-
*/
|
|
731
|
-
Mqtt.prototype._handleResponse = function (msg) {
|
|
732
|
-
if (!msg || !msg.id) {
|
|
733
|
-
return;
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
var o = this.dict_msg[msg.id];
|
|
737
|
-
if (o && o.func) {
|
|
738
|
-
try {
|
|
739
|
-
// 执行回调函数
|
|
740
|
-
o.func(msg);
|
|
741
|
-
} catch (error) {
|
|
742
|
-
console.error("MQTT回调函数执行错误:", error);
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
// 从列表中移除已处理的消息
|
|
746
|
-
this._delMsgById(o.id);
|
|
747
|
-
}
|
|
748
|
-
};
|
|
749
|
-
|
|
750
|
-
/**
|
|
751
|
-
* 保存在线到数据库
|
|
752
|
-
* @param {Array} arr 客户端ID数组
|
|
753
|
-
* @param {number} online 在线情况 0为不在线,1为在线
|
|
754
|
-
*/
|
|
755
|
-
Mqtt.prototype.saveOnline = async function (arr, online = 1) {
|
|
756
|
-
if (!arr || !arr.length) {
|
|
757
|
-
return;
|
|
758
|
-
}
|
|
759
|
-
var body = {
|
|
760
|
-
online,
|
|
761
|
-
};
|
|
762
|
-
var db = $.admin.sql("sys").db();
|
|
763
|
-
db.table = this.config.table || "iot_device";
|
|
764
|
-
db.size = 0;
|
|
765
|
-
var query = {};
|
|
766
|
-
query.clientid_has = arr.join(",");
|
|
767
|
-
await db.set(query, body);
|
|
768
|
-
};
|
|
769
|
-
|
|
770
|
-
/**
|
|
771
|
-
* 获取所有设备
|
|
772
|
-
* @returns {Array} 设备列表
|
|
773
|
-
*/
|
|
774
|
-
Mqtt.prototype.getClients = async function () {
|
|
775
|
-
var db = $.admin.sql("sys").db();
|
|
776
|
-
db.table = this.config.table || "iot_device";
|
|
777
|
-
db.size = 0;
|
|
778
|
-
return await db.get({}, "", "clientid, online");
|
|
779
|
-
};
|
|
780
|
-
|
|
781
|
-
/**
|
|
782
|
-
* 更新在线设备
|
|
783
|
-
*/
|
|
784
|
-
Mqtt.prototype.updateOnline = async function () {
|
|
785
|
-
var now = new Date().getTime();
|
|
786
|
-
var online_expires = this.config.online_expires; // 180
|
|
787
|
-
|
|
788
|
-
// 获取所有客户端
|
|
789
|
-
var drives = await this.getClients();
|
|
790
|
-
var result = this._processDeviceStatus(drives, now, online_expires);
|
|
791
|
-
var { list_online, list_offline, list_has } = result;
|
|
792
|
-
|
|
793
|
-
// 处理数据库在线但缓存缺失的设备
|
|
794
|
-
this._processUnseenDevices(
|
|
795
|
-
drives,
|
|
796
|
-
list_offline,
|
|
797
|
-
list_has,
|
|
798
|
-
now,
|
|
799
|
-
online_expires,
|
|
800
|
-
);
|
|
801
|
-
|
|
802
|
-
// 批量更新设备状态
|
|
803
|
-
await this._updateDeviceStatus(list_offline, list_online);
|
|
804
|
-
};
|
|
805
|
-
|
|
806
|
-
/**
|
|
807
|
-
* 处理设备状态
|
|
808
|
-
* @param {Array} drives 设备列表
|
|
809
|
-
* @param {number} now 当前时间戳
|
|
810
|
-
* @param {number} online_expires 在线过期时间
|
|
811
|
-
* @returns {object} 在线和离线设备列表
|
|
812
|
-
* @private
|
|
813
|
-
*/
|
|
814
|
-
Mqtt.prototype._processDeviceStatus = function (drives, now, online_expires) {
|
|
815
|
-
var list_online = [];
|
|
816
|
-
var list_offline = [];
|
|
817
|
-
var list_has = [];
|
|
818
|
-
|
|
819
|
-
var mods = this.getMods();
|
|
820
|
-
for (var k in mods) {
|
|
821
|
-
var o = mods[k];
|
|
822
|
-
var dict = o.drives || {};
|
|
823
|
-
for (var clientid in dict) {
|
|
824
|
-
list_has.push(clientid);
|
|
825
|
-
// 设备已出现, 清除缺失记录
|
|
826
|
-
delete this.dict_lost[clientid];
|
|
827
|
-
var drive = drives.getObj({ clientid });
|
|
828
|
-
var device = dict[clientid];
|
|
829
|
-
|
|
830
|
-
if (device.online === 1) {
|
|
831
|
-
this._onlineDevice(
|
|
832
|
-
device,
|
|
833
|
-
drive,
|
|
834
|
-
clientid,
|
|
835
|
-
now,
|
|
836
|
-
online_expires,
|
|
837
|
-
list_online,
|
|
838
|
-
list_offline,
|
|
839
|
-
dict,
|
|
840
|
-
);
|
|
841
|
-
} else {
|
|
842
|
-
this._offlineDevice(drive, clientid, list_offline, dict);
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
return { list_online, list_offline, list_has };
|
|
848
|
-
};
|
|
849
|
-
|
|
850
|
-
/**
|
|
851
|
-
* 处理在线设备
|
|
852
|
-
* @param {object} device 设备对象
|
|
853
|
-
* @param {object} drive 数据库中的设备信息
|
|
854
|
-
* @param {string} clientid 设备ID
|
|
855
|
-
* @param {number} now 当前时间戳
|
|
856
|
-
* @param {number} online_expires 在线过期时间
|
|
857
|
-
* @param {Array} list_online 在线设备列表
|
|
858
|
-
* @param {Array} list_offline 离线设备列表
|
|
859
|
-
* @param {object} dict 设备字典
|
|
860
|
-
* @private
|
|
861
|
-
*/
|
|
862
|
-
/* eslint-disable no-param-reassign */
|
|
863
|
-
Mqtt.prototype._onlineDevice = function (
|
|
864
|
-
device,
|
|
865
|
-
drive,
|
|
866
|
-
clientid,
|
|
867
|
-
now,
|
|
868
|
-
online_expires,
|
|
869
|
-
list_online,
|
|
870
|
-
list_offline,
|
|
871
|
-
dict,
|
|
872
|
-
) {
|
|
873
|
-
if (device.time_last) {
|
|
874
|
-
var cha = now - device.time_last;
|
|
875
|
-
if (cha > online_expires) {
|
|
876
|
-
if (drive && drive.online) {
|
|
877
|
-
list_offline.push(clientid);
|
|
878
|
-
}
|
|
879
|
-
// 这里需要修改设备状态,但由于参数修改限制,我们直接修改字典
|
|
880
|
-
// 注意:这里仍然会修改外部对象,但这是业务逻辑需要
|
|
881
|
-
device.online = 0;
|
|
882
|
-
delete dict[clientid];
|
|
883
|
-
} else {
|
|
884
|
-
if (drive && !drive.online) {
|
|
885
|
-
list_online.push(clientid);
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
};
|
|
890
|
-
/* eslint-enable no-param-reassign */
|
|
891
|
-
|
|
892
|
-
/**
|
|
893
|
-
* 处理离线设备
|
|
894
|
-
* @param {object} drive 数据库中的设备信息
|
|
895
|
-
* @param {string} clientid 设备ID
|
|
896
|
-
* @param {Array} list_offline 离线设备列表
|
|
897
|
-
* @param {object} dict 设备字典
|
|
898
|
-
* @private
|
|
899
|
-
*/
|
|
900
|
-
/* eslint-disable no-param-reassign */
|
|
901
|
-
Mqtt.prototype._offlineDevice = function (drive, clientid, list_offline, dict) {
|
|
902
|
-
if (drive && drive.online) {
|
|
903
|
-
list_offline.push(clientid);
|
|
904
|
-
}
|
|
905
|
-
// 从缓存中删除离线设备,避免下次再判断
|
|
906
|
-
delete dict[clientid];
|
|
907
|
-
};
|
|
908
|
-
/* eslint-enable no-param-reassign */
|
|
909
|
-
|
|
910
|
-
/**
|
|
911
|
-
* 处理数据库在线但缓存中缺失的设备, 连续缺失超过在线有效期才判离线
|
|
912
|
-
* @param {Array} drives 设备列表
|
|
913
|
-
* @param {Array} list_offline 离线设备列表
|
|
914
|
-
* @param {Array} list_has 已出现的设备ID列表
|
|
915
|
-
* @param {number} now 当前时间戳
|
|
916
|
-
* @param {number} online_expires 在线过期时间
|
|
917
|
-
* @private
|
|
918
|
-
*/
|
|
919
|
-
Mqtt.prototype._processUnseenDevices = function (
|
|
920
|
-
drives,
|
|
921
|
-
list_offline,
|
|
922
|
-
list_has,
|
|
923
|
-
now,
|
|
924
|
-
online_expires,
|
|
925
|
-
) {
|
|
926
|
-
// 处理未出现的设备
|
|
927
|
-
for (var i = 0; i < drives.length; i++) {
|
|
928
|
-
var { clientid, online } = drives[i];
|
|
929
|
-
if (!online || list_has.indexOf(clientid) !== -1) {
|
|
930
|
-
continue;
|
|
931
|
-
}
|
|
932
|
-
// 首次缺失, 记录时间, 等待下一个周期
|
|
933
|
-
if (!this.dict_lost[clientid]) {
|
|
934
|
-
this.dict_lost[clientid] = now;
|
|
935
|
-
continue;
|
|
936
|
-
}
|
|
937
|
-
// 连续缺失超过在线有效期, 判定离线
|
|
938
|
-
if (now - this.dict_lost[clientid] > online_expires) {
|
|
939
|
-
list_offline.push(clientid);
|
|
940
|
-
delete this.dict_lost[clientid];
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
};
|
|
944
|
-
|
|
945
|
-
/**
|
|
946
|
-
* 更新设备状态
|
|
947
|
-
* @param {Array} list_offline 离线设备列表
|
|
948
|
-
* @param {Array} list_online 在线设备列表
|
|
949
|
-
* @private
|
|
950
|
-
*/
|
|
951
|
-
Mqtt.prototype._updateDeviceStatus = async function (
|
|
952
|
-
list_offline,
|
|
953
|
-
list_online,
|
|
954
|
-
) {
|
|
955
|
-
var promises = [];
|
|
956
|
-
|
|
957
|
-
// 先将设备离线
|
|
958
|
-
var list_off = list_offline.to2D(30);
|
|
959
|
-
for (var i = 0; i < list_off.length; i++) {
|
|
960
|
-
promises.push(this.saveOnline(list_off[i], 0));
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
// 再将设备在线
|
|
964
|
-
var list_on = list_online.to2D(30);
|
|
965
|
-
for (var i = 0; i < list_on.length; i++) {
|
|
966
|
-
promises.push(this.saveOnline(list_on[i], 1));
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
await Promise.allSettled(promises);
|
|
970
|
-
};
|
|
971
|
-
|
|
972
|
-
/**
|
|
973
|
-
* 开始计时器
|
|
974
|
-
*/
|
|
975
|
-
Mqtt.prototype.startTimer = function () {
|
|
976
|
-
if (!this.timer) {
|
|
977
|
-
this.timer = setInterval(() => {
|
|
978
|
-
try {
|
|
979
|
-
this.updateOnline();
|
|
980
|
-
} catch (err) {
|
|
981
|
-
console.error("更新在线设备失败", err);
|
|
982
|
-
}
|
|
983
|
-
}, this.config.online_interval);
|
|
984
|
-
}
|
|
985
|
-
};
|
|
986
|
-
|
|
987
|
-
exports.Mqtt = Mqtt;
|
|
988
|
-
|
|
989
|
-
/**
|
|
990
|
-
* 创建全局管理器
|
|
991
|
-
*/
|
|
992
|
-
if (!$.pool.mqtt) {
|
|
993
|
-
$.pool.mqtt = {};
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
function mqttAdmin(scope, title) {
|
|
997
|
-
var sc = scope || $.val.scope + "";
|
|
998
|
-
var obj = $.pool.mqtt[sc];
|
|
999
|
-
if (!obj) {
|
|
1000
|
-
$.pool.mqtt[sc] = new Mqtt({
|
|
1001
|
-
name: sc,
|
|
1002
|
-
title: title,
|
|
1003
|
-
});
|
|
1004
|
-
obj = $.pool.mqtt[sc];
|
|
1005
|
-
}
|
|
1006
|
-
return obj;
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
/**
|
|
1010
|
-
* mqtt管理器, 用于管理插件
|
|
1011
|
-
* @param {string} scope 作用域
|
|
1012
|
-
* @param {string} title 标题
|
|
1013
|
-
* @returns {object} 返回一个缓存类
|
|
1014
|
-
*/
|
|
1015
|
-
if ($.admin) {
|
|
1016
|
-
$.admin.mqtt = mqttAdmin;
|
|
1017
|
-
}
|