oox 0.3.0-beta9 → 0.3.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/LICENSE +21 -21
- package/README.md +29 -32
- package/app.js +131 -143
- package/bin/argv.js +63 -70
- package/bin/cli.js +57 -43
- package/bin/configurer.js +60 -62
- package/bin/loader.mjs +392 -279
- package/bin/proxy-import.js +12 -0
- package/bin/proxy-require.js +88 -0
- package/bin/register.js +46 -55
- package/bin/starter.js +63 -66
- package/index.js +155 -168
- package/index.mjs +4 -4
- package/logger.js +25 -40
- package/modules/http/index.js +286 -192
- package/modules/http/router.js +205 -0
- package/modules/http/utils.js +75 -73
- package/modules/index.js +86 -88
- package/modules/module.js +11 -16
- package/modules/socketio/client.js +97 -101
- package/modules/socketio/index.js +171 -168
- package/modules/socketio/server.js +188 -136
- package/modules/socketio/socket.js +1 -4
- package/package.json +14 -12
- package/types/app.d.ts +50 -51
- package/types/bin/argv.d.ts +8 -8
- package/types/bin/cli.d.ts +6 -2
- package/types/bin/configurer.d.ts +3 -1
- package/types/bin/proxy-import.d.ts +4 -0
- package/types/bin/proxy-require.d.ts +5 -0
- package/types/bin/register.d.ts +1 -1
- package/types/bin/starter.d.ts +5 -1
- package/types/index.d.ts +78 -76
- package/types/logger.d.ts +5 -4
- package/types/modules/http/index.d.ts +65 -47
- package/types/modules/http/router.d.ts +49 -0
- package/types/modules/http/utils.d.ts +14 -17
- package/types/modules/index.d.ts +24 -24
- package/types/modules/module.d.ts +11 -13
- package/types/modules/socketio/client.d.ts +23 -23
- package/types/modules/socketio/index.d.ts +37 -37
- package/types/modules/socketio/server.d.ts +44 -35
- package/types/modules/socketio/socket.d.ts +11 -11
- package/types/utils.d.ts +6 -6
- package/utils.js +57 -63
- package/bin/proxyer.js +0 -61
- package/types/bin/proxyer.d.ts +0 -1
package/modules/http/index.js
CHANGED
|
@@ -1,192 +1,286 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
Error
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if (
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
1
|
+
import * as http from 'node:http';
|
|
2
|
+
import * as https from 'node:https';
|
|
3
|
+
import { httpRequest, parseHTTPBody } from './utils.js';
|
|
4
|
+
import Router from './router.js';
|
|
5
|
+
import * as oox from '../../index.js';
|
|
6
|
+
import Module, { ModuleConfig } from '../module.js';
|
|
7
|
+
export class HTTPConfig extends ModuleConfig {
|
|
8
|
+
// listen port
|
|
9
|
+
port = 0;
|
|
10
|
+
// service path
|
|
11
|
+
path = '/';
|
|
12
|
+
// browser cross origin
|
|
13
|
+
origin = '';
|
|
14
|
+
// https options
|
|
15
|
+
ssl = {
|
|
16
|
+
// enable https
|
|
17
|
+
enabled: false,
|
|
18
|
+
// ssl certificate path
|
|
19
|
+
cert: '',
|
|
20
|
+
// ssl private key path
|
|
21
|
+
key: '',
|
|
22
|
+
// ssl ca path
|
|
23
|
+
ca: ''
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export default class HTTPModule extends Module {
|
|
27
|
+
name = 'http';
|
|
28
|
+
config = new HTTPConfig;
|
|
29
|
+
server = null;
|
|
30
|
+
router = new Router();
|
|
31
|
+
getUrl() {
|
|
32
|
+
const { host } = oox.config;
|
|
33
|
+
const { port, path } = this.config;
|
|
34
|
+
const protocol = this.config.ssl.enabled ? `https:` : `http:`;
|
|
35
|
+
return `${protocol}//${host}:${port}${path}`;
|
|
36
|
+
}
|
|
37
|
+
// 注册GET路由
|
|
38
|
+
get(path, ...args) {
|
|
39
|
+
this.router.get(path, ...args);
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
// 注册POST路由
|
|
43
|
+
post(path, ...args) {
|
|
44
|
+
this.router.post(path, ...args);
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
// 注册PUT路由
|
|
48
|
+
put(path, ...args) {
|
|
49
|
+
this.router.put(path, ...args);
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
// 注册DELETE路由
|
|
53
|
+
delete(path, ...args) {
|
|
54
|
+
this.router.delete(path, ...args);
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
// 注册全局中间件
|
|
58
|
+
use(middleware) {
|
|
59
|
+
this.router.use(middleware);
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
setConfig(config) {
|
|
63
|
+
Object.assign(this.config, config);
|
|
64
|
+
if (!config.hasOwnProperty('port')) {
|
|
65
|
+
this.config.port = oox.config.port;
|
|
66
|
+
}
|
|
67
|
+
if (!config.hasOwnProperty('origin')) {
|
|
68
|
+
this.config.origin = oox.config.origin;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
getConfig() {
|
|
72
|
+
return this.config;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* start http service
|
|
76
|
+
*/
|
|
77
|
+
async serve() {
|
|
78
|
+
await this.stop();
|
|
79
|
+
const { port, ssl } = this.config;
|
|
80
|
+
if (ssl.enabled) {
|
|
81
|
+
const fs = await import('node:fs');
|
|
82
|
+
const options = {
|
|
83
|
+
key: ssl.key ? fs.readFileSync(ssl.key) : null,
|
|
84
|
+
cert: ssl.cert ? fs.readFileSync(ssl.cert) : null,
|
|
85
|
+
ca: ssl.ca ? fs.readFileSync(ssl.ca) : null
|
|
86
|
+
};
|
|
87
|
+
if (!options.key || !options.cert) {
|
|
88
|
+
throw new Error('HTTPS enabled but missing key or cert');
|
|
89
|
+
}
|
|
90
|
+
this.server = https.createServer(options, this.requestHandler.bind(this));
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
this.server = http.createServer(this.requestHandler.bind(this));
|
|
94
|
+
}
|
|
95
|
+
this.server.listen(port);
|
|
96
|
+
const address = this.server.address();
|
|
97
|
+
if (!address || 'object' !== typeof address)
|
|
98
|
+
throw new Error('Cannot read http server port');
|
|
99
|
+
this.config.port = address.port;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* stop http service
|
|
103
|
+
*/
|
|
104
|
+
stop() {
|
|
105
|
+
if (this.server && this.server.listening)
|
|
106
|
+
return new Promise((resolve, reject) => {
|
|
107
|
+
this.server.close(function (error) {
|
|
108
|
+
if (error)
|
|
109
|
+
reject(error);
|
|
110
|
+
else
|
|
111
|
+
resolve();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* browser cross origin
|
|
117
|
+
*/
|
|
118
|
+
cors(request, response) {
|
|
119
|
+
// origin checking
|
|
120
|
+
const origin = this.config.origin;
|
|
121
|
+
const requestOrigin = request.headers.origin;
|
|
122
|
+
if (origin && requestOrigin) {
|
|
123
|
+
if (origin === '*' ||
|
|
124
|
+
origin === requestOrigin ||
|
|
125
|
+
(Array.isArray(origin) && origin.includes(requestOrigin))) {
|
|
126
|
+
response.setHeader('Access-Control-Allow-Origin', requestOrigin);
|
|
127
|
+
response.setHeader('Vary', 'Origin');
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
response.statusCode = 403;
|
|
131
|
+
response.end();
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
response.setHeader('Access-Control-Max-Age', 3600);
|
|
135
|
+
response.setHeader('Access-Control-Allow-Headers', 'x-caller,content-type');
|
|
136
|
+
response.setHeader('Access-Control-Allow-Methods', '*');
|
|
137
|
+
}
|
|
138
|
+
if (request.method === 'OPTIONS') {
|
|
139
|
+
response.statusCode = 204;
|
|
140
|
+
response.end();
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
async requestHandler(request, response) {
|
|
146
|
+
if (!this.cors(request, response))
|
|
147
|
+
return;
|
|
148
|
+
const url = new URL(request.url, `http://${request.headers.host || 'localhost'}`);
|
|
149
|
+
const method = request.method || 'GET';
|
|
150
|
+
// 尝试匹配路由
|
|
151
|
+
const matched = this.router.match(method, url.pathname);
|
|
152
|
+
if (matched) {
|
|
153
|
+
const req = this.router.createRequestObject(request, url);
|
|
154
|
+
const res = this.router.createResponseObject(response);
|
|
155
|
+
// 解析请求体
|
|
156
|
+
if (request.method !== 'GET' && request.method !== 'HEAD') {
|
|
157
|
+
try {
|
|
158
|
+
req.body = await parseHTTPBody(request);
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
return this.respond(request, response, {
|
|
162
|
+
success: false,
|
|
163
|
+
error: {
|
|
164
|
+
message: error.message,
|
|
165
|
+
stack: error.stack
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
await this.router.handleRoute(matched.route, matched.params, req, res);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
// 回退到RPC调用
|
|
174
|
+
if (url.pathname === this.config.path) {
|
|
175
|
+
await this.call(request, response);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
const error = new Error('Invalid URL');
|
|
179
|
+
return this.respond(request, response, {
|
|
180
|
+
success: false,
|
|
181
|
+
error: {
|
|
182
|
+
message: error.message,
|
|
183
|
+
stack: error.stack
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* 从请求里获取调用的接口和参数
|
|
190
|
+
*/
|
|
191
|
+
async getCallArgsFromRequest(request) {
|
|
192
|
+
const args = await parseHTTPBody(request);
|
|
193
|
+
if (!args || 'object' !== typeof args || !args.action)
|
|
194
|
+
throw new Error('Content Invalid');
|
|
195
|
+
else
|
|
196
|
+
return args;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* HTTP-RPC服务器请求监听方法
|
|
200
|
+
*/
|
|
201
|
+
async call(request, response) {
|
|
202
|
+
let callArgs = Object.create(null);
|
|
203
|
+
try {
|
|
204
|
+
callArgs = await this.getCallArgsFromRequest(request);
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
return this.respond(request, response, {
|
|
208
|
+
success: false,
|
|
209
|
+
error: {
|
|
210
|
+
message: error.message,
|
|
211
|
+
stack: error.stack
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
// global unique id
|
|
216
|
+
const traceId = String(request.headers['x-trace-id'] || '');
|
|
217
|
+
// service name, required
|
|
218
|
+
const caller = String(request.headers['x-caller'] || 'anonymous');
|
|
219
|
+
// client ip or caller service ip
|
|
220
|
+
const ip = String(request.headers['x-ip'] || request.socket.remoteAddress || '');
|
|
221
|
+
// startup client ip
|
|
222
|
+
const sourceIP = String(request.headers['x-real-ip'] || '');
|
|
223
|
+
const { action, params = [] } = callArgs;
|
|
224
|
+
const context = oox.genContext({ traceId, caller, sourceIP, ip, callerId: '' });
|
|
225
|
+
const format = await oox.call(action, params, context);
|
|
226
|
+
this.respond(request, response, format);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* HTTP Response Catch
|
|
230
|
+
*/
|
|
231
|
+
respond(_request, response, returns) {
|
|
232
|
+
let returnsString = '';
|
|
233
|
+
if (!oox.config.errorStack && returns.error) {
|
|
234
|
+
// 不返回错误调用栈信息
|
|
235
|
+
delete returns.error.stack;
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
returnsString = JSON.stringify(returns);
|
|
239
|
+
}
|
|
240
|
+
catch ({ message, stack }) {
|
|
241
|
+
delete returns.body;
|
|
242
|
+
returns.success = false;
|
|
243
|
+
returns.error = {
|
|
244
|
+
message
|
|
245
|
+
};
|
|
246
|
+
if (oox.config.errorStack) {
|
|
247
|
+
// 返回错误调用栈信息
|
|
248
|
+
returns.error.stack = stack;
|
|
249
|
+
}
|
|
250
|
+
returnsString = JSON.stringify(returns);
|
|
251
|
+
}
|
|
252
|
+
response.setHeader('Content-Type', 'application/json');
|
|
253
|
+
response.setHeader('Content-Length', Buffer.byteLength(returnsString));
|
|
254
|
+
response.end(returnsString);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* HTTP RPC
|
|
258
|
+
*/
|
|
259
|
+
async rpc(url, action, params, context) {
|
|
260
|
+
if (!context || !context.traceId) {
|
|
261
|
+
context = oox.getContext();
|
|
262
|
+
}
|
|
263
|
+
const { traceId, caller, sourceIP } = context;
|
|
264
|
+
const headers = {
|
|
265
|
+
'Content-Type': 'application/json',
|
|
266
|
+
'x-trace-id': String(traceId),
|
|
267
|
+
};
|
|
268
|
+
if (caller)
|
|
269
|
+
headers['x-caller'] = String(caller);
|
|
270
|
+
if (sourceIP)
|
|
271
|
+
headers['x-real-ip'] = sourceIP;
|
|
272
|
+
// headers [ 'x-ip' ] = getIPAddress ( 4 ) [ 0 ]
|
|
273
|
+
const format = await httpRequest(url, {
|
|
274
|
+
headers
|
|
275
|
+
}, JSON.stringify({ action, params }));
|
|
276
|
+
if ('string' === typeof format)
|
|
277
|
+
throw new Error(format);
|
|
278
|
+
const { success, error, body } = format;
|
|
279
|
+
if (success)
|
|
280
|
+
return body;
|
|
281
|
+
else if (error)
|
|
282
|
+
throw new Error(error.message);
|
|
283
|
+
else
|
|
284
|
+
throw new Error('[RPC] Unknown Error');
|
|
285
|
+
}
|
|
286
|
+
}
|