koatty 3.10.4-1 → 3.10.4-2
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/CHANGELOG.md +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +982 -985
- package/dist/index.mjs +977 -980
- package/dist/package.json +19 -15
- package/package.json +19 -15
package/dist/index.mjs
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
/*!
|
2
2
|
* @Author: richen
|
3
|
-
* @Date: 2023-12-
|
3
|
+
* @Date: 2023-12-15 00:18:46
|
4
4
|
* @License: BSD (3-Clause)
|
5
5
|
* @Copyright (c) - <richenlin(at)gmail.com>
|
6
6
|
* @HomePage: https://koatty.org/
|
7
7
|
*/
|
8
|
-
import 'reflect-metadata';
|
9
8
|
import { AppEventArr, Koatty } from 'koatty_core';
|
10
9
|
export * from 'koatty_core';
|
11
10
|
import * as path from 'path';
|
@@ -23,130 +22,131 @@ import { Trace } from 'koatty_trace';
|
|
23
22
|
export * from 'koatty_trace';
|
24
23
|
import { NewServe, NewRouter, BindProcessEvent, CONTROLLER_ROUTER } from 'koatty_serve';
|
25
24
|
export * from 'koatty_serve';
|
25
|
+
import 'reflect-metadata';
|
26
26
|
|
27
|
-
/*
|
28
|
-
* @Description: framework logger
|
29
|
-
* @Usage:
|
30
|
-
* @Author: richen
|
31
|
-
* @Date: 2023-12-09 21:56:32
|
32
|
-
* @LastEditTime: 2023-12-09 23:02:27
|
33
|
-
* @License: BSD (3-Clause)
|
34
|
-
* @Copyright (c): <richenlin(at)gmail.com>
|
35
|
-
*/
|
36
|
-
// Logger
|
37
|
-
const Logger = DefaultLogger;
|
38
|
-
/**
|
39
|
-
* SetLogger
|
40
|
-
*
|
41
|
-
* @export
|
42
|
-
* @param {{
|
43
|
-
* logLevel?: LogLevelType;
|
44
|
-
* logFilePath?: string;
|
45
|
-
* sensFields?: string[];
|
46
|
-
* }} config
|
47
|
-
*/
|
48
|
-
function SetLogger(app, config) {
|
49
|
-
if (config.logLevel) {
|
50
|
-
DefaultLogger.setLevel(config.logLevel);
|
51
|
-
}
|
52
|
-
if (config.logFilePath && !app.silent) {
|
53
|
-
Helper.define(app, "logsPath", config.logFilePath);
|
54
|
-
process.env.LOGS_PATH = config.logFilePath;
|
55
|
-
DefaultLogger.setLogFilePath(config.logFilePath);
|
56
|
-
}
|
57
|
-
if (config.sensFields) {
|
58
|
-
DefaultLogger.setSensFields(config.sensFields);
|
59
|
-
}
|
27
|
+
/*
|
28
|
+
* @Description: framework logger
|
29
|
+
* @Usage:
|
30
|
+
* @Author: richen
|
31
|
+
* @Date: 2023-12-09 21:56:32
|
32
|
+
* @LastEditTime: 2023-12-09 23:02:27
|
33
|
+
* @License: BSD (3-Clause)
|
34
|
+
* @Copyright (c): <richenlin(at)gmail.com>
|
35
|
+
*/
|
36
|
+
// Logger
|
37
|
+
const Logger = DefaultLogger;
|
38
|
+
/**
|
39
|
+
* SetLogger
|
40
|
+
*
|
41
|
+
* @export
|
42
|
+
* @param {{
|
43
|
+
* logLevel?: LogLevelType;
|
44
|
+
* logFilePath?: string;
|
45
|
+
* sensFields?: string[];
|
46
|
+
* }} config
|
47
|
+
*/
|
48
|
+
function SetLogger(app, config) {
|
49
|
+
if (config.logLevel) {
|
50
|
+
DefaultLogger.setLevel(config.logLevel);
|
51
|
+
}
|
52
|
+
if (config.logFilePath && !app.silent) {
|
53
|
+
Helper.define(app, "logsPath", config.logFilePath);
|
54
|
+
process.env.LOGS_PATH = config.logFilePath;
|
55
|
+
DefaultLogger.setLogFilePath(config.logFilePath);
|
56
|
+
}
|
57
|
+
if (config.sensFields) {
|
58
|
+
DefaultLogger.setSensFields(config.sensFields);
|
59
|
+
}
|
60
60
|
}
|
61
61
|
|
62
|
-
/*
|
63
|
-
* @Description: framework helper
|
64
|
-
* @Usage:
|
65
|
-
* @Author: richen
|
66
|
-
* @Date: 2023-12-09 21:56:32
|
67
|
-
* @LastEditTime: 2023-12-09 23:01:56
|
68
|
-
* @License: BSD (3-Clause)
|
69
|
-
* @Copyright (c): <richenlin(at)gmail.com>
|
70
|
-
*/
|
71
|
-
/**
|
72
|
-
* Check class file
|
73
|
-
* name should be always the same as class name
|
74
|
-
* class must be unique
|
75
|
-
*
|
76
|
-
* @export
|
77
|
-
* @param {string} fileName
|
78
|
-
* @param {string} xpath
|
79
|
-
* @param {*} target
|
80
|
-
* @param {Set<unknown>} [exSet]
|
81
|
-
* @returns {*}
|
82
|
-
*/
|
83
|
-
function checkClass(fileName, xpath, target, exSet) {
|
84
|
-
if (Helper.isClass(target) && target.name != fileName) { // export default class name{}
|
85
|
-
throw Error(`The file(${xpath}) name should be always the same as class name.`);
|
86
|
-
}
|
87
|
-
if (target["__esModule"]) {
|
88
|
-
if (target.name === undefined) { // export class name{}
|
89
|
-
const keys = Object.keys(target);
|
90
|
-
if (keys[0] != fileName && Helper.isClass(target[keys[0]])) {
|
91
|
-
throw Error(`The file(${xpath}) name should be always the same as class name.`);
|
92
|
-
}
|
93
|
-
}
|
94
|
-
else if (target.name != fileName) { // export default class {}
|
95
|
-
throw Error(`The file(${xpath}) name should be always the same as class name.`);
|
96
|
-
}
|
97
|
-
}
|
98
|
-
if (!exSet) {
|
99
|
-
return;
|
100
|
-
}
|
101
|
-
if (exSet.has(fileName)) {
|
102
|
-
throw new Error(`A same class already exists. at \`${xpath}\`.`);
|
103
|
-
}
|
104
|
-
exSet.add(fileName);
|
105
|
-
return;
|
106
|
-
}
|
107
|
-
/**
|
108
|
-
* Format api interface data format
|
109
|
-
*
|
110
|
-
* @private
|
111
|
-
* @param {Error | string | ApiInput} msg 待处理的接口数据信息|接口msg
|
112
|
-
* @param {*} data 待返回的数据
|
113
|
-
* @param {number} defaultCode 默认错误码
|
114
|
-
* @returns {ApiOutput} 格式化之后的接口数据
|
115
|
-
* @memberof BaseController
|
116
|
-
*/
|
117
|
-
function formatApiData(msg, data, defaultCode) {
|
118
|
-
let obj = {
|
119
|
-
code: defaultCode,
|
120
|
-
message: '',
|
121
|
-
data: null,
|
122
|
-
};
|
123
|
-
if (Helper.isError(msg)) {
|
124
|
-
const { code, message } = msg;
|
125
|
-
obj.code = code || defaultCode;
|
126
|
-
obj.message = message;
|
127
|
-
}
|
128
|
-
else if (Helper.isObject(msg)) {
|
129
|
-
obj = { ...obj, ...msg };
|
130
|
-
}
|
131
|
-
else {
|
132
|
-
obj.message = msg;
|
133
|
-
obj.data = data;
|
134
|
-
}
|
135
|
-
return obj;
|
62
|
+
/*
|
63
|
+
* @Description: framework helper
|
64
|
+
* @Usage:
|
65
|
+
* @Author: richen
|
66
|
+
* @Date: 2023-12-09 21:56:32
|
67
|
+
* @LastEditTime: 2023-12-09 23:01:56
|
68
|
+
* @License: BSD (3-Clause)
|
69
|
+
* @Copyright (c): <richenlin(at)gmail.com>
|
70
|
+
*/
|
71
|
+
/**
|
72
|
+
* Check class file
|
73
|
+
* name should be always the same as class name
|
74
|
+
* class must be unique
|
75
|
+
*
|
76
|
+
* @export
|
77
|
+
* @param {string} fileName
|
78
|
+
* @param {string} xpath
|
79
|
+
* @param {*} target
|
80
|
+
* @param {Set<unknown>} [exSet]
|
81
|
+
* @returns {*}
|
82
|
+
*/
|
83
|
+
function checkClass(fileName, xpath, target, exSet) {
|
84
|
+
if (Helper.isClass(target) && target.name != fileName) { // export default class name{}
|
85
|
+
throw Error(`The file(${xpath}) name should be always the same as class name.`);
|
86
|
+
}
|
87
|
+
if (target["__esModule"]) {
|
88
|
+
if (target.name === undefined) { // export class name{}
|
89
|
+
const keys = Object.keys(target);
|
90
|
+
if (keys[0] != fileName && Helper.isClass(target[keys[0]])) {
|
91
|
+
throw Error(`The file(${xpath}) name should be always the same as class name.`);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
else if (target.name != fileName) { // export default class {}
|
95
|
+
throw Error(`The file(${xpath}) name should be always the same as class name.`);
|
96
|
+
}
|
97
|
+
}
|
98
|
+
if (!exSet) {
|
99
|
+
return;
|
100
|
+
}
|
101
|
+
if (exSet.has(fileName)) {
|
102
|
+
throw new Error(`A same class already exists. at \`${xpath}\`.`);
|
103
|
+
}
|
104
|
+
exSet.add(fileName);
|
105
|
+
return;
|
106
|
+
}
|
107
|
+
/**
|
108
|
+
* Format api interface data format
|
109
|
+
*
|
110
|
+
* @private
|
111
|
+
* @param {Error | string | ApiInput} msg 待处理的接口数据信息|接口msg
|
112
|
+
* @param {*} data 待返回的数据
|
113
|
+
* @param {number} defaultCode 默认错误码
|
114
|
+
* @returns {ApiOutput} 格式化之后的接口数据
|
115
|
+
* @memberof BaseController
|
116
|
+
*/
|
117
|
+
function formatApiData(msg, data, defaultCode) {
|
118
|
+
let obj = {
|
119
|
+
code: defaultCode,
|
120
|
+
message: '',
|
121
|
+
data: null,
|
122
|
+
};
|
123
|
+
if (Helper.isError(msg)) {
|
124
|
+
const { code, message } = msg;
|
125
|
+
obj.code = code || defaultCode;
|
126
|
+
obj.message = message;
|
127
|
+
}
|
128
|
+
else if (Helper.isObject(msg)) {
|
129
|
+
obj = { ...obj, ...msg };
|
130
|
+
}
|
131
|
+
else {
|
132
|
+
obj.message = msg;
|
133
|
+
obj.data = data;
|
134
|
+
}
|
135
|
+
return obj;
|
136
136
|
}
|
137
137
|
|
138
|
-
/*
|
139
|
-
* @Description: framework constants
|
140
|
-
* @Usage:
|
141
|
-
* @Author: richen
|
142
|
-
* @Date: 2023-12-09 21:56:32
|
143
|
-
* @LastEditTime: 2023-12-09 23:00:13
|
144
|
-
* @License: BSD (3-Clause)
|
145
|
-
* @Copyright (c): <richenlin(at)gmail.com>
|
146
|
-
*/
|
147
|
-
const COMPONENT_SCAN = 'COMPONENT_SCAN';
|
148
|
-
const CONFIGURATION_SCAN = 'CONFIGURATION_SCAN';
|
149
|
-
// tslint:disable: no-irregular-whitespace
|
138
|
+
/*
|
139
|
+
* @Description: framework constants
|
140
|
+
* @Usage:
|
141
|
+
* @Author: richen
|
142
|
+
* @Date: 2023-12-09 21:56:32
|
143
|
+
* @LastEditTime: 2023-12-09 23:00:13
|
144
|
+
* @License: BSD (3-Clause)
|
145
|
+
* @Copyright (c): <richenlin(at)gmail.com>
|
146
|
+
*/
|
147
|
+
const COMPONENT_SCAN = 'COMPONENT_SCAN';
|
148
|
+
const CONFIGURATION_SCAN = 'CONFIGURATION_SCAN';
|
149
|
+
// tslint:disable: no-irregular-whitespace
|
150
150
|
const LOGO = `
|
151
151
|
|
152
152
|
┬┌─┌─┐┌─┐┌┬┐┌┬┐┬ ┬
|
@@ -156,881 +156,878 @@ const LOGO = `
|
|
156
156
|
https://github.com/koatty
|
157
157
|
`;
|
158
158
|
|
159
|
-
/*
|
160
|
-
* @Description: base controller
|
161
|
-
* @Usage:
|
162
|
-
* @Author: richen
|
163
|
-
* @Date: 2023-12-09 21:56:32
|
164
|
-
* @LastEditTime: 2023-12-09 23:03:09
|
165
|
-
* @License: BSD (3-Clause)
|
166
|
-
* @Copyright (c): <richenlin(at)gmail.com>
|
167
|
-
*/
|
168
|
-
/**
|
169
|
-
* Base controller
|
170
|
-
*
|
171
|
-
* @export
|
172
|
-
* @class BaseController
|
173
|
-
* @implements {IController}
|
174
|
-
*/
|
175
|
-
class BaseController {
|
176
|
-
/**
|
177
|
-
* instance of BaseController.
|
178
|
-
* @param {Koatty} app
|
179
|
-
* @param {KoattyContext} ctx
|
180
|
-
* @memberof BaseController
|
181
|
-
*/
|
182
|
-
constructor(ctx, ...arg) {
|
183
|
-
this.ctx = ctx;
|
184
|
-
this.init(arg);
|
185
|
-
}
|
186
|
-
/**
|
187
|
-
* init
|
188
|
-
*
|
189
|
-
* @memberof BaseController
|
190
|
-
*/
|
191
|
-
init(...arg) {
|
192
|
-
}
|
193
|
-
/**
|
194
|
-
* Response to normalize json format content for success
|
195
|
-
*
|
196
|
-
* @param {(string | ApiInput)} msg 待处理的message消息
|
197
|
-
* @param {*} [data] 待处理的数据
|
198
|
-
* @param {number} [code=200] 错误码,默认0
|
199
|
-
* @returns {*}
|
200
|
-
* @memberof BaseController
|
201
|
-
*/
|
202
|
-
ok(msg, data, code = 0) {
|
203
|
-
const obj = formatApiData(msg, data, code);
|
204
|
-
return Promise.resolve(obj);
|
205
|
-
}
|
206
|
-
/**
|
207
|
-
* Response to normalize json format content for fail
|
208
|
-
*
|
209
|
-
* @param {(string | ApiInput)} msg
|
210
|
-
* @param {*} [data]
|
211
|
-
* @param {number} [code=1]
|
212
|
-
* @returns {*}
|
213
|
-
* @memberof BaseController
|
214
|
-
*/
|
215
|
-
fail(msg, data, code = 1) {
|
216
|
-
const obj = formatApiData(msg, data, code);
|
217
|
-
this.ctx.body = obj.data;
|
218
|
-
this.ctx.throw(obj.message, obj.code, 200);
|
219
|
-
}
|
220
|
-
}
|
221
|
-
// const properties = ["constructor", "init"];
|
222
|
-
// export const BaseController = new Proxy(Base, {
|
223
|
-
// set(target, key, value, receiver) {
|
224
|
-
// if (Reflect.get(target, key, receiver) === undefined) {
|
225
|
-
// return Reflect.set(target, key, value, receiver);
|
226
|
-
// } else if (key === "init") {
|
227
|
-
// return Reflect.set(target, key, value, receiver);
|
228
|
-
// } else {
|
229
|
-
// throw Error("Cannot redefine getter-only property");
|
230
|
-
// }
|
231
|
-
// },
|
232
|
-
// deleteProperty(target, key) {
|
233
|
-
// throw Error("Cannot delete getter-only property");
|
234
|
-
// },
|
235
|
-
// construct(target, args, newTarget) {
|
236
|
-
// Reflect.ownKeys(target.prototype).map((n) => {
|
237
|
-
// if (newTarget.prototype.hasOwnProperty(n) && !properties.includes(Helper.toString(n))) {
|
238
|
-
// throw Error(`Cannot override the final method "${Helper.toString(n)}"`);
|
239
|
-
// }
|
240
|
-
// });
|
241
|
-
// return Reflect.construct(target, args, newTarget);
|
242
|
-
// }
|
159
|
+
/*
|
160
|
+
* @Description: base controller
|
161
|
+
* @Usage:
|
162
|
+
* @Author: richen
|
163
|
+
* @Date: 2023-12-09 21:56:32
|
164
|
+
* @LastEditTime: 2023-12-09 23:03:09
|
165
|
+
* @License: BSD (3-Clause)
|
166
|
+
* @Copyright (c): <richenlin(at)gmail.com>
|
167
|
+
*/
|
168
|
+
/**
|
169
|
+
* Base controller
|
170
|
+
*
|
171
|
+
* @export
|
172
|
+
* @class BaseController
|
173
|
+
* @implements {IController}
|
174
|
+
*/
|
175
|
+
class BaseController {
|
176
|
+
/**
|
177
|
+
* instance of BaseController.
|
178
|
+
* @param {Koatty} app
|
179
|
+
* @param {KoattyContext} ctx
|
180
|
+
* @memberof BaseController
|
181
|
+
*/
|
182
|
+
constructor(ctx, ...arg) {
|
183
|
+
this.ctx = ctx;
|
184
|
+
this.init(arg);
|
185
|
+
}
|
186
|
+
/**
|
187
|
+
* init
|
188
|
+
*
|
189
|
+
* @memberof BaseController
|
190
|
+
*/
|
191
|
+
init(...arg) {
|
192
|
+
}
|
193
|
+
/**
|
194
|
+
* Response to normalize json format content for success
|
195
|
+
*
|
196
|
+
* @param {(string | ApiInput)} msg 待处理的message消息
|
197
|
+
* @param {*} [data] 待处理的数据
|
198
|
+
* @param {number} [code=200] 错误码,默认0
|
199
|
+
* @returns {*}
|
200
|
+
* @memberof BaseController
|
201
|
+
*/
|
202
|
+
ok(msg, data, code = 0) {
|
203
|
+
const obj = formatApiData(msg, data, code);
|
204
|
+
return Promise.resolve(obj);
|
205
|
+
}
|
206
|
+
/**
|
207
|
+
* Response to normalize json format content for fail
|
208
|
+
*
|
209
|
+
* @param {(string | ApiInput)} msg
|
210
|
+
* @param {*} [data]
|
211
|
+
* @param {number} [code=1]
|
212
|
+
* @returns {*}
|
213
|
+
* @memberof BaseController
|
214
|
+
*/
|
215
|
+
fail(msg, data, code = 1) {
|
216
|
+
const obj = formatApiData(msg, data, code);
|
217
|
+
this.ctx.body = obj.data;
|
218
|
+
this.ctx.throw(obj.message, obj.code, 200);
|
219
|
+
}
|
220
|
+
}
|
221
|
+
// const properties = ["constructor", "init"];
|
222
|
+
// export const BaseController = new Proxy(Base, {
|
223
|
+
// set(target, key, value, receiver) {
|
224
|
+
// if (Reflect.get(target, key, receiver) === undefined) {
|
225
|
+
// return Reflect.set(target, key, value, receiver);
|
226
|
+
// } else if (key === "init") {
|
227
|
+
// return Reflect.set(target, key, value, receiver);
|
228
|
+
// } else {
|
229
|
+
// throw Error("Cannot redefine getter-only property");
|
230
|
+
// }
|
231
|
+
// },
|
232
|
+
// deleteProperty(target, key) {
|
233
|
+
// throw Error("Cannot delete getter-only property");
|
234
|
+
// },
|
235
|
+
// construct(target, args, newTarget) {
|
236
|
+
// Reflect.ownKeys(target.prototype).map((n) => {
|
237
|
+
// if (newTarget.prototype.hasOwnProperty(n) && !properties.includes(Helper.toString(n))) {
|
238
|
+
// throw Error(`Cannot override the final method "${Helper.toString(n)}"`);
|
239
|
+
// }
|
240
|
+
// });
|
241
|
+
// return Reflect.construct(target, args, newTarget);
|
242
|
+
// }
|
243
243
|
// });
|
244
244
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
245
|
+
function TraceHandler(app) {
|
246
|
+
const timeout = (app.config('http_timeout') || 10) * 1000;
|
247
|
+
const encoding = app.config('encoding') || 'utf-8';
|
248
|
+
const openTrace = app.config("open_trace") || false;
|
249
|
+
const asyncHooks = app.config("async_hooks") || false;
|
250
|
+
const options = {
|
251
|
+
RequestIdHeaderName: app.config('trace_header') || 'X-Request-Id',
|
252
|
+
RequestIdName: app.config('trace_id') || "requestId",
|
253
|
+
IdFactory: undefined,
|
254
|
+
Timeout: timeout,
|
255
|
+
Encoding: encoding,
|
256
|
+
OpenTrace: openTrace,
|
257
|
+
AsyncHooks: asyncHooks,
|
258
|
+
};
|
259
|
+
app.use(Trace(options, app));
|
258
260
|
}
|
259
261
|
|
260
|
-
/*
|
261
|
-
* @Description: framework loader
|
262
|
-
* @Usage:
|
263
|
-
* @Author: richen
|
264
|
-
* @Date: 2023-12-09 22:55:49
|
265
|
-
* @LastEditTime: 2023-12-
|
266
|
-
* @License: BSD (3-Clause)
|
267
|
-
* @Copyright (c): <richenlin(at)gmail.com>
|
268
|
-
*/
|
269
|
-
/**
|
270
|
-
*
|
271
|
-
*/
|
272
|
-
class Loader {
|
273
|
-
/**
|
274
|
-
* initialize env
|
275
|
-
*
|
276
|
-
* @static
|
277
|
-
* @param {Koatty} app
|
278
|
-
* @memberof Loader
|
279
|
-
*/
|
280
|
-
static initialize(app) {
|
281
|
-
const env = (process.execArgv ?? []).join(",");
|
282
|
-
if (env.indexOf('ts-node') > -1 || env.indexOf('--debug') > -1) {
|
283
|
-
app.appDebug = true;
|
284
|
-
}
|
285
|
-
// app.env
|
286
|
-
app.env = process.env.KOATTY_ENV || process.env.NODE_ENV;
|
287
|
-
if ((env.indexOf('--production') > -1) || ((app.env ?? '').indexOf('pro') > -1)) {
|
288
|
-
app.appDebug = false;
|
289
|
-
}
|
290
|
-
if (app.appDebug) {
|
291
|
-
app.env = 'development';
|
292
|
-
process.env.NODE_ENV = 'development';
|
293
|
-
process.env.APP_DEBUG = 'true';
|
294
|
-
Logger.setLevel("debug");
|
295
|
-
}
|
296
|
-
else {
|
297
|
-
app.env = 'production';
|
298
|
-
process.env.NODE_ENV = 'production';
|
299
|
-
Logger.setLevel("info");
|
300
|
-
}
|
301
|
-
// define path
|
302
|
-
const rootPath = app.rootPath || process.cwd();
|
303
|
-
const appPath = app.appPath || path.resolve(rootPath, env.indexOf('ts-node') > -1 ? 'src' : 'dist');
|
304
|
-
const koattyPath = path.resolve(__dirname, '..');
|
305
|
-
Helper.define(app, 'rootPath', rootPath);
|
306
|
-
Helper.define(app, 'appPath', appPath);
|
307
|
-
Helper.define(app, 'koattyPath', koattyPath);
|
308
|
-
//
|
309
|
-
if (Helper.isEmpty(app.name)) {
|
310
|
-
const pkg = Helper.safeRequire(`${path.dirname(appPath)}/package.json`);
|
311
|
-
if (pkg.name) {
|
312
|
-
app.name = pkg.name;
|
313
|
-
app.version = app.version || pkg.version;
|
314
|
-
}
|
315
|
-
}
|
316
|
-
process.env.ROOT_PATH = rootPath;
|
317
|
-
process.env.APP_PATH = appPath;
|
318
|
-
process.env.KOATTY_PATH = koattyPath;
|
319
|
-
// Compatible with old version, will be deprecated
|
320
|
-
Helper.define(app, 'prevent', prevent);
|
321
|
-
Helper.define(app, 'thinkPath', koattyPath);
|
322
|
-
process.env.THINK_PATH = koattyPath;
|
323
|
-
}
|
324
|
-
/**
|
325
|
-
* Get component metadata
|
326
|
-
*
|
327
|
-
* @static
|
328
|
-
* @param {Koatty} app
|
329
|
-
* @param {*} target
|
330
|
-
* @returns {*} {any[]}
|
331
|
-
* @memberof Loader
|
332
|
-
*/
|
333
|
-
static GetComponentMetas(app, target) {
|
334
|
-
let componentMetas = [];
|
335
|
-
const componentMeta = IOCContainer.getClassMetadata(TAGGED_CLS, COMPONENT_SCAN, target);
|
336
|
-
if (componentMeta) {
|
337
|
-
if (Helper.isArray(componentMeta)) {
|
338
|
-
componentMetas = componentMeta;
|
339
|
-
}
|
340
|
-
else {
|
341
|
-
componentMetas.push(componentMeta);
|
342
|
-
}
|
343
|
-
}
|
344
|
-
if (componentMetas.length < 1) {
|
345
|
-
componentMetas = [app.appPath];
|
346
|
-
}
|
347
|
-
return componentMetas;
|
348
|
-
}
|
349
|
-
/**
|
350
|
-
* Load all bean, excepted config/*、App.ts
|
351
|
-
*
|
352
|
-
* @static
|
353
|
-
* @param {Koatty} app
|
354
|
-
* @param {*} target
|
355
|
-
* @memberof Loader
|
356
|
-
*/
|
357
|
-
static CheckAllComponents(app, target) {
|
358
|
-
// component metadata
|
359
|
-
const componentMetas = Loader.GetComponentMetas(app, target);
|
360
|
-
// configuration metadata
|
361
|
-
const configurationMetas = Loader.GetConfigurationMetas(app, target);
|
362
|
-
const exSet = new Set();
|
363
|
-
Load(componentMetas, '', (fileName, xpath, xTarget) => {
|
364
|
-
checkClass(fileName, xpath, xTarget, exSet);
|
365
|
-
}, ['**/**.js', '**/**.ts', '!**/**.d.ts'], [...configurationMetas, `${target.name || '.no'}.ts`]);
|
366
|
-
exSet.clear();
|
367
|
-
}
|
368
|
-
/**
|
369
|
-
* Get configuration metadata
|
370
|
-
*
|
371
|
-
* @static
|
372
|
-
* @param {Koatty} app
|
373
|
-
* @param {*} target
|
374
|
-
* @returns {*} {any[]}
|
375
|
-
* @memberof Loader
|
376
|
-
*/
|
377
|
-
static GetConfigurationMetas(app, target) {
|
378
|
-
const confMeta = IOCContainer.getClassMetadata(TAGGED_CLS, CONFIGURATION_SCAN, target);
|
379
|
-
let configurationMetas = [];
|
380
|
-
if (confMeta) {
|
381
|
-
if (Helper.isArray(confMeta)) {
|
382
|
-
configurationMetas = confMeta;
|
383
|
-
}
|
384
|
-
else {
|
385
|
-
configurationMetas.push(confMeta);
|
386
|
-
}
|
387
|
-
}
|
388
|
-
return configurationMetas;
|
389
|
-
}
|
390
|
-
/**
|
391
|
-
* Set Logger level
|
392
|
-
*
|
393
|
-
* @static
|
394
|
-
* @param {Koatty} app
|
395
|
-
* @memberof Loader
|
396
|
-
*/
|
397
|
-
static SetLogger(app) {
|
398
|
-
const data = app.getMetaData('_configs') || [];
|
399
|
-
const configs = data[0] || {};
|
400
|
-
//Logger
|
401
|
-
if (configs.config) {
|
402
|
-
const opt = configs.config;
|
403
|
-
let logLevel = "debug", logFilePath = "", sensFields = [];
|
404
|
-
if (app.env === "production") {
|
405
|
-
logLevel = "info";
|
406
|
-
}
|
407
|
-
if (opt.logs_level) {
|
408
|
-
logLevel = (opt.logs_level).toLowerCase();
|
409
|
-
}
|
410
|
-
if (opt.logs_path) {
|
411
|
-
logFilePath = opt.logs_path;
|
412
|
-
}
|
413
|
-
if (opt.sens_fields) {
|
414
|
-
sensFields = opt.sens_fields;
|
415
|
-
}
|
416
|
-
SetLogger(app, { logLevel, logFilePath, sensFields });
|
417
|
-
}
|
418
|
-
}
|
419
|
-
/**
|
420
|
-
* Load app event hook funcs
|
421
|
-
*
|
422
|
-
* @static
|
423
|
-
* @param {Koatty} app
|
424
|
-
* @param {*} target
|
425
|
-
* @memberof Loader
|
426
|
-
*/
|
427
|
-
static LoadAppEventHooks(app, target) {
|
428
|
-
const eventFuncs = new Map();
|
429
|
-
for (const event of AppEventArr) {
|
430
|
-
let funcs;
|
431
|
-
switch (event) {
|
432
|
-
case "appBoot" /* AppEvent.appBoot */:
|
433
|
-
funcs = IOCContainer.getClassMetadata(TAGGED_CLS, "appBoot" /* AppEvent.appBoot */, target);
|
434
|
-
if (Helper.isArray(funcs)) {
|
435
|
-
eventFuncs.set("appBoot" /* AppEvent.appBoot */, funcs);
|
436
|
-
}
|
437
|
-
break;
|
438
|
-
case "appReady" /* AppEvent.appReady */:
|
439
|
-
funcs = IOCContainer.getClassMetadata(TAGGED_CLS, "appReady" /* AppEvent.appReady */, target);
|
440
|
-
if (Helper.isArray(funcs)) {
|
441
|
-
eventFuncs.set("appReady" /* AppEvent.appReady */, funcs);
|
442
|
-
}
|
443
|
-
break;
|
444
|
-
case "appStart" /* AppEvent.appStart */:
|
445
|
-
funcs = IOCContainer.getClassMetadata(TAGGED_CLS, "appStart" /* AppEvent.appStart */, target);
|
446
|
-
if (Helper.isArray(funcs)) {
|
447
|
-
eventFuncs.set("appStart" /* AppEvent.appStart */, funcs);
|
448
|
-
}
|
449
|
-
break;
|
450
|
-
case "appStop" /* AppEvent.appStop */:
|
451
|
-
funcs = IOCContainer.getClassMetadata(TAGGED_CLS, "appStop" /* AppEvent.appStop */, target);
|
452
|
-
if (Helper.isArray(funcs)) {
|
453
|
-
eventFuncs.set("appStop" /* AppEvent.appStop */, funcs);
|
454
|
-
}
|
455
|
-
break;
|
456
|
-
}
|
457
|
-
}
|
458
|
-
// loop event emit
|
459
|
-
for (const [event, funcs] of eventFuncs) {
|
460
|
-
for (const func of funcs) {
|
461
|
-
app.once(event, () => func(app));
|
462
|
-
}
|
463
|
-
}
|
464
|
-
}
|
465
|
-
/**
|
466
|
-
* Load configuration
|
467
|
-
*
|
468
|
-
* @static
|
469
|
-
* @param {Koatty} app
|
470
|
-
* @param {string[]} [loadPath]
|
471
|
-
* @memberof Loader
|
472
|
-
*/
|
473
|
-
static LoadConfigs(app, loadPath) {
|
474
|
-
const frameConfig = {};
|
475
|
-
// Logger.Debug(`Load configuration path: ${app.thinkPath}/config`);
|
476
|
-
Load(["./config"], app.koattyPath, function (name, path, exp) {
|
477
|
-
frameConfig[name] = exp;
|
478
|
-
});
|
479
|
-
if (Helper.isArray(loadPath)) {
|
480
|
-
loadPath = loadPath.length > 0 ? loadPath : ["./config"];
|
481
|
-
}
|
482
|
-
let appConfig = LoadConfigs(loadPath, app.appPath);
|
483
|
-
appConfig = Helper.extend(frameConfig, appConfig, true);
|
484
|
-
app.setMetaData("_configs", appConfig);
|
485
|
-
}
|
486
|
-
/**
|
487
|
-
* Load middlewares
|
488
|
-
* [async]
|
489
|
-
* @static
|
490
|
-
* @param {*} app
|
491
|
-
* @param {(string | string[])} [loadPath]
|
492
|
-
* @memberof Loader
|
493
|
-
*/
|
494
|
-
static async LoadMiddlewares(app, loadPath) {
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
//Mount
|
502
|
-
//
|
503
|
-
|
504
|
-
|
505
|
-
appMiddleware.
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
const
|
513
|
-
//de-duplication
|
514
|
-
const appMList = new Set(
|
515
|
-
middlewareConfList.forEach((item) => {
|
516
|
-
appMList.add(item);
|
517
|
-
});
|
518
|
-
//Automatically call middleware
|
519
|
-
for (const key of appMList) {
|
520
|
-
const handle = IOCContainer.get(key, "MIDDLEWARE");
|
521
|
-
if (!handle) {
|
522
|
-
Logger.Error(`Middleware ${key} load error.`);
|
523
|
-
continue;
|
524
|
-
}
|
525
|
-
if (!Helper.isFunction(handle.run)) {
|
526
|
-
Logger.Error(`
|
527
|
-
continue;
|
528
|
-
}
|
529
|
-
if (middlewareConf.config[key] === false) {
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
//
|
602
|
-
//
|
603
|
-
//
|
604
|
-
//
|
605
|
-
//
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
// load plugin
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
}
|
649
|
-
|
650
|
-
|
651
|
-
continue;
|
652
|
-
}
|
653
|
-
// sync exec
|
654
|
-
await handle.run(pluginsConf.config[key] ?? {}, app);
|
655
|
-
}
|
656
|
-
}
|
262
|
+
/*
|
263
|
+
* @Description: framework loader
|
264
|
+
* @Usage:
|
265
|
+
* @Author: richen
|
266
|
+
* @Date: 2023-12-09 22:55:49
|
267
|
+
* @LastEditTime: 2023-12-14 23:10:33
|
268
|
+
* @License: BSD (3-Clause)
|
269
|
+
* @Copyright (c): <richenlin(at)gmail.com>
|
270
|
+
*/
|
271
|
+
/**
|
272
|
+
*
|
273
|
+
*/
|
274
|
+
class Loader {
|
275
|
+
/**
|
276
|
+
* initialize env
|
277
|
+
*
|
278
|
+
* @static
|
279
|
+
* @param {Koatty} app
|
280
|
+
* @memberof Loader
|
281
|
+
*/
|
282
|
+
static initialize(app) {
|
283
|
+
const env = (process.execArgv ?? []).join(",");
|
284
|
+
if (env.indexOf('ts-node') > -1 || env.indexOf('--debug') > -1) {
|
285
|
+
app.appDebug = true;
|
286
|
+
}
|
287
|
+
// app.env
|
288
|
+
app.env = process.env.KOATTY_ENV || process.env.NODE_ENV;
|
289
|
+
if ((env.indexOf('--production') > -1) || ((app.env ?? '').indexOf('pro') > -1)) {
|
290
|
+
app.appDebug = false;
|
291
|
+
}
|
292
|
+
if (app.appDebug) {
|
293
|
+
app.env = 'development';
|
294
|
+
process.env.NODE_ENV = 'development';
|
295
|
+
process.env.APP_DEBUG = 'true';
|
296
|
+
Logger.setLevel("debug");
|
297
|
+
}
|
298
|
+
else {
|
299
|
+
app.env = 'production';
|
300
|
+
process.env.NODE_ENV = 'production';
|
301
|
+
Logger.setLevel("info");
|
302
|
+
}
|
303
|
+
// define path
|
304
|
+
const rootPath = app.rootPath || process.cwd();
|
305
|
+
const appPath = app.appPath || path.resolve(rootPath, env.indexOf('ts-node') > -1 ? 'src' : 'dist');
|
306
|
+
const koattyPath = path.resolve(__dirname, '..');
|
307
|
+
Helper.define(app, 'rootPath', rootPath);
|
308
|
+
Helper.define(app, 'appPath', appPath);
|
309
|
+
Helper.define(app, 'koattyPath', koattyPath);
|
310
|
+
//
|
311
|
+
if (Helper.isEmpty(app.name)) {
|
312
|
+
const pkg = Helper.safeRequire(`${path.dirname(appPath)}/package.json`);
|
313
|
+
if (pkg.name) {
|
314
|
+
app.name = pkg.name;
|
315
|
+
app.version = app.version || pkg.version;
|
316
|
+
}
|
317
|
+
}
|
318
|
+
process.env.ROOT_PATH = rootPath;
|
319
|
+
process.env.APP_PATH = appPath;
|
320
|
+
process.env.KOATTY_PATH = koattyPath;
|
321
|
+
// Compatible with old version, will be deprecated
|
322
|
+
Helper.define(app, 'prevent', prevent);
|
323
|
+
Helper.define(app, 'thinkPath', koattyPath);
|
324
|
+
process.env.THINK_PATH = koattyPath;
|
325
|
+
}
|
326
|
+
/**
|
327
|
+
* Get component metadata
|
328
|
+
*
|
329
|
+
* @static
|
330
|
+
* @param {Koatty} app
|
331
|
+
* @param {*} target
|
332
|
+
* @returns {*} {any[]}
|
333
|
+
* @memberof Loader
|
334
|
+
*/
|
335
|
+
static GetComponentMetas(app, target) {
|
336
|
+
let componentMetas = [];
|
337
|
+
const componentMeta = IOCContainer.getClassMetadata(TAGGED_CLS, COMPONENT_SCAN, target);
|
338
|
+
if (componentMeta) {
|
339
|
+
if (Helper.isArray(componentMeta)) {
|
340
|
+
componentMetas = componentMeta;
|
341
|
+
}
|
342
|
+
else {
|
343
|
+
componentMetas.push(componentMeta);
|
344
|
+
}
|
345
|
+
}
|
346
|
+
if (componentMetas.length < 1) {
|
347
|
+
componentMetas = [app.appPath];
|
348
|
+
}
|
349
|
+
return componentMetas;
|
350
|
+
}
|
351
|
+
/**
|
352
|
+
* Load all bean, excepted config/*、App.ts
|
353
|
+
*
|
354
|
+
* @static
|
355
|
+
* @param {Koatty} app
|
356
|
+
* @param {*} target
|
357
|
+
* @memberof Loader
|
358
|
+
*/
|
359
|
+
static CheckAllComponents(app, target) {
|
360
|
+
// component metadata
|
361
|
+
const componentMetas = Loader.GetComponentMetas(app, target);
|
362
|
+
// configuration metadata
|
363
|
+
const configurationMetas = Loader.GetConfigurationMetas(app, target);
|
364
|
+
const exSet = new Set();
|
365
|
+
Load(componentMetas, '', (fileName, xpath, xTarget) => {
|
366
|
+
checkClass(fileName, xpath, xTarget, exSet);
|
367
|
+
}, ['**/**.js', '**/**.ts', '!**/**.d.ts'], [...configurationMetas, `${target.name || '.no'}.ts`]);
|
368
|
+
exSet.clear();
|
369
|
+
}
|
370
|
+
/**
|
371
|
+
* Get configuration metadata
|
372
|
+
*
|
373
|
+
* @static
|
374
|
+
* @param {Koatty} app
|
375
|
+
* @param {*} target
|
376
|
+
* @returns {*} {any[]}
|
377
|
+
* @memberof Loader
|
378
|
+
*/
|
379
|
+
static GetConfigurationMetas(app, target) {
|
380
|
+
const confMeta = IOCContainer.getClassMetadata(TAGGED_CLS, CONFIGURATION_SCAN, target);
|
381
|
+
let configurationMetas = [];
|
382
|
+
if (confMeta) {
|
383
|
+
if (Helper.isArray(confMeta)) {
|
384
|
+
configurationMetas = confMeta;
|
385
|
+
}
|
386
|
+
else {
|
387
|
+
configurationMetas.push(confMeta);
|
388
|
+
}
|
389
|
+
}
|
390
|
+
return configurationMetas;
|
391
|
+
}
|
392
|
+
/**
|
393
|
+
* Set Logger level
|
394
|
+
*
|
395
|
+
* @static
|
396
|
+
* @param {Koatty} app
|
397
|
+
* @memberof Loader
|
398
|
+
*/
|
399
|
+
static SetLogger(app) {
|
400
|
+
const data = app.getMetaData('_configs') || [];
|
401
|
+
const configs = data[0] || {};
|
402
|
+
//Logger
|
403
|
+
if (configs.config) {
|
404
|
+
const opt = configs.config;
|
405
|
+
let logLevel = "debug", logFilePath = "", sensFields = [];
|
406
|
+
if (app.env === "production") {
|
407
|
+
logLevel = "info";
|
408
|
+
}
|
409
|
+
if (opt.logs_level) {
|
410
|
+
logLevel = (opt.logs_level).toLowerCase();
|
411
|
+
}
|
412
|
+
if (opt.logs_path) {
|
413
|
+
logFilePath = opt.logs_path;
|
414
|
+
}
|
415
|
+
if (opt.sens_fields) {
|
416
|
+
sensFields = opt.sens_fields;
|
417
|
+
}
|
418
|
+
SetLogger(app, { logLevel, logFilePath, sensFields });
|
419
|
+
}
|
420
|
+
}
|
421
|
+
/**
|
422
|
+
* Load app event hook funcs
|
423
|
+
*
|
424
|
+
* @static
|
425
|
+
* @param {Koatty} app
|
426
|
+
* @param {*} target
|
427
|
+
* @memberof Loader
|
428
|
+
*/
|
429
|
+
static LoadAppEventHooks(app, target) {
|
430
|
+
const eventFuncs = new Map();
|
431
|
+
for (const event of AppEventArr) {
|
432
|
+
let funcs;
|
433
|
+
switch (event) {
|
434
|
+
case "appBoot" /* AppEvent.appBoot */:
|
435
|
+
funcs = IOCContainer.getClassMetadata(TAGGED_CLS, "appBoot" /* AppEvent.appBoot */, target);
|
436
|
+
if (Helper.isArray(funcs)) {
|
437
|
+
eventFuncs.set("appBoot" /* AppEvent.appBoot */, funcs);
|
438
|
+
}
|
439
|
+
break;
|
440
|
+
case "appReady" /* AppEvent.appReady */:
|
441
|
+
funcs = IOCContainer.getClassMetadata(TAGGED_CLS, "appReady" /* AppEvent.appReady */, target);
|
442
|
+
if (Helper.isArray(funcs)) {
|
443
|
+
eventFuncs.set("appReady" /* AppEvent.appReady */, funcs);
|
444
|
+
}
|
445
|
+
break;
|
446
|
+
case "appStart" /* AppEvent.appStart */:
|
447
|
+
funcs = IOCContainer.getClassMetadata(TAGGED_CLS, "appStart" /* AppEvent.appStart */, target);
|
448
|
+
if (Helper.isArray(funcs)) {
|
449
|
+
eventFuncs.set("appStart" /* AppEvent.appStart */, funcs);
|
450
|
+
}
|
451
|
+
break;
|
452
|
+
case "appStop" /* AppEvent.appStop */:
|
453
|
+
funcs = IOCContainer.getClassMetadata(TAGGED_CLS, "appStop" /* AppEvent.appStop */, target);
|
454
|
+
if (Helper.isArray(funcs)) {
|
455
|
+
eventFuncs.set("appStop" /* AppEvent.appStop */, funcs);
|
456
|
+
}
|
457
|
+
break;
|
458
|
+
}
|
459
|
+
}
|
460
|
+
// loop event emit
|
461
|
+
for (const [event, funcs] of eventFuncs) {
|
462
|
+
for (const func of funcs) {
|
463
|
+
app.once(event, () => func(app));
|
464
|
+
}
|
465
|
+
}
|
466
|
+
}
|
467
|
+
/**
|
468
|
+
* Load configuration
|
469
|
+
*
|
470
|
+
* @static
|
471
|
+
* @param {Koatty} app
|
472
|
+
* @param {string[]} [loadPath]
|
473
|
+
* @memberof Loader
|
474
|
+
*/
|
475
|
+
static LoadConfigs(app, loadPath) {
|
476
|
+
const frameConfig = {};
|
477
|
+
// Logger.Debug(`Load configuration path: ${app.thinkPath}/config`);
|
478
|
+
Load(["./config"], app.koattyPath, function (name, path, exp) {
|
479
|
+
frameConfig[name] = exp;
|
480
|
+
});
|
481
|
+
if (Helper.isArray(loadPath)) {
|
482
|
+
loadPath = loadPath.length > 0 ? loadPath : ["./config"];
|
483
|
+
}
|
484
|
+
let appConfig = LoadConfigs(loadPath, app.appPath);
|
485
|
+
appConfig = Helper.extend(frameConfig, appConfig, true);
|
486
|
+
app.setMetaData("_configs", appConfig);
|
487
|
+
}
|
488
|
+
/**
|
489
|
+
* Load middlewares
|
490
|
+
* [async]
|
491
|
+
* @static
|
492
|
+
* @param {*} app
|
493
|
+
* @param {(string | string[])} [loadPath]
|
494
|
+
* @memberof Loader
|
495
|
+
*/
|
496
|
+
static async LoadMiddlewares(app, loadPath) {
|
497
|
+
// Error handling middleware
|
498
|
+
TraceHandler(app);
|
499
|
+
let middlewareConf = app.config(undefined, "middleware");
|
500
|
+
if (Helper.isEmpty(middlewareConf)) {
|
501
|
+
middlewareConf = { config: {}, list: [] };
|
502
|
+
}
|
503
|
+
//Mount default middleware
|
504
|
+
// Load(loadPath || ["./middleware"], app.koattyPath);
|
505
|
+
//Mount application middleware
|
506
|
+
// const middleware: any = {};
|
507
|
+
const appMiddleware = IOCContainer.listClass("MIDDLEWARE") ?? [];
|
508
|
+
appMiddleware.forEach((item) => {
|
509
|
+
item.id = (item.id ?? "").replace("MIDDLEWARE:", "");
|
510
|
+
if (item.id && Helper.isClass(item.target)) {
|
511
|
+
IOCContainer.reg(item.id, item.target, { scope: "Prototype", type: "MIDDLEWARE", args: [] });
|
512
|
+
}
|
513
|
+
});
|
514
|
+
const middlewareConfList = middlewareConf.list;
|
515
|
+
//de-duplication
|
516
|
+
const appMList = new Set([]);
|
517
|
+
middlewareConfList.forEach((item) => {
|
518
|
+
appMList.add(item);
|
519
|
+
});
|
520
|
+
//Automatically call middleware
|
521
|
+
for (const key of appMList) {
|
522
|
+
const handle = IOCContainer.get(key, "MIDDLEWARE");
|
523
|
+
if (!handle) {
|
524
|
+
Logger.Error(`Middleware ${key} load error.`);
|
525
|
+
continue;
|
526
|
+
}
|
527
|
+
if (!Helper.isFunction(handle.run)) {
|
528
|
+
Logger.Error(`The middleware ${key} must implements interface 'IMiddleware'.`);
|
529
|
+
continue;
|
530
|
+
}
|
531
|
+
if (middlewareConf.config[key] === false) {
|
532
|
+
Logger.Warn(`The middleware ${key} has been loaded but not executed.`);
|
533
|
+
continue;
|
534
|
+
}
|
535
|
+
Logger.Debug(`Load middleware: ${key}`);
|
536
|
+
const result = await handle.run(middlewareConf.config[key] || {}, app);
|
537
|
+
if (Helper.isFunction(result)) {
|
538
|
+
if (result.length < 3) {
|
539
|
+
app.use(result);
|
540
|
+
}
|
541
|
+
else {
|
542
|
+
app.useExp(result);
|
543
|
+
}
|
544
|
+
}
|
545
|
+
}
|
546
|
+
}
|
547
|
+
/**
|
548
|
+
* Load controllers
|
549
|
+
*
|
550
|
+
* @static
|
551
|
+
* @param {*} app
|
552
|
+
* @memberof Loader
|
553
|
+
*/
|
554
|
+
static LoadControllers(app) {
|
555
|
+
const controllerList = IOCContainer.listClass("CONTROLLER");
|
556
|
+
const controllers = [];
|
557
|
+
controllerList.forEach((item) => {
|
558
|
+
item.id = (item.id ?? "").replace("CONTROLLER:", "");
|
559
|
+
if (item.id && Helper.isClass(item.target)) {
|
560
|
+
Logger.Debug(`Load controller: ${item.id}`);
|
561
|
+
// registering to IOC
|
562
|
+
IOCContainer.reg(item.id, item.target, { scope: "Prototype", type: "CONTROLLER", args: [] });
|
563
|
+
const ctl = IOCContainer.getInsByClass(item.target);
|
564
|
+
if (!(ctl instanceof BaseController)) {
|
565
|
+
throw new Error(`class ${item.id} does not inherit from BaseController`);
|
566
|
+
}
|
567
|
+
controllers.push(item.id);
|
568
|
+
}
|
569
|
+
});
|
570
|
+
return controllers;
|
571
|
+
}
|
572
|
+
/**
|
573
|
+
* Load services
|
574
|
+
*
|
575
|
+
* @static
|
576
|
+
* @param {*} app
|
577
|
+
* @memberof Loader
|
578
|
+
*/
|
579
|
+
static LoadServices(app) {
|
580
|
+
const serviceList = IOCContainer.listClass("SERVICE");
|
581
|
+
serviceList.forEach((item) => {
|
582
|
+
item.id = (item.id ?? "").replace("SERVICE:", "");
|
583
|
+
if (item.id && Helper.isClass(item.target)) {
|
584
|
+
Logger.Debug(`Load service: ${item.id}`);
|
585
|
+
// registering to IOC
|
586
|
+
IOCContainer.reg(item.id, item.target, { scope: "Singleton", type: "SERVICE", args: [] });
|
587
|
+
}
|
588
|
+
});
|
589
|
+
}
|
590
|
+
/**
|
591
|
+
* Load components
|
592
|
+
*
|
593
|
+
* @static
|
594
|
+
* @param {*} app
|
595
|
+
* @memberof Loader
|
596
|
+
*/
|
597
|
+
// public static LoadComponents(app: Koatty) {
|
598
|
+
// const componentList = IOCContainer.listClass("COMPONENT");
|
599
|
+
// componentList.forEach((item: ComponentItem) => {
|
600
|
+
// item.id = (item.id ?? "").replace("COMPONENT:", "");
|
601
|
+
// if (item.id && !(item.id).endsWith("Plugin") && Helper.isClass(item.target)) {
|
602
|
+
// Logger.Debug(`Load component: ${item.id}`);
|
603
|
+
// // registering to IOC
|
604
|
+
// IOCContainer.reg(item.id, item.target, { scope: "Singleton", type: "COMPONENT", args: [] });
|
605
|
+
// }
|
606
|
+
// });
|
607
|
+
// }
|
608
|
+
/**
|
609
|
+
* Load components
|
610
|
+
*
|
611
|
+
* @static
|
612
|
+
* @param {*} app
|
613
|
+
* @memberof Loader
|
614
|
+
*/
|
615
|
+
static async LoadComponents(app) {
|
616
|
+
const componentList = IOCContainer.listClass("COMPONENT");
|
617
|
+
const pluginList = [];
|
618
|
+
componentList.forEach(async (item) => {
|
619
|
+
item.id = (item.id ?? "").replace("COMPONENT:", "");
|
620
|
+
if (Helper.isClass(item.target)) {
|
621
|
+
if (item.id && (item.id).endsWith("Plugin")) {
|
622
|
+
pluginList.push(item.id);
|
623
|
+
}
|
624
|
+
// registering to IOC
|
625
|
+
IOCContainer.reg(item.id, item.target, { scope: "Singleton", type: "COMPONENT", args: [] });
|
626
|
+
}
|
627
|
+
});
|
628
|
+
// load plugin config
|
629
|
+
let pluginsConf = app.config(undefined, "plugin");
|
630
|
+
if (Helper.isEmpty(pluginsConf)) {
|
631
|
+
pluginsConf = { config: {}, list: [] };
|
632
|
+
}
|
633
|
+
const pluginConfList = pluginsConf.list ?? [];
|
634
|
+
// load plugin list
|
635
|
+
for (const key of pluginConfList) {
|
636
|
+
const handle = IOCContainer.get(key, "COMPONENT");
|
637
|
+
if (!handle) {
|
638
|
+
Logger.Error(`Plugin ${key} load error.`);
|
639
|
+
continue;
|
640
|
+
}
|
641
|
+
if (!Helper.isFunction(handle.run)) {
|
642
|
+
Logger.Error(`Plugin ${key} must be implements method 'run'.`);
|
643
|
+
continue;
|
644
|
+
}
|
645
|
+
if (pluginsConf.config[key] === false) {
|
646
|
+
Logger.Warn(`Plugin ${key} already loaded but not effective.`);
|
647
|
+
continue;
|
648
|
+
}
|
649
|
+
// sync exec
|
650
|
+
await handle.run(pluginsConf.config[key] ?? {}, app);
|
651
|
+
}
|
652
|
+
}
|
657
653
|
}
|
658
654
|
|
659
|
-
var version = "3.10.4-
|
655
|
+
var version = "3.10.4-2";
|
660
656
|
var engines = {
|
661
657
|
node: ">12.0.0"
|
662
658
|
};
|
663
659
|
|
664
|
-
/*
|
665
|
-
* @Description: framework runtime checker
|
666
|
-
* @Usage:
|
667
|
-
* @Author: richen
|
668
|
-
* @Date: 2023-12-09 21:56:32
|
669
|
-
* @LastEditTime: 2023-12-09 23:01:22
|
670
|
-
* @License: BSD (3-Clause)
|
671
|
-
* @Copyright (c): <richenlin(at)gmail.com>
|
672
|
-
*/
|
673
|
-
const KOATTY_VERSION = version;
|
674
|
-
const ENGINES_VERSION = engines.node.slice(1) || '12.0.0';
|
675
|
-
/**
|
676
|
-
* check node version
|
677
|
-
* @return {void} []
|
678
|
-
*/
|
679
|
-
function checkRuntime() {
|
680
|
-
let nodeEngines = ENGINES_VERSION;
|
681
|
-
nodeEngines = nodeEngines.slice(0, nodeEngines.lastIndexOf('.'));
|
682
|
-
let nodeVersion = process.version;
|
683
|
-
if (nodeVersion[0] === 'v') {
|
684
|
-
nodeVersion = nodeVersion.slice(1);
|
685
|
-
}
|
686
|
-
nodeVersion = nodeVersion.slice(0, nodeVersion.lastIndexOf('.'));
|
687
|
-
if (Helper.toNumber(nodeEngines) > Helper.toNumber(nodeVersion)) {
|
688
|
-
Logger.Error(`Koatty need node version > ${nodeEngines}, current version is ${nodeVersion}, please upgrade it.`);
|
689
|
-
process.exit(-1);
|
690
|
-
}
|
691
|
-
}
|
692
|
-
/**
|
693
|
-
* unittest running environment detection
|
694
|
-
* only support jest
|
695
|
-
* @returns {boolean}
|
696
|
-
*/
|
697
|
-
const checkUTRuntime = () => {
|
698
|
-
let isUTRuntime = false;
|
699
|
-
// UT运行环境判断,暂时先只判断jest
|
700
|
-
const argv = JSON.stringify(process.argv[1]);
|
701
|
-
if (argv.indexOf('jest') > -1) {
|
702
|
-
isUTRuntime = true;
|
703
|
-
}
|
704
|
-
return isUTRuntime;
|
660
|
+
/*
|
661
|
+
* @Description: framework runtime checker
|
662
|
+
* @Usage:
|
663
|
+
* @Author: richen
|
664
|
+
* @Date: 2023-12-09 21:56:32
|
665
|
+
* @LastEditTime: 2023-12-09 23:01:22
|
666
|
+
* @License: BSD (3-Clause)
|
667
|
+
* @Copyright (c): <richenlin(at)gmail.com>
|
668
|
+
*/
|
669
|
+
const KOATTY_VERSION = version;
|
670
|
+
const ENGINES_VERSION = engines.node.slice(1) || '12.0.0';
|
671
|
+
/**
|
672
|
+
* check node version
|
673
|
+
* @return {void} []
|
674
|
+
*/
|
675
|
+
function checkRuntime() {
|
676
|
+
let nodeEngines = ENGINES_VERSION;
|
677
|
+
nodeEngines = nodeEngines.slice(0, nodeEngines.lastIndexOf('.'));
|
678
|
+
let nodeVersion = process.version;
|
679
|
+
if (nodeVersion[0] === 'v') {
|
680
|
+
nodeVersion = nodeVersion.slice(1);
|
681
|
+
}
|
682
|
+
nodeVersion = nodeVersion.slice(0, nodeVersion.lastIndexOf('.'));
|
683
|
+
if (Helper.toNumber(nodeEngines) > Helper.toNumber(nodeVersion)) {
|
684
|
+
Logger.Error(`Koatty need node version > ${nodeEngines}, current version is ${nodeVersion}, please upgrade it.`);
|
685
|
+
process.exit(-1);
|
686
|
+
}
|
687
|
+
}
|
688
|
+
/**
|
689
|
+
* unittest running environment detection
|
690
|
+
* only support jest
|
691
|
+
* @returns {boolean}
|
692
|
+
*/
|
693
|
+
const checkUTRuntime = () => {
|
694
|
+
let isUTRuntime = false;
|
695
|
+
// UT运行环境判断,暂时先只判断jest
|
696
|
+
const argv = JSON.stringify(process.argv[1]);
|
697
|
+
if (argv.indexOf('jest') > -1) {
|
698
|
+
isUTRuntime = true;
|
699
|
+
}
|
700
|
+
return isUTRuntime;
|
705
701
|
};
|
706
702
|
|
707
|
-
/*
|
708
|
-
* @Description: framework bootstrap
|
709
|
-
* @Usage:
|
710
|
-
* @Author: richen
|
711
|
-
* @Date: 2023-12-09 21:56:32
|
712
|
-
* @LastEditTime: 2023-12-
|
713
|
-
* @License: BSD (3-Clause)
|
714
|
-
* @Copyright (c): <richenlin(at)gmail.com>
|
715
|
-
*/
|
716
|
-
/**
|
717
|
-
* execute bootstrap
|
718
|
-
*
|
719
|
-
* @param {*} target
|
720
|
-
* @param {Function} bootFunc
|
721
|
-
* @param {boolean} [isInitiative=false] Whether to actively execute app instantiation,
|
722
|
-
* mainly for unittest scenarios, you need to actively obtain app instances
|
723
|
-
* @returns {Promise<void>}
|
724
|
-
*/
|
725
|
-
const executeBootstrap = async function (target, bootFunc, isInitiative = false) {
|
726
|
-
// checked runtime
|
727
|
-
checkRuntime();
|
728
|
-
// unittest running environment
|
729
|
-
const isUTRuntime = checkUTRuntime();
|
730
|
-
if (!isInitiative && isUTRuntime) {
|
731
|
-
return;
|
732
|
-
}
|
733
|
-
const app = Reflect.construct(target, []);
|
734
|
-
// unittest does not print startup logs
|
735
|
-
if (isUTRuntime) {
|
736
|
-
app.silent = true;
|
737
|
-
Logger.enable(false);
|
738
|
-
}
|
739
|
-
try {
|
740
|
-
!app.silent && Logger.Log("Koatty", LOGO);
|
741
|
-
if (!(app instanceof Koatty)) {
|
742
|
-
throw new Error(`class ${target.name} does not inherit from Koatty`);
|
743
|
-
}
|
744
|
-
// Initialize env
|
745
|
-
Loader.initialize(app);
|
746
|
-
// exec bootFunc
|
747
|
-
if (Helper.isFunction(bootFunc)) {
|
748
|
-
Logger.Log('Koatty', '', 'Execute bootFunc ...');
|
749
|
-
await bootFunc(app);
|
750
|
-
}
|
751
|
-
// Set IOCContainer.app
|
752
|
-
IOCContainer.setApp(app);
|
753
|
-
Logger.Log('Koatty', '', 'ComponentScan ...');
|
754
|
-
// Check all bean
|
755
|
-
Loader.CheckAllComponents(app, target);
|
756
|
-
// Load configuration
|
757
|
-
Logger.Log('Koatty', '', 'Load Configurations ...');
|
758
|
-
// configuration metadata
|
759
|
-
const configurationMetas = Loader.GetConfigurationMetas(app, target);
|
760
|
-
Loader.LoadConfigs(app, configurationMetas);
|
761
|
-
// Load App event hooks
|
762
|
-
Loader.LoadAppEventHooks(app, target);
|
763
|
-
Logger.Log('Koatty', '', 'Emit App Boot ...');
|
764
|
-
await asyncEvent(app, "appBoot" /* AppEvent.appBoot */);
|
765
|
-
// Load Components
|
766
|
-
Logger.Log('Koatty', '', 'Load Components ...');
|
767
|
-
await Loader.LoadComponents(app);
|
768
|
-
// Load Middleware
|
769
|
-
Logger.Log('Koatty', '', 'Load Middlewares ...');
|
770
|
-
await Loader.LoadMiddlewares(app);
|
771
|
-
// Load Services
|
772
|
-
Logger.Log('Koatty', '', 'Load Services ...');
|
773
|
-
Loader.LoadServices(app);
|
774
|
-
// Load Controllers
|
775
|
-
Logger.Log('Koatty', '', 'Load Controllers ...');
|
776
|
-
const controllers = Loader.LoadControllers(app);
|
777
|
-
// Create Server
|
778
|
-
// app.server = newServe(app);
|
779
|
-
Helper.define(app, "server", NewServe(app));
|
780
|
-
// Create router
|
781
|
-
// app.router = newRouter(app);
|
782
|
-
Helper.define(app, "router", NewRouter(app));
|
783
|
-
// Emit app ready event
|
784
|
-
Logger.Log('Koatty', '', 'Emit App Ready ...');
|
785
|
-
await asyncEvent(app, "appReady" /* AppEvent.appReady */);
|
786
|
-
// Load Routers
|
787
|
-
Logger.Log('Koatty', '', 'Load Routers ...');
|
788
|
-
app.router.LoadRouter(controllers);
|
789
|
-
if (!isUTRuntime) {
|
790
|
-
// Start Server
|
791
|
-
app.listen(listenCallback);
|
792
|
-
}
|
793
|
-
return app;
|
794
|
-
}
|
795
|
-
catch (err) {
|
796
|
-
Logger.Error(err);
|
797
|
-
process.exit();
|
798
|
-
}
|
799
|
-
};
|
800
|
-
/**
|
801
|
-
* Listening callback function
|
802
|
-
*
|
803
|
-
* @param {Koatty} app
|
804
|
-
* @returns {*}
|
805
|
-
*/
|
806
|
-
const listenCallback = (app) => {
|
807
|
-
const options = app.server.options;
|
808
|
-
Logger.Log('Koatty', '', '====================================');
|
809
|
-
Logger.Log("Koatty", "", `Nodejs Version: ${process.version}`);
|
810
|
-
Logger.Log("Koatty", "", `Koatty Version: v${KOATTY_VERSION}`);
|
811
|
-
Logger.Log("Koatty", "", `App Environment: ${app.env}`);
|
812
|
-
Logger.Log('Koatty', '', `Server Protocol: ${(options.protocol).toUpperCase()}`);
|
813
|
-
Logger.Log("Koatty", "", `Server running at ${options.protocol === "http2" ? "https" : options.protocol}://${options.hostname || '127.0.0.1'}:${options.port}/`);
|
814
|
-
Logger.Log("Koatty", "", "====================================");
|
815
|
-
// binding event "appStop"
|
816
|
-
Logger.Log('Koatty', '', 'Bind App Stop event ...');
|
817
|
-
BindProcessEvent(app, 'appStop');
|
818
|
-
// tslint:disable-next-line: no-unused-expression
|
819
|
-
app.appDebug && Logger.Warn(`Running in debug mode.`);
|
820
|
-
// Set Logger
|
821
|
-
Loader.SetLogger(app);
|
822
|
-
};
|
823
|
-
/**
|
824
|
-
* Execute event as async
|
825
|
-
*
|
826
|
-
* @param {Koatty} event
|
827
|
-
* @param {string} eventName
|
828
|
-
*/
|
829
|
-
const asyncEvent = async function (event, eventName) {
|
830
|
-
const ls = event.listeners(eventName);
|
831
|
-
// eslint-disable-next-line no-restricted-syntax
|
832
|
-
for await (const func of ls) {
|
833
|
-
if (Helper.isFunction(func)) {
|
834
|
-
func();
|
835
|
-
}
|
836
|
-
}
|
837
|
-
return event.removeAllListeners(eventName);
|
838
|
-
};
|
839
|
-
/**
|
840
|
-
* Bootstrap application
|
841
|
-
*
|
842
|
-
* @export
|
843
|
-
* @param {Function} [bootFunc]
|
844
|
-
* @returns {ClassDecorator}
|
845
|
-
*/
|
846
|
-
function Bootstrap(bootFunc) {
|
847
|
-
return function (target) {
|
848
|
-
if (!(target.prototype instanceof Koatty)) {
|
849
|
-
throw new Error(`class does not inherit from Koatty`);
|
850
|
-
}
|
851
|
-
executeBootstrap(target, bootFunc);
|
852
|
-
};
|
853
|
-
}
|
854
|
-
/**
|
855
|
-
* Actively perform dependency injection
|
856
|
-
* Parse the decorator, return the instantiated app.
|
857
|
-
* @export ExecBootStrap
|
858
|
-
* @param {Function} [bootFunc] callback function
|
859
|
-
* @returns
|
860
|
-
*/
|
861
|
-
function ExecBootStrap(bootFunc) {
|
862
|
-
return async (target) => {
|
863
|
-
if (!(target.prototype instanceof Koatty)) {
|
864
|
-
throw new Error(`class ${target.name} does not inherit from Koatty`);
|
865
|
-
}
|
866
|
-
return await executeBootstrap(target, bootFunc, true);
|
867
|
-
};
|
868
|
-
}
|
869
|
-
/**
|
870
|
-
* Define project scan path
|
871
|
-
*
|
872
|
-
* @export
|
873
|
-
* @param {(string | string[])} [scanPath]
|
874
|
-
* @returns {ClassDecorator}
|
875
|
-
*/
|
876
|
-
function ComponentScan(scanPath) {
|
877
|
-
return (target) => {
|
878
|
-
if (!(target.prototype instanceof Koatty)) {
|
879
|
-
throw new Error(`class does not inherit from Koatty`);
|
880
|
-
}
|
881
|
-
scanPath = scanPath ?? '';
|
882
|
-
IOCContainer.saveClassMetadata(TAGGED_CLS, COMPONENT_SCAN, scanPath, target);
|
883
|
-
};
|
884
|
-
}
|
885
|
-
/**
|
886
|
-
* Define project configuration scan path
|
887
|
-
*
|
888
|
-
* @export
|
889
|
-
* @param {(string | string[])} [scanPath]
|
890
|
-
* @returns {ClassDecorator}
|
891
|
-
*/
|
892
|
-
function ConfigurationScan(scanPath) {
|
893
|
-
return (target) => {
|
894
|
-
if (!(target.prototype instanceof Koatty)) {
|
895
|
-
throw new Error(`class does not inherit from Koatty`);
|
896
|
-
}
|
897
|
-
scanPath = scanPath ?? '';
|
898
|
-
IOCContainer.saveClassMetadata(TAGGED_CLS, CONFIGURATION_SCAN, scanPath, target);
|
899
|
-
};
|
900
|
-
}
|
901
|
-
/**
|
902
|
-
* @description: bind App event hook func
|
903
|
-
* example:
|
904
|
-
* export function TestDecorator(): ClassDecorator {
|
905
|
-
* return (target: Function) => {
|
906
|
-
* BindEventHook(AppEvent.appBoot, (app: Koatty) => {
|
907
|
-
* // todo
|
908
|
-
* return Promise.resolve();
|
909
|
-
* }, target)
|
910
|
-
* }
|
911
|
-
* }
|
912
|
-
* @param {AppEvent} eventName
|
913
|
-
* @param {EventHookFunc} eventFunc
|
914
|
-
* @param {any} target
|
915
|
-
* @return {*}
|
916
|
-
*/
|
917
|
-
function BindEventHook(eventName, eventFunc, target) {
|
918
|
-
IOCContainer.attachClassMetadata(TAGGED_CLS, eventName, eventFunc, target);
|
703
|
+
/*
|
704
|
+
* @Description: framework bootstrap
|
705
|
+
* @Usage:
|
706
|
+
* @Author: richen
|
707
|
+
* @Date: 2023-12-09 21:56:32
|
708
|
+
* @LastEditTime: 2023-12-14 23:06:45
|
709
|
+
* @License: BSD (3-Clause)
|
710
|
+
* @Copyright (c): <richenlin(at)gmail.com>
|
711
|
+
*/
|
712
|
+
/**
|
713
|
+
* execute bootstrap
|
714
|
+
*
|
715
|
+
* @param {*} target
|
716
|
+
* @param {Function} bootFunc
|
717
|
+
* @param {boolean} [isInitiative=false] Whether to actively execute app instantiation,
|
718
|
+
* mainly for unittest scenarios, you need to actively obtain app instances
|
719
|
+
* @returns {Promise<void>}
|
720
|
+
*/
|
721
|
+
const executeBootstrap = async function (target, bootFunc, isInitiative = false) {
|
722
|
+
// checked runtime
|
723
|
+
checkRuntime();
|
724
|
+
// unittest running environment
|
725
|
+
const isUTRuntime = checkUTRuntime();
|
726
|
+
if (!isInitiative && isUTRuntime) {
|
727
|
+
return;
|
728
|
+
}
|
729
|
+
const app = Reflect.construct(target, []);
|
730
|
+
// unittest does not print startup logs
|
731
|
+
if (isUTRuntime) {
|
732
|
+
app.silent = true;
|
733
|
+
Logger.enable(false);
|
734
|
+
}
|
735
|
+
try {
|
736
|
+
!app.silent && Logger.Log("Koatty", LOGO);
|
737
|
+
if (!(app instanceof Koatty)) {
|
738
|
+
throw new Error(`class ${target.name} does not inherit from Koatty`);
|
739
|
+
}
|
740
|
+
// Initialize env
|
741
|
+
Loader.initialize(app);
|
742
|
+
// exec bootFunc
|
743
|
+
if (Helper.isFunction(bootFunc)) {
|
744
|
+
Logger.Log('Koatty', '', 'Execute bootFunc ...');
|
745
|
+
await bootFunc(app);
|
746
|
+
}
|
747
|
+
// Set IOCContainer.app
|
748
|
+
IOCContainer.setApp(app);
|
749
|
+
Logger.Log('Koatty', '', 'ComponentScan ...');
|
750
|
+
// Check all bean
|
751
|
+
Loader.CheckAllComponents(app, target);
|
752
|
+
// Load configuration
|
753
|
+
Logger.Log('Koatty', '', 'Load Configurations ...');
|
754
|
+
// configuration metadata
|
755
|
+
const configurationMetas = Loader.GetConfigurationMetas(app, target);
|
756
|
+
Loader.LoadConfigs(app, configurationMetas);
|
757
|
+
// Load App event hooks
|
758
|
+
Loader.LoadAppEventHooks(app, target);
|
759
|
+
Logger.Log('Koatty', '', 'Emit App Boot ...');
|
760
|
+
await asyncEvent(app, "appBoot" /* AppEvent.appBoot */);
|
761
|
+
// Load Components
|
762
|
+
Logger.Log('Koatty', '', 'Load Components ...');
|
763
|
+
await Loader.LoadComponents(app);
|
764
|
+
// Load Middleware
|
765
|
+
Logger.Log('Koatty', '', 'Load Middlewares ...');
|
766
|
+
await Loader.LoadMiddlewares(app);
|
767
|
+
// Load Services
|
768
|
+
Logger.Log('Koatty', '', 'Load Services ...');
|
769
|
+
Loader.LoadServices(app);
|
770
|
+
// Load Controllers
|
771
|
+
Logger.Log('Koatty', '', 'Load Controllers ...');
|
772
|
+
const controllers = Loader.LoadControllers(app);
|
773
|
+
// Create Server
|
774
|
+
// app.server = newServe(app);
|
775
|
+
Helper.define(app, "server", NewServe(app));
|
776
|
+
// Create router
|
777
|
+
// app.router = newRouter(app);
|
778
|
+
Helper.define(app, "router", NewRouter(app));
|
779
|
+
// Emit app ready event
|
780
|
+
Logger.Log('Koatty', '', 'Emit App Ready ...');
|
781
|
+
await asyncEvent(app, "appReady" /* AppEvent.appReady */);
|
782
|
+
// Load Routers
|
783
|
+
Logger.Log('Koatty', '', 'Load Routers ...');
|
784
|
+
app.router.LoadRouter(controllers);
|
785
|
+
if (!isUTRuntime) {
|
786
|
+
// Start Server
|
787
|
+
app.listen(listenCallback);
|
788
|
+
}
|
789
|
+
return app;
|
790
|
+
}
|
791
|
+
catch (err) {
|
792
|
+
Logger.Error(err);
|
793
|
+
process.exit();
|
794
|
+
}
|
795
|
+
};
|
796
|
+
/**
|
797
|
+
* Listening callback function
|
798
|
+
*
|
799
|
+
* @param {Koatty} app
|
800
|
+
* @returns {*}
|
801
|
+
*/
|
802
|
+
const listenCallback = (app) => {
|
803
|
+
const options = app.server.options;
|
804
|
+
Logger.Log('Koatty', '', '====================================');
|
805
|
+
Logger.Log("Koatty", "", `Nodejs Version: ${process.version}`);
|
806
|
+
Logger.Log("Koatty", "", `Koatty Version: v${KOATTY_VERSION}`);
|
807
|
+
Logger.Log("Koatty", "", `App Environment: ${app.env}`);
|
808
|
+
Logger.Log('Koatty', '', `Server Protocol: ${(options.protocol).toUpperCase()}`);
|
809
|
+
Logger.Log("Koatty", "", `Server running at ${options.protocol === "http2" ? "https" : options.protocol}://${options.hostname || '127.0.0.1'}:${options.port}/`);
|
810
|
+
Logger.Log("Koatty", "", "====================================");
|
811
|
+
// binding event "appStop"
|
812
|
+
Logger.Log('Koatty', '', 'Bind App Stop event ...');
|
813
|
+
BindProcessEvent(app, 'appStop');
|
814
|
+
// tslint:disable-next-line: no-unused-expression
|
815
|
+
app.appDebug && Logger.Warn(`Running in debug mode.`);
|
816
|
+
// Set Logger
|
817
|
+
Loader.SetLogger(app);
|
818
|
+
};
|
819
|
+
/**
|
820
|
+
* Execute event as async
|
821
|
+
*
|
822
|
+
* @param {Koatty} event
|
823
|
+
* @param {string} eventName
|
824
|
+
*/
|
825
|
+
const asyncEvent = async function (event, eventName) {
|
826
|
+
const ls = event.listeners(eventName);
|
827
|
+
// eslint-disable-next-line no-restricted-syntax
|
828
|
+
for await (const func of ls) {
|
829
|
+
if (Helper.isFunction(func)) {
|
830
|
+
func();
|
831
|
+
}
|
832
|
+
}
|
833
|
+
return event.removeAllListeners(eventName);
|
834
|
+
};
|
835
|
+
/**
|
836
|
+
* Bootstrap application
|
837
|
+
*
|
838
|
+
* @export
|
839
|
+
* @param {Function} [bootFunc]
|
840
|
+
* @returns {ClassDecorator}
|
841
|
+
*/
|
842
|
+
function Bootstrap(bootFunc) {
|
843
|
+
return function (target) {
|
844
|
+
if (!(target.prototype instanceof Koatty)) {
|
845
|
+
throw new Error(`class does not inherit from Koatty`);
|
846
|
+
}
|
847
|
+
executeBootstrap(target, bootFunc);
|
848
|
+
};
|
849
|
+
}
|
850
|
+
/**
|
851
|
+
* Actively perform dependency injection
|
852
|
+
* Parse the decorator, return the instantiated app.
|
853
|
+
* @export ExecBootStrap
|
854
|
+
* @param {Function} [bootFunc] callback function
|
855
|
+
* @returns
|
856
|
+
*/
|
857
|
+
function ExecBootStrap(bootFunc) {
|
858
|
+
return async (target) => {
|
859
|
+
if (!(target.prototype instanceof Koatty)) {
|
860
|
+
throw new Error(`class ${target.name} does not inherit from Koatty`);
|
861
|
+
}
|
862
|
+
return await executeBootstrap(target, bootFunc, true);
|
863
|
+
};
|
864
|
+
}
|
865
|
+
/**
|
866
|
+
* Define project scan path
|
867
|
+
*
|
868
|
+
* @export
|
869
|
+
* @param {(string | string[])} [scanPath]
|
870
|
+
* @returns {ClassDecorator}
|
871
|
+
*/
|
872
|
+
function ComponentScan(scanPath) {
|
873
|
+
return (target) => {
|
874
|
+
if (!(target.prototype instanceof Koatty)) {
|
875
|
+
throw new Error(`class does not inherit from Koatty`);
|
876
|
+
}
|
877
|
+
scanPath = scanPath ?? '';
|
878
|
+
IOCContainer.saveClassMetadata(TAGGED_CLS, COMPONENT_SCAN, scanPath, target);
|
879
|
+
};
|
880
|
+
}
|
881
|
+
/**
|
882
|
+
* Define project configuration scan path
|
883
|
+
*
|
884
|
+
* @export
|
885
|
+
* @param {(string | string[])} [scanPath]
|
886
|
+
* @returns {ClassDecorator}
|
887
|
+
*/
|
888
|
+
function ConfigurationScan(scanPath) {
|
889
|
+
return (target) => {
|
890
|
+
if (!(target.prototype instanceof Koatty)) {
|
891
|
+
throw new Error(`class does not inherit from Koatty`);
|
892
|
+
}
|
893
|
+
scanPath = scanPath ?? '';
|
894
|
+
IOCContainer.saveClassMetadata(TAGGED_CLS, CONFIGURATION_SCAN, scanPath, target);
|
895
|
+
};
|
896
|
+
}
|
897
|
+
/**
|
898
|
+
* @description: bind App event hook func
|
899
|
+
* example:
|
900
|
+
* export function TestDecorator(): ClassDecorator {
|
901
|
+
* return (target: Function) => {
|
902
|
+
* BindEventHook(AppEvent.appBoot, (app: Koatty) => {
|
903
|
+
* // todo
|
904
|
+
* return Promise.resolve();
|
905
|
+
* }, target)
|
906
|
+
* }
|
907
|
+
* }
|
908
|
+
* @param {AppEvent} eventName
|
909
|
+
* @param {EventHookFunc} eventFunc
|
910
|
+
* @param {any} target
|
911
|
+
* @return {*}
|
912
|
+
*/
|
913
|
+
function BindEventHook(eventName, eventFunc, target) {
|
914
|
+
IOCContainer.attachClassMetadata(TAGGED_CLS, eventName, eventFunc, target);
|
919
915
|
}
|
920
916
|
|
921
|
-
/*
|
922
|
-
* @Description: component interface
|
923
|
-
* @Usage:
|
924
|
-
* @Author: richen
|
925
|
-
* @Date: 2023-12-09 21:56:32
|
926
|
-
* @LastEditTime: 2023-12-09 23:03:33
|
927
|
-
* @License: BSD (3-Clause)
|
928
|
-
* @Copyright (c): <richenlin(at)gmail.com>
|
929
|
-
*/
|
930
|
-
|
931
|
-
|
932
|
-
*
|
933
|
-
*
|
934
|
-
* @
|
935
|
-
* @
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
IOCContainer.
|
941
|
-
|
942
|
-
}
|
943
|
-
|
944
|
-
|
945
|
-
*
|
946
|
-
*
|
947
|
-
* @
|
948
|
-
* @
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
IOCContainer.
|
954
|
-
IOCContainer.
|
955
|
-
|
956
|
-
}
|
957
|
-
|
958
|
-
|
959
|
-
*
|
960
|
-
*
|
961
|
-
* @
|
962
|
-
* @
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
IOCContainer.
|
968
|
-
|
969
|
-
}
|
970
|
-
|
971
|
-
|
972
|
-
*
|
973
|
-
*
|
974
|
-
* @
|
975
|
-
* @
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
IOCContainer.
|
981
|
-
|
982
|
-
}
|
983
|
-
|
984
|
-
|
985
|
-
*
|
986
|
-
*
|
987
|
-
* @
|
988
|
-
* @
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
917
|
+
/*
|
918
|
+
* @Description: component interface
|
919
|
+
* @Usage:
|
920
|
+
* @Author: richen
|
921
|
+
* @Date: 2023-12-09 21:56:32
|
922
|
+
* @LastEditTime: 2023-12-09 23:03:33
|
923
|
+
* @License: BSD (3-Clause)
|
924
|
+
* @Copyright (c): <richenlin(at)gmail.com>
|
925
|
+
*/
|
926
|
+
// tslint:disable-next-line: no-import-side-effect
|
927
|
+
/**
|
928
|
+
* Indicates that an decorated class is a "component".
|
929
|
+
*
|
930
|
+
* @export
|
931
|
+
* @param {string} [identifier] component name
|
932
|
+
* @returns {ClassDecorator}
|
933
|
+
*/
|
934
|
+
function Component(identifier) {
|
935
|
+
return (target) => {
|
936
|
+
identifier = identifier || IOCContainer.getIdentifier(target);
|
937
|
+
IOCContainer.saveClass("COMPONENT", target, identifier);
|
938
|
+
};
|
939
|
+
}
|
940
|
+
/**
|
941
|
+
* Indicates that an decorated class is a "controller".
|
942
|
+
*
|
943
|
+
* @export
|
944
|
+
* @param {string} [path] controller router path
|
945
|
+
* @returns {ClassDecorator}
|
946
|
+
*/
|
947
|
+
function Controller(path = "") {
|
948
|
+
return (target) => {
|
949
|
+
const identifier = IOCContainer.getIdentifier(target);
|
950
|
+
IOCContainer.saveClass("CONTROLLER", target, identifier);
|
951
|
+
IOCContainer.savePropertyData(CONTROLLER_ROUTER, path, target, identifier);
|
952
|
+
};
|
953
|
+
}
|
954
|
+
/**
|
955
|
+
* Indicates that an decorated class is a "middleware".
|
956
|
+
*
|
957
|
+
* @export
|
958
|
+
* @param {string} [identifier] class name
|
959
|
+
* @returns {ClassDecorator}
|
960
|
+
*/
|
961
|
+
function Middleware(identifier) {
|
962
|
+
return (target) => {
|
963
|
+
identifier = identifier || IOCContainer.getIdentifier(target);
|
964
|
+
IOCContainer.saveClass("MIDDLEWARE", target, identifier);
|
965
|
+
};
|
966
|
+
}
|
967
|
+
/**
|
968
|
+
* Indicates that an decorated class is a "service".
|
969
|
+
*
|
970
|
+
* @export
|
971
|
+
* @param {string} [identifier] class name
|
972
|
+
* @returns {ClassDecorator}
|
973
|
+
*/
|
974
|
+
function Service(identifier) {
|
975
|
+
return (target) => {
|
976
|
+
identifier = identifier || IOCContainer.getIdentifier(target);
|
977
|
+
IOCContainer.saveClass("SERVICE", target, identifier);
|
978
|
+
};
|
979
|
+
}
|
980
|
+
/**
|
981
|
+
* Indicates that an decorated class is a "plugin".
|
982
|
+
*
|
983
|
+
* @export
|
984
|
+
* @param {string} [identifier] class name
|
985
|
+
* @returns {ClassDecorator}
|
986
|
+
*/
|
987
|
+
function Plugin(identifier) {
|
988
|
+
return (target) => {
|
989
|
+
identifier = identifier || IOCContainer.getIdentifier(target);
|
990
|
+
//
|
991
|
+
if (!identifier.endsWith("Plugin")) {
|
992
|
+
throw Error("Plugin class name must be 'Plugin' suffix.");
|
993
|
+
}
|
994
|
+
IOCContainer.saveClass("COMPONENT", target, `${identifier}`);
|
995
|
+
};
|
999
996
|
}
|
1000
997
|
|
1001
|
-
/*
|
1002
|
-
* @Description: base service
|
1003
|
-
* @Usage:
|
1004
|
-
* @Author: richen
|
1005
|
-
* @Date: 2023-12-09 21:56:32
|
1006
|
-
* @LastEditTime: 2023-12-09 23:03:23
|
1007
|
-
* @License: BSD (3-Clause)
|
1008
|
-
* @Copyright (c): <richenlin(at)gmail.com>
|
1009
|
-
*/
|
1010
|
-
/**
|
1011
|
-
* Base service
|
1012
|
-
*
|
1013
|
-
* @export
|
1014
|
-
* @class Base
|
1015
|
-
*/
|
1016
|
-
class BaseService {
|
1017
|
-
/**
|
1018
|
-
* instance of BaseController.
|
1019
|
-
* @param {Koatty} app
|
1020
|
-
* @param {KoattyContext} ctx
|
1021
|
-
* @memberof BaseController
|
1022
|
-
*/
|
1023
|
-
constructor(...arg) {
|
1024
|
-
this.init(arg);
|
1025
|
-
}
|
1026
|
-
/**
|
1027
|
-
* init
|
1028
|
-
*
|
1029
|
-
* @protected
|
1030
|
-
* @memberof BaseController
|
1031
|
-
*/
|
1032
|
-
init(...arg) {
|
1033
|
-
}
|
998
|
+
/*
|
999
|
+
* @Description: base service
|
1000
|
+
* @Usage:
|
1001
|
+
* @Author: richen
|
1002
|
+
* @Date: 2023-12-09 21:56:32
|
1003
|
+
* @LastEditTime: 2023-12-09 23:03:23
|
1004
|
+
* @License: BSD (3-Clause)
|
1005
|
+
* @Copyright (c): <richenlin(at)gmail.com>
|
1006
|
+
*/
|
1007
|
+
/**
|
1008
|
+
* Base service
|
1009
|
+
*
|
1010
|
+
* @export
|
1011
|
+
* @class Base
|
1012
|
+
*/
|
1013
|
+
class BaseService {
|
1014
|
+
/**
|
1015
|
+
* instance of BaseController.
|
1016
|
+
* @param {Koatty} app
|
1017
|
+
* @param {KoattyContext} ctx
|
1018
|
+
* @memberof BaseController
|
1019
|
+
*/
|
1020
|
+
constructor(...arg) {
|
1021
|
+
this.init(arg);
|
1022
|
+
}
|
1023
|
+
/**
|
1024
|
+
* init
|
1025
|
+
*
|
1026
|
+
* @protected
|
1027
|
+
* @memberof BaseController
|
1028
|
+
*/
|
1029
|
+
init(...arg) {
|
1030
|
+
}
|
1034
1031
|
}
|
1035
1032
|
|
1036
1033
|
export { BaseController, BaseService, BindEventHook, Bootstrap, Component, ComponentScan, ConfigurationScan, Controller, ExecBootStrap, Logger, Middleware, Plugin, Service };
|