@weave-js/core 0.9.4 → 0.11.1

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.
Files changed (98) hide show
  1. package/lib/ExtendableError.js +33 -0
  2. package/lib/broker/context.js +25 -13
  3. package/lib/broker/{default-options.js → defaultOptions.js} +25 -6
  4. package/lib/broker/index.js +224 -194
  5. package/lib/buildRuntime.js +70 -0
  6. package/lib/cache/adapters/base.js +143 -0
  7. package/lib/cache/adapters/inMemory.js +154 -0
  8. package/lib/cache/adapters/inMemoryLru.js +140 -0
  9. package/lib/cache/adapters/index.js +46 -0
  10. package/lib/cache/base.js +49 -44
  11. package/lib/cache/lock.js +21 -4
  12. package/lib/constants.js +8 -5
  13. package/lib/errorHandler.js +19 -0
  14. package/lib/errors.js +17 -10
  15. package/lib/helper/{define-action.js → defineAction.js} +3 -1
  16. package/lib/helper/{define-broker-options.js → defineBrokerOptions.js} +2 -0
  17. package/lib/helper/{define-service.js → defineService.js} +4 -1
  18. package/lib/index.js +17 -92
  19. package/lib/logger/format/asHumanReadable.js +4 -3
  20. package/lib/logger/index.js +7 -1
  21. package/lib/logger/levels.js +8 -7
  22. package/lib/logger/tools.js +4 -0
  23. package/lib/logger/utils/format.js +18 -4
  24. package/lib/metrics/constants.js +8 -6
  25. package/lib/metrics/types/gauge.js +1 -1
  26. package/lib/middlewares/action-hooks/index.js +62 -14
  27. package/lib/middlewares/bulkhead/index.js +5 -4
  28. package/lib/middlewares/cache/index.js +106 -0
  29. package/lib/middlewares/circuit-breaker/index.js +41 -16
  30. package/lib/middlewares/context-tracker/index.js +3 -3
  31. package/lib/middlewares/error-handler/index.js +3 -3
  32. package/lib/middlewares/index.js +2 -1
  33. package/lib/middlewares/metrics/getMiddlewareWrapper.js +2 -2
  34. package/lib/middlewares/metrics/index.js +2 -2
  35. package/lib/middlewares/retry/index.js +11 -10
  36. package/lib/middlewares/timeout/index.js +5 -5
  37. package/lib/middlewares/tracing/index.js +27 -14
  38. package/lib/middlewares/tracing/tags.js +43 -0
  39. package/lib/middlewares/validator/index.js +6 -6
  40. package/lib/registry/{action-endpoint.js → actionEndpoint.js} +0 -0
  41. package/lib/registry/collections/{action-collection.js → actionCollection.js} +2 -2
  42. package/lib/registry/collections/{endpoint-collection.js → endpointCollection.js} +19 -3
  43. package/lib/registry/collections/{event-collection.js → eventCollection.js} +15 -9
  44. package/lib/registry/collections/{node-collection.js → nodeCollection.js} +1 -1
  45. package/lib/registry/collections/{service-collection.js → serviceCollection.js} +2 -2
  46. package/lib/registry/{event-endpoint.js → eventEndpoint.js} +1 -1
  47. package/lib/registry/node.js +1 -1
  48. package/lib/registry/registry.js +19 -38
  49. package/lib/registry/service/service.js +2 -2
  50. package/lib/registry/{service-item.js → serviceItem.js} +1 -1
  51. package/lib/runtime/{init-action-invoker.js → initActionInvoker.js} +3 -3
  52. package/lib/runtime/initCache.js +19 -0
  53. package/lib/runtime/{init-context-factory.js → initContextFactory.js} +2 -2
  54. package/lib/runtime/{init-eventbus.js → initEventbus.js} +11 -10
  55. package/lib/runtime/{init-logger.js → initLogger.js} +0 -0
  56. package/lib/runtime/{init-metrics.js → initMetrics.js} +11 -10
  57. package/lib/runtime/{init-middleware-manager.js → initMiddlewareManager.js} +1 -1
  58. package/lib/runtime/{init-registry.js → initRegistry.js} +1 -1
  59. package/lib/runtime/{init-service-manager.js → initServiceManager.js} +0 -0
  60. package/lib/runtime/{init-tracing.js → initTracing.js} +2 -1
  61. package/lib/runtime/{init-transport.js → initTransport.js} +0 -0
  62. package/lib/runtime/{init-uuid-factory.js → initUuidFactory.js} +0 -0
  63. package/lib/runtime/{init-validator.js → initValidator.js} +1 -1
  64. package/lib/tracing/collectors/base.js +11 -19
  65. package/lib/tracing/collectors/event.js +2 -2
  66. package/lib/tracing/collectors/index.js +2 -2
  67. package/lib/tracing/span.js +8 -6
  68. package/lib/transport/InboundTransformStream.js +75 -0
  69. package/lib/transport/adapters/{adapter-base.js → adapteBase.js} +16 -1
  70. package/lib/transport/adapters/adapters.js +1 -1
  71. package/lib/transport/adapters/dummy/index.js +3 -3
  72. package/lib/transport/adapters/index.js +1 -1
  73. package/lib/transport/adapters/tcp/discovery/index.js +45 -31
  74. package/lib/transport/adapters/tcp/index.js +20 -13
  75. package/lib/transport/adapters/tcp/tcpReader.js +1 -0
  76. package/lib/transport/adapters/tcp/tcpWriteStream.js +1 -1
  77. package/lib/transport/adapters/tcp/tcpWriter.js +2 -2
  78. package/lib/transport/createMessage.js +11 -0
  79. package/lib/transport/createTransport.js +215 -172
  80. package/lib/transport/errorPayloadFactory.js +18 -0
  81. package/lib/transport/{message-handlers.js → messageHandlers.js} +92 -23
  82. package/lib/transport/messageTypes.js +23 -0
  83. package/lib/types.js +86 -75
  84. package/lib/utils/index.js +1 -1
  85. package/lib/utils/options.js +4 -2
  86. package/lib/utils/{restore-error.js → restoreError.js} +1 -1
  87. package/package.json +6 -12
  88. package/CHANGELOG.md +0 -1317
  89. package/lib/cache/index.js +0 -48
  90. package/lib/cache/memory.js +0 -91
  91. package/lib/middlewares/tracing/buildTags.js +0 -17
  92. package/lib/new-errors.js +0 -25
  93. package/lib/runtime/init-cache.js +0 -10
  94. package/lib/tracing/collectors/console.js +0 -34
  95. package/lib/tracing/index.js +0 -3
  96. package/lib/tracing/tracer.js +0 -64
  97. package/lib/transport/message-types.js +0 -59
  98. package/lib/transport/message.js +0 -16
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * Author: Kevin Ries (kevin@fachw3rk.de)
3
3
  * -----
