mm_os 4.2.6 → 4.2.8

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.
Files changed (74) hide show
  1. package/README.md +1 -1
  2. package/README_EN.md +2 -2
  3. package/adapter/adapter.js +105 -52
  4. package/adapter/custom_persistence.js +32 -31
  5. package/adapter/mqtt.js +59 -79
  6. package/adapter/socket.js +188 -58
  7. package/adapter/web.js +92 -68
  8. package/adapter/websocket.js +43 -146
  9. package/com/api/drive.js +732 -708
  10. package/com/api/index.js +196 -198
  11. package/com/cmd/config.tpl.json +48 -122
  12. package/com/cmd/drive.js +176 -1548
  13. package/com/cmd/index.js +287 -1066
  14. package/com/cmd/job/config.json +66 -0
  15. package/com/cmd/job/index.js +241 -0
  16. package/com/cmd/job/test.js +188 -0
  17. package/com/cmd/script.tpl.js +12 -33
  18. package/com/db/drive.js +2206 -2019
  19. package/com/db/index.js +241 -242
  20. package/com/event/config.tpl.json +3 -1
  21. package/com/event/drive.js +3 -1
  22. package/com/event/index.js +73 -49
  23. package/com/event/script.tpl.js +1 -1
  24. package/com/mqtt/config.tpl.json +16 -8
  25. package/com/mqtt/drive.js +696 -676
  26. package/com/mqtt/index.js +1012 -822
  27. package/com/mqtt/index.test.js +503 -0
  28. package/com/mqtt/mm_mqtt.js +446 -420
  29. package/com/mqtt/script.tpl.js +3 -7
  30. package/com/nav/drive.js +7 -7
  31. package/com/nav/index.js +228 -231
  32. package/com/param/index.js +19 -17
  33. package/com/pendant/index.js +467 -441
  34. package/com/socket/drive.js +679 -616
  35. package/com/socket/index.js +94 -48
  36. package/com/sql/drive.js +1283 -1259
  37. package/com/sql/index.js +152 -150
  38. package/com/static/drive.js +1 -1
  39. package/com/static/index.js +232 -226
  40. package/com/task/drive.js +428 -405
  41. package/com/task/index.js +154 -148
  42. package/com/template/drive.js +1 -1
  43. package/com/template/index.js +141 -138
  44. package/com.js +87 -6
  45. package/common/middleware/web_after/index.js +4 -10
  46. package/common/middleware/web_base/index.js +1 -1
  47. package/common/middleware/web_cors/index.js +1 -1
  48. package/common/middleware/web_error/index.js +131 -119
  49. package/common/middleware/web_error/middleware.json +2 -1
  50. package/common/middleware/web_logger/index.js +1 -1
  51. package/common/middleware/web_main/index.js +2 -0
  52. package/common/middleware/web_static/index.js +2 -2
  53. package/common/middleware/web_waf/index.js +1 -1
  54. package/core/app/config.tpl.json +4 -4
  55. package/core/app/index.js +710 -534
  56. package/core/middleware/index.js +1 -9
  57. package/core/mod/config.tpl.json +1 -1
  58. package/core/model/config.tpl.json +1 -1
  59. package/core/plugin/config.tpl.json +15 -3
  60. package/core/plugin/index.js +31 -0
  61. package/core/pusher/index.js +158 -161
  62. package/core/scene/loop.js +1306 -1255
  63. package/core/store/index.js +1794 -1755
  64. package/core/store/sql.js +1488 -1464
  65. package/core/zone/bat/index.js +744 -728
  66. package/core/zone/config.tpl.json +3 -3
  67. package/core/zone/index.js +655 -616
  68. package/os.js +0 -4
  69. package/package.json +16 -16
  70. package/server.js +583 -427
  71. package/com/cmd/nlp.js +0 -525
  72. package/core/app/index copy.js +0 -611
  73. package/software.js +0 -194
  74. package/tcp.js +0 -279
