oox 0.0.7 → 0.2.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/rpc/http.class.js CHANGED
@@ -1,327 +1,312 @@
1
-
2
- const http = require ( 'http' )
3
-
4
- const { parseHTTPBody, getTraceIdByStack, getIPAddress, httpRequest } = require ( '../util' )
5
-
6
- const Context = require ( './context.class' )
7
-
8
- const RPC = require ( './rpc.interface.class' )
9
-
10
- const Global = require ( '../global' )
11
-
12
-
13
-
14
- module.exports = class HTTPModule {
15
-
16
-
17
-
18
- /**
19
- * @type {RPC}
20
- */
21
- rpc = null
22
-
23
-
24
-
25
- /**
26
- * listen port
27
- */
28
- port = 0
29
-
30
-
31
-
32
- /**
33
- * socket.io service path
34
- */
35
- path = '/'
36
-
37
-
38
-
39
- /**
40
- * @param {{port:Number, path:String}} config
41
- */
42
- set config ( config ) {
43
-
44
- if ( !config ) return this.rpc.config.gateway.http = null
45
-
46
- config = this.rpc.config.gateway.http = Object.assign ( this.config || { }, config )
47
-
48
- this.port = config.port || 0
49
-
50
- if ( config.path ) this.path = config.path
51
- else config.path = this.path
52
- }
53
-
54
-
55
-
56
- get config ( ) {
57
-
58
- return this.rpc.config.gateway.http
59
- }
60
-
61
-
62
-
63
- /**
64
- * @type {http.Server}
65
- */
66
- server = null
67
-
68
-
69
-
70
- /**
71
- *
72
- * @param {RPC} rpc
73
- */
74
- constructor ( rpc ) {
75
-
76
- this.rpc = rpc
77
- }
78
-
79
-
80
-
81
- /**
82
- * start http service
83
- * @returns {http.Server}
84
- */
85
- async serve ( ) {
86
-
87
- await this.stop ( )
88
-
89
- const config = this.config
90
-
91
- if ( !config ) return
92
-
93
- const { port } = config
94
-
95
- const isRndPort = 'number' !== typeof port || port === 0
96
-
97
- const server =
98
- this.server = http.createServer ( this.call.bind ( this ) )
99
-
100
- server.listen ( isRndPort ? 0 : port )
101
-
102
- config.port = server.address ( ).port
103
- config.path = this.path
104
-
105
- return server
106
- }
107
-
108
-
109
-
110
- /**
111
- * stop http service
112
- */
113
- stop ( ) {
114
-
115
- if ( this.server && this.server.listening )
116
- return new Promise ( ( resolve, reject ) => {
117
-
118
- this.server.close ( function ( error ) {
119
-
120
- if ( error ) reject ( error )
121
- else resolve ( )
122
- } )
123
- } )
124
- }
125
-
126
-
127
-
128
- /**
129
- * CORS
130
- * @param {http.IncomingMessage} request
131
- * @param {http.ServerResponse} response
132
- */
133
- cors ( request, response ) {
134
-
135
- // origin checking
136
- if ( this.rpc.config.origin ) {
137
-
138
- const origin = this.rpc.config.origin
139
-
140
- const requestOrigin = request.headers.origin
141
-
142
- if ( origin === '*' ) {
143
-
144
- response.setHeader ( 'Access-Control-Allow-Origin', '*' )
145
- } else if ( origin === requestOrigin || Array.isArray ( origin ) && origin.includes ( requestOrigin ) ) {
146
-
147
- response.setHeader ( 'Access-Control-Allow-Origin', requestOrigin )
148
-
149
- response.setHeader ( 'Vary', 'Origin' )
150
- } else {
151
-
152
- response.statusCode = 403
153
-
154
- response.end ( )
155
-
156
- return false
157
- }
158
-
159
- response.setHeader ( 'Access-Control-Max-Age', 3600 )
160
- response.setHeader ( 'Access-Control-Allow-Headers', 'x-caller,content-type' )
161
- response.setHeader ( 'Access-Control-Allow-Methods', 'POST' )
162
- }
163
-
164
- if ( request.method === 'OPTIONS' ) {
165
-
166
- response.statusCode = 204
167
-
168
- response.end ( )
169
-
170
- return false
171
- }
172
-
173
- return true
174
- }
175
-
176
-
177
-
178
- /**
179
- * HTTP-RPC服务器请求监听方法
180
- * @param {http.IncomingMessage} request
181
- * @param {http.ServerResponse} response
182
- */
183
- async call ( request, response ) {
184
-
185
- if ( request.url !== this.path ) {
186
-
187
- return this.respond ( request, response, new Error ( 'URL Incorrect' ) )
188
- }
189
-
190
- if ( !this.cors ( request, response ) ) return
191
-
192
- let body = Object.create ( null )
193
-
194
- try {
195
-
196
- body = await parseHTTPBody ( request )
197
-
198
- if ( !body || 'object' !== typeof body ) throw new Error ( 'Content Invalid' )
199
-
200
- } catch ( error ) {
201
-
202
- return this.respond ( request, response, error )
203
- }
204
-
205
- // global unique id
206
- const traceId = request.headers [ 'x-trace-id' ]
207
-
208
- // service name, required
209
- const caller = request.headers [ 'x-caller' ] || 'anonymous'
210
-
211
- // client ip or caller service ip
212
- const ip = request.headers [ 'x-ip' ] || request.socket.remoteAddress
213
-
214
- // startup client ip
215
- const sourceIP = request.headers [ 'x-real-ip' ]
216
-
217
- const { action, params = [ ] } = body
218
-
219
- const context = Global.genContext ( { traceId, caller, sourceIP, ip } )
220
-
221
- const format = await this.rpc.call ( action, params, context )
222
-
223
- this.respond ( request, response, format )
224
- }
225
-
226
-
227
-
228
- /**
229
- * HTTP Response Catch
230
- * @param {http.IncomingMessage} request
231
- * @param {http.ServerResponse} response
232
- * @param {Object} format
233
- * @param {Boolean} format.success
234
- * @param {Error} format.error
235
- * @param {any} format.body
236
- */
237
- respond ( request, response, format ) {
238
-
239
- let formatString = ''
240
-
241
- if ( format instanceof Error ) {
242
-
243
- format = {
244
- success: false,
245
- error: {
246
- message: format.message,
247
- stack: format.stack
248
- }
249
- }
250
- }
251
-
252
- try {
253
-
254
- formatString = JSON.stringify ( format )
255
- } catch ( { message, stack } ) {
256
-
257
- delete format.body
258
-
259
- format.success = false
260
-
261
- format.error = {
262
- message,
263
- stack
264
- }
265
-
266
- formatString = JSON.stringify ( format )
267
- }
268
-
269
- response.setHeader ( 'Content-Type', 'application/json' )
270
-
271
- response.setHeader ( 'Content-Length', Buffer.byteLength ( formatString ) )
272
-
273
- response.end ( formatString )
274
- }
275
-
276
-
277
-
278
- /**
279
- * HTTP RPC
280
- * @param {String|URL|http.RequestOptions} url
281
- * @param {String} action 函数名称
282
- * @param {Array} params 参数列表
283
- * @param {Context} context 上下文
284
- */
285
- static async call ( url, action, params, context ) {
286
-
287
- if ( !context || !context.traceId ) {
288
-
289
- let trace = { }
290
-
291
- Error.captureStackTrace ( trace )
292
-
293
- context = Global.genContextByStack ( trace.stack )
294
- }
295
-
296
- const { traceId, caller, sourceIP } = context
297
-
298
- const headers = {
299
- 'Content-Type': 'application/json',
300
- 'x-trace-id': String ( traceId ),
301
- }
302
-
303
- if ( caller ) headers [ 'x-caller' ] = String ( caller )
304
-
305
- if ( sourceIP ) headers [ 'x-real-ip' ] = sourceIP
306
-
307
- headers [ 'x-ip' ] = getIPAddress ( 4 ) [ 0 ]
308
-
309
- const format = await httpRequest ( url, {
310
- headers
311
- }, JSON.stringify ( { action, params } ) )
312
-
313
- if ( 'string' === typeof format ) throw new Error ( format )
314
-
315
- const { error, body } = format
316
-
317
- if ( error ) {
318
-
319
- const asyncError = new Error ( error.message )
320
-
321
- throw asyncError
322
- } else {
323
-
324
- return body
325
- }
326
- }
1
+
2
+ const http = require ( 'http' )
3
+
4
+ const { parseHTTPBody, getIPAddress, httpRequest } = require ( '../util' )
5
+
6
+ const Context = require ( './context.class' )
7
+
8
+ const RPC = require ( './rpc.interface.class' )
9
+
10
+ const Global = require ( '../global' )
11
+
12
+
13
+
14
+ module.exports = class HTTPModule {
15
+
16
+
17
+
18
+ /**
19
+ * @type {RPC}
20
+ */
21
+ rpc = null
22
+
23
+
24
+
25
+ /**
26
+ * listen port
27
+ */
28
+ port = 0
29
+
30
+
31
+
32
+ /**
33
+ * socket.io service path
34
+ */
35
+ path = '/'
36
+
37
+
38
+
39
+ /**
40
+ * @param {{port:Number, path:String}} config
41
+ */
42
+ set config ( config ) {
43
+
44
+ if ( !config ) return this.rpc.config.gateway.http = null
45
+
46
+ config = this.rpc.config.gateway.http = Object.assign ( this.config || { }, config )
47
+
48
+ this.port = config.port || 0
49
+
50
+ if ( config.path ) this.path = config.path
51
+ else config.path = this.path
52
+ }
53
+
54
+
55
+
56
+ get config ( ) {
57
+
58
+ return this.rpc.config.gateway.http
59
+ }
60
+
61
+
62
+
63
+ /**
64
+ * @type {http.Server}
65
+ */
66
+ server = null
67
+
68
+
69
+
70
+ /**
71
+ *
72
+ * @param {RPC} rpc
73
+ */
74
+ constructor ( rpc ) {
75
+
76
+ this.rpc = rpc
77
+ }
78
+
79
+
80
+
81
+ /**
82
+ * start http service
83
+ * @returns {http.Server}
84
+ */
85
+ async serve ( ) {
86
+
87
+ await this.stop ( )
88
+
89
+ const config = this.config
90
+
91
+ if ( !config ) return
92
+
93
+ const { port } = config
94
+
95
+ const isRndPort = 'number' !== typeof port || port === 0
96
+
97
+ const server =
98
+ this.server = http.createServer ( this.call.bind ( this ) )
99
+
100
+ server.listen ( isRndPort ? 0 : port )
101
+
102
+ config.port = server.address ( ).port
103
+ config.path = this.path
104
+
105
+ return server
106
+ }
107
+
108
+
109
+
110
+ /**
111
+ * stop http service
112
+ */
113
+ stop ( ) {
114
+
115
+ if ( this.server && this.server.listening )
116
+ return new Promise ( ( resolve, reject ) => {
117
+
118
+ this.server.close ( function ( error ) {
119
+
120
+ if ( error ) reject ( error )
121
+ else resolve ( )
122
+ } )
123
+ } )
124
+ }
125
+
126
+
127
+
128
+ /**
129
+ * CORS
130
+ * @param {http.IncomingMessage} request
131
+ * @param {http.ServerResponse} response
132
+ */
133
+ cors ( request, response ) {
134
+
135
+ // origin checking
136
+ if ( this.rpc.config.origin ) {
137
+
138
+ const origin = this.rpc.config.origin
139
+
140
+ const requestOrigin = request.headers.origin
141
+
142
+ if ( origin === '*' ) {
143
+
144
+ response.setHeader ( 'Access-Control-Allow-Origin', '*' )
145
+ } else if ( origin === requestOrigin || Array.isArray ( origin ) && origin.includes ( requestOrigin ) ) {
146
+
147
+ response.setHeader ( 'Access-Control-Allow-Origin', requestOrigin )
148
+
149
+ response.setHeader ( 'Vary', 'Origin' )
150
+ } else {
151
+
152
+ response.statusCode = 403
153
+
154
+ response.end ( )
155
+
156
+ return false
157
+ }
158
+
159
+ response.setHeader ( 'Access-Control-Max-Age', 3600 )
160
+ response.setHeader ( 'Access-Control-Allow-Headers', 'x-caller,content-type' )
161
+ response.setHeader ( 'Access-Control-Allow-Methods', 'POST' )
162
+ }
163
+
164
+ if ( request.method === 'OPTIONS' ) {
165
+
166
+ response.statusCode = 204
167
+
168
+ response.end ( )
169
+
170
+ return false
171
+ }
172
+
173
+ return true
174
+ }
175
+
176
+
177
+
178
+ /**
179
+ * HTTP-RPC服务器请求监听方法
180
+ * @param {http.IncomingMessage} request
181
+ * @param {http.ServerResponse} response
182
+ */
183
+ async call ( request, response ) {
184
+
185
+ if ( request.url !== this.path ) {
186
+
187
+ return this.respond ( request, response, new Error ( 'URL Incorrect' ) )
188
+ }
189
+
190
+ if ( !this.cors ( request, response ) ) return
191
+
192
+ let body = Object.create ( null )
193
+
194
+ try {
195
+
196
+ body = await parseHTTPBody ( request )
197
+
198
+ if ( !body || 'object' !== typeof body ) throw new Error ( 'Content Invalid' )
199
+
200
+ } catch ( error ) {
201
+
202
+ return this.respond ( request, response, error )
203
+ }
204
+
205
+ // global unique id
206
+ const traceId = request.headers [ 'x-trace-id' ]
207
+
208
+ // service name, required
209
+ const caller = request.headers [ 'x-caller' ] || 'anonymous'
210
+
211
+ // client ip or caller service ip
212
+ const ip = request.headers [ 'x-ip' ] || request.socket.remoteAddress
213
+
214
+ // startup client ip
215
+ const sourceIP = request.headers [ 'x-real-ip' ]
216
+
217
+ const { action, params = [ ] } = body
218
+
219
+ const context = Global.genContext ( { traceId, caller, sourceIP, ip } )
220
+
221
+ const format = await this.rpc.call ( action, params, context )
222
+
223
+ this.respond ( request, response, format )
224
+ }
225
+
226
+
227
+
228
+ /**
229
+ * HTTP Response Catch
230
+ * @param {http.IncomingMessage} request
231
+ * @param {http.ServerResponse} response
232
+ * @param {Object} format
233
+ * @param {Boolean} format.success
234
+ * @param {Error} format.error
235
+ * @param {any} format.body
236
+ */
237
+ respond ( request, response, format ) {
238
+
239
+ let formatString = ''
240
+
241
+ try {
242
+
243
+ formatString = JSON.stringify ( format )
244
+ } catch ( { message, stack } ) {
245
+
246
+ delete format.body
247
+
248
+ format.success = false
249
+
250
+ format.error = {
251
+ message,
252
+ stack
253
+ }
254
+
255
+ formatString = JSON.stringify ( format )
256
+ }
257
+
258
+ response.setHeader ( 'Content-Type', 'application/json' )
259
+
260
+ response.setHeader ( 'Content-Length', Buffer.byteLength ( formatString ) )
261
+
262
+ response.end ( formatString )
263
+ }
264
+
265
+
266
+
267
+ /**
268
+ * HTTP RPC
269
+ * @param {String|URL|http.RequestOptions} url
270
+ * @param {String} action 函数名称
271
+ * @param {Array} params 参数列表
272
+ * @param {Context} context 上下文
273
+ */
274
+ static async call ( url, action, params, context ) {
275
+
276
+ if ( !context || !context.traceId ) {
277
+
278
+ context = Global.getContext ( )
279
+ }
280
+
281
+ const { traceId, caller, sourceIP } = context
282
+
283
+ const headers = {
284
+ 'Content-Type': 'application/json',
285
+ 'x-trace-id': String ( traceId ),
286
+ }
287
+
288
+ if ( caller ) headers [ 'x-caller' ] = String ( caller )
289
+
290
+ if ( sourceIP ) headers [ 'x-real-ip' ] = sourceIP
291
+
292
+ headers [ 'x-ip' ] = getIPAddress ( 4 ) [ 0 ]
293
+
294
+ const format = await httpRequest ( url, {
295
+ headers
296
+ }, JSON.stringify ( { action, params } ) )
297
+
298
+ if ( 'string' === typeof format ) throw new Error ( format )
299
+
300
+ const { error, body } = format
301
+
302
+ if ( error ) {
303
+
304
+ const asyncError = new Error ( error.message )
305
+
306
+ throw asyncError
307
+ } else {
308
+
309
+ return body
310
+ }
311
+ }
327
312
  }