4
- * Copyright 2020 Fachwerk
4
+ * Copyright 2021 Fachwerk
5
5
  */
6
6
 
7
7
  /**
@@ -9,13 +9,16 @@
9
9
  * @typedef {import('../types.js').TransportAdapter} TransportAdapter
10
10
  * @typedef {import('../types.js').Transport} Transport
11
11
  * @typedef {import('../types').TransportMessage} TransportMessage
12
+ * @typedef {import('../types').Context} Context
12
13
  */
13
14
 
14
15
  // Own packages
15
16
  const { WeaveError, WeaveQueueSizeExceededError } = require('../errors')
16
- const MessageTypes = require('./message-types')
17
+ const { createMessage } = require('./createMessage')
18
+ const MessageTypes = require('./messageTypes')
17
19
  const utils = require('@weave-js/utils')
18
- const createMessageHandler = require('./message-handlers')
20
+ const createMessageHandler = require('./messageHandlers')
21
+ const { errorPayloadFactory } = require('./errorPayloadFactory')
19
22
 
20
23
  /**
21
24
  * Create a Transport adapter
@@ -25,133 +28,24 @@ const createMessageHandler = require('./message-handlers')
25
28
  */
26
29
  exports.createTransport = (runtime, adapter) => {
27
30
  const transport = Object.create(null)
28
- const { nodeId, middlewareHandler } = runtime
31
+ const { nodeId, middlewareHandler, createLogger } = runtime
29
32
 
30
33
  let heartbeatTimer
31
34
  let checkNodesTimer
32
35
  let checkOfflineNodesTimer
33
36
  let updateLocalNodeTimer
34
37
 
35
- const log = runtime.createLogger('TRANSPORT')
36
-
38
+ // Pending action store
37
39
  const pending = {
38
40
  requests: new Map(),
39
41
  requestStreams: new Map(),
40
- responseStreams: new Map()
41
- }
42
-
43
- // Outgoing request
44
- const doRequest = (context, resolve, reject) => {
45
- const isStream = utils.isStream(context.options.stream)
46
-
47
- const request = {
48
- targetNodeId: context.nodeId,
49
- action: context.action.name,
50
- context,
51
- resolve,
52
- reject,
53
- isStream
54
- }
55
-
56
- log.debug(`Send request for ${request.action} to node ${request.targetNodeId}.`)
57
-
58
- pending.requests.set(context.id, request)
59
-
60
- const payload = {
61
- id: context.id,
62
- action: context.action.name,
63
- data: context.data,
64
- timeout: context.options.timeout,
65
- meta: context.meta,
66
- level: context.level,
67
- metrics: context.metrics,
68
- requestId: context.requestId,
69
- parentId: context.parentId,
70
- isStream
71
- }
72
-
73
- // Handle object mode streams
74
- if (isStream) {
75
- if (utils.isStreamObjectMode(context.options.stream)) {
76
- payload.meta = payload.meta || {}
77
- payload.meta.$isObjectModeStream = true
78
- }
79
- payload.sequence = 0
80
- }
81
-
82
- const message = transport.createMessage(MessageTypes.MESSAGE_REQUEST, context.nodeId, payload)
83
-
84
- return transport.send(message)
85
- .then(() => {
86
- // send stream
87
- if (isStream) {
88
- const stream = context.options.stream
89
- payload.meta = {}
90
-
91
- if (utils.isStreamObjectMode(context.options.stream)) {
92
- payload.meta.$isObjectModeStream = true
93
- }
94
-
95
- stream.on('data', data => {
96
- stream.pause()
97
- const chunks = []
98
-
99
- // The chunk is larger than maxBufferSize
100
- if (data instanceof Buffer && runtime.options.transport.maxChunkSize > 0 && data.length > runtime.options.transport.maxChunkSize) {
101
- const length = data.length
102
- let i = 0
103
- while (i < length) {
104
- chunks.push(data.slice(i, i += runtime.options.transport.maxChunkSize))
105
- }
106
- } else {
107
- chunks.push(data)
108
- }
109
-
110
- // Send chunks from chunk buffer
111
- for (const chunk of chunks) {
112
- const payloadCopy = Object.assign({}, payload)
113
- payloadCopy.sequence = ++payload.sequence
114
- payloadCopy.chunk = chunk
115
- payloadCopy.isStream = true
116
- payload.data = null
117
-
118
- const message = transport.createMessage(MessageTypes.MESSAGE_REQUEST, context.nodeId, payloadCopy)
119
- transport.send(message)
120
- }
121
-
122
- // resume stream
123
- stream.resume()
124
- return
125
- })
126
-
127
- stream.on('end', () => {
128
- const payloadCopy = Object.assign({}, payload)
129
- payloadCopy.sequence = ++payload.sequence
130
- payloadCopy.chunk = null
131
- payloadCopy.isStream = false
132
- const message = transport.createMessage(MessageTypes.MESSAGE_REQUEST, context.nodeId, payloadCopy)
133
- return transport.send(message)
134
- })
135
-
136
- stream.on('error', (_) => {
137
- const payloadCopy = Object.assign({}, payload)
138
- payloadCopy.sequence = ++payload.sequence
139
- payloadCopy.chunk = null
140
- payloadCopy.isStream = false
141
-
142
- // todo: Attach error on payload
143
-
144
- const message = transport.createMessage(MessageTypes.MESSAGE_REQUEST, context.nodeId, payloadCopy)
145
- return transport.send(message)
146
- })
147
- }
148
- })
149
- .catch((error) => {
150
- reject(error)
151
- })
42
+ responseStreams: new Map(),
43
+ outboundResponseStreams: new Map(),
44
+ outboundRequestStreams: new Map()
152
45
  }
153
46
 
154
- transport.log = runtime.createLogger('TRANSPORT')
47
+ transport.log = createLogger('TRANSPORT')
48
+ transport.reconnectInProgress = false
155
49
  transport.isConnected = false
156
50
  transport.isDisconnecting = false
157
51
  transport.isReady = false
@@ -167,24 +61,24 @@ exports.createTransport = (runtime, adapter) => {
167
61
  }
168
62
  }
