topbit 1.0.0 → 3.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.
Files changed (89) hide show
  1. package/LICENSE +128 -0
  2. package/README.cn.md +1519 -0
  3. package/README.md +1483 -0
  4. package/bin/app.js +17 -0
  5. package/bin/loadinfo.sh +18 -0
  6. package/bin/new-ctl.js +234 -0
  7. package/bin/newapp.js +22 -0
  8. package/demo/allow.js +98 -0
  9. package/demo/cert/localhost-cert.pem +19 -0
  10. package/demo/cert/localhost-privkey.pem +28 -0
  11. package/demo/controller/api.js +15 -0
  12. package/demo/extends.js +5 -0
  13. package/demo/group-api.js +161 -0
  14. package/demo/group-api2.js +109 -0
  15. package/demo/http2.js +34 -0
  16. package/demo/http2_proxy_backend.js +45 -0
  17. package/demo/http2proxy.js +48 -0
  18. package/demo/http_proxy_backend.js +44 -0
  19. package/demo/httpproxy.js +47 -0
  20. package/demo/loader.js +27 -0
  21. package/demo/log.js +118 -0
  22. package/demo/memlimit.js +31 -0
  23. package/demo/min.js +7 -0
  24. package/demo/serv.js +15 -0
  25. package/images/middleware.jpg +0 -0
  26. package/images/topbit-middleware.png +0 -0
  27. package/images/topbit.png +0 -0
  28. package/package.json +42 -11
  29. package/src/_loadExtends.js +21 -0
  30. package/src/bodyparser.js +420 -0
  31. package/src/connfilter.js +125 -0
  32. package/src/context1.js +166 -0
  33. package/src/context2.js +182 -0
  34. package/src/ctxpool.js +39 -0
  35. package/src/ext.js +318 -0
  36. package/src/extends/Http2Pool.js +365 -0
  37. package/src/extends/__randstring.js +24 -0
  38. package/src/extends/cookie.js +44 -0
  39. package/src/extends/cors.js +334 -0
  40. package/src/extends/errorlog.js +252 -0
  41. package/src/extends/http2limit.js +126 -0
  42. package/src/extends/http2proxy.js +691 -0
  43. package/src/extends/jwt.js +217 -0
  44. package/src/extends/mixlogger.js +63 -0
  45. package/src/extends/paramcheck.js +266 -0
  46. package/src/extends/proxy.js +662 -0
  47. package/src/extends/realip.js +34 -0
  48. package/src/extends/referer.js +68 -0
  49. package/src/extends/resource.js +398 -0
  50. package/src/extends/session.js +174 -0
  51. package/src/extends/setfinal.js +50 -0
  52. package/src/extends/sni.js +48 -0
  53. package/src/extends/sse.js +293 -0
  54. package/src/extends/timing.js +111 -0
  55. package/src/extends/tofile.js +123 -0
  56. package/src/fastParseUrl.js +426 -0
  57. package/src/headerLimit.js +18 -0
  58. package/src/http1.js +336 -0
  59. package/src/http2.js +337 -0
  60. package/src/httpc.js +251 -0
  61. package/src/lib/npargv.js +354 -0
  62. package/src/lib/zipdata.js +45 -0
  63. package/src/loader/loader.js +999 -0
  64. package/src/logger.js +32 -0
  65. package/src/loggermsg.js +349 -0
  66. package/src/makeId.js +200 -0
  67. package/src/midcore.js +213 -0
  68. package/src/middleware1.js +103 -0
  69. package/src/middleware2.js +116 -0
  70. package/src/monitor.js +380 -0
  71. package/src/movefile.js +30 -0
  72. package/src/optionsCheck.js +54 -0
  73. package/src/randstring.js +23 -0
  74. package/src/router.js +682 -0
  75. package/src/sendmsg.js +27 -0
  76. package/src/strong.js +72 -0
  77. package/src/token/token.js +461 -0
  78. package/src/topbit.js +1293 -0
  79. package/src/versionCheck.js +31 -0
  80. package/test/test-bigctx.js +29 -0
  81. package/test/test-daemon-args.js +7 -0
  82. package/test/test-ext.js +81 -0
  83. package/test/test-find.js +69 -0
  84. package/test/test-route-sort.js +71 -0
  85. package/test/test-route.js +49 -0
  86. package/test/test-route2.js +51 -0
  87. package/test/test-run-args.js +7 -0
  88. package/test/test-url.js +52 -0
  89. package/main.js +0 -0
