oox 0.0.6 → 0.1.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/util.js CHANGED
@@ -1,352 +1,373 @@
1
-
2
- const os = require ( 'os' )
3
-
4
- const http = require ( 'http' )
5
-
6
- const https = require ( 'https' )
7
-
8
- const querystring = require('querystring')
9
-
10
- const Context = require ( './rpc/context.class' )
11
-
12
-
13
-
14
- exports.getIPAddress = function ( version = 4 ) {
15
-
16
- const interfaces = os.networkInterfaces ( )
17
-
18
- const ip = [ ]
19
-
20
- for ( const name of Object.keys ( interfaces ) )
21
- for ( const intf of interfaces [ name ] )
22
- if ( intf.mac !== '00:00:00:00:00:00' )
23
- if ( ( version !== 4 && version !== 6 ) || 'IPv' + version === intf.family )
24
- ip.push ( intf.address )
25
-
26
- if ( !ip.length ) {
27
- if ( version !== 6 ) ip.push ( '127.0.0.1' )
28
- if ( version !== 4 ) ip.push ( '::1' )
29
- }
30
-
31
- return ip
32
- }
33
-
34
-
35
-
36
- /**
37
- * String => Buffer
38
- * @param {*} stream
39
- * @param {*} totalLength
40
- * @returns {Promise<Buffer>}
41
- */
42
- exports.stream2buffer = function ( stream, totalLength=0 ) {
43
-
44
- return new Promise ( function ( resolve, reject ) {
45
-
46
- let buffers = [ ]
47
-
48
- stream.on ( 'error', reject )
49
-
50
- if ( totalLength ) {
51
-
52
- stream.on ( 'data', function ( data ) { buffers.push ( data ) } )
53
- } else {
54
-
55
- stream.on ( 'data', function ( data ) {
56
- buffers.push ( data )
57
- totalLength += data.length
58
- } )
59
- }
60
-
61
- stream.on ( 'end', function ( ) { resolve ( Buffer.concat ( buffers, totalLength ) ) } )
62
- } )
63
- }
64
-
65
-
66
-
67
- /**
68
- * Request => JSONObject
69
- * @param {http.IncomingMessage} request
70
- */
71
- exports.parseHTTPBody = async function ( request ) {
72
-
73
- if ( request.method === 'GET' ) return null
74
-
75
- let contentType = request.headers [ 'content-type' ]
76
-
77
- // application/json; charset=utf-8
78
- if ( contentType ) contentType = contentType.split ( ';' ) [ 0 ].trim ( )
79
-
80
- const contentSize = request.headers [ 'content-length' ]
81
-
82
- const buffer = await exports.stream2buffer ( request, +contentSize || 0 )
83
-
84
- if ( contentSize && buffer.length !== +contentSize ) throw new Error ( 'Content-Length Incorrect' )
85
-
86
- const bodyString = buffer.toString ( )
87
-
88
- /*
89
- if ( 'application/x-www-form-urlencoded' === contentType )
90
- return querystring.parse ( bodyString )
91
- */
92
-
93
- try {
94
-
95
- return JSON.parse ( bodyString )
96
- } catch ( error ) {
97
-
98
- return bodyString
99
- }
100
- }
101
-
102
-
103
-
104
- /**
105
- * http request
106
- * @param {URL|String|http.RequestOptions} url
107
- * @param {http.RequestOptions|String} options
108
- * @param {String} body
109
- */
110
- exports.httpRequest = function ( url, options, body ) {
111
-
112
- if ( 'string' === typeof options ) {
113
-
114
- body = options
115
- options = { }
116
- }
117
-
118
- return new Promise ( function ( resolve, reject ) {
119
-
120
- const request = http.request ( url, options, async function ( response ) {
121
-
122
- try {
123
-
124
- const result = await exports.parseHTTPBody ( response )
125
-
126
- resolve ( result )
127
- } catch ( error ) {
128
-
129
- const decoration = new Error ( `${response.statusCode} - ${error.message}` )
130
-
131
- reject ( decoration )
132
- }
133
- } )
134
-
135
- request.on ( 'error', reject )
136
-
137
- if ( body ) {
138
-
139
- request.method = 'POST'
140
-
141
- request.setHeader ( 'Content-Type', 'application/json' )
142
-
143
- request.setHeader ( 'Content-Length', Buffer.byteLength ( body ) )
144
-
145
- request.write ( body )
146
- }
147
-
148
- request.end ( )
149
- } )
150
- }
151
-
152
-
153
-
154
- exports.getAllCallablePropertyNames = function ( obj ) {
155
-
156
- if ( !obj ) return [ ]
157
-
158
- let props = [ ], tmpProps = [ ], index = 0, size = 0, tmpProp = ''
159
-
160
- const bans = [ "constructor", "__defineGetter__", "__defineSetter__"
161
- , "hasOwnProperty", "__lookupGetter__", "__lookupSetter__"
162
- , "isPrototypeOf", "propertyIsEnumerable", "toString"
163
- , "valueOf", "__proto__", "toLocaleString" ]
164
-
165
- do {
166
-
167
- tmpProps = Object.getOwnPropertyNames ( obj )
168
-
169
- index = -1, size = tmpProps.length
170
-
171
- while ( ++index < size ) {
172
-
173
- tmpProp = tmpProps [ index ]
174
-
175
- if ( !props.includes ( tmpProp ) && !bans.includes ( tmpProp ) ) {
176
-
177
- props.push ( tmpProp )
178
- }
179
- }
180
-
181
- } while ( obj = Object.getPrototypeOf ( obj ) )
182
-
183
- return props
184
- }
185
-
186
-
187
-
188
- /**
189
- *
190
- * @param {Object} methods
191
- * @param {Map<String,Function>} kvMethods
192
- * @param {Array<String>} nameStack
193
- */
194
- exports.genKVMethods = function ( methods, kvMethods=new Map(), nameStack=[] ) {
195
-
196
- let keys = exports.getAllCallablePropertyNames ( methods )
197
-
198
- let index = -1, size = keys.length
199
-
200
- while ( ++index < size ) {
201
-
202
- let key = keys [ index ]
203
-
204
- /**
205
- * @type {Function}
206
- */
207
- let val = methods [ key ]
208
-
209
- if ( 'function' === typeof val ) {
210
-
211
- kvMethods.set ( nameStack.concat ( key ).join ( '.' ), val.bind ( methods ) )
212
- } else {
213
-
214
- exports.genKVMethods ( val, kvMethods, nameStack.concat ( key ) )
215
- }
216
- }
217
-
218
- return kvMethods
219
- }
220
-
221
-
222
-
223
- /**
224
- * parse traceId from execution stack
225
- * @param {String} stack
226
- * @returns {String}
227
- */
228
- exports.getTraceIdByStack = function ( stack ) {
229
-
230
- if ( !stack ) {
231
-
232
- let trace = { }
233
-
234
- Error.captureStackTrace ( trace )
235
-
236
- stack = trace.stack
237
- }
238
-
239
- const prefix = 'OOXTrace.<computed>'
240
-
241
- const index = stack.indexOf ( prefix )
242
-
243
- if ( index === -1 ) return null
244
-
245
- return stack.slice ( index ).match ( /(?<=as\s).*?(?=\s|\])/ ) [ 0 ]
246
- }
247
-
248
-
249
-
250
- /**
251
- *
252
- * @param {String} traceId 全局唯一请求ID
253
- * @param {Map<String,Function>} methods 服务函数扁平化列表
254
- */
255
- exports.genOOXTrace = function ( traceId, methods ) {
256
-
257
- const OOXTrace = { /* OOXTrace.<computed> [as traceId] */ }
258
-
259
-
260
-
261
- /**
262
- * trace magic function
263
- * @param {String} action
264
- * @param {Array} params
265
- * @param {Context} context
266
- */
267
- OOXTrace [ traceId ] = async function ( action, params, context ) {
268
-
269
- const __proxy = '__proxy', _proxy = '_proxy'
270
-
271
-
272
-
273
- // 目标函数
274
- const target = methods.get ( action )
275
-
276
- // 目标代理函数
277
- const targetProxy = methods.get ( action + _proxy )
278
-
279
- // 即不存在目标也不存在目标代理时, 报错函数不存在
280
- if ( !target && !targetProxy ) throw new Error ( 'Invalid Action [' + action + ']' )
281
-
282
-
283
-
284
- // 最顶层代理
285
- const topProxy = methods.get ( __proxy )
286
-
287
- if ( topProxy ) {
288
-
289
- const proxyReturns = await topProxy ( action, params, context )
290
-
291
- if ( proxyReturns !== undefined ) return proxyReturns
292
- }
293
-
294
-
295
-
296
- // 'x.y.z' => [ 'x', 'y', 'z' ]
297
- const nameStack = action.split ( '.' ), size = nameStack.length - 1
298
-
299
- let index = -1, proxyPrefix = ''
300
-
301
-
302
-
303
- // 根代理遍历
304
- while ( ++index < size ) {
305
-
306
- // x.
307
- // x.y.
308
- proxyPrefix += nameStack [ index ] + '.'
309
-
310
- // x.__proxy
311
- // x.y.__proxy
312
- const rootProxy = methods.get ( proxyPrefix + __proxy )
313
-
314
- // x.__proxy ( 'y.z', ... )
315
- // x.y.__proxy ( 'z', ... )
316
- if ( rootProxy ) {
317
-
318
- const proxyReturns = await rootProxy ( nameStack.slice ( index ).join ( '.' ), params, context )
319
-
320
- if ( proxyReturns !== undefined ) return proxyReturns
321
- }
322
- }
323
-
324
-
325
-
326
- // 同级代理
327
- const layerProxy = methods.get ( proxyPrefix + _proxy )
328
-
329
- if ( layerProxy ) {
330
-
331
- const proxyReturns = await layerProxy ( nameStack [ index ], params, context )
332
-
333
- if ( proxyReturns !== undefined ) return proxyReturns
334
- }
335
-
336
-
337
-
338
- if ( targetProxy ) {
339
-
340
- const proxyReturns = await targetProxy ( params, context )
341
-
342
- if ( proxyReturns !== undefined ) return proxyReturns
343
- }
344
-
345
-
346
-
347
- // make sure target action execute after all proxies
348
- if ( target ) return await target ( ...params )
349
- }
350
-
351
- return OOXTrace
352
- }
1
+
2
+ const os = require ( 'os' )
3
+
4
+ const http = require ( 'http' )
5
+
6
+ const https = require ( 'https' )
7
+
8
+ const querystring = require('querystring')
9
+
10
+ const Context = require ( './rpc/context.class' )
11
+
12
+ const Middleware = require ( './middleware' )
13
+
14
+
15
+
16
+ exports.getIPAddress = function ( version = 4 ) {
17
+
18
+ const interfaces = os.networkInterfaces ( )
19
+
20
+ const ip = [ ]
21
+
22
+ for ( const name of Object.keys ( interfaces ) )
23
+ for ( const intf of interfaces [ name ] )
24
+ if ( intf.mac !== '00:00:00:00:00:00' )
25
+ if ( ( version !== 4 && version !== 6 ) || 'IPv' + version === intf.family )
26
+ ip.push ( intf.address )
27
+
28
+ if ( !ip.length ) {
29
+ if ( version !== 6 ) ip.push ( '127.0.0.1' )
30
+ if ( version !== 4 ) ip.push ( '::1' )
31
+ }
32
+
33
+ return ip
34
+ }
35
+
36
+
37
+
38
+ /**
39
+ * String => Buffer
40
+ * @param {*} stream
41
+ * @param {*} totalLength
42
+ * @returns {Promise<Buffer>}
43
+ */
44
+ exports.stream2buffer = function ( stream, totalLength=0 ) {
45
+
46
+ return new Promise ( function ( resolve, reject ) {
47
+
48
+ let buffers = [ ]
49
+
50
+ stream.on ( 'error', reject )
51
+
52
+ if ( totalLength ) {
53
+
54
+ stream.on ( 'data', function ( data ) { buffers.push ( data ) } )
55
+ } else {
56
+
57
+ stream.on ( 'data', function ( data ) {
58
+ buffers.push ( data )
59
+ totalLength += data.length
60
+ } )
61
+ }
62
+
63
+ stream.on ( 'end', function ( ) { resolve ( Buffer.concat ( buffers, totalLength ) ) } )
64
+ } )
65
+ }
66
+
67
+
68
+
69
+ /**
70
+ * Request => JSONObject
71
+ * @param {http.IncomingMessage} request
72
+ */
73
+ exports.parseHTTPBody = async function ( request ) {
74
+
75
+ if ( request.method === 'GET' ) return null
76
+
77
+ let contentType = request.headers [ 'content-type' ]
78
+
79
+ // application/json; charset=utf-8
80
+ if ( contentType ) contentType = contentType.split ( ';' ) [ 0 ].trim ( )
81
+
82
+ const contentSize = request.headers [ 'content-length' ]
83
+
84
+ const buffer = await exports.stream2buffer ( request, +contentSize || 0 )
85
+
86
+ if ( contentSize && buffer.length !== +contentSize ) throw new Error ( 'Content-Length Incorrect' )
87
+
88
+ const bodyString = buffer.toString ( )
89
+
90
+ /*
91
+ if ( 'application/x-www-form-urlencoded' === contentType )
92
+ return querystring.parse ( bodyString )
93
+ */
94
+
95
+ try {
96
+
97
+ return JSON.parse ( bodyString )
98
+ } catch ( error ) {
99
+
100
+ return bodyString
101
+ }
102
+ }
103
+
104
+
105
+
106
+ /**
107
+ * http request
108
+ * @param {URL|String|http.RequestOptions} url
109
+ * @param {http.RequestOptions|String} options
110
+ * @param {String} body
111
+ */
112
+ exports.httpRequest = function ( url, options, body ) {
113
+
114
+ if ( 'string' === typeof options ) {
115
+
116
+ body = options
117
+ options = { }
118
+ }
119
+
120
+ return new Promise ( function ( resolve, reject ) {
121
+
122
+ const request = http.request ( url, options, async function ( response ) {
123
+
124
+ try {
125
+
126
+ const result = await exports.parseHTTPBody ( response )
127
+
128
+ resolve ( result )
129
+ } catch ( error ) {
130
+
131
+ const decoration = new Error ( `${response.statusCode} - ${error.message}` )
132
+
133
+ reject ( decoration )
134
+ }
135
+ } )
136
+
137
+ request.on ( 'error', reject )
138
+
139
+ if ( body ) {
140
+
141
+ request.method = 'POST'
142
+
143
+ request.setHeader ( 'Content-Type', 'application/json' )
144
+
145
+ request.setHeader ( 'Content-Length', Buffer.byteLength ( body ) )
146
+
147
+ request.write ( body )
148
+ }
149
+
150
+ request.end ( )
151
+ } )
152
+ }
153
+
154
+
155
+
156
+ exports.getAllCallablePropertyNames = function ( obj ) {
157
+
158
+ if ( !obj ) return [ ]
159
+
160
+ let props = [ ], tmpProps = [ ], index = 0, size = 0, tmpProp = ''
161
+
162
+ const bans = [ "constructor", "__defineGetter__", "__defineSetter__"
163
+ , "hasOwnProperty", "__lookupGetter__", "__lookupSetter__"
164
+ , "isPrototypeOf", "propertyIsEnumerable", "toString"
165
+ , "valueOf", "__proto__", "toLocaleString" ]
166
+
167
+ do {
168
+
169
+ tmpProps = Object.getOwnPropertyNames ( obj )
170
+
171
+ index = -1, size = tmpProps.length
172
+
173
+ while ( ++index < size ) {
174
+
175
+ tmpProp = tmpProps [ index ]
176
+
177
+ if ( !props.includes ( tmpProp ) && !bans.includes ( tmpProp ) ) {
178
+
179
+ props.push ( tmpProp )
180
+ }
181
+ }
182
+
183
+ } while ( obj = Object.getPrototypeOf ( obj ) )
184
+
185
+ return props
186
+ }
187
+
188
+
189
+
190
+ /**
191
+ *
192
+ * @param {Object} methods
193
+ * @param {Map<String,Function>} kvMethods
194
+ * @param {Array<String>} nameStack
195
+ */
196
+ exports.genKVMethods = function ( methods, kvMethods=new Map(), nameStack=[] ) {
197
+
198
+ let keys = exports.getAllCallablePropertyNames ( methods )
199
+
200
+ let index = -1, size = keys.length
201
+
202
+ while ( ++index < size ) {
203
+
204
+ let key = keys [ index ]
205
+
206
+ /**
207
+ * @type {Function}
208
+ */
209
+ let val = methods [ key ]
210
+
211
+ if ( 'function' === typeof val ) {
212
+
213
+ const action = nameStack.concat ( key ).join ( '.' )
214
+
215
+ // 中間件函數脫殼綁定
216
+ Middleware.wrappedActions.set ( action, val )
217
+
218
+ kvMethods.set ( action, val.bind ( methods ) )
219
+ } else {
220
+
221
+ exports.genKVMethods ( val, kvMethods, nameStack.concat ( key ) )
222
+ }
223
+ }
224
+
225
+ return kvMethods
226
+ }
227
+
228
+
229
+
230
+ /**
231
+ * parse traceId from execution stack
232
+ * @param {String} stack
233
+ * @returns {String}
234
+ */
235
+ exports.getTraceIdByStack = function ( stack ) {
236
+
237
+ if ( !stack ) {
238
+
239
+ let trace = { }
240
+
241
+ Error.captureStackTrace ( trace )
242
+
243
+ stack = trace.stack
244
+ }
245
+
246
+ const prefix = 'OOXTrace.<computed>'
247
+
248
+ const index = stack.indexOf ( prefix )
249
+
250
+ if ( index === -1 ) return null
251
+
252
+ return stack.slice ( index ).match ( /(?<=as\s).*?(?=\s|\])/ ) [ 0 ]
253
+ }
254
+
255
+
256
+
257
+ /**
258
+ *
259
+ * @param {String} traceId 全局唯一请求ID
260
+ * @param {Map<String,Function>} methods 服务函数扁平化列表
261
+ */
262
+ exports.genOOXTrace = function ( traceId, methods ) {
263
+
264
+ const OOXTrace = { /* OOXTrace.<computed> [as traceId] */ }
265
+
266
+
267
+
268
+ /**
269
+ * trace magic function
270
+ * @param {String} action
271
+ * @param {Array} params
272
+ * @param {Context} context
273
+ */
274
+ OOXTrace [ traceId ] = async function ( action, params, context ) {
275
+
276
+ const __proxy = '__proxy', _proxy = '_proxy'
277
+
278
+
279
+
280
+ // 目标函数
281
+ const target = methods.get ( action )
282
+
283
+ // 目标代理函数
284
+ const targetProxy = methods.get ( action + _proxy )
285
+
286
+ // 即不存在目标也不存在目标代理时, 报错函数不存在
287
+ if ( !target && !targetProxy ) throw new Error ( 'Invalid Action [' + action + ']' )
288
+
289
+
290
+
291
+ // 最顶层代理
292
+ const topProxy = methods.get ( __proxy )
293
+
294
+ if ( topProxy ) {
295
+
296
+ const proxyReturns = await topProxy ( action, params, context )
297
+
298
+ if ( proxyReturns !== undefined ) return proxyReturns
299
+ }
300
+
301
+
302
+
303
+ // 'x.y.z' => [ 'x', 'y', 'z' ]
304
+ const nameStack = action.split ( '.' ), size = nameStack.length - 1
305
+
306
+ let index = -1, proxyPrefix = ''
307
+
308
+
309
+
310
+ // 根代理遍历
311
+ while ( ++index < size ) {
312
+
313
+ // x.
314
+ // x.y.
315
+ proxyPrefix += nameStack [ index ] + '.'
316
+
317
+ // x.__proxy
318
+ // x.y.__proxy
319
+ const rootProxy = methods.get ( proxyPrefix + __proxy )
320
+
321
+ // x.__proxy ( 'y.z', ... )
322
+ // x.y.__proxy ( 'z', ... )
323
+ if ( rootProxy ) {
324
+
325
+ const proxyReturns = await rootProxy ( nameStack.slice ( index ).join ( '.' ), params, context )
326
+
327
+ if ( proxyReturns !== undefined ) return proxyReturns
328
+ }
329
+ }
330
+
331
+
332
+
333
+ // 同级代理
334
+ const layerProxy = methods.get ( proxyPrefix + _proxy )
335
+
336
+ if ( layerProxy ) {
337
+
338
+ const proxyReturns = await layerProxy ( nameStack [ index ], params, context )
339
+
340
+ if ( proxyReturns !== undefined ) return proxyReturns
341
+ }
342
+
343
+
344
+
345
+ if ( targetProxy ) {
346
+
347
+ const proxyReturns = await targetProxy ( params, context )
348
+
349
+ if ( proxyReturns !== undefined ) return proxyReturns
350
+ }
351
+
352
+
353
+
354
+ // make sure target action execute after all proxies
355
+ if ( target ) {
356
+
357
+ const sourceMethod = Middleware.wrappedActions.get ( action )
358
+
359
+ const middlewareNames = Middleware.actionMiddlewares.get ( sourceMethod )
360
+
361
+ if ( middlewareNames && middlewareNames.length ) for ( const name of middlewareNames ) {
362
+
363
+ const middleware = Middleware.middlewares.get ( name )
364
+
365
+ await middleware ( action, params, context )
366
+ }
367
+
368
+ return await target ( ...params )
369
+ }
370
+ }
371
+
372
+ return OOXTrace
373
+ }