topbit 2.0.0 → 3.0.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.
- package/README.cn.md +132 -177
- package/README.md +801 -592
- package/bin/new-ctl.js +7 -3
- package/demo/allow.js +13 -13
- package/demo/controller/api.js +15 -0
- package/demo/extends.js +5 -0
- package/demo/http2.js +34 -0
- package/demo/http2_proxy_backend.js +45 -0
- package/demo/http2proxy.js +48 -0
- package/demo/http_proxy_backend.js +44 -0
- package/demo/httpproxy.js +47 -0
- package/demo/loader.js +27 -0
- package/demo/log.js +1 -1
- package/demo/memlimit.js +1 -1
- package/demo/min.js +1 -1
- package/demo/serv.js +1 -1
- package/images/topbit-middleware.webp +0 -0
- package/images/topbit.png +0 -0
- package/package.json +7 -6
- package/src/_loadExtends.js +21 -0
- package/src/bodyparser.js +1 -1
- package/src/context1.js +19 -19
- package/src/context2.js +11 -8
- package/src/ctxpool.js +1 -0
- package/src/extends/Http2Pool.js +365 -0
- package/src/extends/__randstring.js +24 -0
- package/src/extends/cookie.js +44 -0
- package/src/extends/cors.js +334 -0
- package/src/extends/errorlog.js +252 -0
- package/src/extends/http2limit.js +126 -0
- package/src/extends/http2proxy.js +691 -0
- package/src/extends/jwt.js +217 -0
- package/src/extends/mixlogger.js +63 -0
- package/src/extends/paramcheck.js +266 -0
- package/src/extends/proxy.js +662 -0
- package/src/extends/realip.js +34 -0
- package/src/extends/referer.js +68 -0
- package/src/extends/resource.js +398 -0
- package/src/extends/session.js +174 -0
- package/src/extends/setfinal.js +50 -0
- package/src/extends/sni.js +48 -0
- package/src/extends/sse.js +293 -0
- package/src/extends/timing.js +111 -0
- package/src/extends/tofile.js +123 -0
- package/src/http1.js +15 -16
- package/src/http2.js +5 -5
- package/src/httpc.js +3 -3
- package/src/lib/npargv.js +354 -0
- package/src/lib/zipdata.js +45 -0
- package/src/middleware1.js +15 -16
- package/src/middleware2.js +4 -9
- package/src/token/token.js +4 -5
- package/src/topbit.js +13 -11
- package/test/{test-helper.js → test-ext.js} +1 -1
- package/test/test-route.js +1 -1
- package/cache/allow.js +0 -130
- package/cache/errserv.js +0 -45
- package/cache/minserv.js +0 -167
- package/cache/router.js +0 -84
- package/cache/servsock.js +0 -286
- package/cache/sni.js +0 -66
- package/images/titbit-middleware.png +0 -0
- package/images/titbit.png +0 -0
- package/tmp/buff-code +0 -134
- package/tmp/devplan +0 -9
- package/tmp/evt-test.js +0 -34
- package/tmp/fastParseUrl.js +0 -302
- package/tmp/router-rule.js +0 -559
- package/tmp/test-cdps.js +0 -122
- package/tmp/titbit.js +0 -1286
- /package/{cache/rsa → demo/cert}/localhost-cert.pem +0 -0
- /package/{cache/rsa → demo/cert}/localhost-privkey.pem +0 -0
package/tmp/titbit.js
DELETED
|
@@ -1,1286 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('node:fs');
|
|
4
|
-
const cluster = require('node:cluster');
|
|
5
|
-
const os = require('node:os');
|
|
6
|
-
const {spawn} = require('node:child_process');
|
|
7
|
-
const bodyParser = require('./bodyparser.js');
|
|
8
|
-
const middleware1 = require('./middleware1.js');
|
|
9
|
-
const middleware2 = require('./middleware2.js');
|
|
10
|
-
const router = require('./router.js');
|
|
11
|
-
const connfilter = require('./connfilter.js');
|
|
12
|
-
const http1 = require('./http1.js');
|
|
13
|
-
const httpt = require('./http2.js');
|
|
14
|
-
const httpc = require('./httpc.js');
|
|
15
|
-
const loggermsg = require('./loggermsg.js');
|
|
16
|
-
const monitor = require('./monitor.js');
|
|
17
|
-
const strong = require('./strong.js');
|
|
18
|
-
const optionsCheck = require('./optionsCheck.js');
|
|
19
|
-
const versionCheck = require('./versionCheck.js');
|
|
20
|
-
const context1 = require('./context1.js');
|
|
21
|
-
const context2 = require('./context2.js');
|
|
22
|
-
const helper = require('./helper.js');
|
|
23
|
-
|
|
24
|
-
let __instance__ = 0;
|
|
25
|
-
|
|
26
|
-
let vchk = versionCheck();
|
|
27
|
-
|
|
28
|
-
if (vchk.stat === false) {
|
|
29
|
-
console.error(vchk.errmsg);
|
|
30
|
-
process.exit(1);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
let _titbit_server_running = `
|
|
34
|
-
:.:.:.:.:.:.titbit in service.:.:.:.:.:.:
|
|
35
|
-
`;
|
|
36
|
-
|
|
37
|
-
let _titbit_home_page = `<!DOCTYPE html><html>
|
|
38
|
-
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width"></head>
|
|
39
|
-
<body>
|
|
40
|
-
<div style="width:90%;margin:auto;margin-top:1rem;color:#4a4a4f;">
|
|
41
|
-
<div style="text-align:center;">
|
|
42
|
-
<h1>titbit</h1>
|
|
43
|
-
<br>
|
|
44
|
-
<p>功能强大、简洁高效的Web开发框架。</p>
|
|
45
|
-
<p>文档 & 仓库:
|
|
46
|
-
<a style="text-decoration:none;color:#345689;" href="https://gitee.com/daoio/titbit" target=_blank>
|
|
47
|
-
titbit</a></p>
|
|
48
|
-
</div>
|
|
49
|
-
</div>
|
|
50
|
-
</body>
|
|
51
|
-
</html>`;
|
|
52
|
-
|
|
53
|
-
function sigExit() {
|
|
54
|
-
process.kill(0, 'SIGTERM');
|
|
55
|
-
|
|
56
|
-
//防止有监听SIGTERM不退出的情况。
|
|
57
|
-
setTimeout(() => {
|
|
58
|
-
process.kill(0, 'SIGKILL');
|
|
59
|
-
}, 5);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function makeSubAppForGroup(app, grp_name) {
|
|
63
|
-
let makeOptions = (grp, opts) => {
|
|
64
|
-
if (!opts || typeof opts !== 'object') {
|
|
65
|
-
return {group: grp}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
let options = {...opts}
|
|
69
|
-
|
|
70
|
-
options.group = grp
|
|
71
|
-
|
|
72
|
-
return options
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
let subapp = {
|
|
76
|
-
/* middleware: (mids, options=null) => {
|
|
77
|
-
if (!Array.isArray(mids)) mids = [mids]
|
|
78
|
-
|
|
79
|
-
for (let m of mids) {
|
|
80
|
-
app.use(m, makeOptions(grp_name, options))
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return subapp
|
|
84
|
-
}, */
|
|
85
|
-
|
|
86
|
-
pre: (mid, options=null) => {
|
|
87
|
-
app.pre(mid, makeOptions(grp_name, options))
|
|
88
|
-
return subapp
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
use: (mid, options=null) => {
|
|
92
|
-
app.use(mid, makeOptions(grp_name, options))
|
|
93
|
-
return subapp
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
Object.defineProperties(subapp, {
|
|
98
|
-
__mids__: {
|
|
99
|
-
enumerable: false,
|
|
100
|
-
writable: true,
|
|
101
|
-
value:[]
|
|
102
|
-
},
|
|
103
|
-
__prefix__: {
|
|
104
|
-
enumerable: false,
|
|
105
|
-
writable: true,
|
|
106
|
-
value: ''
|
|
107
|
-
},
|
|
108
|
-
__group__: {
|
|
109
|
-
enumerable: false,
|
|
110
|
-
writable: true,
|
|
111
|
-
value: ''
|
|
112
|
-
},
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
return subapp
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* @param {object} options 初始化选项,参考值如下:
|
|
120
|
-
* - debug 调试模式,默认为false
|
|
121
|
-
* - maxConn 最大连接数,使用daemon接口,则每个进程都可以最多处理maxConn限制数量,0表示不限制。
|
|
122
|
-
* - deny {Array} IP字符串数组,表示要拒绝访问的IP。
|
|
123
|
-
* - maxIPRequest {number} 单个IP单元时间内最大访问次数。
|
|
124
|
-
* - unitTime {number} 单元时间,配合maxIPRequest,默认为1表示1秒钟清空一次。
|
|
125
|
-
* - maxIPCache {number} 最大IP缓存个数,配合限制IP访问次数使用,默认为50000。
|
|
126
|
-
* - allow {Array} 限制IP请求次数的白名单。
|
|
127
|
-
* - useLimit {bool} 启用连接限制,用于限制请求的选项需要启用此选项才会生效。
|
|
128
|
-
* - timeout {number} 超时。
|
|
129
|
-
* - cert {string} 启用HTTPS要使用的证书文件路径。
|
|
130
|
-
* - key {string} 启用HTTPS的密钥文件路径。
|
|
131
|
-
* - globalLog {bool} 启用全局日志。
|
|
132
|
-
* - maxBody {number} 表示POST/PUT提交表单的最大字节数,包括上传文件。
|
|
133
|
-
* - maxFiles {number} 最大上传文件数量,超过则不处理。
|
|
134
|
-
* - daemon {bool} 启用守护进程模式。
|
|
135
|
-
* - pidFile {string} 保存Master进程PID的文件路径。
|
|
136
|
-
* - logFile {string} 日志文件。
|
|
137
|
-
* - errorLogFile {string} 错误日志文件。
|
|
138
|
-
* - logType {string} 日志类型,支持stdio、file、self
|
|
139
|
-
* - logHandle {function} 自定义日志处理函数,接收参数为worker和msg(json格式的日志)
|
|
140
|
-
* - logHistory {number} 最大日志文件数量,默认为50。
|
|
141
|
-
* - server {object} 服务器选项,参考http2.createSecureServer
|
|
142
|
-
* - notFound {string} 404页面数据。
|
|
143
|
-
* - parseBody {bool} 自动解析上传文件数据,默认为true。
|
|
144
|
-
* - http2 {bool} 默认false。
|
|
145
|
-
* - allowHTTP1 {bool} 默认为false。
|
|
146
|
-
* - loadInfoFile {string} daemon为true,负载信息会输出到设置的文件,默认为空
|
|
147
|
-
* - memFactor {number} 控制内存最大使用量的系数,范围从 -0.48 ~ 0.36,会使用基本系数加上此值并乘以内存总量。默认值0.28。
|
|
148
|
-
* RSS基本系数是0.52。不要设置的太低,提供比较低的值是为了测试使用。
|
|
149
|
-
* - maxUrlLength 最大URL长度,包括path和querystring
|
|
150
|
-
* - maxpool 请求上下文的最大缓存池数量。
|
|
151
|
-
* - loadMonitor true|false,表示是否启用负载监控功能,在daemon模式有效,默认为true。
|
|
152
|
-
* - monitorTimeSlice 子进程获取系统占用资源的定时器时间片,毫秒值,默认为500。
|
|
153
|
-
* - maxQuery 最大允许的querystring的参数,默认为12。
|
|
154
|
-
* - fastParseQuery 快速解析querystring,默认为false,会把多个重名的解析为数组,true表示快速解析,不允许重复的名字,否则仅第一个生效。
|
|
155
|
-
* - maxFormLength 在multipart/form-data类型提交数据时,单个form项的最大值,默认为1000000字节。
|
|
156
|
-
* - errorHandle 收集错误并处理的函数,默认是输出错误信息,接收参数为两个,第一个是错误信息,第二个是错误的名字描述。
|
|
157
|
-
* - ignoreSlash 忽略末尾的/,默认为true。
|
|
158
|
-
* - maxLoadRate 在自动创建子进程平衡负载模式,最大子进程负载率限制:25 ~ 98表示百分比。
|
|
159
|
-
* - streamTimeout http2Stream超时,若不设置,默认采用timeout的设置。
|
|
160
|
-
*/
|
|
161
|
-
|
|
162
|
-
let titbit = function (options = {}) {
|
|
163
|
-
|
|
164
|
-
if (! (this instanceof titbit) ) {
|
|
165
|
-
return new titbit(options);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (__instance__ > 0) throw new Error('titbit遵循单例模式,不能构造多次,多个实例是错误的使用方式。你可以在多进程或多线程中构造新的实例。');
|
|
169
|
-
|
|
170
|
-
__instance__ += 1;
|
|
171
|
-
|
|
172
|
-
this.config = {
|
|
173
|
-
//此配置表示POST/PUT提交表单的最大字节数,也是上传文件的最大限制,
|
|
174
|
-
maxBody : 50_000_000,
|
|
175
|
-
maxFiles : 12,
|
|
176
|
-
daemon : false, //开启守护进程
|
|
177
|
-
|
|
178
|
-
//开启守护进程模式后,如果设置路径不为空字符串,则会把pid写入到此文件,可用于服务管理。
|
|
179
|
-
pidFile : '',
|
|
180
|
-
logFile : '',
|
|
181
|
-
errorLogFile : '',
|
|
182
|
-
|
|
183
|
-
//最大日志文件数量
|
|
184
|
-
logHistory : 50,
|
|
185
|
-
|
|
186
|
-
logMaxLines : 50000,
|
|
187
|
-
|
|
188
|
-
// stdio or file
|
|
189
|
-
logType : 'stdio',
|
|
190
|
-
|
|
191
|
-
//开启HTTPS
|
|
192
|
-
https : false,
|
|
193
|
-
|
|
194
|
-
http2 : false,
|
|
195
|
-
|
|
196
|
-
allowHTTP1 : false,
|
|
197
|
-
|
|
198
|
-
//HTTPS密钥和证书的路径
|
|
199
|
-
key : '',
|
|
200
|
-
cert : '',
|
|
201
|
-
|
|
202
|
-
//服务器选项,参考http2.createSecureServer、tls.createServer
|
|
203
|
-
server : {
|
|
204
|
-
//TLS握手连接(HANDSHAKE)超时
|
|
205
|
-
handshakeTimeout: 9000
|
|
206
|
-
},
|
|
207
|
-
|
|
208
|
-
//设置服务器超时,毫秒单位。
|
|
209
|
-
timeout : 20000,
|
|
210
|
-
|
|
211
|
-
debug : false,
|
|
212
|
-
|
|
213
|
-
notFound : 'not found',
|
|
214
|
-
badRequest : 'bad request',
|
|
215
|
-
//展示负载信息,必须使用daemon接口
|
|
216
|
-
showLoadInfo : true,
|
|
217
|
-
loadInfoType : 'text', // text | json | orgjson | --null
|
|
218
|
-
loadInfoFile : '',
|
|
219
|
-
|
|
220
|
-
ignoreSlash: true,
|
|
221
|
-
parseBody: true,
|
|
222
|
-
|
|
223
|
-
useLimit: false,
|
|
224
|
-
|
|
225
|
-
//启用全局日志
|
|
226
|
-
globalLog: false,
|
|
227
|
-
logHandle : null,
|
|
228
|
-
realIP: false,
|
|
229
|
-
|
|
230
|
-
//内存使用控制系数,-0.35 ~ 0.35
|
|
231
|
-
memFactor : 0.28,
|
|
232
|
-
|
|
233
|
-
autoDecodeQuery : true,
|
|
234
|
-
|
|
235
|
-
maxUrlLength: 1152,
|
|
236
|
-
|
|
237
|
-
maxpool : 4096,
|
|
238
|
-
|
|
239
|
-
//子进程汇报资源信息的定时器毫秒数。
|
|
240
|
-
monitorTimeSlice: 500,
|
|
241
|
-
|
|
242
|
-
//querystring最大个数
|
|
243
|
-
maxQuery: 15,
|
|
244
|
-
|
|
245
|
-
//快速解析querystring,多个同名的值会仅设置第一个,不会解析成数组。
|
|
246
|
-
fastParseQuery: false,
|
|
247
|
-
|
|
248
|
-
strong : false,
|
|
249
|
-
|
|
250
|
-
//在multipart格式中,限制单个表单项的最大长度。
|
|
251
|
-
maxFormLength: 1000000,
|
|
252
|
-
|
|
253
|
-
//允许的最大表单键值个数。
|
|
254
|
-
maxFormKey: 100,
|
|
255
|
-
|
|
256
|
-
errorHandle: (err, errname = '') => {
|
|
257
|
-
if (err) {
|
|
258
|
-
if (err.code === 'HPE_INVALID_EOF_STATE' || err.code === 'ERR_HTTP_REQUEST_TIMEOUT') {
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
this.config.debug && console.error(errname, err);
|
|
264
|
-
},
|
|
265
|
-
|
|
266
|
-
//-1表示使用timeout的设置。
|
|
267
|
-
streamTimeout: -1,
|
|
268
|
-
|
|
269
|
-
requestTimeout: 100000,
|
|
270
|
-
|
|
271
|
-
maxLoadRate: 75
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
this.whoami = 'titbit';
|
|
275
|
-
|
|
276
|
-
this.limit = {
|
|
277
|
-
maxConn : 1024,
|
|
278
|
-
deny : null,
|
|
279
|
-
deny_type : 'o',
|
|
280
|
-
//每秒单个IP可以进行请求次数的上限,0表示不限制。
|
|
281
|
-
maxIPRequest : 0,
|
|
282
|
-
unitTime : 1000,
|
|
283
|
-
maxIPCache : 50000,
|
|
284
|
-
allow : null,
|
|
285
|
-
allow_type : 'o',
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
if (typeof options !== 'object') options = {};
|
|
289
|
-
|
|
290
|
-
for(let k in options) {
|
|
291
|
-
switch (k) {
|
|
292
|
-
case 'maxConn':
|
|
293
|
-
optionsCheck(k, options[k], this.limit, {type: 'number', min: 0});
|
|
294
|
-
break;
|
|
295
|
-
|
|
296
|
-
case 'deny':
|
|
297
|
-
optionsCheck(k, options[k], this.limit, {type: ['object', 'function']});
|
|
298
|
-
this.limit.deny_type = (typeof options[k])[0];
|
|
299
|
-
break;
|
|
300
|
-
|
|
301
|
-
case 'maxIPRequest':
|
|
302
|
-
optionsCheck(k, options[k], this.limit, {type: 'number', min: 0});
|
|
303
|
-
break;
|
|
304
|
-
|
|
305
|
-
case 'unitTime':
|
|
306
|
-
if (typeof options[k] === 'number' && options[k] >= 0.1 && options[k] <= 86400) {
|
|
307
|
-
this.limit.unitTime = parseInt(options[k] * 1000);
|
|
308
|
-
}
|
|
309
|
-
break;
|
|
310
|
-
|
|
311
|
-
case 'maxIPCache':
|
|
312
|
-
optionsCheck(k, options[k], this.limit, {type: 'number', min: 1024});
|
|
313
|
-
break;
|
|
314
|
-
|
|
315
|
-
case 'allow':
|
|
316
|
-
optionsCheck(k, options[k], this.limit, {type: ['object', 'function']});
|
|
317
|
-
this.limit.allow_type = (typeof options[k])[0];
|
|
318
|
-
break;
|
|
319
|
-
|
|
320
|
-
case 'logHandle':
|
|
321
|
-
case 'errorHandle':
|
|
322
|
-
optionsCheck(k, options[k], this.config, {type: 'function'});
|
|
323
|
-
break;
|
|
324
|
-
|
|
325
|
-
case 'logMaxLines':
|
|
326
|
-
optionsCheck(k, options[k], this.config, {type: 'number', min: 1, max: 5000000});
|
|
327
|
-
break;
|
|
328
|
-
|
|
329
|
-
case 'memFactor':
|
|
330
|
-
optionsCheck(k, options[k], this.config, {type: 'number', min: -0.58, max: 0.36});
|
|
331
|
-
break;
|
|
332
|
-
|
|
333
|
-
case 'maxUrlLength':
|
|
334
|
-
optionsCheck(k, options[k], this.config, {type: 'number', min: 1, max: 4096});
|
|
335
|
-
break;
|
|
336
|
-
|
|
337
|
-
case 'maxpool':
|
|
338
|
-
optionsCheck(k, options[k], this.config, {type: 'number', min: 2, max: 50000});
|
|
339
|
-
break;
|
|
340
|
-
|
|
341
|
-
case 'monitorTimeSlice':
|
|
342
|
-
optionsCheck(k, options[k], this.config, {type: 'number', min: 5, max: 5000});
|
|
343
|
-
break;
|
|
344
|
-
|
|
345
|
-
case 'maxLoadRate':
|
|
346
|
-
optionsCheck(k, options[k], this.config, {type: 'number', min: 25, max: 98});
|
|
347
|
-
break;
|
|
348
|
-
|
|
349
|
-
case 'maxFiles':
|
|
350
|
-
case 'maxBody':
|
|
351
|
-
case 'maxQuery':
|
|
352
|
-
case 'requestTimeout':
|
|
353
|
-
case 'timeout':
|
|
354
|
-
case 'streamTimeout':
|
|
355
|
-
optionsCheck(k, options[k], this.config, {type: 'number', min: 0});
|
|
356
|
-
break;
|
|
357
|
-
|
|
358
|
-
case 'maxFormLength':
|
|
359
|
-
case 'maxFormKey':
|
|
360
|
-
case 'logHistory':
|
|
361
|
-
optionsCheck(k, options[k], this.config, {type: 'number', min: 1});
|
|
362
|
-
break;
|
|
363
|
-
|
|
364
|
-
case 'logType':
|
|
365
|
-
optionsCheck(k, options[k], this.config, {list: ['stdio','file', '']});
|
|
366
|
-
break;
|
|
367
|
-
|
|
368
|
-
case 'loadInfoType':
|
|
369
|
-
optionsCheck(k, options[k], this.config, {list: ['--null', 'text', 'json', 'orgjson']});
|
|
370
|
-
break;
|
|
371
|
-
|
|
372
|
-
case 'loadMonitor':
|
|
373
|
-
this.config.showLoadInfo = !!options[k];
|
|
374
|
-
break;
|
|
375
|
-
|
|
376
|
-
case 'showLoadInfo':
|
|
377
|
-
case 'daemon':
|
|
378
|
-
case 'debug':
|
|
379
|
-
case 'globalLog':
|
|
380
|
-
case 'ignoreSlash':
|
|
381
|
-
case 'parseBody':
|
|
382
|
-
case 'useLimit':
|
|
383
|
-
case 'http2':
|
|
384
|
-
case 'https':
|
|
385
|
-
case 'autoDecodeQuery':
|
|
386
|
-
case 'realIP':
|
|
387
|
-
case 'fastParseQuery':
|
|
388
|
-
case 'allowHTTP1':
|
|
389
|
-
this.config[k] = !!options[k]; break;
|
|
390
|
-
|
|
391
|
-
case 'notFound':
|
|
392
|
-
case 'badRequest':
|
|
393
|
-
case 'logFile':
|
|
394
|
-
case 'errorLogFile':
|
|
395
|
-
case 'loadInfoFile':
|
|
396
|
-
case 'pidFile':
|
|
397
|
-
optionsCheck(k, options[k], this.config, {type: 'string'});
|
|
398
|
-
break;
|
|
399
|
-
|
|
400
|
-
case 'strong':
|
|
401
|
-
this.config[k] = options[k]; break;
|
|
402
|
-
|
|
403
|
-
default:
|
|
404
|
-
if (this.config[k] === undefined) {
|
|
405
|
-
setTimeout(() => {
|
|
406
|
-
console.error(`\x1b[7m!!未知选项: ${k}\n!!请查看文档使用正确的选项。\n\x1b[0m`);
|
|
407
|
-
}, 500);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
if (options.server && typeof options.server === 'object') {
|
|
413
|
-
for (let x in options.server) {
|
|
414
|
-
this.config.server[x] = options.server[x];
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if (options.key && options.cert) {
|
|
419
|
-
this.config.cert = options.cert;
|
|
420
|
-
this.config.key = options.key;
|
|
421
|
-
this.config.https = true;
|
|
422
|
-
} else if (this.config.server.SNICallback && typeof this.config.server.SNICallback === 'function') {
|
|
423
|
-
this.config.https = true;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
if (this.config.streamTimeout < 0) {
|
|
427
|
-
this.config.streamTimeout = this.config.timeout;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
//记录当前的运行情况
|
|
431
|
-
this.rundata = {
|
|
432
|
-
conn : 0,
|
|
433
|
-
platform : os.platform(),
|
|
434
|
-
host : '',
|
|
435
|
-
port : 0,
|
|
436
|
-
cpuLast : {user:0,system:0},
|
|
437
|
-
cpuTime : {user:0,system:0},
|
|
438
|
-
mem : {
|
|
439
|
-
rss : 0,
|
|
440
|
-
heapTotal: 0,
|
|
441
|
-
heapUsed : 0,
|
|
442
|
-
external : 0,
|
|
443
|
-
//rss + external
|
|
444
|
-
total: 0,
|
|
445
|
-
arrayBuffers: 0
|
|
446
|
-
},
|
|
447
|
-
cpus : 0
|
|
448
|
-
};
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
* 用于限制在daemon模式,子进程如果真的超出最大内存限制则会重启子进程。
|
|
452
|
-
* 因为RSS包括了Buffer的占用,所以maxrss包括Buffer默认的最大限制。
|
|
453
|
-
* 在Node 12+版本测试默认heaptotal可以稍微超过2G。
|
|
454
|
-
* */
|
|
455
|
-
this.totalmem = os.totalmem();
|
|
456
|
-
this.topmem = 2147483648;
|
|
457
|
-
|
|
458
|
-
if (this.topmem > this.totalmem) {
|
|
459
|
-
this.topmem = parseInt(this.totalmem * 0.9);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
this.secure = {
|
|
463
|
-
//minmem : 50000 超过最大内存限制则只有在连接数为0时才会重启进程
|
|
464
|
-
//而超过diemem则直接kill 这限制的是对heap的使用
|
|
465
|
-
//parseInt(this.topmem * (0.5 + this.config.memFactor) )
|
|
466
|
-
diemem : this.topmem,
|
|
467
|
-
|
|
468
|
-
//parseInt(this.topmem * (0.5 + this.config.memFactor) )
|
|
469
|
-
maxmem : parseInt(this.topmem * 0.95),
|
|
470
|
-
|
|
471
|
-
maxrss : parseInt(this.totalmem * (0.52 + this.config.memFactor) )
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
//运行时服务,需要在全局添加一些服务插件可以放在此处。
|
|
475
|
-
//如果需要把app相关配置信息,router等传递给请求上下文可以放在此处。
|
|
476
|
-
Object.defineProperty(this, 'service', {
|
|
477
|
-
enumerable: false,
|
|
478
|
-
writable: false,
|
|
479
|
-
configurable: false,
|
|
480
|
-
value: Object.create(null)
|
|
481
|
-
});
|
|
482
|
-
|
|
483
|
-
this.bodyparser = new bodyParser({
|
|
484
|
-
maxFormKey: this.config.maxFormKey,
|
|
485
|
-
maxFiles: this.config.maxFiles,
|
|
486
|
-
maxFormLength: this.config.maxFormLength
|
|
487
|
-
});
|
|
488
|
-
|
|
489
|
-
this.router = new router(this.config);
|
|
490
|
-
this.router.__subapp__ = makeSubAppForGroup.bind(this,this);
|
|
491
|
-
|
|
492
|
-
//连接过滤和计数以及超时控制。
|
|
493
|
-
this.connfilter = connfilter;
|
|
494
|
-
|
|
495
|
-
if (this.config.http2) {
|
|
496
|
-
if (this.config.allowHTTP1) {
|
|
497
|
-
this.config.server.allowHTTP1 = true;
|
|
498
|
-
} else if (this.config.server.allowHTTP1) {
|
|
499
|
-
this.config.allowHTTP1 = true;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
if (this.config.http2 && !this.config.allowHTTP1) {
|
|
504
|
-
this.midware = new middleware2(this.config);
|
|
505
|
-
} else {
|
|
506
|
-
this.midware = new middleware1(this.config);
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
this.eventTable = {};
|
|
510
|
-
this.server = {};
|
|
511
|
-
this.__pre_mids__ = [];
|
|
512
|
-
let opts = {
|
|
513
|
-
config: this.config,
|
|
514
|
-
events: this.eventTable,
|
|
515
|
-
router: this.router,
|
|
516
|
-
midware: this.midware,
|
|
517
|
-
service: this.service,
|
|
518
|
-
isWorker: this.isWorker,
|
|
519
|
-
};
|
|
520
|
-
|
|
521
|
-
if (this.config.http2 && !this.config.allowHTTP1) {
|
|
522
|
-
this.httpServ = new httpt(opts);
|
|
523
|
-
} else {
|
|
524
|
-
this.httpServ = new http1(opts);
|
|
525
|
-
if (this.config.http2 && this.config.allowHTTP1) {
|
|
526
|
-
let hc = new httpc();
|
|
527
|
-
hc.init(this);
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
this.logger = null;
|
|
532
|
-
this.monitor = null;
|
|
533
|
-
|
|
534
|
-
this.__init__();
|
|
535
|
-
};
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
*
|
|
539
|
-
* @param {string} path 路由字符串
|
|
540
|
-
* @param {function} cb 回调函数
|
|
541
|
-
* @param {object|string} options 选项
|
|
542
|
-
*/
|
|
543
|
-
titbit.prototype.get = function(path, cb, options='') {
|
|
544
|
-
return this.router.get(path, cb, options)
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
/**
|
|
548
|
-
*
|
|
549
|
-
* @param {string} path 路由字符串
|
|
550
|
-
* @param {function} cb 回调函数
|
|
551
|
-
* @param {object|string} options 选项
|
|
552
|
-
*/
|
|
553
|
-
titbit.prototype.post = function(path, cb, options='') {
|
|
554
|
-
return this.router.post(path, cb, options)
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
/**
|
|
558
|
-
*
|
|
559
|
-
* @param {string} path 路由字符串
|
|
560
|
-
* @param {function} cb 回调函数
|
|
561
|
-
* @param {object|string} options 选项
|
|
562
|
-
*/
|
|
563
|
-
titbit.prototype.put = function(path, cb, options='') {
|
|
564
|
-
return this.router.put(path, cb, options)
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
/**
|
|
568
|
-
*
|
|
569
|
-
* @param {string} path 路由字符串
|
|
570
|
-
* @param {function} cb 回调函数
|
|
571
|
-
* @param {object|string} options 选项
|
|
572
|
-
*/
|
|
573
|
-
titbit.prototype.delete = function(path, cb, options='') {
|
|
574
|
-
return this.router.delete(path, cb, options)
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
/**
|
|
578
|
-
*
|
|
579
|
-
* @param {string} path 路由字符串
|
|
580
|
-
* @param {function} cb 回调函数
|
|
581
|
-
* @param {object|string} options 选项
|
|
582
|
-
*/
|
|
583
|
-
titbit.prototype.options = function(path, cb, options='') {
|
|
584
|
-
return this.router.options(path, cb, options)
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
*
|
|
589
|
-
* @param {string} path 路由字符串
|
|
590
|
-
* @param {function} cb 回调函数
|
|
591
|
-
* @param {object|string} options 选项
|
|
592
|
-
*/
|
|
593
|
-
titbit.prototype.patch = function(path, cb, options='') {
|
|
594
|
-
return this.router.patch(path, cb, options)
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
/**
|
|
598
|
-
*
|
|
599
|
-
* @param {string} path 路由字符串
|
|
600
|
-
* @param {function} cb 回调函数
|
|
601
|
-
* @param {object|string} options 选项
|
|
602
|
-
*/
|
|
603
|
-
titbit.prototype.head = function(path, cb, options='') {
|
|
604
|
-
return this.router.head(path, cb, options)
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
/**
|
|
608
|
-
*
|
|
609
|
-
* @param {string} path 路由字符串
|
|
610
|
-
* @param {function} cb 回调函数
|
|
611
|
-
* @param {object|string} options 选项
|
|
612
|
-
*/
|
|
613
|
-
titbit.prototype.trace = function(path, cb, options='') {
|
|
614
|
-
return this.router.trace(path, cb, options)
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
/**
|
|
618
|
-
*
|
|
619
|
-
* @param {string} grp_name 路由分组名称
|
|
620
|
-
* @param {function} cb 回调函数
|
|
621
|
-
* @param {boolean} prefix 是否作为前缀路经,默认为true,当检测到路由是合法的模式会自动设置为前缀路径
|
|
622
|
-
*/
|
|
623
|
-
titbit.prototype.group = function(grp_name, cb, prefix=true) {
|
|
624
|
-
return this.router.group(grp_name, cb, prefix)
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
/**
|
|
628
|
-
*
|
|
629
|
-
* @param {Array} mids
|
|
630
|
-
* @returns {object} - 属性值group函数
|
|
631
|
-
*/
|
|
632
|
-
titbit.prototype.middleware = function(mids, options=null) {
|
|
633
|
-
let submid = {
|
|
634
|
-
group: (grp_name, cb, prefix=true) => {
|
|
635
|
-
let subapp = makeSubAppForGroup(this, grp_name);
|
|
636
|
-
subapp.__mids__.push({
|
|
637
|
-
mids: mids,
|
|
638
|
-
options: options
|
|
639
|
-
});
|
|
640
|
-
|
|
641
|
-
subapp.__group__ = grp_name.trim();
|
|
642
|
-
|
|
643
|
-
return this.router.__group__(grp_name, cb, subapp, prefix, this.router.__subapp__);
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
return submid;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
/**
|
|
651
|
-
* @param {array} marr method数组,示例['GET','HEAD']。
|
|
652
|
-
* @param {string} path 路由字符串。
|
|
653
|
-
* @param {function} callback 请求处理回调函数,必须是async声明。
|
|
654
|
-
* @param {string} name 请求命名,默认为空字符串,可以不写。
|
|
655
|
-
*/
|
|
656
|
-
titbit.prototype.map = function (marr, path, callback, name = '') {
|
|
657
|
-
return this.router.map(marr, name, callback, name);
|
|
658
|
-
};
|
|
659
|
-
|
|
660
|
-
/**
|
|
661
|
-
* @param {string} path 路由字符串。
|
|
662
|
-
* @param {function} callback 请求处理回调函数,必须是async声明。
|
|
663
|
-
* @param {string} name 请求命名,默认为空字符串,可以不写。
|
|
664
|
-
*/
|
|
665
|
-
titbit.prototype.any = function (path, callback, name = '') {
|
|
666
|
-
return this.router.any(name, callback, name);
|
|
667
|
-
};
|
|
668
|
-
|
|
669
|
-
titbit.prototype.__init__ = function () {
|
|
670
|
-
if (this.__init_flag__) return false;
|
|
671
|
-
//workers记录了在cluster模式,每个worker的启动时间,这可以在disconnect事件中检测。
|
|
672
|
-
Object.defineProperties(this, {
|
|
673
|
-
workers: {
|
|
674
|
-
enumerable: false,
|
|
675
|
-
configurable: false,
|
|
676
|
-
writable: false,
|
|
677
|
-
value: Object.create(null)
|
|
678
|
-
},
|
|
679
|
-
workerCount: {
|
|
680
|
-
enumerable: false,
|
|
681
|
-
configurable: false,
|
|
682
|
-
writable: false,
|
|
683
|
-
value: {
|
|
684
|
-
total : 0,
|
|
685
|
-
cur : 0,
|
|
686
|
-
max : 0,
|
|
687
|
-
canAutoFork: true,
|
|
688
|
-
}
|
|
689
|
-
},
|
|
690
|
-
|
|
691
|
-
msgEvent: {
|
|
692
|
-
enumerable: false,
|
|
693
|
-
configurable: false,
|
|
694
|
-
writable: false,
|
|
695
|
-
value: Object.create(null)
|
|
696
|
-
}
|
|
697
|
-
});
|
|
698
|
-
|
|
699
|
-
//如果worker运行在很短时间内退出说明可能存在问题,这时候则终止master进程并立即给出错误信息。
|
|
700
|
-
//注意这是在运行开始就要判断并解决的问题。设置值最好不低于100,也不要太高。
|
|
701
|
-
this.workerErrorTime = 500;
|
|
702
|
-
this.errorBreakCount = 0;
|
|
703
|
-
this.keepWorkersTimer = null;
|
|
704
|
-
|
|
705
|
-
if (this.config.globalLog) {
|
|
706
|
-
this.logger = new loggermsg(this.config);
|
|
707
|
-
if (this.isMaster) {
|
|
708
|
-
this.logger._checkBeforeInit();
|
|
709
|
-
this.logger.init();
|
|
710
|
-
this.setMsgEvent('_log', this.logger.msgEvent());
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
if (this.config.showLoadInfo) {
|
|
715
|
-
this.monitor = new monitor({
|
|
716
|
-
config : this.config,
|
|
717
|
-
secure : this.secure,
|
|
718
|
-
workers : this.workers,
|
|
719
|
-
rundata : this.rundata,
|
|
720
|
-
workerCount : this.workerCount
|
|
721
|
-
});
|
|
722
|
-
|
|
723
|
-
if (this.isMaster) {
|
|
724
|
-
this.setMsgEvent('_load', this.monitor.msgEvent());
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
if (this.config.strong === true) {
|
|
729
|
-
this.config.strong = {}
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
if (this.config.strong && this.config.strong.toString() === '[object Object]') {
|
|
733
|
-
let no_exit = new strong(this.config.strong);
|
|
734
|
-
no_exit.init();
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
this.helper = helper;
|
|
738
|
-
this.ext = helper;
|
|
739
|
-
|
|
740
|
-
this.context = (type = '') => {
|
|
741
|
-
if (type === 1 || type === '1') return new context1();
|
|
742
|
-
else if (type === 2 || type === '2') return new context2();
|
|
743
|
-
return (this.config.http2 && !this.config.allowHTTP1) ? new context2() : new context1();
|
|
744
|
-
};
|
|
745
|
-
|
|
746
|
-
this.initMsgEvent();
|
|
747
|
-
this.__init_flag__ = true;
|
|
748
|
-
};
|
|
749
|
-
|
|
750
|
-
/**
|
|
751
|
-
* 提供一个守护进程消息事件监听机制,记录对应事件和函数,并进行回调处理,
|
|
752
|
-
* 进而抽离出负载、日志等功能作为独立的模块。消息必须是JSON对象,type字段说明了事件类型。
|
|
753
|
-
*/
|
|
754
|
-
titbit.prototype.initMsgEvent = function () {
|
|
755
|
-
this.setMsgEvent('_eaddr', (w, msg, handle = undefined) => {
|
|
756
|
-
let errmsg = '\x1b[1;35m端口已被使用,请先停止正在运行的进程。\n在Linux/Unix上,可通过\n\t'
|
|
757
|
-
+'ps -e -o user,pid,ppid,comm,args | grep node | grep -v grep\n'
|
|
758
|
-
+' 或\n\tss -utlp\n查看相关进程。在Windows上通过任务管理器查找并结束相关进程。\x1b[0m';
|
|
759
|
-
|
|
760
|
-
console.error(errmsg);
|
|
761
|
-
sigExit();
|
|
762
|
-
}, 'once');
|
|
763
|
-
|
|
764
|
-
this.setMsgEvent('_route-table', (w, msg, handle = undefined) => {
|
|
765
|
-
console.log(msg.route);
|
|
766
|
-
console.log('PID:', process.pid, msg.listen, msg.protocol);
|
|
767
|
-
console.log(_titbit_server_running);
|
|
768
|
-
}, 'once');
|
|
769
|
-
|
|
770
|
-
this.setMsgEvent('_server-error', (w, msg, handle=undefined) => {
|
|
771
|
-
let hintText = '出现这种情况说明遇到了错误情况不得不终止服务,请根据错误提示信息排查解决。';
|
|
772
|
-
console.error(`\x1b[1;35m${msg.message}\n${hintText}\x1b[0m`);
|
|
773
|
-
sigExit();
|
|
774
|
-
}, 'once');
|
|
775
|
-
|
|
776
|
-
};
|
|
777
|
-
|
|
778
|
-
/**
|
|
779
|
-
* @param {string} - evt
|
|
780
|
-
* @param {function} - callback
|
|
781
|
-
* */
|
|
782
|
-
titbit.prototype.on = function(evt, callback) {
|
|
783
|
-
if (evt === 'requestError') {
|
|
784
|
-
if (typeof callback === 'function') {
|
|
785
|
-
this.httpServ.requestError = callback;
|
|
786
|
-
}
|
|
787
|
-
return;
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
if (!this.eventTable[evt]) {
|
|
791
|
-
this.eventTable[evt] = [ callback ];
|
|
792
|
-
} else {
|
|
793
|
-
this.eventTable[evt].push(callback);
|
|
794
|
-
}
|
|
795
|
-
};
|
|
796
|
-
|
|
797
|
-
/**
|
|
798
|
-
* @param {function} midcall
|
|
799
|
-
* @param {object} options 支持选项:group、name。
|
|
800
|
-
*/
|
|
801
|
-
titbit.prototype.add = function (midcall, options = {}) {
|
|
802
|
-
this.midware.add(midcall, options);
|
|
803
|
-
return this;
|
|
804
|
-
};
|
|
805
|
-
|
|
806
|
-
/**
|
|
807
|
-
* @param {function} midcall
|
|
808
|
-
* @param {object} options 支持选项:group、name、pre。
|
|
809
|
-
*/
|
|
810
|
-
titbit.prototype.use = function (midcall, options = {}) {
|
|
811
|
-
if (typeof options === 'object' && options.pre !== undefined) {
|
|
812
|
-
if (options.pre) {
|
|
813
|
-
return this.pre(midcall, options);
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
this.midware.addCache(midcall, options);
|
|
818
|
-
return this;
|
|
819
|
-
};
|
|
820
|
-
|
|
821
|
-
/**
|
|
822
|
-
* @param {function} midcall
|
|
823
|
-
* @param {object} options 支持选项:group、name。
|
|
824
|
-
*/
|
|
825
|
-
titbit.prototype.pre = function(midcall, options = {}) {
|
|
826
|
-
this.__pre_mids__.push({
|
|
827
|
-
callback: midcall,
|
|
828
|
-
options: options
|
|
829
|
-
});
|
|
830
|
-
|
|
831
|
-
return this;
|
|
832
|
-
};
|
|
833
|
-
|
|
834
|
-
/**
|
|
835
|
-
*
|
|
836
|
-
* @param {string|symbol} key
|
|
837
|
-
* @param {string|object|array|boolean|number|function} serv
|
|
838
|
-
*/
|
|
839
|
-
titbit.prototype.addService = function (key, serv) {
|
|
840
|
-
if (typeof key === 'object') {
|
|
841
|
-
for (let k in key) {
|
|
842
|
-
this.service[k] = key[k];
|
|
843
|
-
}
|
|
844
|
-
return this;
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
this.service[key] = serv;
|
|
848
|
-
return this;
|
|
849
|
-
};
|
|
850
|
-
|
|
851
|
-
titbit.prototype.getService = function (key) {
|
|
852
|
-
return this.service[key] || null;
|
|
853
|
-
};
|
|
854
|
-
|
|
855
|
-
titbit.prototype.clearService = function () {
|
|
856
|
-
for (let k in this.service) delete this.service[k];
|
|
857
|
-
};
|
|
858
|
-
|
|
859
|
-
/**
|
|
860
|
-
* 根据配置情况确定运行HTTP/1.1还是HTTP/2
|
|
861
|
-
* @param {number} port 端口号
|
|
862
|
-
* @param {string} host IP地址,可以是IPv4或IPv6
|
|
863
|
-
* 0.0.0.0 对应使用IPv6则是::
|
|
864
|
-
*/
|
|
865
|
-
titbit.prototype.run = function(port = 2368, host = '0.0.0.0') {
|
|
866
|
-
if (this.config.server.SNICallback && typeof this.config.server.SNICallback === 'function' && !this.config.https) {
|
|
867
|
-
this.config.https = true;
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
this.router.argsRouteSort();
|
|
871
|
-
|
|
872
|
-
this.rundata.host = (typeof port == 'number' ? host : '');
|
|
873
|
-
this.rundata.port = port;
|
|
874
|
-
|
|
875
|
-
//如果没有添加路由则添加默认路由
|
|
876
|
-
if (this.router.count === 0) {
|
|
877
|
-
this.router.get('/*', async c => {
|
|
878
|
-
c.setHeader('content-type', 'text/html; charset=utf-8');
|
|
879
|
-
c.res.body = _titbit_home_page;
|
|
880
|
-
});
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
//如果发现更改了service指向,则让this.httpServ.service重新指向this.service。
|
|
884
|
-
if (this.service !== this.httpServ.service) {
|
|
885
|
-
this.httpServ.service = this.service;
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
this.midware.addFromCache();
|
|
889
|
-
|
|
890
|
-
this.config.parseBody && this.add(this.bodyparser);
|
|
891
|
-
|
|
892
|
-
this.add(this.httpServ);
|
|
893
|
-
|
|
894
|
-
let m = null;
|
|
895
|
-
while((m = this.__pre_mids__.pop()) !== undefined) {
|
|
896
|
-
this.add(m.callback, m.options);
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
//必须放在最后,用于返回最终数据。
|
|
900
|
-
this.midware.addFinal();
|
|
901
|
-
|
|
902
|
-
if (this.config.useLimit) {
|
|
903
|
-
let connlimit = new this.connfilter(this.limit, this.rundata);
|
|
904
|
-
this.on('connection', connlimit.callback);
|
|
905
|
-
} else {
|
|
906
|
-
this.on('connection', (sock) => {
|
|
907
|
-
this.rundata.conn++;
|
|
908
|
-
sock.on('close', () => {
|
|
909
|
-
this.rundata.conn--;
|
|
910
|
-
});
|
|
911
|
-
|
|
912
|
-
});
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
/**
|
|
916
|
-
* 输出路由表,如果是启用了cluster,则通过发送消息的方式让master进程输出。
|
|
917
|
-
* */
|
|
918
|
-
if (this.config.debug) {
|
|
919
|
-
if (typeof port === 'string' && port.indexOf('.sock') > 0) {
|
|
920
|
-
host = '';
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
let is_https = this.config.https;
|
|
924
|
-
|
|
925
|
-
let protocol = this.config.http2
|
|
926
|
-
? ('http2' + (is_https ? '[https]' : ''))
|
|
927
|
-
: (is_https ? 'https' : 'http');
|
|
928
|
-
|
|
929
|
-
if (cluster.isMaster) {
|
|
930
|
-
this.router.printTable();
|
|
931
|
-
console.log(`PID: ${process.pid}, Listen ${host}:${port}, Protocol: ${protocol}`);
|
|
932
|
-
console.log(_titbit_server_running);
|
|
933
|
-
} else if (process.send && typeof process.send === 'function') {
|
|
934
|
-
process.send({type:'_route-table',
|
|
935
|
-
route : this.router.getTable(),
|
|
936
|
-
listen : `Listen: ${host}${host.length > 0 ? ':' : ''}${port}, `,
|
|
937
|
-
protocol : `Protocol: ${protocol}`
|
|
938
|
-
});
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
this.server = this.httpServ.run(port, host);
|
|
943
|
-
return this.server;
|
|
944
|
-
};
|
|
945
|
-
//run end
|
|
946
|
-
|
|
947
|
-
/**
|
|
948
|
-
* @param {string} evt
|
|
949
|
-
* @param {function} callback
|
|
950
|
-
* @param {string} mode always | once,默认always。
|
|
951
|
-
* */
|
|
952
|
-
titbit.prototype.setMsgEvent = function (evt, callback, mode = 'always') {
|
|
953
|
-
if (cluster.isWorker) {
|
|
954
|
-
return;
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
if (typeof callback !== 'function') {
|
|
958
|
-
console.error('setMsgEvent: callback not a function');
|
|
959
|
-
return false;
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
this.msgEvent[evt] = {
|
|
963
|
-
count : 0,
|
|
964
|
-
mode : mode,
|
|
965
|
-
callback : callback
|
|
966
|
-
};
|
|
967
|
-
return true;
|
|
968
|
-
};
|
|
969
|
-
|
|
970
|
-
titbit.prototype.getMsgEvent = function (evt) {
|
|
971
|
-
if (this.msgEvent[evt]) return this.msgEvent[evt];
|
|
972
|
-
return null;
|
|
973
|
-
};
|
|
974
|
-
|
|
975
|
-
titbit.prototype.removeMsgEvent = function (evt) {
|
|
976
|
-
if (this.msgEvent[evt]) {
|
|
977
|
-
let e = this.msgEvent[evt];
|
|
978
|
-
delete this.msgEvent[evt];
|
|
979
|
-
return e;
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
return false;
|
|
983
|
-
};
|
|
984
|
-
|
|
985
|
-
/**
|
|
986
|
-
* worker用于快速发送消息给master进程。
|
|
987
|
-
* @param {string} evtname 要发送消息的事件名称。
|
|
988
|
-
* @param {string|object} msg 要发送的消息。
|
|
989
|
-
* */
|
|
990
|
-
titbit.prototype.send = function (evtname, msg, handle = undefined) {
|
|
991
|
-
if (!cluster.isWorker || !process.send || typeof process.send !== 'function') return;
|
|
992
|
-
|
|
993
|
-
if (!msg) return;
|
|
994
|
-
|
|
995
|
-
let typn = typeof msg;
|
|
996
|
-
|
|
997
|
-
if (typn === 'string' || typn === 'number') msg = {msg: msg};
|
|
998
|
-
|
|
999
|
-
msg.type = evtname;
|
|
1000
|
-
|
|
1001
|
-
process.send(msg, handle);
|
|
1002
|
-
};
|
|
1003
|
-
|
|
1004
|
-
titbit.prototype.workerMsg = function (callback) {
|
|
1005
|
-
if (cluster.isWorker && callback && typeof callback === 'function') {
|
|
1006
|
-
process.on('message', callback);
|
|
1007
|
-
}
|
|
1008
|
-
};
|
|
1009
|
-
|
|
1010
|
-
titbit.prototype.daemonMessage = function () {
|
|
1011
|
-
if (cluster.isWorker) {
|
|
1012
|
-
return;
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
let self = this;
|
|
1016
|
-
for (let k in this.msgEvent) {
|
|
1017
|
-
this.msgEvent[k].count = 0;
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
|
-
cluster.on('message', (worker, msg, handle) => {
|
|
1021
|
-
try {
|
|
1022
|
-
if (typeof msg === 'object' && msg.type !== undefined) {
|
|
1023
|
-
if (self.msgEvent[msg.type] === undefined) {
|
|
1024
|
-
return;
|
|
1025
|
-
}
|
|
1026
|
-
let devt = self.msgEvent[msg.type];
|
|
1027
|
-
if (devt.mode === 'once' && devt.count > 0) {
|
|
1028
|
-
return;
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
if (devt.count < 30000000000) {
|
|
1032
|
-
devt.count += 1;
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
devt.callback(worker, msg, handle);
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
} catch (err) {
|
|
1039
|
-
self.config.debug && console.error(err);
|
|
1040
|
-
}
|
|
1041
|
-
});
|
|
1042
|
-
};
|
|
1043
|
-
|
|
1044
|
-
titbit.prototype.autoWorker = function (max) {
|
|
1045
|
-
if (typeof max === 'number' && max > 0) {
|
|
1046
|
-
this.workerCount.max = max;
|
|
1047
|
-
} else {
|
|
1048
|
-
throw new Error('autoWorker参数必须是一个大于0的数字,表示最大允许创建多少个子进程处理请求。');
|
|
1049
|
-
}
|
|
1050
|
-
};
|
|
1051
|
-
|
|
1052
|
-
/**
|
|
1053
|
-
* 调度类型,默认不做任何设置,采用Node.js cluster模块的默认设置。
|
|
1054
|
-
* @param {string} sch
|
|
1055
|
-
*/
|
|
1056
|
-
titbit.prototype.sched = function (sch = '') {
|
|
1057
|
-
if (sch === 'rr') {
|
|
1058
|
-
cluster.schedulingPolicy = cluster.SCHED_RR;
|
|
1059
|
-
} else if (sch === 'none') {
|
|
1060
|
-
cluster.schedulingPolicy = cluster.SCHED_NONE;
|
|
1061
|
-
} else {
|
|
1062
|
-
return cluster.schedulingPolicy;
|
|
1063
|
-
}
|
|
1064
|
-
};
|
|
1065
|
-
|
|
1066
|
-
titbit.prototype._checkDaemonArgs = function () {
|
|
1067
|
-
|
|
1068
|
-
if (process.argv.indexOf('--daemon') > 0) {
|
|
1069
|
-
} else if (this.config.daemon) {
|
|
1070
|
-
let args = process.argv.slice(1);
|
|
1071
|
-
args.push('--daemon');
|
|
1072
|
-
|
|
1073
|
-
const serv = spawn (process.argv[0], args, {
|
|
1074
|
-
detached: true,
|
|
1075
|
-
stdio: ['ignore', 1, 2]
|
|
1076
|
-
});
|
|
1077
|
-
|
|
1078
|
-
serv.unref();
|
|
1079
|
-
process.exit(0);
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
};
|
|
1083
|
-
|
|
1084
|
-
titbit.prototype.workerEventHandle = function () {
|
|
1085
|
-
cluster.on('listening', (worker, addr) => {
|
|
1086
|
-
this.workerCount.canAutoFork = true;
|
|
1087
|
-
this.workerCount.cur += 1;
|
|
1088
|
-
|
|
1089
|
-
let onerr = err => {
|
|
1090
|
-
this.config.errorHandle(err, '--ERR-WORKER--');
|
|
1091
|
-
};
|
|
1092
|
-
|
|
1093
|
-
worker.on('error', onerr);
|
|
1094
|
-
worker.process.on('error', onerr);
|
|
1095
|
-
|
|
1096
|
-
this.workers[ worker.id ] = {
|
|
1097
|
-
startTime : Date.now(),
|
|
1098
|
-
address : addr,
|
|
1099
|
-
id : worker.id,
|
|
1100
|
-
pid : worker.process.pid,
|
|
1101
|
-
conn: 0,
|
|
1102
|
-
mem: {
|
|
1103
|
-
rss : 0,
|
|
1104
|
-
heapTotal: 0,
|
|
1105
|
-
heapUsed: 0,
|
|
1106
|
-
external: 0,
|
|
1107
|
-
total: 0
|
|
1108
|
-
},
|
|
1109
|
-
cpu: {user:0, system:0},
|
|
1110
|
-
cputm : 1000
|
|
1111
|
-
};
|
|
1112
|
-
|
|
1113
|
-
});
|
|
1114
|
-
|
|
1115
|
-
let exitTip = () => {
|
|
1116
|
-
setTimeout(() => {
|
|
1117
|
-
let errmsg = `worker进程在限制的最短时间内(${this.workerErrorTime}ms)退出,请检测代码是否存在错误。`;
|
|
1118
|
-
console.error(errmsg);
|
|
1119
|
-
process.kill(0, 'SIGTERM');
|
|
1120
|
-
}, 15);
|
|
1121
|
-
};
|
|
1122
|
-
|
|
1123
|
-
cluster.on('disconnect', worker => {
|
|
1124
|
-
worker.kill('SIGTERM');
|
|
1125
|
-
});
|
|
1126
|
-
|
|
1127
|
-
cluster.on('exit', (worker, code, signal) => {
|
|
1128
|
-
this.workerCount.canAutoFork = true;
|
|
1129
|
-
this.workerCount.cur -= 1;
|
|
1130
|
-
let w = this.workers[worker.id];
|
|
1131
|
-
if (w) {
|
|
1132
|
-
let tm = Date.now();
|
|
1133
|
-
if (tm - w.startTime <= this.workerErrorTime && this.errorBreakCount <= 0 && code) {
|
|
1134
|
-
exitTip();
|
|
1135
|
-
} else {
|
|
1136
|
-
delete this.workers[w.id];
|
|
1137
|
-
}
|
|
1138
|
-
this.errorBreakCount = 1;
|
|
1139
|
-
} else {
|
|
1140
|
-
exitTip();
|
|
1141
|
-
}
|
|
1142
|
-
});
|
|
1143
|
-
|
|
1144
|
-
};
|
|
1145
|
-
|
|
1146
|
-
titbit.prototype.keepWorkers = function () {
|
|
1147
|
-
let keepworkers = () => {
|
|
1148
|
-
let num_dis = this.workerCount.total - Object.keys(cluster.workers).length;
|
|
1149
|
-
|
|
1150
|
-
if (num_dis <= 0) return;
|
|
1151
|
-
|
|
1152
|
-
for (let i = 0; i < num_dis; i++) {
|
|
1153
|
-
cluster.fork();
|
|
1154
|
-
}
|
|
1155
|
-
};
|
|
1156
|
-
|
|
1157
|
-
process.on('SIGCHLD', (sig) => {
|
|
1158
|
-
if (this.workerCount.cur >= this.workerCount.total) {
|
|
1159
|
-
return;
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
cluster.fork();
|
|
1163
|
-
|
|
1164
|
-
//测试kill多个子进程会有信号丢失的情况,设置定时器做最后的检测。
|
|
1165
|
-
if (this.keepWorkersTimer === null) {
|
|
1166
|
-
this.keepWorkersTimer = setTimeout (() => {
|
|
1167
|
-
this.keepWorkersTimer = null;
|
|
1168
|
-
keepworkers();
|
|
1169
|
-
}, 2000);
|
|
1170
|
-
}
|
|
1171
|
-
|
|
1172
|
-
});
|
|
1173
|
-
|
|
1174
|
-
if (process.platform === 'win32') {
|
|
1175
|
-
setInterval(() => {
|
|
1176
|
-
keepworkers();
|
|
1177
|
-
}, 1024);
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
};
|
|
1181
|
-
|
|
1182
|
-
/**
|
|
1183
|
-
* 这个函数是可以用于运维部署,此函数默认会根据CPU核数创建对应的子进程处理请求。
|
|
1184
|
-
* @param {number} port 端口号
|
|
1185
|
-
* @param {string} IP地址,IPv4或IPv6,如果检测为数字,则会把数字赋值给num。
|
|
1186
|
-
* @param {number} num,要创建的子进程数量,0表示自动,这时候根据CPU核心数量创建。
|
|
1187
|
-
*/
|
|
1188
|
-
titbit.prototype.daemon = function(port = 2368, host = '0.0.0.0', num = 0) {
|
|
1189
|
-
if (typeof host === 'number') {
|
|
1190
|
-
num = host;
|
|
1191
|
-
host = '0.0.0.0';
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
//确保自动创建的worker在终止时不会误认为是系统错误。
|
|
1195
|
-
setTimeout(() => {
|
|
1196
|
-
this.errorBreakCount += 1;
|
|
1197
|
-
}, this.workerErrorTime + 120);
|
|
1198
|
-
|
|
1199
|
-
this._checkDaemonArgs();
|
|
1200
|
-
|
|
1201
|
-
if (cluster.isMaster) {
|
|
1202
|
-
let osCPUS = os.cpus().length;
|
|
1203
|
-
if (num > (osCPUS*2) ) {
|
|
1204
|
-
num = 0;
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
if (num <= 0) {
|
|
1208
|
-
num = osCPUS;
|
|
1209
|
-
//如果CPU核心数超过2个,则使用核心数-1的子进程处理请求。
|
|
1210
|
-
if (num > 2) {
|
|
1211
|
-
num -= 1;
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
this.workerCount.total = num;
|
|
1216
|
-
|
|
1217
|
-
this.rundata.port = port;
|
|
1218
|
-
|
|
1219
|
-
this.rundata.host = (typeof port === 'number' ? host : '');
|
|
1220
|
-
|
|
1221
|
-
if (typeof this.config.loadInfoFile !== 'string') {
|
|
1222
|
-
this.config.loadInfoFile = '';
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
if (typeof this.config.pidFile === 'string' && this.config.pidFile.length > 0) {
|
|
1226
|
-
fs.writeFile(this.config.pidFile, `${process.pid}`, (err) => {
|
|
1227
|
-
err && console.error(err);
|
|
1228
|
-
});
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
|
-
this.daemonMessage();
|
|
1232
|
-
|
|
1233
|
-
//clear router and service
|
|
1234
|
-
this.clearService();
|
|
1235
|
-
this.router.clear();
|
|
1236
|
-
this.midware.midGroup = {};
|
|
1237
|
-
|
|
1238
|
-
this.workerEventHandle();
|
|
1239
|
-
|
|
1240
|
-
this.keepWorkers();
|
|
1241
|
-
|
|
1242
|
-
for (let i = 0; i < num; i++) {
|
|
1243
|
-
cluster.fork();
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
return this;
|
|
1247
|
-
|
|
1248
|
-
} else if (cluster.isWorker) {
|
|
1249
|
-
|
|
1250
|
-
if (this.config.showLoadInfo) {
|
|
1251
|
-
this.monitor.workerSend();
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1254
|
-
this.server = this.run(port, host);
|
|
1255
|
-
return this.server;
|
|
1256
|
-
}
|
|
1257
|
-
};
|
|
1258
|
-
|
|
1259
|
-
Object.defineProperty(titbit.prototype, 'isMaster', {
|
|
1260
|
-
get: () => {
|
|
1261
|
-
return cluster.isPrimary || cluster.isMaster;
|
|
1262
|
-
}
|
|
1263
|
-
});
|
|
1264
|
-
|
|
1265
|
-
Object.defineProperty(titbit.prototype, 'isPrimary', {
|
|
1266
|
-
get: () => {
|
|
1267
|
-
return cluster.isPrimary || cluster.isMaster;
|
|
1268
|
-
}
|
|
1269
|
-
});
|
|
1270
|
-
|
|
1271
|
-
Object.defineProperty(titbit.prototype, 'isWorker', {
|
|
1272
|
-
get: () => {
|
|
1273
|
-
return cluster.isWorker;
|
|
1274
|
-
}
|
|
1275
|
-
});
|
|
1276
|
-
|
|
1277
|
-
Object.keys(titbit.prototype).forEach(x => {
|
|
1278
|
-
Object.defineProperty(titbit.prototype, x, {
|
|
1279
|
-
enumerable: false,
|
|
1280
|
-
configurable: true,
|
|
1281
|
-
writable: true,
|
|
1282
|
-
value: titbit.prototype[x]
|
|
1283
|
-
});
|
|
1284
|
-
});
|
|
1285
|
-
|
|
1286
|
-
module.exports = titbit;
|