169
63
 
64
+ const getErrorPayload = errorPayloadFactory(runtime)
65
+
170
66
  transport.connect = () => {
171
67
  return new Promise(resolve => {
172
68
  transport.resolveConnect = resolve
173
69
  transport.log.info('Connecting to transport adapter...')
174
70
 
175
71
  const doConnect = (isTryReconnect) => {
176
- let reconnectInProgress = false
177
-
178
72
  const errorHandler = (error) => {
179
73
  // Skip reconnect, if the adapter is disconnecting or an reconnect is in progress.
180
- if (transport.isDisconnecting || reconnectInProgress) {
74
+ if (transport.isDisconnecting || transport.reconnectInProgress) {
181
75
  return
182
76
  }
183
77
 
184
78
  transport.log.warn('Connection failed')
185
79
  transport.log.debug(error)
186
80
 
187
- reconnectInProgress = true
81
+ transport.reconnectInProgress = true
188
82
 
189
83
  if (!error.skipRetry) {
190
84
  setTimeout(() => {
@@ -207,11 +101,11 @@ exports.createTransport = (runtime, adapter) => {
207
101
  transport.isConnected = false
208
102
  transport.isReady = false
209
103
 
210
- runtime.eventBus.broadcastLocal('$transporter.disconnected', { isGracefull: true })
104
+ runtime.eventBus.broadcastLocal('$transporter.disconnected', { isGraceful: true })
211
105
 
212
106
  stopTimers()
213
107
 
214
- const message = transport.createMessage(MessageTypes.MESSAGE_DISCONNECT)
108
+ const message = createMessage(MessageTypes.MESSAGE_DISCONNECT)
215
109
  return transport.send(message)
216
110
  .then(() => {
217
111
  adapter.close()
@@ -221,10 +115,10 @@ exports.createTransport = (runtime, adapter) => {
221
115
  })
222
116
  }
223
117
 
224
- transport.setReady = () => {
118
+ transport.setReady = async () => {
225
119
  if (transport.isConnected) {
226
120
  transport.isReady = true
227
- transport.sendNodeInfo()
121
+ await transport.sendNodeInfo()
228
122
  }
229
123
  }
230
124
 
@@ -233,16 +127,18 @@ exports.createTransport = (runtime, adapter) => {
233
127
  * @param {*} sender sender node ID.
234
128
  * @returns {Promise} Promise
235
129
  */
236
- transport.sendNodeInfo = (sender) => {
130
+ transport.sendNodeInfo = async (sender) => {
237
131
  if (!transport.isConnected || !transport.isReady) {
238
132
  return Promise.resolve()
239
133
  }
240
134
 
135
+ // Collect own node info and send it to remote nodes
241
136
  const info = runtime.registry.getLocalNodeInfo()
242
- const message = transport.createMessage(MessageTypes.MESSAGE_INFO, sender, {
137
+ const message = createMessage(MessageTypes.MESSAGE_INFO, sender, {
243
138
  ...info,
244
139
  instanceId: runtime.state.instanceId
245
140
  })
141
+
246
142
  return transport.send(message)
247
143
  }
248
144
 
@@ -251,28 +147,42 @@ exports.createTransport = (runtime, adapter) => {
251
147
  * @param {TransportMessage} message Message to send
252
148
  * @returns {Promise} Promise
253
149
  */
254
- transport.send = (message) => {
150
+ transport.send = async (message) => {
255
151
  transport.statistics.sent.packages = transport.statistics.sent.packages + 1
256
- log.verbose(`Send ${message.type.toUpperCase()} packet to ${message.targetNodeId || 'all nodes'}`)
152
+ transport.log.verbose(`Send ${message.type.toUpperCase()} packet to ${message.targetNodeId || 'all nodes'}`)
257
153
  return adapter.preSend(message)
258
154
  }
259
155
 
260
156
  transport.sendPing = (nodeId) => {
261
- const pingMessage = transport.createMessage(MessageTypes.MESSAGE_PING, nodeId, { dispatchTime: Date.now() })
157
+ const pingMessage = createMessage(MessageTypes.MESSAGE_PING, nodeId, { dispatchTime: Date.now() })
262
158
  return transport.send(pingMessage)
263
159
  }
264
160
 
161
+ /**
162
+ * Send discovery message to all nodes.
163
+ * @returns {void}
164
+ */
265
165
  transport.discoverNodes = () => {
266
- const discoveryMessage = transport.createMessage(MessageTypes.MESSAGE_DISCOVERY)
166
+ const discoveryMessage = createMessage(MessageTypes.MESSAGE_DISCOVERY)
267
167
  transport.send(discoveryMessage)
268
168
  }
269
169
 
270
- transport.discoverNode = (target) => {
271
- const discoveryMessage = transport.createMessage(MessageTypes.MESSAGE_DISCOVERY, target)
272
- transport.send(discoveryMessage)
170
+ /**
171
+ * Send discovery message to all nodes.
172
+ * @param{string} target - Target node ID
173
+ * @returns {Promise<void>} - Promise
174
+ */
175
+ transport.discoverNode = async (target) => {
176
+ const discoveryMessage = createMessage(MessageTypes.MESSAGE_DISCOVERY, target)
177
+ return transport.send(discoveryMessage)
273
178
  }
274
179
 
275
- transport.sendEvent = (context) => {
180
+ /**
181
+ * Send an event
182
+ * @param {Context} context - Context
183
+ * @returns {Promise<void>} - Promise
184
+ */
185
+ transport.sendEvent = async (context) => {
276
186
  const isBroadcast = context.eventType === 'broadcast'
277
187
 
278
188
  const payload = {
@@ -287,12 +197,12 @@ exports.createTransport = (runtime, adapter) => {
287
197
  isBroadcast
288
198
  }
289
199
 
290
- const message = transport.createMessage(MessageTypes.MESSAGE_EVENT, context.endpoint ? context.nodeId : null, payload)
200
+ const message = createMessage(MessageTypes.MESSAGE_EVENT, context.endpoint ? context.nodeId : null, payload)
291
201
  return transport.send(message)
292
202
  }
293
203
 
294
204
  transport.sendBroadcastEvent = (nodeId, eventName, data, groups) => {
295
- log.verbose(`Send ${eventName} to ${nodeId}`)
205
+ transport.log.verbose(`Send ${eventName} to ${nodeId}`)
296
206
 
297
207
  const payload = {
298
208
  data,
@@ -301,18 +211,20 @@ exports.createTransport = (runtime, adapter) => {
301
211
  isBroadcast: true
302
212
  }
303
213
 
304
- const message = transport.createMessage(MessageTypes.MESSAGE_EVENT, nodeId, payload)
305
- transport.send(message)
214
+ const message = createMessage(MessageTypes.MESSAGE_EVENT, nodeId, payload)
215
+ return transport.send(message)
306
216
  }
307
217
 
308
218
  transport.removePendingRequestsById = (requestId) => {
309
219
  pending.requests.delete(requestId)
310
220
  pending.requestStreams.delete(requestId)
311
221
  pending.responseStreams.delete(requestId)
222
+ pending.outboundResponseStreams.delete(requestId)
223
+ pending.outboundRequestStreams.delete(requestId)
312
224
  }
313
225
 
314
226
  transport.removePendingRequestsByNodeId = (nodeId) => {
315
- log.debug(`Remove pending requests for node ${nodeId}.`)
227
+ transport.log.debug(`Remove pending requests for node ${nodeId}.`)
316
228
  pending.requests.forEach((request, requestId) => {
317
229
  if (request.nodeId === nodeId) {
318
230
  pending.requests.delete(requestId)
@@ -324,15 +236,7 @@ exports.createTransport = (runtime, adapter) => {
324
236
  })
325
237
  }
326
238
 
327
- transport.createMessage = (type, targetNodeId, payload) => {
328
- return {
329
- type: type || MessageTypes.MESSAGE_UNKNOWN,
330
- targetNodeId,
331
- payload: payload || {}
332
- }
333
- }
334
-
335
- transport.request = (context) => {
239
+ transport.sendRequest = (context) => {
336
240
  // If the queue size is set, check the queue size and reject the job when the limit is reached.
337
241
  if (runtime.options.transport.maxQueueSize && runtime.options.transport.maxQueueSize < pending.requests.size) {
338
242
  return Promise.reject(new WeaveQueueSizeExceededError({
@@ -343,10 +247,142 @@ exports.createTransport = (runtime, adapter) => {
343
247
  }))
344
248
  }
345
249
 
346
- return new Promise((resolve, reject) => doRequest(context, resolve, reject))
250
+ return new Promise((resolve, reject) => {
251
+ const isStream = utils.isStream(context.options.stream)
252
+
253
+ const request = {
254
+ targetNodeId: context.nodeId,
255
+ action: context.action.name,
256
+ context,
257
+ resolve,
258
+ reject,
259
+ isStream
260
+ }
261
+
262
+ transport.log.debug(`Send request for ${request.action} to node ${request.targetNodeId}.`)
263
+
264
+ pending.requests.set(context.id, request)
265
+
266
+ const payload = {
267
+ id: context.id,
268
+ action: context.action.name,
269
+ data: context.data,
270
+ timeout: context.options.timeout,
271
+ meta: context.meta,
272
+ level: context.level,
273
+ metrics: context.metrics,
274
+ requestId: context.requestId,
275
+ parentId: context.parentId,
276
+ isStream
277
+ }
278
+
279
+ // Handle object mode streams
280
+ if (isStream) {
281
+ const stream = context.options.stream
282
+
283
+ if (!pending.outboundRequestStreams.has(payload.id)) {
284
+ pending.outboundRequestStreams.set(payload.id, stream)
285
+ }
286
+
287
+ if (utils.isStreamObjectMode(stream)) {
288
+ payload.meta = payload.meta || {}
289
+ payload.meta.$isObjectModeStream = true
290
+ }
291
+ payload.sequence = 0
292
+ }
293
+
294
+ const message = createMessage(MessageTypes.MESSAGE_REQUEST, context.nodeId, payload)
295
+
296
+ return transport.send(message)
297
+ .then(() => {
298
+ // send stream
299
+ if (isStream) {
300
+ const stream = context.options.stream
301
+ payload.meta = {}
302
+
303
+ if (utils.isStreamObjectMode(context.options.stream)) {
304
+ payload.meta.$isObjectModeStream = true
305
+ }
306
+
307
+ stream.on('data', data => {
308
+ stream.pause()
309
+ const chunks = []
310
+
311
+ // The chunk is larger than maxBufferSize
312
+ if (data instanceof Buffer && runtime.options.transport.maxChunkSize > 0 && data.length > runtime.options.transport.maxChunkSize) {
313
+ const length = data.length
314
+ let i = 0
315
+ while (i < length) {
316
+ chunks.push(data.slice(i, i += runtime.options.transport.maxChunkSize))
317
+ }
318
+ } else {
319
+ chunks.push(data)
320
+ }
321
+
322
+ // Send chunks from chunk buffer
323
+ for (const chunk of chunks) {
324
+ const payloadCopy = Object.assign({}, payload)
325
+ payloadCopy.sequence = ++payload.sequence
326
+ payloadCopy.chunk = chunk
327
+ payloadCopy.isStream = true
328
+ payload.data = null
329
+
330
+ const message = createMessage(MessageTypes.MESSAGE_REQUEST, context.nodeId, payloadCopy)
331
+ transport.send(message)
332
+ }
333
+
334
+ // resume stream
335
+ stream.resume()
336
+ return
337
+ })
338
+
339
+ stream.on('end', () => {
340
+ const payloadCopy = Object.assign({}, payload)
341
+
342
+ payloadCopy.sequence = ++payload.sequence
343
+ payloadCopy.chunk = null
344
+ payloadCopy.isStream = false
345
+
346
+ pending.outboundRequestStreams.delete(payload.id)
347
+
348
+ const message = createMessage(MessageTypes.MESSAGE_REQUEST, context.nodeId, payloadCopy)
349
+ return transport.send(message)
350
+ })
351
+
352
+ stream.on('error', (error) => {
353
+ const payloadCopy = Object.assign({}, payload)
354
+ payloadCopy.sequence = ++payload.sequence
355
+ payloadCopy.chunk = null
356
+ payloadCopy.isStream = false
357
+
358
+ if (error) {
359
+ payloadCopy.success = false
360
+ payloadCopy.error = getErrorPayload(error)
361
+ }
362
+
363
+ pending.outboundRequestStreams.delete(payload.id)
364
+
365
+ const message = createMessage(MessageTypes.MESSAGE_REQUEST, context.nodeId, payloadCopy)
366
+ return transport.send(message)
367
+ })
368
+ }
369
+ })
370
+ .catch((error) => {
371
+ reject(error)
372
+ })
373
+ })
347
374
  }
348
375
 
349
- transport.response = (target, contextId, data, meta, error) => {
376
+ /**
377
+ * Send response for an open request.
378
+ * @param {string} target - Target node ID
379
+ * @param {string} contextId - Context ID
380
+ * @param {any} data - Data
381
+ * @param {Object} meta - Meta data
382
+ * @param {WeaveError=} error - Error
383
+ * @returns {Promise<void>} - Promise
384
+ */
385
+ transport.sendResponse = (target, contextId, data, meta, error) => {
350
386
  // Check if data is a stream
351
387
  const isStream = utils.isStream(data)
352
388
 
@@ -360,19 +396,16 @@ exports.createTransport = (runtime, adapter) => {
360
396
 
361
397
  // If an error is occurs, we attach the an error object to the payload.
362
398
  if (error) {
363
- payload.error = {
364
- name: error.name,
365
- message: error.message,
366
- nodeId: error.nodeId || nodeId,
367
- code: error.code,
368
- type: error.type,
369
- stack: error.stack,
370
- data: error.data
371
- }
399
+ payload.error = getErrorPayload(error)
372
400
  }
373
401
 
374
402
  if (isStream) {
375
403
  const stream = data
404
+
405
+ if (!pending.outboundResponseStreams.has(payload.id)) {
406
+ pending.outboundResponseStreams.set(payload.id, stream)
407
+ }
408
+
376
409
  payload.data = null
377
410
  payload.sequence = 0
378
411
  payload.isStream = true
@@ -406,9 +439,9 @@ exports.createTransport = (runtime, adapter) => {
406
439
  payloadCopy.sequence = ++payload.sequence
407
440
 
408
441
  payloadCopy.chunk = chunk
409
- transport.log.debug('Send Stream chunk to ', target)
442
+ transport.log.debug(`Send Stream chunk to ${target}`)
410
443
 
411
- const message = transport.createMessage(MessageTypes.MESSAGE_RESPONSE, target, payloadCopy)
444
+ const message = createMessage(MessageTypes.MESSAGE_RESPONSE, target, payloadCopy)
412
445
  transport.send(message)
413
446
  }
414
447
 
@@ -424,10 +457,11 @@ exports.createTransport = (runtime, adapter) => {
424
457
  payloadCopy.chunk = null
425
458
  payloadCopy.isStream = false
426
459
 
427
- transport.log.debug('Send end stream chunk to ', target)
460
+ transport.log.debug(`Send end stream chunk to ${target}`)
428
461
 
429
- const message = transport.createMessage(MessageTypes.MESSAGE_RESPONSE, target, payloadCopy)
462
+ const message = createMessage(MessageTypes.MESSAGE_RESPONSE, target, payloadCopy)
430
463
  transport.send(message)
464
+ pending.outboundResponseStreams.delete(payload.id)
431
465
  })
432
466
 
433
467
  stream.on('error', (error) => {
@@ -439,18 +473,23 @@ exports.createTransport = (runtime, adapter) => {
439
473
 
440
474
  if (error) {
441
475
  payloadCopy.success = false
476
+ payloadCopy.error = getErrorPayload(error)
442
477
  }
443
- const message = transport.createMessage(MessageTypes.MESSAGE_RESPONSE, target, payloadCopy)
478
+
479
+ transport.log.debug(`Send closing chunk to ${target}`)
480
+
481
+ const message = createMessage(MessageTypes.MESSAGE_RESPONSE, target, payloadCopy)
444
482
  transport.send(message)
483
+ pending.outboundResponseStreams.delete(payload.id)
445
484
  })
446
485
 
447
486
  payload.data = null
448
- const message = transport.createMessage(MessageTypes.MESSAGE_RESPONSE, target, payload)
487
+ const message = createMessage(MessageTypes.MESSAGE_RESPONSE, target, payload)
449
488
  return transport.send(message)
450
489
  .then(() => stream.resume())
451
490
  }
452
491
 
453
- const message = transport.createMessage(MessageTypes.MESSAGE_RESPONSE, target, payload)
492
+ const message = createMessage(MessageTypes.MESSAGE_RESPONSE, target, payload)
454
493
  return transport.send(message)
455
494
  }
456
495
 
@@ -528,7 +567,11 @@ exports.createTransport = (runtime, adapter) => {
528
567
  adapter.subscribe(MessageTypes.MESSAGE_PONG, nodeId),
529
568
  adapter.subscribe(MessageTypes.MESSAGE_DISCONNECT),
530
569
  adapter.subscribe(MessageTypes.MESSAGE_HEARTBEAT),
531
- adapter.subscribe(MessageTypes.MESSAGE_EVENT, nodeId)
570
+ adapter.subscribe(MessageTypes.MESSAGE_EVENT, nodeId),
571
+ adapter.subscribe(MessageTypes.MESSAGE_RESPONSE_STREAM_BACKPRESSURE, nodeId),
572
+ adapter.subscribe(MessageTypes.MESSAGE_RESPONSE_STREAM_RESUME, nodeId),
573
+ adapter.subscribe(MessageTypes.MESSAGE_REQUEST_STREAM_BACKPRESSURE, nodeId),
574
+ adapter.subscribe(MessageTypes.MESSAGE_REQUEST_STREAM_RESUME, nodeId)
532
575
  ])
533
576
  }
534
577
 
@@ -567,7 +610,7 @@ exports.createTransport = (runtime, adapter) => {
567
610
  const node = runtime.registry.nodeCollection.localNode
568
611
  node.updateLocalInfo()
569
612
 
570
- log.verbose(`Send heartbeat from ${node.id}`)
613
+ transport.log.verbose(`Send heartbeat from ${node.id}`)
571
614
 
572
615
  const payload = {
573
616
  cpu: node.cpu,
@@ -575,7 +618,7 @@ exports.createTransport = (runtime, adapter) => {
575
618
  sequence: node.sequence
576
619
  }
577
620
 
578
- const message = transport.createMessage(MessageTypes.MESSAGE_HEARTBEAT, null, payload)
621
+ const message = createMessage(MessageTypes.MESSAGE_HEARTBEAT, null, payload)
579
622
  transport.send(message)
580
623
  }
581
624
 
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Error Payload factory
3
+ * @param {import("../types").Runtime} runtime Runtime
4
+ * @returns {function(Error)} Generate error payload object
5
+ */
6
+ const errorPayloadFactory = (runtime) => (error) => {
7
+ return {
8
+ name: error.name,
9
+ message: error.message,
10
+ nodeId: error.nodeId || runtime.nodeId,
11
+ code: error.code,
12
+ type: error.type,
13
+ stack: error.stack,
14
+ data: error.data
15
+ }
16
+ }
17
+
18
+ module.exports = { errorPayloadFactory }