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/midcore.js ADDED
@@ -0,0 +1,213 @@
1
+ 'use strict';
2
+
3
+ class MidCore {
4
+
5
+ constructor(options = {}) {
6
+ this.debug = true;
7
+ if (options.debug !== undefined) {
8
+ this.debug = options.debug;
9
+ }
10
+
11
+ this.errorHandle = options.errorHandle;
12
+
13
+ if (typeof this.errorHandle !== 'function') {
14
+ this.errorHandle = (err, errname) => {
15
+ this.debug && console.error(errname, err);
16
+ };
17
+ }
18
+
19
+ this.globalKey = `_GLOBAL_0129_${Math.random().toString(16).substring(2)}_`;
20
+
21
+ this.midGroup = {};
22
+
23
+ this.midGroup[ this.globalKey ] = [
24
+ async (ctx) => {
25
+ if (typeof ctx.requestCall === 'function') {
26
+ return await ctx.requestCall(ctx);
27
+ }
28
+ }
29
+ ];
30
+
31
+ this.stackCache = [];
32
+ }
33
+
34
+ /**
35
+ * @param {function} midcall 回调函数
36
+ * @param {array|object|string} 选项
37
+ */
38
+ addCache(midcall, options = {}) {
39
+ this.stackCache.push({
40
+ callback: midcall,
41
+ options: options
42
+ });
43
+ };
44
+
45
+ /**
46
+ * @param {object} groupTable 路由分组表
47
+ */
48
+ addFromCache() {
49
+ let m = null;
50
+ while((m = this.stackCache.pop()) !== undefined) {
51
+ this.add(m.callback, m.options);
52
+ }
53
+ };
54
+
55
+ //如果某一分组添加时,已经有全局中间件,需要先把全局中间件添加到此分组。
56
+ initGroup(group, fromGroup='') {
57
+ this.midGroup[group] = [];
58
+ let mids = this.midGroup[this.globalKey];
59
+
60
+ /* if (fromGroup && group !== fromGroup && this.midGroup[fromGroup])
61
+ mids = this.midGroup[fromGroup]; */
62
+
63
+ for(let i=0; i < mids.length; i++) {
64
+ this.midGroup[group].push(mids[i]);
65
+ }
66
+ };
67
+
68
+ /**
69
+ * @param {async function} midcall 接受参数(ctx, next)。
70
+ * @param {string|Array|object} options 选项。
71
+ * options如果是字符串则表示针对分组添加中间件,如果是数组或正则表达式则表示匹配规则。
72
+ * 如果你想针对某一分组添加中间件,同时还要设置匹配规则,则可以使用以下形式:
73
+ * {
74
+ * pathname : string | Array,
75
+ * group : string
76
+ * }
77
+ */
78
+ add(midcall, options = {}) {
79
+ if (typeof midcall === 'object') {
80
+ if (midcall.mid && typeof midcall.mid === 'function') {
81
+
82
+ midcall = midcall.mid();
83
+
84
+ } else if (midcall.middleware
85
+ && typeof midcall.middleware === 'function'
86
+ && midcall.middleware.constructor.name === 'AsyncFunction')
87
+ {
88
+ midcall = midcall.middleware.bind(midcall);
89
+ }
90
+
91
+ }
92
+
93
+ if (typeof midcall !== 'function' || midcall.constructor.name !== 'AsyncFunction') {
94
+ throw new Error('callback and middleware function must use async');
95
+ }
96
+
97
+ let pathname = null;
98
+ let group = null;
99
+ let method = null;
100
+ //let from_group = '';
101
+ if (typeof options === 'string') {
102
+ if (options[0] === '@') {
103
+ options = { group: options.substring(1) }
104
+ } else {
105
+ options = [options]
106
+ }
107
+ }
108
+
109
+ if (Array.isArray(options)) {
110
+ pathname = options;
111
+ } if (options && typeof options === 'object') {
112
+ if (options.name !== undefined) {
113
+ if (typeof options.name === 'string' && options.name.trim()) {
114
+ pathname = [options.name.trim()];
115
+ } else if (Array.isArray(options.name) && options.name.length > 0) {
116
+ pathname = options.name;
117
+ }
118
+ }
119
+
120
+ if (options.group !== undefined && typeof options.group === 'string') {
121
+ group = options.group;
122
+ }
123
+
124
+ /* if (options.from && typeof options.from === 'string') {
125
+ from_group = options.from;
126
+ } */
127
+
128
+ if (options.method !== undefined) {
129
+ if (typeof options.method === 'string' && options.method.length > 0) {
130
+ method = [options.method];
131
+ } else if (Array.isArray(options.method) && options.method.length > 0) {
132
+ method = options.method;
133
+ }
134
+ //请求方法如果传递了小写,都转换为大写。
135
+ method && method.forEach((m, index) => {
136
+ method[index] = m.toUpperCase();
137
+ });
138
+ }
139
+ }
140
+
141
+ let self = this;
142
+ let makeRealMid = (prev_mid, grp) => {
143
+ let nextcall = self.midGroup[grp][prev_mid];
144
+
145
+ if (!method && !pathname) {
146
+ return async (ctx) => { return await midcall(ctx, nextcall); };
147
+ }
148
+
149
+ let methodTable = null;
150
+ method && (methodTable = {}) && method.forEach(a => { methodTable[a] = true; });
151
+
152
+ let nameTable = null;
153
+ pathname && (nameTable = {}) && pathname.forEach(a => { nameTable[a] = true; });
154
+
155
+ if (methodTable && !nameTable) {
156
+ return async (ctx) => {
157
+ if (!methodTable[ctx.method]) {
158
+ return await nextcall(ctx);
159
+ }
160
+
161
+ return await midcall(ctx, nextcall);
162
+ }
163
+ }
164
+
165
+ if (!methodTable && nameTable) {
166
+ return async (ctx) => {
167
+ if (!nameTable[ctx.name]) {
168
+ return await nextcall(ctx);
169
+ }
170
+
171
+ return await midcall(ctx, nextcall);
172
+ }
173
+ }
174
+
175
+ return async (ctx) => {
176
+ if (!methodTable[ctx.method] || !nameTable[ctx.name]) {
177
+ return await nextcall(ctx);
178
+ }
179
+
180
+ return await midcall(ctx, nextcall);
181
+ };
182
+ };
183
+
184
+ let last = 0;
185
+ if (group) {
186
+ if (!this.midGroup[group]) {
187
+ this.initGroup(group);
188
+ //this.initGroup(group, from_group);
189
+ }
190
+ last = this.midGroup[group].length - 1;
191
+ this.midGroup[group].push(makeRealMid(last, group));
192
+ } else {
193
+ //全局添加中间件
194
+ for (let k in this.midGroup) {
195
+ last = this.midGroup[k].length - 1;
196
+ this.midGroup[k].push(makeRealMid(last, k));
197
+ }
198
+ }
199
+ return this;
200
+ }
201
+
202
+ exec(ctx, group='') {
203
+ if (!group || this.midGroup[group] === undefined) {
204
+ group = this.globalKey;
205
+ }
206
+
207
+ let last = this.midGroup[group].length - 1;
208
+ return this.midGroup[group][last](ctx);
209
+ }
210
+
211
+ }
212
+
213
+ module.exports = MidCore;
@@ -0,0 +1,103 @@
1
+ /**
2
+ module middleware1
3
+ Copyright (C) 2019.08 BraveWang
4
+ */
5
+ 'use strict';
6
+
7
+ const MidCore = require('./midcore.js');
8
+
9
+ class Middleware extends MidCore {
10
+ /**
11
+ * 执行中间件,其中核心则是请求回调函数。
12
+ * @param {object} ctx 请求上下文实例。
13
+ */
14
+ async run(ctx) {
15
+ try {
16
+ await this.exec(ctx, ctx.group);
17
+ } catch (err) {
18
+
19
+ this.errorHandle(err, '--ERR-res--');
20
+
21
+ try {
22
+ if (ctx.res && !ctx.res.writableEnded) {
23
+ ctx.res.statusCode = 500;
24
+ ctx.res.end();
25
+ }
26
+ } catch (err) {}
27
+
28
+ } finally {
29
+ ctx.req = null;
30
+ ctx.res = null;
31
+ ctx.data = null;
32
+ ctx.box = null;
33
+ ctx.service = null;
34
+ ctx.requestCall = null;
35
+ ctx.headers = null;
36
+ ctx.body = null;
37
+ ctx.rawBody = null;
38
+ ctx.files = null;
39
+ ctx.param = null;
40
+ ctx.user = null;
41
+ ctx = null;
42
+ }
43
+ }
44
+
45
+ /** 这是最终添加的请求中间件。基于洋葱模型,这个中间件最先执行,所以最后会返回响应结果。*/
46
+ /**
47
+ *
48
+ * Node 12 开始废除了finished属性。
49
+ *
50
+ */
51
+ addFinal() {
52
+ let fr = async (ctx, next) => {
53
+ await next(ctx);
54
+
55
+ if (!ctx.res || ctx.res.writableEnded || !ctx.res.writable || ctx.res.destroyed) {
56
+ return;
57
+ }
58
+
59
+ /**
60
+ * 如果已经设置了content-type或者消息头已经发送则直接返回
61
+ */
62
+ let content_type = 'text/plain;charset=utf-8';
63
+ let datatype = typeof ctx.data;
64
+
65
+ if (!(ctx.res.headersSent || ctx.res.hasHeader('content-type')) )
66
+ {
67
+ if (datatype === 'object') {
68
+ ctx.res.setHeader('content-type','application/json;charset=utf-8');
69
+ }
70
+ else if (datatype === 'string' && ctx.data.length > 1) {
71
+ switch (ctx.data[0]) {
72
+ case '{':
73
+ case '[':
74
+ content_type = 'application/json;charset=utf-8'; break;
75
+ case '<':
76
+ if (ctx.data[1] == '!') {
77
+ content_type = 'text/html;charset=utf-8';
78
+ }
79
+ break;
80
+ default:;
81
+ }
82
+ ctx.res.setHeader('content-type', content_type);
83
+ }
84
+ }
85
+
86
+ if (!ctx.data) {
87
+ ctx.res.end()
88
+ } else if (ctx.data instanceof Buffer || datatype === 'string') {
89
+ ctx.res.end(ctx.data, ctx.dataEncoding)
90
+ } else if (datatype === 'number') {
91
+ ctx.res.end(`${ctx.data}`)
92
+ } else {
93
+ ctx.res.end(JSON.stringify(ctx.data))
94
+ }
95
+
96
+ }
97
+
98
+ this.add(fr)
99
+ }
100
+
101
+ }
102
+
103
+ module.exports = Middleware;
@@ -0,0 +1,116 @@
1
+ /**
2
+ module middleware2
3
+ Copyright (C) 2019.08 BraveWang
4
+ */
5
+ 'use strict';
6
+
7
+ const MidCore = require('./midcore.js');
8
+
9
+ class Middleware extends MidCore {
10
+
11
+ /**
12
+ * 执行中间件,其中核心则是请求回调函数。
13
+ * @param {object} ctx 请求上下文实例。
14
+ */
15
+ async run(ctx) {
16
+ try {
17
+ await this.exec(ctx, ctx.group);
18
+ } catch (err) {
19
+
20
+ this.errorHandle(err, '--ERR-RESPONSE--');
21
+
22
+ if (ctx.stream && !ctx.stream.destroyed && ctx.stream.writable) {
23
+ try {
24
+ if (!ctx.stream.headersSent) {
25
+ ctx.stream.respond({
26
+ ':status' : '500'
27
+ });
28
+ }
29
+ //ctx.stream.close();
30
+ ctx.stream.end();
31
+ } catch (err) {}
32
+ }
33
+ } finally {
34
+ ctx.data = null;
35
+ ctx.dataHeaders = null;
36
+ ctx.stream = null;
37
+ ctx.req = null;
38
+ ctx.res = null;
39
+ ctx.service = null;
40
+ ctx.box = null;
41
+ ctx.requestCall = null;
42
+ ctx.body = null;
43
+ ctx.headers = null;
44
+ ctx.rawBody = null;
45
+ ctx.files = null;
46
+ ctx.param = null;
47
+ ctx.user = null;
48
+ ctx = null;
49
+ }
50
+
51
+ }
52
+
53
+ /** 这是最终添加的请求中间件。基于洋葱模型,这个中间件最先执行,所以最后会返回响应结果。 */
54
+ addFinal() {
55
+ let fr = async (ctx, next) => {
56
+ await next(ctx);
57
+
58
+ if(!ctx.stream || ctx.stream.closed || ctx.stream.destroyed || !ctx.stream.writable) {
59
+ return ;
60
+ }
61
+
62
+ let content_type = 'text/plain;charset=utf-8';
63
+ let datatype = typeof ctx.data;
64
+
65
+ /** 如果还没有发送头部信息,则判断content-type类型,然后返回。 */
66
+
67
+ if (!ctx.stream.headersSent) {
68
+
69
+ if (!ctx.dataHeaders['content-type']) {
70
+
71
+ if (ctx.data instanceof Buffer || datatype === 'number') {
72
+ ctx.dataHeaders['content-type'] = content_type;
73
+ }
74
+ else if (datatype === 'object') {
75
+ ctx.dataHeaders['content-type'] = 'application/json;charset=utf-8';
76
+ }
77
+ else if (datatype === 'string' && ctx.data.length > 1) {
78
+ switch (ctx.data[0]) {
79
+ case '{':
80
+ case '[':
81
+ content_type = 'application/json;charset=utf-8'; break;
82
+
83
+ case '<':
84
+ if (ctx.data[1] == '!') {
85
+ content_type = 'text/html;charset=utf-8';
86
+ }
87
+ break;
88
+
89
+ default:;
90
+ }
91
+
92
+ ctx.setHeader('content-type', content_type);
93
+ }
94
+
95
+ }
96
+
97
+ ctx.stream.respond(ctx.dataHeaders)
98
+ }
99
+
100
+ if (!ctx.data) {
101
+ ctx.stream.end()
102
+ } else if (ctx.data instanceof Buffer || datatype === 'string') {
103
+ ctx.stream.end(ctx.data, ctx.dataEncoding)
104
+ } else if (datatype === 'number') {
105
+ ctx.stream.end(`${ctx.data}`)
106
+ } else {
107
+ ctx.stream.end(JSON.stringify(ctx.data))
108
+ }
109
+ }
110
+
111
+ this.add(fr)
112
+ }
113
+
114
+ }
115
+
116
+ module.exports = Middleware;