topbit 3.0.3 → 3.0.5
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/demo/controller/__mid.js +11 -0
- package/demo/controller/api/test.js +27 -0
- package/demo/controller/api.js +12 -0
- package/demo/loader.js +5 -3
- package/package.json +1 -1
- package/src/loader/loader.js +108 -442
- package/src/midcore.js +1 -1
- package/src/token/token.js +3 -3
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
class Test {
|
|
4
|
+
constructor() {
|
|
5
|
+
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async get(ctx) {
|
|
9
|
+
ctx.ok([
|
|
10
|
+
ctx.method, ctx.path, ctx.routepath, ctx.param
|
|
11
|
+
])
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
__mid() {
|
|
15
|
+
return [
|
|
16
|
+
{
|
|
17
|
+
middleware: async (ctx, next) => {
|
|
18
|
+
console.log(`test ${ctx.method} start`)
|
|
19
|
+
await next(ctx)
|
|
20
|
+
console.log(`test ${ctx.method} end`)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = Test
|
package/demo/controller/api.js
CHANGED
|
@@ -10,6 +10,18 @@ class Api {
|
|
|
10
10
|
ctx.method, ctx.path, ctx.routepath, ctx.param
|
|
11
11
|
])
|
|
12
12
|
}
|
|
13
|
+
|
|
14
|
+
__mid() {
|
|
15
|
+
return [
|
|
16
|
+
{
|
|
17
|
+
middleware: async (ctx, next) => {
|
|
18
|
+
console.log(`api ${ctx.method} start`)
|
|
19
|
+
await next(ctx)
|
|
20
|
+
console.log(`api ${ctx.method} end`)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
13
25
|
}
|
|
14
26
|
|
|
15
27
|
module.exports = Api
|
package/demo/loader.js
CHANGED
|
@@ -7,7 +7,7 @@ let {Loader} = Topbit
|
|
|
7
7
|
|
|
8
8
|
let app = new Topbit({
|
|
9
9
|
debug: true,
|
|
10
|
-
|
|
10
|
+
loadInfoFile: '--mem',
|
|
11
11
|
})
|
|
12
12
|
|
|
13
13
|
if (app.isWorker) {
|
|
@@ -22,6 +22,8 @@ if (app.isWorker) {
|
|
|
22
22
|
|
|
23
23
|
app.sched('none')
|
|
24
24
|
|
|
25
|
-
app.autoWorker(
|
|
25
|
+
app.autoWorker(12)
|
|
26
26
|
|
|
27
|
-
app.daemon(1234,
|
|
27
|
+
app.daemon(1234, 5)
|
|
28
|
+
|
|
29
|
+
//console.log(app.midware.midGroup)
|
package/package.json
CHANGED
package/src/loader/loader.js
CHANGED
|
@@ -3,12 +3,6 @@
|
|
|
3
3
|
const fs = require('node:fs');
|
|
4
4
|
const process = require('node:process');
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* 全局中间件容易因为group选项引发问题,若要把加载的controller目录隔离出来,需要针对每个分组加载中间件。
|
|
8
|
-
* 就是在全局中间件不指定group的情况下,默认是所有group而不是全局。
|
|
9
|
-
* 这样对前缀支持也可以完全兼容。
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
6
|
let outWarning = (text, errname = 'Warning', color = '\x1b[2;31;47m') => {
|
|
13
7
|
setTimeout(() => {
|
|
14
8
|
console.error(`${color} ${errname}: ${text} \x1b[0m\n`);
|
|
@@ -16,32 +10,10 @@ let outWarning = (text, errname = 'Warning', color = '\x1b[2;31;47m') => {
|
|
|
16
10
|
};
|
|
17
11
|
|
|
18
12
|
let nameErrorInfo = '名称不能有空格换行特殊字符等,仅支持 字母 数字 减号 下划线,字母开头。';
|
|
19
|
-
|
|
20
|
-
//获取模型文件列表
|
|
21
|
-
function getModelFiles(filepath) {
|
|
22
|
-
let mlist = fs.readdirSync(filepath, { withFileTypes: true });
|
|
23
|
-
|
|
24
|
-
let rlist = [];
|
|
25
|
-
|
|
26
|
-
for (let i=0; i < mlist.length; i++) {
|
|
27
|
-
if (!mlist[i].isFile()) continue;
|
|
28
|
-
|
|
29
|
-
if (mlist[i].name.substring(mlist[i].name.length-3) !== '.js')
|
|
30
|
-
continue;
|
|
31
|
-
|
|
32
|
-
if (mlist[i].name[0] === '!' || mlist[i].name[0] === '_')
|
|
33
|
-
continue;
|
|
34
|
-
|
|
35
|
-
rlist.push(mlist[i].name);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return rlist;
|
|
39
|
-
}
|
|
40
13
|
|
|
41
14
|
class TopbitLoader {
|
|
42
15
|
|
|
43
16
|
constructor(options = {}) {
|
|
44
|
-
//let appDir = __dirname + '.';
|
|
45
17
|
let appDir = '.';
|
|
46
18
|
|
|
47
19
|
this.globalMidTable = [];
|
|
@@ -63,73 +35,49 @@ class TopbitLoader {
|
|
|
63
35
|
this.optionsCacheLog = null;
|
|
64
36
|
|
|
65
37
|
this.methodNumber = {
|
|
66
|
-
get: 1,
|
|
67
|
-
|
|
68
|
-
put: 3,
|
|
69
|
-
delete: 4,
|
|
70
|
-
_delete: 4,
|
|
71
|
-
options: 5,
|
|
72
|
-
head: 6,
|
|
73
|
-
trace: 7,
|
|
74
|
-
patch: 8,
|
|
75
|
-
list: 9
|
|
38
|
+
get: 1, post: 2, put: 3, delete: 4, _delete: 4,
|
|
39
|
+
options: 5, head: 6, trace: 7, patch: 8, list: 9
|
|
76
40
|
}
|
|
77
41
|
|
|
78
42
|
this.config = {
|
|
79
|
-
//当作为模块引入时,根据路径关系,
|
|
80
|
-
//可能的位置是node_modules/titbit-loader/loader.js,
|
|
81
|
-
//所以默认在父级目录两层和node_modules同级。
|
|
82
43
|
appPath : appDir,
|
|
83
|
-
controllerPath : appDir+'/controller',
|
|
84
|
-
|
|
85
|
-
midwarePath : appDir+'/middleware',
|
|
86
|
-
loadModel : true,
|
|
44
|
+
controllerPath : appDir + '/controller',
|
|
45
|
+
midwarePath : appDir + '/middleware',
|
|
87
46
|
|
|
88
47
|
deep : 1,
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
modelNamePre: '',
|
|
92
|
-
|
|
93
|
-
//如果作为数组则会去加载指定的子目录
|
|
48
|
+
// 如果作为数组则会去加载指定的子目录
|
|
94
49
|
subgroup : null,
|
|
95
|
-
|
|
96
50
|
prePath: '',
|
|
97
|
-
|
|
98
51
|
homeFile: '',
|
|
99
|
-
|
|
52
|
+
|
|
53
|
+
// 控制器初始化参数,默认为 app.service
|
|
100
54
|
initArgs: null,
|
|
101
55
|
|
|
102
56
|
multi: false,
|
|
103
|
-
|
|
104
57
|
optionsRoute: true,
|
|
105
|
-
|
|
106
58
|
fileAsGroup: true,
|
|
107
59
|
|
|
108
60
|
beforeController: null,
|
|
109
|
-
afterController: null
|
|
61
|
+
afterController: null,
|
|
62
|
+
|
|
63
|
+
// 新的核心:模型加载钩子函数
|
|
64
|
+
modelLoader: null
|
|
110
65
|
};
|
|
111
66
|
|
|
112
|
-
|
|
113
|
-
//考虑这样的情况:controller目录中存在 xyz.js文件和xyz目录。
|
|
67
|
+
// 用于在fileAsGroup模式,为options添加的分组避免和文件的分组冲突。
|
|
114
68
|
this.groupTag = '@';
|
|
115
69
|
|
|
116
|
-
|
|
70
|
+
// 组中间件的缓存
|
|
117
71
|
this.groupCache = {};
|
|
118
72
|
this.globalCache = [];
|
|
119
73
|
|
|
120
|
-
//在加载Model时可能需要传递参数
|
|
121
|
-
this.mdb = null;
|
|
122
|
-
this.mdbMap = null;
|
|
123
|
-
|
|
124
74
|
this.routepreg = /^[a-z\d\-\_]+$/i;
|
|
125
75
|
|
|
126
76
|
for (let k in options) {
|
|
127
|
-
|
|
128
77
|
if (k == 'appPath') continue;
|
|
129
78
|
|
|
130
79
|
if (k === 'subgroup') {
|
|
131
80
|
if (typeof options[k] === 'string') options[k] = [ options[k] ];
|
|
132
|
-
|
|
133
81
|
if (options[k] instanceof Array) {
|
|
134
82
|
this.config.subgroup = options[k];
|
|
135
83
|
}
|
|
@@ -144,6 +92,7 @@ class TopbitLoader {
|
|
|
144
92
|
switch (k) {
|
|
145
93
|
case 'beforeController':
|
|
146
94
|
case 'afterController':
|
|
95
|
+
case 'modelLoader': // 仅保留这个与 Model 相关的配置
|
|
147
96
|
if (typeof options[k] === 'function') this.config[k] = options[k];
|
|
148
97
|
break;
|
|
149
98
|
|
|
@@ -152,15 +101,9 @@ class TopbitLoader {
|
|
|
152
101
|
break;
|
|
153
102
|
|
|
154
103
|
case 'homeFile':
|
|
155
|
-
case 'modelNamePre':
|
|
156
104
|
;(typeof options[k] === 'string') && (this.config[k] = options[k]);
|
|
157
105
|
break;
|
|
158
106
|
|
|
159
|
-
case 'mname':
|
|
160
|
-
;(typeof options[k] === 'string' || typeof options[k] === 'symbol') && (this.config[k] = options[k]);
|
|
161
|
-
break;
|
|
162
|
-
|
|
163
|
-
case 'loadModel':
|
|
164
107
|
case 'multi':
|
|
165
108
|
case 'optionsRoute':
|
|
166
109
|
case 'fileAsGroup':
|
|
@@ -168,7 +111,6 @@ class TopbitLoader {
|
|
|
168
111
|
break;
|
|
169
112
|
|
|
170
113
|
case 'controllerPath':
|
|
171
|
-
case 'modelPath':
|
|
172
114
|
case 'midwarePath':
|
|
173
115
|
if (options[k][0] !== '/') {
|
|
174
116
|
this.config[k] = `${this.config.appPath}/${options[k]}`;
|
|
@@ -179,6 +121,7 @@ class TopbitLoader {
|
|
|
179
121
|
}
|
|
180
122
|
}
|
|
181
123
|
|
|
124
|
+
// 仅检查 controller 和 middleware 目录
|
|
182
125
|
try {
|
|
183
126
|
fs.accessSync(this.config.controllerPath, fs.constants.F_OK);
|
|
184
127
|
} catch (err) {
|
|
@@ -194,42 +137,20 @@ class TopbitLoader {
|
|
|
194
137
|
fs.mkdirSync(this.config.midwarePath);
|
|
195
138
|
}
|
|
196
139
|
}
|
|
197
|
-
|
|
198
|
-
try {
|
|
199
|
-
fs.accessSync(this.config.modelPath, fs.constants.F_OK);
|
|
200
|
-
} catch (err) {
|
|
201
|
-
if (this.config.modelPath.length > 0) {
|
|
202
|
-
fs.mkdirSync(this.config.modelPath);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (options.mdb !== undefined && this.config.loadModel) {
|
|
207
|
-
this.mdb = options.mdb;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
options.mdbMap && (this.mdbMap = options.mdbMap);
|
|
211
140
|
}
|
|
212
141
|
|
|
213
142
|
fmtPrePath() {
|
|
214
143
|
let prepath = this.config.prePath.trim().replace(/\/+/g, '/');
|
|
215
|
-
if (prepath === '/')
|
|
216
|
-
prepath = '';
|
|
144
|
+
if (prepath === '/') prepath = '';
|
|
217
145
|
else if (prepath.length > 0) {
|
|
218
|
-
if (prepath[0] !== '/') {
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
if (prepath[ prepath.length - 1 ] === '/') {
|
|
222
|
-
prepath = prepath.substring(0, prepath.length - 1);
|
|
223
|
-
}
|
|
146
|
+
if (prepath[0] !== '/') prepath = `/${prepath}`;
|
|
147
|
+
if (prepath[ prepath.length - 1 ] === '/') prepath = prepath.substring(0, prepath.length - 1);
|
|
224
148
|
}
|
|
225
|
-
|
|
226
149
|
this.config.prePath = prepath;
|
|
227
150
|
}
|
|
228
151
|
|
|
229
152
|
_fmtSubGroup() {
|
|
230
|
-
if (!(this.config.subgroup instanceof Array))
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
153
|
+
if (!(this.config.subgroup instanceof Array)) return;
|
|
233
154
|
let a;
|
|
234
155
|
for (let i = 0; i < this.config.subgroup.length; i++) {
|
|
235
156
|
a = this.config.subgroup[i];
|
|
@@ -238,19 +159,39 @@ class TopbitLoader {
|
|
|
238
159
|
}
|
|
239
160
|
}
|
|
240
161
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
162
|
+
/**
|
|
163
|
+
* 初始化入口 (Async)
|
|
164
|
+
*/
|
|
165
|
+
async init(app) {
|
|
166
|
+
// 注入应用基础信息到 service,供 Controller 或 Model 使用
|
|
167
|
+
Object.defineProperties(app.service, {
|
|
168
|
+
__prepath__: {
|
|
169
|
+
value: this.config.prePath,
|
|
170
|
+
configurable: false, writable: false, enumerable: false
|
|
171
|
+
},
|
|
172
|
+
__appdir__: {
|
|
173
|
+
value: this.config.appPath,
|
|
174
|
+
configurable: false, writable: false, enumerable: false
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// 1. 执行模型加载钩子 (如果存在)
|
|
179
|
+
if (this.config.modelLoader) {
|
|
180
|
+
await this.config.modelLoader(app.service);
|
|
181
|
+
}
|
|
245
182
|
|
|
183
|
+
// 2. 加载控制器 (路由)
|
|
246
184
|
this.loadController(app);
|
|
185
|
+
|
|
186
|
+
// 3. 加载中间件
|
|
247
187
|
this.loadMidware(app);
|
|
248
|
-
|
|
188
|
+
|
|
189
|
+
app.service.__topbit_loader__ = true;
|
|
249
190
|
}
|
|
250
191
|
|
|
251
192
|
loadController(app) {
|
|
252
|
-
if (app.service.
|
|
253
|
-
outWarning('您已经使用
|
|
193
|
+
if (app.service.__topbit_loader__ && !this.config.multi) {
|
|
194
|
+
outWarning('您已经使用topbit-loader加载过路由,多次加载容易导致路由冲突,重复操作将会被终止。');
|
|
254
195
|
outWarning('若有需要,可设置选项multi为true允许多次加载。', ' 提示');
|
|
255
196
|
return false;
|
|
256
197
|
}
|
|
@@ -261,6 +202,10 @@ class TopbitLoader {
|
|
|
261
202
|
this.readControllers(this.config.controllerPath, cfiles);
|
|
262
203
|
let cob = null;
|
|
263
204
|
let Ctlr;
|
|
205
|
+
|
|
206
|
+
// 默认注入 app.service
|
|
207
|
+
const initArg = this.config.initArgs || app.service;
|
|
208
|
+
|
|
264
209
|
for (let k in cfiles) {
|
|
265
210
|
try {
|
|
266
211
|
Ctlr = require(k);
|
|
@@ -272,7 +217,7 @@ class TopbitLoader {
|
|
|
272
217
|
cob = new Ctlr();
|
|
273
218
|
|
|
274
219
|
if (cob.init && typeof cob.init === 'function') {
|
|
275
|
-
cob.init(
|
|
220
|
+
cob.init(initArg);
|
|
276
221
|
}
|
|
277
222
|
|
|
278
223
|
if (this.config.beforeController) {
|
|
@@ -333,112 +278,69 @@ class TopbitLoader {
|
|
|
333
278
|
let routeParam = '/:id';
|
|
334
279
|
|
|
335
280
|
if (cob.param !== undefined && cob.param !== null && typeof cob.param === 'string') {
|
|
336
|
-
routeParam = cob.param.trim()
|
|
337
|
-
.replace(/\s+/g, '')
|
|
338
|
-
.replace(/\/{2,}/g, '/');
|
|
281
|
+
routeParam = cob.param.trim().replace(/\s+/g, '').replace(/\/{2,}/g, '/');
|
|
339
282
|
if (routeParam.length > 0 && routeParam[0] !== '/') {
|
|
340
283
|
routeParam = `/${routeParam}`;
|
|
341
284
|
}
|
|
342
285
|
}
|
|
343
286
|
|
|
344
287
|
Object.defineProperty(cob, '__route__', {
|
|
345
|
-
configurable: false,
|
|
346
|
-
writable: false,
|
|
347
|
-
enumerable: false,
|
|
288
|
+
configurable: false, writable: false, enumerable: false,
|
|
348
289
|
value: route_path
|
|
349
290
|
});
|
|
350
291
|
|
|
351
|
-
|
|
292
|
+
// 辅助函数:简化路由注册
|
|
293
|
+
const bindRoute = (method, suffix, fnName, typeName) => {
|
|
294
|
+
app.router[method](`${route_path}${suffix}`, cob[fnName].bind(cob), {
|
|
295
|
+
name: `${npre}/${typeName}`,
|
|
296
|
+
group: group
|
|
297
|
+
});
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
if (cob.post && typeof cob.post === 'function') {
|
|
352
301
|
let postParam = (cob.postParam && typeof cob.postParam === 'string') ? cob.postParam : '';
|
|
353
|
-
|
|
354
302
|
postParam = postParam.replace(/\/+/g, '/');
|
|
355
|
-
|
|
356
303
|
if (postParam === '/') postParam = '';
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
app.router.post(`${route_path}${postParam}`, cob.post.bind(cob),
|
|
363
|
-
{
|
|
364
|
-
name: `${npre}/${this.methodNumber.post}`,
|
|
365
|
-
group: group
|
|
366
|
-
}
|
|
367
|
-
);
|
|
368
|
-
|
|
304
|
+
if (postParam.length > 0 && postParam[0] !== '/') postParam = `/${postParam}`;
|
|
305
|
+
|
|
306
|
+
bindRoute('post', postParam, 'post', this.methodNumber.post);
|
|
369
307
|
}
|
|
370
308
|
|
|
371
309
|
let real_delete_method = '';
|
|
372
|
-
if (cob.delete && typeof cob.delete === 'function')
|
|
373
|
-
|
|
374
|
-
} else if (cob._delete && typeof cob._delete === 'function') {
|
|
375
|
-
real_delete_method = '_delete';
|
|
376
|
-
}
|
|
310
|
+
if (cob.delete && typeof cob.delete === 'function') real_delete_method = 'delete';
|
|
311
|
+
else if (cob._delete && typeof cob._delete === 'function') real_delete_method = '_delete';
|
|
377
312
|
|
|
378
313
|
if (real_delete_method) {
|
|
379
|
-
|
|
380
|
-
cob[real_delete_method].bind(cob),
|
|
381
|
-
{
|
|
382
|
-
name: `${npre}/${this.methodNumber.delete}`,
|
|
383
|
-
group: group
|
|
384
|
-
}
|
|
385
|
-
);
|
|
314
|
+
bindRoute('delete', routeParam, real_delete_method, this.methodNumber.delete);
|
|
386
315
|
}
|
|
387
316
|
|
|
388
|
-
if (cob.put
|
|
389
|
-
|
|
390
|
-
{
|
|
391
|
-
name: `${npre}/${this.methodNumber.put}`,
|
|
392
|
-
group: group
|
|
393
|
-
}
|
|
394
|
-
);
|
|
317
|
+
if (cob.put && typeof cob.put === 'function') {
|
|
318
|
+
bindRoute('put', routeParam, 'put', this.methodNumber.put);
|
|
395
319
|
}
|
|
396
320
|
|
|
397
|
-
if (cob.get
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
321
|
+
if (cob.get && typeof cob.get === 'function') {
|
|
322
|
+
bindRoute('get', routeParam, 'get', this.methodNumber.get);
|
|
323
|
+
// 主页路由
|
|
324
|
+
if (this.config.homeFile === cf.pathname) {
|
|
325
|
+
app.router.get('/', cob.get.bind(cob), { name: 'home', group: group });
|
|
402
326
|
}
|
|
403
|
-
);
|
|
404
|
-
//主页只支持GET请求
|
|
405
|
-
if (this.config.homeFile === cf.pathname) {
|
|
406
|
-
app.router.get('/', cob.get.bind(cob), {
|
|
407
|
-
name: 'home',
|
|
408
|
-
group: group
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
327
|
}
|
|
412
328
|
|
|
413
|
-
if (cob.list
|
|
329
|
+
if (cob.list && typeof cob.list === 'function') {
|
|
414
330
|
let listParam = (cob.listParam && typeof cob.listParam === 'string') ? cob.listParam : '';
|
|
415
|
-
|
|
416
331
|
listParam = listParam.replace(/\/+/g, '/');
|
|
417
|
-
|
|
418
332
|
if (listParam === '/') listParam = '';
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
app.router.get(`${route_path}${listParam}`, cob.list.bind(cob),{
|
|
425
|
-
name: `${npre}/${this.methodNumber.list}`,
|
|
426
|
-
group: group
|
|
427
|
-
});
|
|
333
|
+
if (listParam.length > 0 && listParam[0] !== '/') listParam = `/${listParam}`;
|
|
334
|
+
|
|
335
|
+
bindRoute('get', listParam, 'list', this.methodNumber.list);
|
|
428
336
|
}
|
|
429
337
|
|
|
430
|
-
if (cob.patch
|
|
431
|
-
|
|
432
|
-
name: `${npre}/${this.methodNumber.patch}`,
|
|
433
|
-
group: group
|
|
434
|
-
});
|
|
338
|
+
if (cob.patch && typeof cob.patch === 'function') {
|
|
339
|
+
bindRoute('patch', routeParam, 'patch', this.methodNumber.patch);
|
|
435
340
|
}
|
|
436
341
|
|
|
437
|
-
if (cob.options
|
|
438
|
-
|
|
439
|
-
name: `${npre}/${this.methodNumber.options}`,
|
|
440
|
-
group: group
|
|
441
|
-
});
|
|
342
|
+
if (cob.options && typeof cob.options === 'function') {
|
|
343
|
+
bindRoute('options', routeParam, 'options', this.methodNumber.options);
|
|
442
344
|
} else if (this.config.optionsRoute) {
|
|
443
345
|
let real_group = this.config.fileAsGroup ? dirgroup : group;
|
|
444
346
|
let tag = this.config.fileAsGroup ? this.groupTag : '';
|
|
@@ -451,11 +353,8 @@ class TopbitLoader {
|
|
|
451
353
|
}
|
|
452
354
|
}
|
|
453
355
|
|
|
454
|
-
if (cob.head
|
|
455
|
-
|
|
456
|
-
name: `${npre}/${this.methodNumber.head}`,
|
|
457
|
-
group: group
|
|
458
|
-
});
|
|
356
|
+
if (cob.head && typeof cob.head === 'function') {
|
|
357
|
+
bindRoute('head', routeParam, 'head', this.methodNumber.head);
|
|
459
358
|
}
|
|
460
359
|
|
|
461
360
|
this.fileMidTable[cf.filegroup] = {
|
|
@@ -496,15 +395,10 @@ class TopbitLoader {
|
|
|
496
395
|
}
|
|
497
396
|
|
|
498
397
|
/**
|
|
499
|
-
*
|
|
500
|
-
* 中间件不宜过度使用,否则容易混乱。
|
|
398
|
+
* 加载中间件
|
|
501
399
|
*/
|
|
502
400
|
loadMidware(app) {
|
|
503
|
-
if (app.service.
|
|
504
|
-
outWarning('您已经使用titbit-loader加载过中间件,多个实例容易会导致中间件多次加载或冲突,重复操作将会被终止。');
|
|
505
|
-
outWarning('若有需要,可设置选项multi为true允许多次加载。', ' 提示');
|
|
506
|
-
return false;
|
|
507
|
-
}
|
|
401
|
+
if (app.service.__topbit_loader__ && !this.config.multi) return;
|
|
508
402
|
|
|
509
403
|
this._getGroupList();
|
|
510
404
|
|
|
@@ -564,19 +458,9 @@ class TopbitLoader {
|
|
|
564
458
|
|
|
565
459
|
checkMiddleware(m) {
|
|
566
460
|
if (m.middleware === undefined) return false;
|
|
567
|
-
|
|
568
|
-
if (
|
|
569
|
-
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
if (m.middleware.mid && typeof m.middleware.mid === 'function') {
|
|
573
|
-
return true;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
if (m.middleware.middleware && typeof m.middleware.middleware === 'function') {
|
|
577
|
-
return true;
|
|
578
|
-
}
|
|
579
|
-
|
|
461
|
+
if (typeof m.middleware === 'function' && m.middleware.constructor.name === 'AsyncFunction') return true;
|
|
462
|
+
if (m.middleware.mid && typeof m.middleware.mid === 'function') return true;
|
|
463
|
+
if (m.middleware.middleware && typeof m.middleware.middleware === 'function') return true;
|
|
580
464
|
return false;
|
|
581
465
|
}
|
|
582
466
|
|
|
@@ -619,43 +503,27 @@ class TopbitLoader {
|
|
|
619
503
|
}
|
|
620
504
|
return false;
|
|
621
505
|
} else if (m.mode === 'online' || m.mode === 'product') {
|
|
622
|
-
//只在正式环境加载
|
|
623
506
|
if (app.service.TEST || app.service.DEV) {
|
|
624
|
-
//console.log(`测试环境不加载中间件`, m);
|
|
625
507
|
return false;
|
|
626
508
|
}
|
|
627
509
|
return true;
|
|
628
510
|
}
|
|
629
511
|
}
|
|
630
|
-
//console.log('加载···', m);
|
|
631
512
|
return true;
|
|
632
513
|
}
|
|
633
514
|
|
|
634
515
|
loadGlobalMidware(app, m) {
|
|
635
|
-
|
|
636
|
-
if (this._checkMidwareMode(app, m) === false) {
|
|
637
|
-
return;
|
|
638
|
-
}
|
|
516
|
+
if (this._checkMidwareMode(app, m) === false) return;
|
|
639
517
|
|
|
640
|
-
let opts = null;
|
|
641
|
-
|
|
642
518
|
let makeOpts = (groupname = null) => {
|
|
643
519
|
let op = {};
|
|
644
|
-
if (m.method !== undefined)
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
if (groupname) {
|
|
648
|
-
op.group = groupname[0] === '/' ? groupname : `/${groupname}`;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
if (m.pre) {
|
|
652
|
-
op.pre = true;
|
|
653
|
-
}
|
|
520
|
+
if (m.method !== undefined) op.method = m.method;
|
|
521
|
+
if (groupname) op.group = groupname[0] === '/' ? groupname : `/${groupname}`;
|
|
522
|
+
if (m.pre) op.pre = true;
|
|
654
523
|
return op;
|
|
655
524
|
};
|
|
656
525
|
|
|
657
526
|
let mobj;
|
|
658
|
-
|
|
659
527
|
let group = this.groupList;
|
|
660
528
|
|
|
661
529
|
if (group) {
|
|
@@ -668,30 +536,18 @@ class TopbitLoader {
|
|
|
668
536
|
for (let g of group) {
|
|
669
537
|
mobj && app.use(mobj, makeOpts(g));
|
|
670
538
|
}
|
|
671
|
-
|
|
672
539
|
return;
|
|
673
540
|
}
|
|
674
|
-
|
|
675
541
|
}
|
|
676
542
|
|
|
677
543
|
loadGroupMidware(app, m, group) {
|
|
678
|
-
|
|
679
|
-
if (
|
|
680
|
-
return;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
if ((!m.name || m.name === '') && !m.middleware) {
|
|
684
|
-
return;
|
|
685
|
-
}
|
|
544
|
+
if (this._checkMidwareMode(app, m) === false) return;
|
|
545
|
+
if ((!m.name || m.name === '') && !m.middleware) return;
|
|
686
546
|
let opts = {
|
|
687
547
|
group: `${this.config.prePath}${group}`,
|
|
688
548
|
};
|
|
689
|
-
if (m.method !== undefined)
|
|
690
|
-
|
|
691
|
-
}
|
|
692
|
-
if (m.pre) {
|
|
693
|
-
opts.pre = true;
|
|
694
|
-
}
|
|
549
|
+
if (m.method !== undefined) opts.method = m.method;
|
|
550
|
+
if (m.pre) opts.pre = true;
|
|
695
551
|
|
|
696
552
|
let mobj = this.getMidwareInstance(m);
|
|
697
553
|
if (mobj) {
|
|
@@ -704,23 +560,10 @@ class TopbitLoader {
|
|
|
704
560
|
}
|
|
705
561
|
}
|
|
706
562
|
|
|
707
|
-
/**
|
|
708
|
-
*
|
|
709
|
-
* @param {object} app
|
|
710
|
-
* @param {object} m
|
|
711
|
-
* @param {string} f
|
|
712
|
-
* @param {string} group 包括前缀的分组,若开启fileAsGroup则为filegroup
|
|
713
|
-
* @param {string} dirgroup 文件名,不包括前缀
|
|
714
|
-
* @returns
|
|
715
|
-
*/
|
|
716
563
|
loadFileMidware(app, m, f, group, dirgroup) {
|
|
717
|
-
if (this._checkMidwareMode(app, m) === false)
|
|
718
|
-
return;
|
|
719
|
-
}
|
|
564
|
+
if (this._checkMidwareMode(app, m) === false) return;
|
|
720
565
|
|
|
721
|
-
//group已经带有prepath前缀。
|
|
722
566
|
let opts = { group };
|
|
723
|
-
|
|
724
567
|
f = `${this.config.prePath}${f}`;
|
|
725
568
|
|
|
726
569
|
if (!this.fileAsGroup && m.path === undefined) {
|
|
@@ -730,9 +573,7 @@ class TopbitLoader {
|
|
|
730
573
|
];
|
|
731
574
|
}
|
|
732
575
|
|
|
733
|
-
if (m.path && typeof m.path === 'string')
|
|
734
|
-
m.path = [ m.path ];
|
|
735
|
-
}
|
|
576
|
+
if (m.path && typeof m.path === 'string') m.path = [ m.path ];
|
|
736
577
|
|
|
737
578
|
if (m.path && Array.isArray(m.path)) {
|
|
738
579
|
opts.name = [];
|
|
@@ -740,168 +581,13 @@ class TopbitLoader {
|
|
|
740
581
|
for (let p of m.path) {
|
|
741
582
|
path_num = this.methodNumber[p.toLowerCase()];
|
|
742
583
|
if (path_num === undefined) continue;
|
|
743
|
-
|
|
744
584
|
opts.name.push(`${f}/${path_num}`);
|
|
745
585
|
}
|
|
746
586
|
}
|
|
747
587
|
|
|
748
|
-
if (m.pre)
|
|
749
|
-
opts.pre = true;
|
|
750
|
-
}
|
|
751
|
-
|
|
588
|
+
if (m.pre) opts.pre = true;
|
|
752
589
|
let mobj = this.getMidwareInstance(m);
|
|
753
|
-
if (mobj)
|
|
754
|
-
app.use(mobj, opts);
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
loadModelMap(app) {
|
|
759
|
-
if (typeof this.mdbMap !== 'object')
|
|
760
|
-
throw new Error('mdbMap必须是object类型。');
|
|
761
|
-
|
|
762
|
-
let defpath = this.config.modelPath;
|
|
763
|
-
let sk;
|
|
764
|
-
let curpath;
|
|
765
|
-
let obj;
|
|
766
|
-
|
|
767
|
-
let loadObj = (serv, odb, fpath) => {
|
|
768
|
-
let mlist = getModelFiles(fpath);
|
|
769
|
-
let mname;
|
|
770
|
-
mlist.forEach(m => {
|
|
771
|
-
mname = m.substring(0, m.length - 3);
|
|
772
|
-
serv[mname] = this.getModelInstance(fpath + '/' + m, odb);
|
|
773
|
-
});
|
|
774
|
-
};
|
|
775
|
-
for (let k in this.mdbMap) {
|
|
776
|
-
obj = this.mdbMap[k];
|
|
777
|
-
if (!obj || typeof obj !== 'object') continue;
|
|
778
|
-
|
|
779
|
-
sk = '@' + k;
|
|
780
|
-
if (!app.service[sk]) app.service[sk] = {};
|
|
781
|
-
curpath = obj.path || defpath;
|
|
782
|
-
|
|
783
|
-
loadObj(app.service[sk], obj.mdb || null, curpath);
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
defineServiceFunction(app) {
|
|
789
|
-
if (app.service.getModel) return;
|
|
790
|
-
|
|
791
|
-
let sfe = function (mk, mpre, name, key = '') {
|
|
792
|
-
let m;
|
|
793
|
-
if (!key) {
|
|
794
|
-
m = mk ? this[mk] : this;
|
|
795
|
-
let oo = m[mpre + name];
|
|
796
|
-
if (!oo) throw new Error(`无法获取模型实例${name}`);
|
|
797
|
-
return oo;
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
let k = '@' + key;
|
|
801
|
-
if (!this[k] || !this[k][name]) throw new Error(`无法获取模型实例${name}`);
|
|
802
|
-
return this[k][name];
|
|
803
|
-
};
|
|
804
|
-
|
|
805
|
-
app.service.getModel = sfe.bind(app.service, this.config.mname, this.config.modelNamePre);
|
|
806
|
-
|
|
807
|
-
let fm = function (key) {
|
|
808
|
-
let k = '@' + key;
|
|
809
|
-
if (!this[k]) throw new Error('无法获取服务容器 ' + key);
|
|
810
|
-
return this[k];
|
|
811
|
-
};
|
|
812
|
-
|
|
813
|
-
app.service.modelMap = fm.bind(app.service);
|
|
814
|
-
|
|
815
|
-
Object.defineProperties(app.service, {
|
|
816
|
-
__prepath__: {
|
|
817
|
-
value: this.config.prePath,
|
|
818
|
-
configurable: false,
|
|
819
|
-
writable: false,
|
|
820
|
-
enumerable: false
|
|
821
|
-
},
|
|
822
|
-
|
|
823
|
-
__appdir__: {
|
|
824
|
-
value: this.config.appPath,
|
|
825
|
-
configurable: false,
|
|
826
|
-
writable: false,
|
|
827
|
-
enumerable: false
|
|
828
|
-
}
|
|
829
|
-
});
|
|
830
|
-
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
bindModelAttr(app) {
|
|
834
|
-
if (this.config.mname) {
|
|
835
|
-
if (app.service[this.config.mname] === undefined) app.service[this.config.mname] = {};
|
|
836
|
-
app.service.__model__ = app.service[this.config.mname];
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
/**
|
|
841
|
-
* 加载数据库操作接口,一个表要对应一个js文件,
|
|
842
|
-
*/
|
|
843
|
-
loadModel(app) {
|
|
844
|
-
if (this.config.mname && app.service[this.config.mname] === undefined) {
|
|
845
|
-
app.service[this.config.mname] = {};
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
this.bindModelAttr(app);
|
|
849
|
-
|
|
850
|
-
try {
|
|
851
|
-
|
|
852
|
-
let mlist = getModelFiles(this.config.modelPath);
|
|
853
|
-
|
|
854
|
-
mlist.forEach( m => {
|
|
855
|
-
this.requireModel(app, m);
|
|
856
|
-
});
|
|
857
|
-
|
|
858
|
-
} catch (err) {
|
|
859
|
-
console.error(err);
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
getModelInstance(mfile, db) {
|
|
864
|
-
let m = require(mfile);
|
|
865
|
-
|
|
866
|
-
// Arrow Function has no prototype
|
|
867
|
-
if (typeof m !== 'function' || m.prototype === undefined) {
|
|
868
|
-
if (m.init && typeof m.init === 'function') {
|
|
869
|
-
m.init(db);
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
return m;
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
return db ? new m(db) : new m();
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
requireModel(app, mfile) {
|
|
879
|
-
try {
|
|
880
|
-
let mobj = this.getModelInstance(this.config.modelPath + '/' + mfile, this.mdb);
|
|
881
|
-
|
|
882
|
-
let mname = mfile.substring(0, mfile.length-3);
|
|
883
|
-
|
|
884
|
-
mname = `${this.config.modelNamePre}${mname}`;
|
|
885
|
-
|
|
886
|
-
if (!this.config.mname) {
|
|
887
|
-
if (app.service[mname] !== undefined) {
|
|
888
|
-
outWarning(`model 冲突 ---- ${mfile}{${mname}} 已经设置。`);
|
|
889
|
-
return false;
|
|
890
|
-
}
|
|
891
|
-
app.service[mname] = mobj;
|
|
892
|
-
} else {
|
|
893
|
-
if (app.service[this.config.mname][mname] !== undefined) {
|
|
894
|
-
outWarning(`model 冲突 ---- ${mfile}{${mname}} 已经设置。`);
|
|
895
|
-
return false;
|
|
896
|
-
}
|
|
897
|
-
app.service[this.config.mname][mname] = mobj;
|
|
898
|
-
}
|
|
899
|
-
} catch (err) {
|
|
900
|
-
console.error(err.message, ' -- ', mfile);
|
|
901
|
-
return false;
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
return true;
|
|
590
|
+
if (mobj) app.use(mobj, opts);
|
|
905
591
|
}
|
|
906
592
|
|
|
907
593
|
stripExtName(filename) {
|
|
@@ -911,10 +597,6 @@ class TopbitLoader {
|
|
|
911
597
|
|
|
912
598
|
/**
|
|
913
599
|
* 读取控制器目录中的文件
|
|
914
|
-
* @param {string} cdir
|
|
915
|
-
* @param {object} cfiles
|
|
916
|
-
* @param {number} deep
|
|
917
|
-
* @param {string} dirgroup
|
|
918
600
|
*/
|
|
919
601
|
readControllers(cdir, cfiles, deep = 0, dirgroup = '') {
|
|
920
602
|
let files = fs.readdirSync(cdir, {withFileTypes:true});
|
|
@@ -924,16 +606,10 @@ class TopbitLoader {
|
|
|
924
606
|
|
|
925
607
|
if (files[i].isDirectory() && deep < 1) {
|
|
926
608
|
|
|
927
|
-
if (files[i].name[0] == '!')
|
|
928
|
-
continue;
|
|
929
|
-
}
|
|
609
|
+
if (files[i].name[0] == '!') continue;
|
|
930
610
|
|
|
931
|
-
//检测是否启用了分组控制
|
|
932
|
-
//这时候,只有在subgroup之内的才会去加载
|
|
933
611
|
if (this.config.subgroup instanceof Array) {
|
|
934
|
-
if (this.config.subgroup.indexOf(files[i].name) < 0)
|
|
935
|
-
continue;
|
|
936
|
-
}
|
|
612
|
+
if (this.config.subgroup.indexOf(files[i].name) < 0) continue;
|
|
937
613
|
}
|
|
938
614
|
|
|
939
615
|
if (this.routepreg.test(files[i].name) === false) {
|
|
@@ -947,17 +623,9 @@ class TopbitLoader {
|
|
|
947
623
|
);
|
|
948
624
|
|
|
949
625
|
} else if (files[i].isFile()) {
|
|
950
|
-
if (files[i].name[0] === '!')
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
if (files[i].name.length < 4) {
|
|
955
|
-
continue;
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
if (files[i].name.substring(files[i].name.length-3) !== '.js') {
|
|
959
|
-
continue;
|
|
960
|
-
}
|
|
626
|
+
if (files[i].name[0] === '!') continue;
|
|
627
|
+
if (files[i].name.length < 4) continue;
|
|
628
|
+
if (files[i].name.substring(files[i].name.length-3) !== '.js') continue;
|
|
961
629
|
|
|
962
630
|
if (this.config.subgroup instanceof Array && deep < 1) {
|
|
963
631
|
if (this.config.subgroup.indexOf('') < 0 && this.config.subgroup.indexOf('/') < 0) {
|
|
@@ -966,7 +634,6 @@ class TopbitLoader {
|
|
|
966
634
|
}
|
|
967
635
|
|
|
968
636
|
if (files[i].name == '__mid.js') {
|
|
969
|
-
//顶层并且忽略全局中间件选项为false则加载全局中间件。
|
|
970
637
|
if (deep == 0) {
|
|
971
638
|
this.globalMidTable = require(cdir+'/'+files[i].name);
|
|
972
639
|
} else {
|
|
@@ -991,9 +658,8 @@ class TopbitLoader {
|
|
|
991
658
|
};
|
|
992
659
|
}
|
|
993
660
|
}
|
|
994
|
-
|
|
995
661
|
}
|
|
996
662
|
|
|
997
663
|
}
|
|
998
664
|
|
|
999
|
-
module.exports = TopbitLoader;
|
|
665
|
+
module.exports = TopbitLoader;
|
package/src/midcore.js
CHANGED
package/src/token/token.js
CHANGED
|
@@ -328,14 +328,14 @@ class TopbitToken {
|
|
|
328
328
|
return opts
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
-
|
|
331
|
+
makeToken(info, id=null, key=null) {
|
|
332
332
|
let riv = randstring(this.ivLength)
|
|
333
333
|
let tid = id || this.randId()
|
|
334
334
|
let token = this.makeikv(info, {id: tid, iv: riv, key: key||this.key})
|
|
335
335
|
return `${riv}.${token}`
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
-
|
|
338
|
+
verifyToken(edata) {
|
|
339
339
|
let tarr = edata.split('.')
|
|
340
340
|
|
|
341
341
|
if (tarr.length != 2 || !tarr[0] || !tarr[1]) {
|
|
@@ -420,7 +420,7 @@ class TopbitToken {
|
|
|
420
420
|
return c.status(self.failedCode).to('!token')
|
|
421
421
|
}
|
|
422
422
|
|
|
423
|
-
let uinfo = self.
|
|
423
|
+
let uinfo = self.verifyToken(token)
|
|
424
424
|
|
|
425
425
|
if (!uinfo.ok) {
|
|
426
426
|
return c.status(self.failedCode).to(uinfo.errcode)
|