package/adapter/mqtt.js CHANGED
@@ -13,10 +13,8 @@ class Mqtt extends Adapter {
13
13
  cache: true,
14
14
  prefix: 'mqtt_',
15
15
  ttl: 3600000,
16
- push_topic: 'client/iot/${client_id}',
17
- receive_topic: 'client/iot/${client_id}',
18
16
  auth_enabled: false,
19
- auth_users: [], // 用户名密码列表,格式: {username: 'user', password: 'pass'}
17
+ auth_users: [], // 用户名密码列表,格式: { clientid: 'server', username: 'user', password: 'pass'}
20
18
  };
21
19
  /**
22
20
  * 构造函数
@@ -34,17 +32,23 @@ class Mqtt extends Adapter {
34
32
  * @returns {object} 适配器实例
35
33
  * @private
36
34
  */
37
- Mqtt.prototype._init = function (cache) {
35
+ Mqtt.prototype._init = async function (cache) {
38
36
  // 创建自定义持久化实例
39
37
  let persist = null;
40
- if (this.server && cache) {
38
+ if (this.web && cache) {
41
39
  persist = new Persist(this.config, cache);
42
40
  this.log('info', 'MQTT使用自定义持久化');
43
41
  }
44
- // 创建aedes实例,传入自定义持久化
42
+ // 创建aedes实例
43
+ // 注意: aedes v1构造函数不初始化persistence,需要调用listen()
45
44
  this.broker = new Aedes({
46
- persist: persist
45
+ persistence: persist,
46
+ preConnect: function (client, packet, callback) {
47
+ callback(null, true);
48
+ }
47
49
  });
50
+ // 必须调用listen()初始化persistence,否则客户端连接时会崩溃
51
+ await this.broker.listen();
48
52
  // 创建TCP服务器
49
53
  this.web = net.createServer(this.broker.handle);
50
54
 
@@ -64,18 +68,18 @@ Mqtt.prototype._init = function (cache) {
64
68
 
65
69
  /**
66
70
  * 检查用户是否存在
67
- * @param {string} client_id 客户端ID
71
+ * @param {string} clientid 客户端ID
68
72
  * @param {string} username 用户名
69
73
  * @param {string} password 密码
70
74
  * @returns {Promise<boolean>} 是否存在
71
75
  */
72
- Mqtt.prototype.checkUser = async function (client_id, username, password) {
73
- this.log('debug', '检查用户', { client_id });
76
+ Mqtt.prototype.checkUser = async function (clientid, username, password) {
77
+ this.log('debug', '检查用户', clientid, username);
74
78
  let pass = password ? password.toString() : '';
75
79
  // 查找匹配的用户
76
80
  // 在实际应用中,这里可以改为异步数据库查询
77
81
  // 例如: return await db.query('SELECT * FROM users WHERE username = ? AND password = ?', [username, password_str]);
78
- return this.config.auth_users.find(u => u.username === username && u.password === pass);
82
+ return this.config.auth_users.find(u => u.clientid === clientid && u.username === username && u.password === pass);
79
83
  };
80
84
 
81
85
  /**
@@ -98,21 +102,21 @@ Mqtt.prototype._setupAuth = function () {
98
102
  // 如果启用了身份验证
99
103
  if (this.config.auth_enabled) {
100
104
  // 监听认证事件
101
- this.broker.auth = async (client, username, password, callback) => {
105
+ this.broker.authenticate = async (client, username, password, callback) => {
102
106
  try {
103
107
  // 转换密码格式为字符串
104
108
  let password_str = password ? password.toString() : '';
105
109
 
106
- // 记录认证尝试
107
- this.log('debug', `MQTT认证尝试: clientId=${client.id}, username=${username}, password=${password_str ? '[存在]' : '[不存在]'}`);
110
+ // // 记录认证尝试
111
+ // this.log('debug', `MQTT认证尝试: clientId=${client.id}, username=${username}, password=${password_str ? '[存在]' : '[不存在]'}`);
108
112
 
109
113
  // 如果提供了自定义验证函数,则使用自定义验证
110
114
  let user = await this.auth(client, username, password_str);
111
115
  if (user) {
112
- this.log('info', `MQTT认证成功: clientId=${client.id}, username=${username}`);
116
+ // this.log('info', `MQTT认证成功: clientId=${client.id}, username=${username}`);
113
117
  return callback(null, true);
114
118
  } else {
115
- this.log('warn', `MQTT认证失败: clientId=${client.id}, username=${username}, 用户名或密码错误`);
119
+ // this.log('warn', `MQTT认证失败: clientId=${client.id}, username=${username}, 用户名或密码错误`);
116
120
  return callback(new Error('用户名或密码错误'));
117
121
  }
118
122
  } catch (error) {
@@ -120,75 +124,34 @@ Mqtt.prototype._setupAuth = function () {
120
124
  return callback(new Error('认证服务内部错误'));
121
125
  }
122
126
  };
123
-
124
- this.log('info', 'MQTT身份验证已启用');
125
127
  }
126
128
  };
127
129
 
128
130
  /**
129
131
  * 启动MQTT服务器
132
+ * @returns {Promise} 返回Promise,等待服务端启动完成
130
133
  */
131
134
  Mqtt.prototype.start = function () {
132
- let {
133
- host,
134
- port
135
- } = this.config;
136
-
137
- this.web.listen(port, host, () => {
138
- this.log('info', `MQTT启动成功!访问地址:mqtt://${host}:${port}`);
139
- if (this.config.auth_enabled) {
140
- this.log('info', 'MQTT身份验证已启用');
141
- }
142
- });
135
+ var _this = this;
136
+ return new Promise((resolve, reject) => {
137
+ let {
138
+ host,
139
+ port
140
+ } = _this.config;
141
+
142
+ _this.web.listen(port, host, () => {
143
+ _this.log('info', `MQTT服务端启动!访问地址:mqtt://${host}:${port}`);
144
+ resolve();
145
+ });
143
146
 
144
- // 监听服务器错误
145
- this.web.on('error', (error) => {
146
- this.log('error', 'MQTT服务器启动失败:', error);
147
+ // 监听服务器错误
148
+ _this.web.on('error', (error) => {
149
+ _this.log('error', 'MQTT服务器启动失败:', error);
150
+ reject(error);
151
+ });
147
152
  });
148
153
  };
149
154
 
150
- /**
151
- * 发送消息
152
- * @private
153
- * @param {string} client_id 客户端ID
154
- * @param {string} message 消息内容
155
- * @param {object} [options] 发送选项
156
- * @param {number} [options.qos=0] QoS级别(0, 1, 2)
157
- * @param {boolean} [options.retain=false] 是否为retain消息
158
- * @returns {boolean} 发送是否成功
159
- */
160
- Mqtt.prototype._send = function (client_id, message, options) {
161
- let client = this.clients.get(client_id);
162
- if (client) {
163
- try {
164
- // 默认选项
165
- const OPTS = {
166
- qos: 0,
167
- retain: false,
168
- push_topic: null, ...options || {}};
169
-
170
- // MQTT通常需要发布到特定主题,这里简单处理
171
- // 实际应用中可能需要根据协议规范处理
172
- let topic = OPTS.push_topic || this.config.push_topic.replace('${client_id}', client_id);
173
- this.broker.publish({
174
- topic: topic,
175
- payload: message,
176
- qos: OPTS.qos,
177
- retain: OPTS.retain
178
- });
179
-
180
- this.log('debug', `MQTT服务器向 ${client_id} 发送消息: ${message}, qos: ${OPTS.qos}, retain: ${OPTS.retain}`);
181
- return true;
182
- } catch (error) {
183
- this.log('error', 'MQTT发送消息失败:', error);
184
- return false;
185
- }
186
- } else {
187
- this.log('warn', `MQTT客户端 ${client_id} 不存在或已关闭`);
188
- return false;
189
- }
190
- };
191
-
192
155
  /**
193
156
  * 发布消息到指定主题
194
157
  * @param {string} topic 主题
@@ -202,8 +165,7 @@ Mqtt.prototype.publish = function (topic, message, options) {
202
165
  try {
203
166
  // 默认选项
204
167
  const OPTS = {qos: 0,
205
- retain: false,
206
- push_topic: null, ...options || {}};
168
+ retain: false, ...options || {}};
207
169
 
208
170
  this.broker.publish({
209
171
  topic: topic,
@@ -246,7 +208,7 @@ Mqtt.prototype.stop = function () {
246
208
  this._stop();
247
209
 
248
210
  // 关闭服务器
249
- this.web.close(() => {
211
+ this.broker.close(() => {
250
212
  // 清空客户端集合
251
213
  this.clients.clear();
252
214
  this.log('info', 'MQTT服务器已停止');
@@ -259,16 +221,34 @@ Mqtt.prototype.stop = function () {
259
221
  */
260
222
  Mqtt.prototype._stop = function () {
261
223
  // 关闭所有客户端连接
262
- for (let [client_id, client] of this.clients) {
224
+ for (let [clientid, client] of this.clients) {
263
225
  try {
264
226
  // 使用MQTT客户端的断开连接方法
265
227
  if (client && client.close) {
266
228
  client.close();
267
229
  }
268
230
  } catch (error) {
269
- this.log('error', `关闭MQTT客户端 ${client_id} 失败:`, error);
231
+ this.log('error', `关闭MQTT客户端 ${clientid} 失败:`, error);
270
232
  }
271
233
  }
272
234
  };
273
235
 
236
+ /**
237
+ * 监听MQTT事件
238
+ * @param {string} event 事件名称
239
+ * @param {...*} args 事件参数
240
+ */
241
+ Mqtt.prototype.on = function (event, ...args) {
242
+ this.broker.on(event, ...args);
243
+ };
244
+
245
+ /**
246
+ * 取消监听MQTT事件
247
+ * @param {string} event 事件名称
248
+ * @param {...*} args 事件参数
249
+ */
250
+ Mqtt.prototype.off = function (event, ...args) {
251
+ this.broker.off(event, ...args);
252
+ };
253
+
274
254
  exports.Mqtt = Mqtt;
package/adapter/socket.js CHANGED
@@ -9,106 +9,236 @@ class Socket extends Adapter {
9
9
  host: '0.0.0.0',
10
10
  port: 8200
11
11
  };
12
- /**
13
- * 构造函数
14
- * @param {object} config 配置对象
15
- * @param {object} parent 父对象
16
- */
17
12
  constructor(config, parent) {
18
13
  super({ ...Socket.config, ...config }, parent);
19
14
  }
20
15
  }
21
16
 
22
17
  /**
23
- * 初始化适配器
18
+ * 初始化 - 供外部调用
19
+ * @param {object} server 服务器实例
24
20
  * @returns {object} 适配器实例
25
- * @private
26
21
  */
27
- Socket.prototype._init = function () {
28
- // 创建TCP服务器
29
- this.web = net.createServer(this._onConn.bind(this));
30
-
22
+ Socket.prototype.init = function (server) {
23
+ if (server) {
24
+ this.getServer = function () { return server; };
25
+ }
26
+ this._middleware = [];
31
27
  return this;
32
28
  };
33
29
 
30
+ /**
31
+ * 注册中间件
32
+ * @param {Function} middleware async (ctx, next) => {}
33
+ */
34
+ Socket.prototype.use = function (middleware) {
35
+ this._middleware.push(middleware);
36
+ };
37
+
38
+ /**
39
+ * 启动适配器
40
+ */
41
+ Socket.prototype.start = function () {
42
+ var self = this;
43
+ var { host, port } = this.config;
44
+
45
+ this.web = net.createServer(function (socket) {
46
+ self._onConn(socket);
47
+ });
48
+
49
+ this.web.listen(port, host, function () {
50
+ self.log('info', 'Socket服务已启动!监听地址:' + host + ':' + port);
51
+ });
52
+
53
+ this.web.on('error', function (error) {
54
+ self.log('error', 'Socket启动失败:', error);
55
+ });
56
+ };
34
57
  /**
35
58
  * 客户端连接处理
36
- * @param {Socket} socket 客户端socket
37
- * @private
59
+ * @param {net.Socket} socket TCP socket
38
60
  */
39
61
  Socket.prototype._onConn = function (socket) {
40
- // 生成唯一客户端ID
41
- let client_id = `client_${this.genClientId()}`;
42
- // 存储客户端连接
43
- this.clients.set(client_id, socket);
44
-
45
- // 记录连接日志
46
- this.log('info', `客户端连接成功: ${client_id} (${socket.remoteAddress}:${socket.remotePort})`);
47
-
48
- // 监听数据接收
49
- socket.on('data', (data) => {
50
- this.log('debug', `服务器接收 ${client_id} 消息: ${data.toString()}`);
51
- this._onMessage(client_id, data.toString());
62
+ var self = this;
63
+ var client_ip = socket.remoteAddress || '127.0.0.1';
64
+ var clientid = 'tcp_' + this.genClientId();
65
+
66
+ this.clients.set(clientid, socket);
67
+ this.log('info', 'Socket客户端连接成功:', client_ip, clientid);
68
+
69
+ // 缓存未处理完的数据(TCP 粘包处理)
70
+ var buffer = '';
71
+
72
+ socket.on('data', function (data) {
73
+ buffer += data.toString();
74
+
75
+ // 尝试按换行符分割完整消息
76
+ var lines = buffer.split('\n');
77
+ // 最后一段可能是未完成的消息,保留到 buffer
78
+ buffer = lines.pop() || '';
79
+
80
+ for (var i = 0; i < lines.length; i++) {
81
+ var line = lines[i].trim();
82
+ if (!line) continue;
83
+ self._onData(line, socket, clientid);
84
+ }
52
85
  });
53
86
 
54
- // 监听连接关闭
55
- socket.on('close', () => {
56
- this._onClose(client_id);
87
+ socket.on('close', function () {
88
+ self._onClose(clientid);
89
+ self.clients.delete(clientid);
57
90
  });
58
91
 
59
- // 监听错误事件
60
- socket.on('error', (error) => {
61
- this._onError(client_id, error);
92
+ socket.on('error', function (err) {
93
+ self.log('error', 'Socket客户端错误:', clientid, err);
94
+ self.clients.delete(clientid);
62
95
  });
63
96
  };
64
97
 
65
98
  /**
66
- * 启动适配器
99
+ * 收到一行完整数据
100
+ * @param {string} body_str 消息内容
101
+ * @param {net.Socket} socket TCP socket
102
+ * @param {string} clientid 客户端ID
67
103
  */
68
- Socket.prototype.start = function () {
69
- let { host, port } = this.config;
70
- this.web.listen(port, host, () => {
71
- this.log('info', `启动成功!监听地址:${host}:${port}`);
72
- });
104
+ Socket.prototype._onData = function (body_str, socket, clientid) {
105
+ var self = this;
106
+
107
+ // 尝试解析 JSON
108
+ var json;
109
+ if (body_str.indexOf('{') === 0 || body_str.indexOf('[') === 0) {
110
+ try {
111
+ json = JSON.parse(body_str);
112
+ } catch (e) {
113
+ // 非 JSON 格式,按原始消息处理
114
+ }
115
+ }
116
+
117
+ // 创建最小上下文
118
+ var ctx = {
119
+ clientid: clientid,
120
+ socket: socket,
121
+ message: json || body_str,
122
+ ip: socket.remoteAddress || '127.0.0.1',
123
+ send: function (data) {
124
+ var str = typeof data === 'object' ? JSON.stringify(data) : data;
125
+ if (socket.writable) {
126
+ socket.write(str + '\n');
127
+ }
128
+ },
129
+ close: function () {
130
+ socket.end();
131
+ }
132
+ };
133
+
134
+ if (json && json.method) {
135
+ // 有 method 字段,走 methods 分发
136
+ this._dispatchMethod(json, ctx);
137
+ } else {
138
+ // 走中间件链
139
+ this._runMiddleware(ctx);
140
+ }
141
+ };
142
+
143
+ /**
144
+ * 分发方法调用
145
+ * @param {object} json {id, method, params}
146
+ * @param {object} ctx 上下文
147
+ */
148
+ Socket.prototype._dispatchMethod = function (json, ctx) {
149
+ var self = this;
150
+ var { id, method, params } = json;
151
+
152
+ // 如果有 result 字段且是回复消息,触发回调
153
+ if (json.result && id) {
154
+ // 交由中间件处理(未来可扩展回调)
155
+ this._runMiddleware(ctx);
156
+ return;
157
+ }
158
+
159
+ // 查找方法
160
+ // 先从 adapter 自身的 methods 找,再从全局 $.methods 找
161
+ var handler = this.methods && this.methods[method];
162
+ if (!handler) {
163
+ handler = $.methods && $.methods[method];
164
+ }
73
165
 
74
- // 监听服务器错误
75
- this.web.on('error', (error) => {
76
- this.log('error', '启动失败:', error);
166
+ if (handler) {
167
+ // 异步执行方法
168
+ Promise.resolve().then(function () {
169
+ return handler(params, ctx);
170
+ }).then(function (result) {
171
+ if (result !== undefined && result !== null && id) {
172
+ var ret = { id: id };
173
+ if (typeof result === 'object' && !Array.isArray(result)) {
174
+ Object.assign(ret, result);
175
+ } else {
176
+ ret.result = result;
177
+ }
178
+ ctx.send(ret);
179
+ }
180
+ }).catch(function (err) {
181
+ self.log('error', 'Socket方法执行错误:', err);
182
+ if (id) {
183
+ var err_ret = { id: id, error: { message: err.message || '执行失败' } };
184
+ ctx.send(err_ret);
185
+ }
186
+ });
187
+ } else {
188
+ // 未找到方法,走中间件链
189
+ this._runMiddleware(ctx);
190
+ }
191
+ };
192
+
193
+ /**
194
+ * 运行中间件链
195
+ * @param {object} ctx 上下文
196
+ */
197
+ Socket.prototype._runMiddleware = function (ctx) {
198
+ var mw = this._middleware;
199
+ if (mw.length === 0) return;
200
+
201
+ var idx = 0;
202
+ var self = this;
203
+ function next() {
204
+ var fn = mw[idx++];
205
+ if (fn) {
206
+ return Promise.resolve(fn(ctx, next));
207
+ }
208
+ return Promise.resolve();
209
+ }
210
+ next().catch(function (err) {
211
+ self.log('error', 'Socket中间件错误:', err);
77
212
  });
78
213
  };
79
214
 
80
215
  /**
81
216
  * 发送消息
82
- * @param {string} client_id 客户端ID
217
+ * @param {string} clientid 客户端ID
83
218
  * @param {string} message 消息内容
84
219
  * @returns {boolean} 发送是否成功
85
- * @private
86
220
  */
87
- Socket.prototype._send = function (client_id, message) {
88
- let socket = this.clients.get(client_id);
221
+ Socket.prototype._send = function (clientid, message) {
222
+ let socket = this.clients.get(clientid);
89
223
  if (socket && !socket.destroyed) {
90
- socket.write(message);
91
- this.log('debug', `服务器向 ${client_id} 发送消息: ${message}`);
224
+ var str = typeof message === 'object' ? JSON.stringify(message) : message;
225
+ socket.write(str + '\n');
92
226
  return true;
93
- } else {
94
- this.log('warn', `客户端 ${client_id} 不存在或已关闭`);
95
- return false;
96
227
  }
228
+ return false;
97
229
  };
98
230
 
99
231
  /**
100
232
  * 停止适配器
101
233
  */
102
234
  Socket.prototype.stop = function () {
103
- // 调用父类的_stop方法
104
235
  this._stop();
105
-
106
- // 关闭服务器
107
- this.web.close(() => {
108
- // 清空客户端集合
109
- this.clients.clear();
110
- this.log('info', '服务器已停止');
111
- });
236
+ if (this.web) {
237
+ this.web.close(function () {
238
+ this.clients.clear();
239
+ this.log('info', 'Socket服务已停止');
240
+ }.bind(this));
241
+ }
112
242
  };
113
243
 
114
- exports.Socket = Socket;
244
+ exports.Socket = Socket;
package/adapter/web.js CHANGED
@@ -1,68 +1,92 @@
1
- const Koa = require('koa');
2
- const { Adapter } = require('./adapter');
3
-
4
- /**
5
- * Web适配器类
6
- * 基于Koa框架的HTTP服务器适配器
7
- */
8
- class Web extends Adapter {
9
- static config = {
10
- host: '0.0.0.0',
11
- port: 8000
12
- };
13
-
14
- /**
15
- * 构造函数
16
- * @param {object} config 配置参数
17
- * @param {object} parent 父对象
18
- */
19
- constructor(config, parent) {
20
- super({ ...Web.config, ...config }, parent);
21
- }
22
- }
23
-
24
- /**
25
- * 预置
26
- */
27
- Web.prototype._preset = function () {
28
- this.web = new Koa(this.config);
29
- // 设置cookie签名密钥
30
- this.web.keys = ['mos-secret-key-2024', 'mos-backup-key-2024'];
31
- };
32
-
33
- /**
34
- * 使用中间件
35
- * @param {Function} middleware 中间件函数
36
- */
37
- Web.prototype.use = function (middleware) {
38
- this.web.use(middleware);
39
- };
40
-
41
- /**
42
- * 初始化
43
- * @param {object} server 服务器实例
44
- * @returns {object} 适配器实例
45
- */
46
- Web.prototype.init = function (server) {
47
- if (server) {
48
- this.getServer = function () {
49
- return server;
50
- };
51
- }
52
- return this;
53
- };
54
-
55
- /**
56
- * 启动
57
- */
58
- Web.prototype.start = function () {
59
- var {
60
- host,
61
- port
62
- } = this.config;
63
- this.web.listen(port, host, () => {
64
- this.log('info', `web启动成功!访问网址:http://${host}:${port}`);
65
- });
66
- };
67
-
68
- exports.Web = Web;
1
+ const Koa = require('koa');
2
+ const { Adapter } = require('./adapter');
3
+
4
+ /**
5
+ * Web适配器类
6
+ * 基于Koa框架的HTTP服务器适配器
7
+ */
8
+ class Web extends Adapter {
9
+ static config = {
10
+ host: '0.0.0.0',
11
+ port: 8000,
12
+ };
13
+
14
+ /**
15
+ * 构造函数
16
+ * @param {object} config 配置参数
17
+ * @param {object} parent 父对象
18
+ */
19
+ constructor(config, parent) {
20
+ super({ ...Web.config, ...config }, parent);
21
+ }
22
+ }
23
+
24
+ /**
25
+ * 预置
26
+ */
27
+ Web.prototype._preset = function () {
28
+ this.web = new Koa(this.config);
29
+ // 设置cookie签名密钥
30
+ this.web.keys = ['mos-secret-key-2024', 'mos-backup-key-2024'];
31
+
32
+ // 添加客户端断开处理中间件(必须在最前面)
33
+ this.web.use(async (ctx, next) => {
34
+ try {
35
+ await next();
36
+ } catch (err) {
37
+ if (err.code === 'ERR_STREAM_PREMATURE_CLOSE') {
38
+ // 客户端断开连接,无需处理
39
+ return;
40
+ }
41
+ throw err;
42
+ }
43
+ });
44
+ };
45
+
46
+ /**
47
+ * 使用中间件
48
+ * @param {Function} middleware 中间件函数
49
+ */
50
+ Web.prototype.use = function (middleware) {
51
+ this.web.use(middleware);
52
+ };
53
+
54
+ /**
55
+ * 获取当前中间件处理函数
56
+ * @returns {Function} 组合后的中间件函数
57
+ */
58
+ Web.prototype._getFn = function () {
59
+ return this.web.callback();
60
+ };
61
+
62
+ /**
63
+ * 初始化
64
+ * @param {object} server 服务器实例
65
+ * @returns {object} 适配器实例
66
+ */
67
+ Web.prototype.init = function (server) {
68
+ if (server) {
69
+ this.getServer = function () {
70
+ return server;
71
+ };
72
+ }
73
+ return this;
74
+ };
75
+
76
+ /**
77
+ * 启动
78
+ */
79
+ Web.prototype.start = function () {
80
+ var { host, port } = this.config;
81
+ this.server = this.web.listen(port, host, () => {
82
+ this.log('info', `web服务端已启动!访问网址:http://${host}:${port}`);
83
+ });
84
+
85
+ // 配置服务器超时参数
86
+ this.server.timeout = 60000; // 请求超时 60s(默认120s)
87
+ this.server.headersTimeout = 65000; // 请求头超时(需大于timeout)
88
+ this.server.keepAliveTimeout = 65000; // Keep-Alive 超时
89
+ this.server.requestTimeout = 60000; // Node.js 14+ 请求超时
90
+ };
91
+
92
+ exports.Web = Web;