package/src/logger.js ADDED
@@ -0,0 +1,32 @@
1
+ 'use strict'
2
+ const process = require('node:process');
3
+
4
+ module.exports = function (msg) {
5
+ let tm = new Date();
6
+ let tmstr =
7
+ `${tm.getFullYear()}-${tm.getMonth()+1}-${tm.getDate()} ${tm.getHours()}:${tm.getMinutes()}:${tm.getSeconds()}`;
8
+
9
+ let log_data = {
10
+ type : '_log',
11
+ success : true,
12
+ status : msg.status,
13
+ method: msg.method,
14
+ ip: msg.ip,
15
+ real_ip: msg.real_ip,
16
+ log : `@ ${msg.method} | ${msg.link} | ${msg.status} | ${tmstr} | ${msg.ip} | ${msg.agent} | ${msg.real_ip}\n`
17
+ };
18
+
19
+ if (msg.status >= 400) {
20
+ log_data.success = false;
21
+ }
22
+
23
+ if (process.send && typeof process.send === 'function') {
24
+ process.send(log_data);
25
+ } else {
26
+ if (log_data.success) {
27
+ console.log(log_data.log);
28
+ } else {
29
+ console.error(log_data.log);
30
+ }
31
+ }
32
+ };
@@ -0,0 +1,349 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+
6
+ const fsp = fs.promises;
7
+
8
+ let fmtTime = () => {
9
+ let t = new Date();
10
+ let m = t.getMonth() + 1;
11
+ let d = t.getDate();
12
+ let h = t.getHours();
13
+ let mt = t.getMinutes();
14
+ let sec = t.getSeconds();
15
+
16
+ return `${t.getFullYear()}_${m < 10 ? '0' : ''}${m}_${d < 10 ? '0' : ''}${d}`
17
+ + `_${h < 10 ? '0' : ''}${h}_${mt < 10 ? '0' : ''}${mt}`
18
+ + `_${sec < 10 ? '0' : ''}${sec}`;
19
+ };
20
+
21
+ class loggermsg {
22
+
23
+ constructor (options) {
24
+ this.config = options;
25
+
26
+ this.out = null;
27
+
28
+ this.fout = null;
29
+ this.ferr = null;
30
+
31
+ this.watchReset = false;
32
+
33
+ this.count = 0;
34
+
35
+ this.errCount = 0;
36
+
37
+ this.maxLines = this.config.logMaxLines;
38
+
39
+ this.maxSize = 200 * this.maxLines;
40
+
41
+ this.checkLock = false;
42
+
43
+ this.historyList = [];
44
+ this.errHistoryList = [];
45
+
46
+ this.logfile = '';
47
+ this.logDir = '';
48
+ this.errfile = '';
49
+ this.errLogDir = '';
50
+
51
+ this.prefix = '';
52
+ this.eprefix = '';
53
+
54
+ this.premap = {
55
+ logfile: 'prefix',
56
+ errfile: 'eprefix'
57
+ };
58
+
59
+ this.parseLogPath();
60
+ this.parsePrefix();
61
+ }
62
+
63
+ parsePrefix() {
64
+ let keys = ['logfile', 'errfile'];
65
+
66
+ keys.forEach(a => {
67
+ let leng = this[a].length
68
+ let extname = this[a].substring(leng-4).toLowerCase()
69
+ let k = this.premap[a]
70
+
71
+ if (extname === '.log') {
72
+ this[k] = this[a].substring(0, leng-4) + '_'
73
+ } else {
74
+ this[k] = this[a] + '_'
75
+ }
76
+
77
+ })
78
+ }
79
+
80
+ parseLogPath () {
81
+ if (this.config.logType !== 'file') return;
82
+
83
+ this.logfile = path.basename(this.config.logFile);
84
+ this.errfile = path.basename(this.config.errorLogFile);
85
+ this.logDir = path.resolve( path.dirname(this.config.logFile) );
86
+ this.errLogDir = path.resolve( path.dirname(this.config.errorLogFile) );
87
+ }
88
+
89
+ //在init之后运行
90
+ watch () {
91
+ if (this.config.logType !== 'file') {
92
+ return;
93
+ }
94
+
95
+ let wtf = (evt, fname) => {
96
+ if (this.watchReset) {
97
+ return;
98
+ }
99
+
100
+ if (evt === 'rename') {
101
+ if (fname !== this.logfile && fname !== this.errfile ) {
102
+ return;
103
+ }
104
+ this.watchReset = true;
105
+ this.destroy();
106
+ this.init();
107
+ this.watchReset = false;
108
+ }
109
+ };
110
+
111
+ try {
112
+ fs.watch(this.logDir, wtf);
113
+ } catch (err) {}
114
+
115
+ if (this.logDir !== this.errLogDir) {
116
+ try {
117
+ fs.watch(this.errLogDir, wtf);
118
+ } catch (err) {}
119
+ }
120
+
121
+ }
122
+
123
+ destroy () {
124
+ try {
125
+ if (this.fout && !this.fout.destroyed) {
126
+ this.fout.destroy();
127
+ }
128
+ if (this.ferr && !this.ferr.destroyed) {
129
+ this.ferr.destroy();
130
+ }
131
+ } catch (err) {}
132
+
133
+ this.fout = this.ferr = this.out = null;
134
+ }
135
+
136
+ /**
137
+ * 用于init之前的检测工作,主要检测日志文件是否已经超过了最大限制,
138
+ * 如果服务进程反复运行,会导致日志文件不断增大。
139
+ * 解决方案就是如果初始检测发现日志文件已经存在并且已经超过最大限制,
140
+ * 则直接设置计数为maxLines,让日志处理程序自动把它保存为备份日志文件。
141
+ * */
142
+ async _checkBeforeInit () {
143
+ if (this.config.logType !== 'file') return;
144
+
145
+ try {
146
+ await fsp.access(this.config.logFile);
147
+ let fa = await fsp.stat(this.config.logFile);
148
+
149
+ if (fa.size >= this.maxSize) {
150
+ this.count = this.maxLines;
151
+ }
152
+ } catch (err) {
153
+
154
+ }
155
+
156
+ try {
157
+ await fsp.access(this.config.errorLogFile);
158
+ let fb = await fsp.stat(this.config.errorLogFile);
159
+ if (fb.size >= this.maxSize) {
160
+ this.errCount = this.maxLines;
161
+ }
162
+ } catch (err) {
163
+
164
+ }
165
+
166
+ }
167
+
168
+ init () {
169
+ if (this.config.logType === 'file') {
170
+ this.out = null;
171
+
172
+ if (this.fout === null) {
173
+ try {
174
+ this.fout = fs.createWriteStream(this.config.logFile, { flags: 'a+', mode: 0o644 });
175
+
176
+ this.fout.on('close', () => {
177
+ this.fout = null;
178
+ });
179
+
180
+ this.fout.on('error', err => {
181
+ this.fout = null;
182
+ });
183
+ } catch (err) {
184
+ this.config.errorHandle(err, '--ERR-LOGGER-INIT--');
185
+ }
186
+ }
187
+
188
+ if (this.ferr === null) {
189
+ try {
190
+ this.ferr = fs.createWriteStream(this.config.errorLogFile, { flags: 'a+', mode: 0o644 });
191
+
192
+ this.ferr.on('close', () => {
193
+ this.ferr = null;
194
+ });
195
+
196
+ this.ferr.on('error', err => {
197
+ this.ferr = null;
198
+ });
199
+
200
+ } catch (err) {
201
+ this.config.errorHandle(err, '--ERR-LOGGER-INIT--');
202
+ }
203
+ }
204
+
205
+ } else if (this.config.logType === 'stdio') {
206
+ if (!this.out) {
207
+ let opts = {
208
+ stdout: process.stdout,
209
+ stderr: process.stderr
210
+ };
211
+
212
+ this.out = new console.Console(opts);
213
+ }
214
+ }
215
+ }
216
+
217
+ async _checkAndInit (k, ct, fname, curname, dirname, hlist) {
218
+ if (!this[k]) return;
219
+ if (this[ct] < this.maxLines) return;
220
+
221
+ let prename = this.premap[curname];
222
+
223
+ let history_logfile = `${this[dirname]}/${this[prename]}${fmtTime()}.log`;
224
+
225
+ let st = true;
226
+
227
+ await fsp.rename(fname, history_logfile).catch(err => {
228
+ st = false;
229
+ //检测是否还存在日志文件,若没有则初始化。
230
+ fs.access(fname, err => {
231
+ if (!err) return;
232
+ this[k] && !this[k].destroyed && this[k].destroy();
233
+ this[ct] = 0;
234
+ this.init();
235
+ });
236
+ });
237
+
238
+ if (!st) return;
239
+
240
+ this[hlist].push(history_logfile);
241
+ this[k] && !this[k].destroyed && this[k].destroy();
242
+ this[k] = null;
243
+ this[ct] = 0;
244
+
245
+ this.init();
246
+ }
247
+
248
+ async checkLog () {
249
+ if (this.checkLock) return;
250
+
251
+ this.checkLock = true;
252
+ try {
253
+ this.clearHistoryList('historyList');
254
+ this.clearHistoryList('errHistoryList');
255
+
256
+ await this._checkAndInit('fout', 'count',
257
+ this.config.logFile,
258
+ 'logfile',
259
+ 'logDir',
260
+ 'historyList');
261
+
262
+ await this._checkAndInit('ferr', 'errCount',
263
+ this.config.errorLogFile,
264
+ 'errfile',
265
+ 'errLogDir',
266
+ 'errHistoryList');
267
+
268
+ } catch (err) {
269
+ this.config.errorHandle(err, '--ERR-CHECK-LOG--');
270
+ } finally {
271
+ this.checkLock = false;
272
+ }
273
+
274
+ }
275
+
276
+ clearHistoryList(k) {
277
+ let hlist = this[k];
278
+
279
+ if (!hlist || !Array.isArray(hlist)) return;
280
+
281
+ if (hlist.length > (this.config.logHistory + 2)) {
282
+ let hfile;
283
+ let i=0;
284
+ let total = 3;
285
+ while (i < total) {
286
+ hfile = hlist.shift();
287
+
288
+ if (!hfile) return;
289
+
290
+ fs.unlink(hfile, err => {
291
+ err && (!err.code || err.code !== 'ENOENT') && this.config.errorHandle(err, '--ERR-UNLINK-LOG--')
292
+ });
293
+
294
+ i += 1;
295
+ }
296
+ }
297
+ }
298
+
299
+ msgEvent () {
300
+ if (typeof this.config.logHandle === 'function') {
301
+ return this.config.logHandle
302
+ }
303
+
304
+ let handle_none = (w, msg, handle) => {}
305
+
306
+ if (this.config.logType === '') {
307
+ return handle_none
308
+ }
309
+
310
+ let handle_file = (w, msg, handle) => {
311
+ if (msg.success) {
312
+ this.fout && this.fout.write(msg.log) && (this.count += 1);
313
+ } else {
314
+ this.ferr && this.ferr.write(msg.log) && (this.errCount += 1);
315
+ }
316
+
317
+ if (!this.fout || !this.ferr) {
318
+ this.init();
319
+ }
320
+
321
+ this.checkLog();
322
+ }
323
+
324
+ let handle_stdio = (w, msg, handle) => {
325
+ if (this.out) {
326
+ msg.success ? this.out.log(msg.log) : this.out.error(msg.log);
327
+ } else {
328
+ this.init();
329
+ }
330
+ }
331
+
332
+ if (this.config.logType === 'file') {
333
+ return handle_file
334
+ }
335
+
336
+ /*
337
+ if (this.config.logType === 'mix') {
338
+ return (w, msg, handle) => {
339
+ handle_file(w, msg, handle)
340
+ handle_stdio(w, msg, handle)
341
+ }
342
+ }*/
343
+
344
+ return handle_stdio
345
+ }
346
+
347
+ }
348
+
349
+ module.exports = loggermsg;
package/src/makeId.js ADDED
@@ -0,0 +1,200 @@
1
+ 'use strict'
2
+
3
+ const randstring = require('./randstring.js');
4
+
5
+ //2017-2-25 2050
6
+ let start_time = 1490390182066
7
+
8
+ let start_year = 2024
9
+
10
+ if ((new Date()).getFullYear() > 2085) {
11
+ start_year = 2086
12
+ }
13
+
14
+ let loopch = [
15
+ "0","1","2","3","4","5","6","7","8","9",
16
+ "a","b","c","d","e","f","g","h","i","j",
17
+ "k","l","m","n","o","p","q","r","s","t",
18
+ "u","v","w","x","y","z"
19
+ ]
20
+
21
+ let msloopch = []
22
+ for (let x of loopch) {
23
+ for (let y of loopch) {
24
+ msloopch.push(x+y)
25
+ }
26
+ }
27
+
28
+ let sloopch = msloopch.slice(0, 100)
29
+ let yloopch = msloopch.slice(36, 500)
30
+
31
+ msloopch = msloopch.slice(parseInt(Math.random() * 100))
32
+
33
+ let loopLength = loopch.length
34
+ let sloopLength = sloopch.length
35
+ let yloopLength = yloopch.length
36
+
37
+ class Clocks {
38
+ constructor() {
39
+ this.clocks = {
40
+ y: 0,
41
+ m: 0,
42
+ d: 0
43
+ }
44
+
45
+ this.startYear = 2024
46
+ }
47
+
48
+ rand() {
49
+ for (let k in this.clocks) {
50
+ this.clocks[k] = parseInt(loopLength * Math.random())
51
+ }
52
+ }
53
+
54
+ getFullTime() {
55
+ return this.getTime() + this.getCharTime()
56
+ }
57
+
58
+ getTime() {
59
+ let t = new Date()
60
+ let year = t.getFullYear()
61
+ let month = t.getMonth()
62
+ let dat = t.getDate()
63
+ let hour = t.getHours()
64
+ let minute = t.getMinutes()
65
+ let seconds = t.getSeconds()
66
+ let ms = t.getMilliseconds()
67
+
68
+ let yind = year - this.startYear
69
+
70
+ if (yind < 0 || yind >= yloopLength) yind = 0
71
+
72
+ //bits: 2 + 1 + 1 + 1 + 2 + 2 + 2 = 11
73
+ return yloopch[yind] + loopch[month] + loopch[dat] + loopch[hour] + sloopch[minute] + sloopch[seconds] + msloopch[ms]
74
+ }
75
+
76
+ getCharTime() {
77
+ let str = loopch[this.clocks.y] + loopch[this.clocks.m] + loopch[this.clocks.d]
78
+
79
+ this.clocks.d++
80
+ if (this.clocks.d >= loopLength) {
81
+ this.clocks.d = 0
82
+ this.clocks.m++
83
+ if (this.clocks.m >= loopLength) {
84
+ this.clocks.m = 0
85
+ this.clocks.y++
86
+ if (this.clocks.y >= loopLength) {
87
+ this.clocks.y = 0
88
+ }
89
+ }
90
+ }
91
+
92
+ return str
93
+ }
94
+
95
+ }
96
+
97
+ function longId(idLen=18, idPre = '') {
98
+ let pstr = (Date.now() - start_time).toString(16)
99
+ let leng = pstr.length
100
+ if (idLen < 18) idLen = 18
101
+ return idPre + pstr + randstring(idLen - leng)
102
+ }
103
+
104
+ function makeId(idLen = 12, idPre = '') {
105
+ if (idLen > 17) {
106
+ return longId(idLen, idPre);
107
+ }
108
+
109
+ let tmstr = Math.random().toString(16).substring(2);
110
+
111
+ if (tmstr.length < idLen) {
112
+ tmstr = `${tmstr}${randstring(idLen - tmstr.length)}`;
113
+ }
114
+
115
+ if (tmstr.length > idLen) {
116
+ tmstr = tmstr.substring(tmstr.length - idLen);
117
+ }
118
+
119
+ if (idPre) {
120
+ return `${idPre}${tmstr}`;
121
+ }
122
+
123
+ return tmstr;
124
+ }
125
+
126
+ let b_year = 2**47
127
+ let b_month = 2**43
128
+ let b_date = 2**38
129
+ let b_hour = 2**33
130
+ let b_min = 2**27
131
+ let b_sec = 2**21
132
+ let b_msec = 2**11
133
+
134
+ let end_max = 4096
135
+
136
+ function numId(obj) {
137
+ let t = new Date()
138
+
139
+ let first_num = (t.getFullYear() - start_year) * b_year + (t.getMonth()+1) * b_month
140
+ + t.getDate() * b_date + t.getHours() * b_hour + t.getMinutes() * b_min
141
+ + t.getSeconds() * b_sec + t.getMilliseconds() * b_msec
142
+
143
+ let fnum = first_num + obj.endnum
144
+
145
+ obj.endnum++
146
+
147
+ if (obj.endnum >= end_max) {
148
+ obj.endnum = 0
149
+ }
150
+
151
+ return fnum
152
+ }
153
+
154
+ function bigId(obj, a='', b='') {
155
+ let fnum = numId(obj)
156
+ return (BigInt(fnum) * 1000n + BigInt(parseInt(Math.random() * 1000))).toString()
157
+ }
158
+
159
+ Object.defineProperty(makeId, 'numId', {
160
+ enumerable: false,
161
+ configurable: false,
162
+ get: function () {
163
+ let oo = {
164
+ endnum: parseInt(Math.random() * 2000)
165
+ }
166
+
167
+ return numId.bind(null, oo)
168
+ }
169
+ })
170
+
171
+ Object.defineProperty(makeId, 'bigId', {
172
+ enumerable: false,
173
+ configurable: false,
174
+ get: function () {
175
+ let oo = {
176
+ endnum: parseInt(Math.random() * 2000)
177
+ }
178
+
179
+ return bigId.bind(null, oo)
180
+ }
181
+ })
182
+
183
+ makeId.longId = longId
184
+
185
+ Object.defineProperty(makeId, 'serialId', {
186
+ enumerable: false,
187
+ configurable: false,
188
+ get: function () {
189
+ let _next = new Clocks()
190
+ _next.rand()
191
+
192
+ return function sid(idLen=16, idPre='') {
193
+ if (idLen < 14) return makeId(idLen, idPre)
194
+
195
+ return idPre + _next.getFullTime() + randstring(idLen - 14)
196
+ }
197
+ }
198
+ })
199
+
200
+ module.exports = makeId;