wok-server 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/index.js +17 -3
- package/dist/log/file.js +4 -11
- package/dist/mvc/config.js +23 -16
- package/dist/mvc/handler/json.js +27 -0
- package/dist/mvc/index.js +6 -295
- package/dist/mvc/render/file.js +3 -85
- package/dist/mvc/server.js +265 -0
- package/dist/mvc/static/header.js +67 -0
- package/dist/mvc/static/index.js +6 -0
- package/dist/mvc/static/mime-type.js +84 -0
- package/dist/mvc/static/server-cache-config.js +66 -0
- package/dist/mvc/static/server-cache.js +133 -0
- package/dist/mvc/static/static-handler.js +355 -0
- package/dist/mysql/manager/ops/update.js +15 -1
- package/dist/mysql/manager/ops/utils.js +4 -0
- package/dist/validation/index.js +12 -1
- package/dist/validation/validator/array.js +7 -11
- package/dist/validation/validator/min.js +2 -2
- package/documentation/zh-cn/config.md +31 -0
- package/documentation/zh-cn/mvc.md +48 -0
- package/documentation/zh-cn/mysql.md +72 -0
- package/documentation/zh-cn/validate.md +21 -15
- package/package.json +1 -1
- package/types/config/index.d.ts +10 -0
- package/types/mvc/config.d.ts +13 -1
- package/types/mvc/handler/json.d.ts +14 -0
- package/types/mvc/index.d.ts +3 -36
- package/types/mvc/server.d.ts +85 -0
- package/types/mvc/static/header.d.ts +27 -0
- package/types/mvc/static/index.d.ts +3 -0
- package/types/mvc/static/mime-type.d.ts +2 -0
- package/types/mvc/static/server-cache-config.d.ts +30 -0
- package/types/mvc/static/server-cache.d.ts +76 -0
- package/types/mvc/static/static-handler.d.ts +72 -0
- package/types/mysql/manager/ops/update.d.ts +7 -1
- package/types/validation/validator/array.d.ts +2 -2
- package/types/validation/validator/min.d.ts +2 -2
- package/types/validation/validator/plain-obj.d.ts +1 -1
package/dist/config/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerConfig = exports.getConfig = void 0;
|
|
3
|
+
exports.generateConfig = exports.registerConfig = exports.getConfig = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const dotenv_1 = require("dotenv");
|
|
6
6
|
const validation_1 = require("../validation");
|
|
@@ -31,6 +31,21 @@ function registerConfig(defaultConfig, envPrefix, validation) {
|
|
|
31
31
|
if (configEnvMap.has(envPrefix)) {
|
|
32
32
|
throw new exception_1.ConfigException(`The prefix "${envPrefix}" has already been registered`);
|
|
33
33
|
}
|
|
34
|
+
const config = generateConfig(defaultConfig, envPrefix, validation);
|
|
35
|
+
configEnvMap.set(envPrefix, config);
|
|
36
|
+
return config;
|
|
37
|
+
}
|
|
38
|
+
exports.registerConfig = registerConfig;
|
|
39
|
+
/**
|
|
40
|
+
* 根据环境变量来生成配置对象,与 registerConfig 的参数是一致的,和 registerConfig 不同的是
|
|
41
|
+
* generateConfig 可以多次重复使用,方便在运行时更改环境变量后再生成配置,而调用 registerConfig
|
|
42
|
+
* 一旦注册后不能再被更改。之所以这样设计是为了方便程序的测试,模拟不同的环境来运行程序,和其它的
|
|
43
|
+
* 一些特殊需求。
|
|
44
|
+
* @param defaultConfig
|
|
45
|
+
* @param envPrefix
|
|
46
|
+
* @param validation
|
|
47
|
+
*/
|
|
48
|
+
function generateConfig(defaultConfig, envPrefix, validation) {
|
|
34
49
|
// 环境变量匹配
|
|
35
50
|
for (const propName in defaultConfig) {
|
|
36
51
|
const defaultVal = defaultConfig[propName];
|
|
@@ -53,10 +68,9 @@ function registerConfig(defaultConfig, envPrefix, validation) {
|
|
|
53
68
|
throw new exception_1.ConfigException(`Error in verifying configuration information, configuration prefix:${envPrefix}`);
|
|
54
69
|
}
|
|
55
70
|
}
|
|
56
|
-
configEnvMap.set(envPrefix, defaultConfig);
|
|
57
71
|
return defaultConfig;
|
|
58
72
|
}
|
|
59
|
-
exports.
|
|
73
|
+
exports.generateConfig = generateConfig;
|
|
60
74
|
function buildEnvName(envPrefix, propName) {
|
|
61
75
|
let part2 = propName.replace(/[A-Z]+/g, subStr => `_${subStr}`);
|
|
62
76
|
if (part2.startsWith('_')) {
|
package/dist/log/file.js
CHANGED
|
@@ -14,14 +14,7 @@ let QUEUE = [];
|
|
|
14
14
|
*/
|
|
15
15
|
function fileStore(log) {
|
|
16
16
|
QUEUE.push(log);
|
|
17
|
-
setTimeout(() =>
|
|
18
|
-
try {
|
|
19
|
-
write();
|
|
20
|
-
}
|
|
21
|
-
catch (e) {
|
|
22
|
-
console.error('Writing log file failed', e);
|
|
23
|
-
}
|
|
24
|
-
}, 0);
|
|
17
|
+
setTimeout(() => write().catch(e => console.error('Writing log file failed', e)), 0);
|
|
25
18
|
}
|
|
26
19
|
exports.fileStore = fileStore;
|
|
27
20
|
function buildFilePath() {
|
|
@@ -35,18 +28,18 @@ function buildFilePath() {
|
|
|
35
28
|
fileName += '.log';
|
|
36
29
|
return (0, path_1.resolve)(config_1.config.fileDir, fileName);
|
|
37
30
|
}
|
|
38
|
-
function write() {
|
|
31
|
+
async function write() {
|
|
39
32
|
if (!QUEUE.length) {
|
|
40
33
|
return;
|
|
41
34
|
}
|
|
42
35
|
const path = buildFilePath();
|
|
43
36
|
const dir = (0, path_1.dirname)(path);
|
|
44
37
|
if (!(0, fs_1.existsSync)(dir)) {
|
|
45
|
-
(0,
|
|
38
|
+
await (0, promises_1.mkdir)(dir, { recursive: true });
|
|
46
39
|
}
|
|
47
40
|
const lines = QUEUE.join(os_1.EOL);
|
|
48
|
-
(0, fs_1.appendFileSync)(path, lines);
|
|
49
41
|
QUEUE = [];
|
|
42
|
+
await (0, promises_1.appendFile)(path, lines);
|
|
50
43
|
}
|
|
51
44
|
if (config_1.config.file) {
|
|
52
45
|
/**
|
package/dist/mvc/config.js
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.getConfig = void 0;
|
|
4
4
|
const config_1 = require("../config");
|
|
5
5
|
const validation_1 = require("../validation");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
6
|
+
function getConfig() {
|
|
7
|
+
return (0, config_1.generateConfig)({
|
|
8
|
+
port: 8080,
|
|
9
|
+
timeout: 30000,
|
|
10
|
+
accessLog: false,
|
|
11
|
+
corsAllowHeaders: '*',
|
|
12
|
+
corsAllowMethods: '*',
|
|
13
|
+
corsAllowOrigin: '*',
|
|
14
|
+
tlsEnable: false,
|
|
15
|
+
tlsKey: '',
|
|
16
|
+
tlsCert: ''
|
|
17
|
+
}, 'SERVER', {
|
|
18
|
+
port: [(0, validation_1.notNull)(), (0, validation_1.min)(80), (0, validation_1.max)(65535)],
|
|
19
|
+
timeout: [(0, validation_1.notNull)(), (0, validation_1.min)(1000), (0, validation_1.max)(60000)],
|
|
20
|
+
accessLog: [(0, validation_1.notNull)()],
|
|
21
|
+
corsAllowOrigin: [(0, validation_1.notBlank)()],
|
|
22
|
+
corsAllowHeaders: [(0, validation_1.notBlank)()],
|
|
23
|
+
corsAllowMethods: [(0, validation_1.notBlank)()],
|
|
24
|
+
tlsEnable: [(0, validation_1.notNull)()]
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
exports.getConfig = getConfig;
|
package/dist/mvc/handler/json.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createJsonHandler = void 0;
|
|
4
|
+
const cache_1 = require("../../cache");
|
|
4
5
|
const i18n_1 = require("../../i18n");
|
|
5
6
|
const validation_1 = require("../../validation");
|
|
6
7
|
/**
|
|
@@ -27,6 +28,26 @@ function createJsonHandler(opts) {
|
|
|
27
28
|
(0, validation_1.validate)(body, opts.validation);
|
|
28
29
|
}
|
|
29
30
|
}
|
|
31
|
+
// 缓存处理
|
|
32
|
+
if (opts.cache) {
|
|
33
|
+
const cacheInfo = await opts.cache(body, exchange);
|
|
34
|
+
const buffer = (0, cache_1.getCache)().get(cacheInfo.key);
|
|
35
|
+
if (buffer && buffer instanceof Buffer) {
|
|
36
|
+
renderJsonBuffer(exchange, buffer);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const res = await opts.handle(body, { request: exchange.request });
|
|
40
|
+
if (!res) {
|
|
41
|
+
// 无结果不缓存
|
|
42
|
+
exchange.respond({ statusCode: 200 });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const buffer = Buffer.from(JSON.stringify(res), 'utf-8');
|
|
46
|
+
(0, cache_1.getCache)().put(cacheInfo.key, buffer, cacheInfo.expiresInSeconds);
|
|
47
|
+
renderJsonBuffer(exchange, buffer);
|
|
48
|
+
}
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
30
51
|
const res = await opts.handle(body, { request: exchange.request });
|
|
31
52
|
if (!res) {
|
|
32
53
|
exchange.respond({ statusCode: 200 });
|
|
@@ -36,3 +57,9 @@ function createJsonHandler(opts) {
|
|
|
36
57
|
};
|
|
37
58
|
}
|
|
38
59
|
exports.createJsonHandler = createJsonHandler;
|
|
60
|
+
function renderJsonBuffer(exchange, buffer) {
|
|
61
|
+
const { response } = exchange;
|
|
62
|
+
response.setHeader('content-type', 'application/json; charset=UTF-8');
|
|
63
|
+
response.statusCode = 200;
|
|
64
|
+
response.end(buffer);
|
|
65
|
+
}
|
package/dist/mvc/index.js
CHANGED
|
@@ -2,193 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.stopWebServer = exports.startWebServer = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const
|
|
6
|
-
const promises_1 = require("fs/promises");
|
|
7
|
-
const http_1 = require("http");
|
|
8
|
-
const https_1 = require("https");
|
|
9
|
-
const os_1 = require("os");
|
|
10
|
-
const path_1 = require("path");
|
|
11
|
-
const log_1 = require("../log");
|
|
12
|
-
const access_log_1 = require("./access-log");
|
|
13
|
-
const config_1 = require("./config");
|
|
14
|
-
const exchange_1 = require("./exchange");
|
|
15
|
-
const render_1 = require("./render");
|
|
16
|
-
/**
|
|
17
|
-
* 处理请求,完成拦截器和路由的流程.
|
|
18
|
-
*
|
|
19
|
-
* @param interceptors 拦截器
|
|
20
|
-
* @param routers 路由
|
|
21
|
-
* @param req
|
|
22
|
-
* @param res
|
|
23
|
-
* @param staticSettings
|
|
24
|
-
*/
|
|
25
|
-
async function handleRequest(interceptors, routers, req, res, staticSettings) {
|
|
26
|
-
req.socket.remoteAddress;
|
|
27
|
-
const { method } = req;
|
|
28
|
-
// cros 支持
|
|
29
|
-
res.setHeader('Access-Control-Allow-Origin', config_1.config.corsAllowOrigin);
|
|
30
|
-
res.setHeader('Access-Control-Allow-Headers', config_1.config.corsAllowHeaders);
|
|
31
|
-
res.setHeader('Access-Control-Allow-Methods', config_1.config.corsAllowMethods);
|
|
32
|
-
if (method === 'OPTIONS') {
|
|
33
|
-
res.statusCode = 200;
|
|
34
|
-
res.end();
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
const exchange = new exchange_1.ServerExchange(req, res);
|
|
38
|
-
// 顺序执行拦截器
|
|
39
|
-
await handleInterceptor(interceptors, 0, exchange, req, res, routers, staticSettings);
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* 处理拦截器.
|
|
43
|
-
* @param interceptors 拦截器
|
|
44
|
-
* @param idx 当前要执行的拦截器下标
|
|
45
|
-
* @param exchange 传输对象
|
|
46
|
-
* @param req
|
|
47
|
-
* @param res
|
|
48
|
-
* @param routers 路由
|
|
49
|
-
* @param staticSettings
|
|
50
|
-
*/
|
|
51
|
-
async function handleInterceptor(interceptors, idx, exchange, req, res, routers, staticSettings) {
|
|
52
|
-
const interceptor = interceptors[idx];
|
|
53
|
-
// 到最后一个了,那么执行路由处理
|
|
54
|
-
if (!interceptor) {
|
|
55
|
-
await handleRouter(exchange, routers, staticSettings);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
await interceptor(exchange, () => handleInterceptor(interceptors, idx + 1, exchange, req, res, routers, staticSettings));
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* 处理路由.
|
|
62
|
-
* @param exchange
|
|
63
|
-
* @param routers
|
|
64
|
-
* @param staticSettings
|
|
65
|
-
* @returns
|
|
66
|
-
*/
|
|
67
|
-
async function handleRouter(exchange, routers, staticSettings) {
|
|
68
|
-
const url = exchange.request.url;
|
|
69
|
-
if (url === undefined) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
// 判定路由
|
|
73
|
-
const idx = url.indexOf('?');
|
|
74
|
-
let path = idx === -1 ? url : url.substring(0, idx);
|
|
75
|
-
const router = routers[path];
|
|
76
|
-
if (!router) {
|
|
77
|
-
// 路由找不不到,尝试静态文件
|
|
78
|
-
if ((exchange.request.method || '').toLowerCase() === 'get' && staticSettings.length) {
|
|
79
|
-
await handleStatic(exchange, routers, path, staticSettings);
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
respond404(exchange, routers, path);
|
|
83
|
-
}
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
// 执行路由
|
|
87
|
-
await router(exchange);
|
|
88
|
-
// 在路由顺利处理的情况下,如果 res 没有 end ,就表示响应没有完成
|
|
89
|
-
// 也就是说路由没有做响应处理,或处理没有完成就结束了,给予错误提示
|
|
90
|
-
if (!exchange.response.writableEnded) {
|
|
91
|
-
throw new Error(`RouterHandler unresponsive, url: ${url}`);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* 处理静态文件
|
|
96
|
-
* @param exchange
|
|
97
|
-
* @param routers
|
|
98
|
-
* @param path
|
|
99
|
-
* @param staticDir
|
|
100
|
-
* @returns
|
|
101
|
-
*/
|
|
102
|
-
async function handleStatic(exchange, routers, path, staticSettings) {
|
|
103
|
-
// 匹配
|
|
104
|
-
let matchedSetting;
|
|
105
|
-
for (const setting of staticSettings) {
|
|
106
|
-
if (setting.path === '/') {
|
|
107
|
-
matchedSetting = setting;
|
|
108
|
-
break;
|
|
109
|
-
}
|
|
110
|
-
if (path.startsWith(setting.path)) {
|
|
111
|
-
matchedSetting = setting;
|
|
112
|
-
break;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
if (!matchedSetting) {
|
|
116
|
-
respond404(exchange, routers, path);
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
let finalPath = matchedSetting.path === '/' ? path : path.substring(matchedSetting.path.length);
|
|
120
|
-
if (finalPath.startsWith('/')) {
|
|
121
|
-
finalPath = finalPath.substring(1);
|
|
122
|
-
}
|
|
123
|
-
const fullPath = (0, path_1.resolve)(matchedSetting.dir, finalPath);
|
|
124
|
-
if (!(0, fs_1.existsSync)(fullPath)) {
|
|
125
|
-
respond404(exchange, routers, path);
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
const statRes = await (0, promises_1.stat)(fullPath);
|
|
129
|
-
// 目录,寻找 index.html
|
|
130
|
-
if (statRes.isDirectory()) {
|
|
131
|
-
const indexPath = (0, path_1.resolve)(fullPath, 'index.html');
|
|
132
|
-
if (!(0, fs_1.existsSync)(indexPath)) {
|
|
133
|
-
respond404(exchange, routers, path);
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
const indexStat = await (0, promises_1.stat)(indexPath);
|
|
137
|
-
if (!indexStat.isFile()) {
|
|
138
|
-
respond404(exchange, routers, path);
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
// Cache-Control
|
|
142
|
-
if (matchedSetting.cacheAge >= 0) {
|
|
143
|
-
exchange.response.setHeader('Cache-Control', matchedSetting.cacheAge === 0 ? 'no-store' : `max-age=${matchedSetting.cacheAge}`);
|
|
144
|
-
}
|
|
145
|
-
await exchange.respondFile(indexPath, false);
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
// 文件直接渲染
|
|
149
|
-
if (statRes.isFile()) {
|
|
150
|
-
// Cache-Control
|
|
151
|
-
if (matchedSetting.cacheAge >= 0) {
|
|
152
|
-
exchange.response.setHeader('Cache-Control', matchedSetting.cacheAge === 0 ? 'no-store' : `max-age=${matchedSetting.cacheAge}`);
|
|
153
|
-
}
|
|
154
|
-
await exchange.respondFile(fullPath, false);
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
// 其它类型,404
|
|
158
|
-
respond404(exchange, routers, path);
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* 404响应
|
|
162
|
-
*
|
|
163
|
-
* @param exchange
|
|
164
|
-
* @param routers
|
|
165
|
-
* @param path
|
|
166
|
-
*/
|
|
167
|
-
async function respond404(exchange, routers, path) {
|
|
168
|
-
const handler = routers['*'];
|
|
169
|
-
if (handler) {
|
|
170
|
-
await handler(exchange);
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
exchange.respondErrMsg(`${path} not found`, 404);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* 获取 ipv4 地址列表
|
|
178
|
-
* @returns
|
|
179
|
-
*/
|
|
180
|
-
function getIpv4List() {
|
|
181
|
-
const ifs = (0, os_1.networkInterfaces)();
|
|
182
|
-
const res = [];
|
|
183
|
-
for (const name in ifs) {
|
|
184
|
-
const list = ifs[name];
|
|
185
|
-
if (!list) {
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
res.push(...list.filter(info => info.family === 'IPv4').map(info => info.address));
|
|
189
|
-
}
|
|
190
|
-
return res;
|
|
191
|
-
}
|
|
5
|
+
const server_1 = require("./server");
|
|
192
6
|
/**
|
|
193
7
|
* 服务实例.
|
|
194
8
|
*/
|
|
@@ -198,103 +12,11 @@ let SERVER;
|
|
|
198
12
|
* @param opts
|
|
199
13
|
*/
|
|
200
14
|
async function startWebServer(opts) {
|
|
201
|
-
(0, https_1.createServer)({
|
|
202
|
-
cert: '', key: ''
|
|
203
|
-
}, () => {
|
|
204
|
-
});
|
|
205
15
|
if (SERVER) {
|
|
206
16
|
throw new Error('The server has already been started!');
|
|
207
17
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if (opts.static) {
|
|
211
|
-
// 重复记录表 ,作用是为了路径去重判定,可以提示哪些路径是重复的
|
|
212
|
-
const duplicateMap = new Map();
|
|
213
|
-
for (const entry of Object.entries(opts.static)) {
|
|
214
|
-
const [path, setting] = entry;
|
|
215
|
-
const dir = (0, path_1.isAbsolute)(setting.dir) ? setting.dir : (0, path_1.resolve)(process.cwd(), setting.dir);
|
|
216
|
-
if (!(0, fs_1.existsSync)(dir)) {
|
|
217
|
-
throw new Error(`Static file configuration error,path ${dir} does not exist,config dir:${setting.dir}`);
|
|
218
|
-
}
|
|
219
|
-
const statRes = await (0, promises_1.stat)(dir);
|
|
220
|
-
if (!statRes.isDirectory()) {
|
|
221
|
-
throw new Error(`Static file configuration error,path ${dir} is not a directory,config dir:${setting.dir}`);
|
|
222
|
-
}
|
|
223
|
-
let finalPath = path.startsWith('/') ? path : '/' + path;
|
|
224
|
-
// 保持以 / 结尾,为了匹配方便
|
|
225
|
-
if (!finalPath.endsWith('/')) {
|
|
226
|
-
finalPath += '/';
|
|
227
|
-
}
|
|
228
|
-
if (duplicateMap.has(finalPath)) {
|
|
229
|
-
throw new Error(`Static path duplicated: ${duplicateMap.get(finalPath)} and ${path}`);
|
|
230
|
-
}
|
|
231
|
-
duplicateMap.set(finalPath, path);
|
|
232
|
-
staticSettings.push({ path: finalPath, dir, cacheAge: setting.cacheAge || 0 });
|
|
233
|
-
}
|
|
234
|
-
// 优先级排序
|
|
235
|
-
staticSettings.sort((o1, o2) => {
|
|
236
|
-
let priority1 = o1.path === '/' ? -1 : o1.path.split('/').length;
|
|
237
|
-
let priority2 = o2.path === '/' ? -1 : o2.path.split('/').length;
|
|
238
|
-
// 如果 o1 优先级高,就应该排前面,返回小于0的值,反之亦然\
|
|
239
|
-
// 前面的优先级值是值越大优先级越高,反过来减
|
|
240
|
-
return priority2 - priority1;
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
// 如果启用请求日志,增加拦截器
|
|
244
|
-
let interceptors = [];
|
|
245
|
-
if (config_1.config.accessLog) {
|
|
246
|
-
interceptors.push(access_log_1.accessLogInterceptor);
|
|
247
|
-
}
|
|
248
|
-
if (opts.interceptors) {
|
|
249
|
-
interceptors.push(...opts.interceptors);
|
|
250
|
-
}
|
|
251
|
-
SERVER = (0, http_1.createServer)((req, res) => {
|
|
252
|
-
res.setHeader('Server', 'Wok Server');
|
|
253
|
-
res.on('error', error => {
|
|
254
|
-
// 如果响应流发生错误,只能把信息记录下来
|
|
255
|
-
(0, log_1.getLogger)().error(`Response Error:${req.url}`, error);
|
|
256
|
-
});
|
|
257
|
-
handleRequest(interceptors, opts.routers, req, res, staticSettings).catch(error => {
|
|
258
|
-
(0, log_1.getLogger)().error(`Handle request failed:${req.url}`, error);
|
|
259
|
-
if (!res.writableEnded) {
|
|
260
|
-
// 响应 500
|
|
261
|
-
(0, render_1.renderError)(res, error.message ? error.message : 'Internal Server Error', 500);
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
});
|
|
265
|
-
SERVER.setTimeout(config_1.config.timeout);
|
|
266
|
-
SERVER.on('timeout', (socket) => {
|
|
267
|
-
socket.end('HTTP/1.1 408 Timeout\ncontent-type: application/json; charset=utf-8\n\n{"message":"Request timeout"}');
|
|
268
|
-
});
|
|
269
|
-
if (opts.preHandler) {
|
|
270
|
-
await opts.preHandler(SERVER);
|
|
271
|
-
}
|
|
272
|
-
const server = SERVER;
|
|
273
|
-
await new Promise((resolve, reject) => {
|
|
274
|
-
server.on('error', e => {
|
|
275
|
-
if (e.code === 'EADDRINUSE') {
|
|
276
|
-
reject(`Port ${config_1.config.port} is already in use.`);
|
|
277
|
-
}
|
|
278
|
-
else {
|
|
279
|
-
reject(e);
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
server.listen(config_1.config.port, resolve);
|
|
283
|
-
});
|
|
284
|
-
console.log('App running at: ');
|
|
285
|
-
getIpv4List().forEach(ip => {
|
|
286
|
-
if (config_1.config.port === 80) {
|
|
287
|
-
console.log(`http://${ip}`);
|
|
288
|
-
}
|
|
289
|
-
else {
|
|
290
|
-
console.log(`http://${ip}:${config_1.config.port}`);
|
|
291
|
-
}
|
|
292
|
-
});
|
|
293
|
-
process.on('beforeExit', () => {
|
|
294
|
-
if (server.listening) {
|
|
295
|
-
server.close();
|
|
296
|
-
}
|
|
297
|
-
});
|
|
18
|
+
SERVER = new server_1.WokServer(opts);
|
|
19
|
+
await SERVER.start();
|
|
298
20
|
}
|
|
299
21
|
exports.startWebServer = startWebServer;
|
|
300
22
|
/**
|
|
@@ -305,24 +27,13 @@ async function stopWebServer() {
|
|
|
305
27
|
if (!SERVER) {
|
|
306
28
|
return;
|
|
307
29
|
}
|
|
308
|
-
|
|
309
|
-
const server = SERVER;
|
|
310
|
-
await new Promise((res, rej) => {
|
|
311
|
-
server.close(err => {
|
|
312
|
-
if (err) {
|
|
313
|
-
rej(err);
|
|
314
|
-
}
|
|
315
|
-
else {
|
|
316
|
-
res();
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
});
|
|
320
|
-
}
|
|
30
|
+
SERVER.stop();
|
|
321
31
|
SERVER = undefined;
|
|
322
32
|
}
|
|
323
33
|
exports.stopWebServer = stopWebServer;
|
|
34
|
+
process.on('beforeExit', stopWebServer);
|
|
324
35
|
tslib_1.__exportStar(require("./exchange"), exports);
|
|
325
36
|
tslib_1.__exportStar(require("./handler"), exports);
|
|
37
|
+
tslib_1.__exportStar(require("./interceptor"), exports);
|
|
326
38
|
tslib_1.__exportStar(require("./render"), exports);
|
|
327
39
|
tslib_1.__exportStar(require("./router"), exports);
|
|
328
|
-
tslib_1.__exportStar(require("./interceptor"), exports);
|
package/dist/mvc/render/file.js
CHANGED
|
@@ -3,92 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.renderFile = void 0;
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
5
|
const promises_1 = require("fs/promises");
|
|
6
|
-
const json_1 = require("./json");
|
|
7
6
|
const path_1 = require("path");
|
|
8
7
|
const zlib_1 = require("zlib");
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
*/
|
|
12
|
-
const frequentlyUsedContentTypeTable = {
|
|
13
|
-
aac: 'audio/aac',
|
|
14
|
-
abw: 'application/x-abiword',
|
|
15
|
-
arc: 'application/x-freearc',
|
|
16
|
-
avi: 'video/x-msvideo',
|
|
17
|
-
azw: 'application/vnd.amazon.ebook',
|
|
18
|
-
bin: 'application/octet-stream',
|
|
19
|
-
bmp: 'image/bmp',
|
|
20
|
-
bz: 'application/x-bzip',
|
|
21
|
-
bz2: 'application/x-bzip2',
|
|
22
|
-
csh: 'application/x-csh',
|
|
23
|
-
css: 'text/css',
|
|
24
|
-
csv: 'text/csv',
|
|
25
|
-
doc: 'application/msword',
|
|
26
|
-
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
27
|
-
eot: 'application/vnd.ms-fontobject',
|
|
28
|
-
epub: 'application/epub+zip',
|
|
29
|
-
gif: 'image/gif',
|
|
30
|
-
htm: 'text/html',
|
|
31
|
-
html: 'text/html',
|
|
32
|
-
ico: 'image/vnd.microsoft.icon',
|
|
33
|
-
ics: 'text/calendar',
|
|
34
|
-
jar: 'application/java-archive',
|
|
35
|
-
jpeg: 'image/jpeg',
|
|
36
|
-
jpg: 'image/jpeg',
|
|
37
|
-
js: 'text/javascript',
|
|
38
|
-
json: 'application/json',
|
|
39
|
-
jsonld: 'application/ld+json',
|
|
40
|
-
mid: 'audio/midi',
|
|
41
|
-
midi: 'audio/midi',
|
|
42
|
-
mjs: 'text/javascript',
|
|
43
|
-
mp3: 'audio/mpeg',
|
|
44
|
-
mpeg: 'video/mpeg',
|
|
45
|
-
mpkg: 'application/vnd.apple.installer+xml',
|
|
46
|
-
odp: 'application/vnd.oasis.opendocument.presentation',
|
|
47
|
-
ods: 'application/vnd.oasis.opendocument.spreadsheet',
|
|
48
|
-
odt: 'application/vnd.oasis.opendocument.text',
|
|
49
|
-
oga: 'audio/ogg',
|
|
50
|
-
ogv: 'video/ogg',
|
|
51
|
-
ogx: 'application/ogg',
|
|
52
|
-
otf: 'font/otf',
|
|
53
|
-
png: 'image/png',
|
|
54
|
-
pdf: 'application/pdf',
|
|
55
|
-
ppt: 'application/vnd.ms-powerpoint',
|
|
56
|
-
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
57
|
-
rar: 'application/x-rar-compressed',
|
|
58
|
-
rtf: 'application/rtf',
|
|
59
|
-
sh: 'application/x-sh',
|
|
60
|
-
svg: 'image/svg+xml',
|
|
61
|
-
swf: 'application/x-shockwave-flash',
|
|
62
|
-
tar: 'application/x-tar',
|
|
63
|
-
tif: 'image/tiff',
|
|
64
|
-
tiff: 'image/tiff',
|
|
65
|
-
ttf: 'font/ttf',
|
|
66
|
-
txt: 'text/plain',
|
|
67
|
-
vsd: 'application/vnd.visio',
|
|
68
|
-
wav: 'audio/wav',
|
|
69
|
-
weba: 'audio/webm',
|
|
70
|
-
webm: 'video/webm',
|
|
71
|
-
webp: 'image/webp',
|
|
72
|
-
woff: 'font/woff',
|
|
73
|
-
woff2: 'font/woff2',
|
|
74
|
-
xhtml: 'application/xhtml+xml',
|
|
75
|
-
xls: 'application/vnd.ms-excel',
|
|
76
|
-
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
77
|
-
xml: 'application/xml',
|
|
78
|
-
xul: 'application/vnd.mozilla.xul+xml',
|
|
79
|
-
zip: 'application/zip',
|
|
80
|
-
'3gp': 'video/3gpp',
|
|
81
|
-
'3g2': 'video/3gpp2',
|
|
82
|
-
'7z': 'application/x-7z-compressed'
|
|
83
|
-
};
|
|
84
|
-
function decideContentType(fileName) {
|
|
85
|
-
const idx = fileName.lastIndexOf('.');
|
|
86
|
-
if (idx === -1) {
|
|
87
|
-
return undefined;
|
|
88
|
-
}
|
|
89
|
-
const suffix = fileName.substring(idx + 1);
|
|
90
|
-
return frequentlyUsedContentTypeTable[suffix];
|
|
91
|
-
}
|
|
8
|
+
const static_1 = require("../static");
|
|
9
|
+
const json_1 = require("./json");
|
|
92
10
|
/**
|
|
93
11
|
* 响应一个文件.
|
|
94
12
|
* @param request 请求信息
|
|
@@ -108,7 +26,7 @@ async function renderFile(request, response, filePath, download = false) {
|
|
|
108
26
|
isDownload = true;
|
|
109
27
|
}
|
|
110
28
|
else {
|
|
111
|
-
contentType = decideContentType(fileName);
|
|
29
|
+
contentType = (0, static_1.decideContentType)(fileName);
|
|
112
30
|
if (!contentType) {
|
|
113
31
|
isDownload = true;
|
|
114
32
|
}
|