@weave-js/core 0.10.0 → 0.12.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/.eslintrc.js +1 -1
- package/jest.config.js +1 -1
- package/lib/ExtendableError.js +33 -0
- package/lib/broker/context.js +58 -46
- package/lib/broker/{default-options.js → defaultOptions.js} +31 -13
- package/lib/broker/index.js +273 -251
- package/lib/buildRuntime.js +70 -0
- package/lib/cache/adapters/base.js +119 -0
- package/lib/cache/adapters/inMemory.js +154 -0
- package/lib/cache/adapters/inMemoryLru.js +140 -0
- package/lib/cache/adapters/index.js +10 -0
- package/lib/cache/getCacheKeyByObject.js +31 -0
- package/lib/cache/getPropertyFromDataOrMetadata.js +20 -0
- package/lib/cache/lock.js +34 -11
- package/lib/constants.js +11 -8
- package/lib/{error-handler.js → errorHandler.js} +8 -8
- package/lib/errors.js +46 -39
- package/lib/helper/{define-action.js → defineAction.js} +5 -3
- package/lib/helper/{define-broker-options.js → defineBrokerOptions.js} +4 -2
- package/lib/helper/{define-service.js → defineService.js} +6 -3
- package/lib/index.js +25 -22
- package/lib/logger/base.js +38 -29
- package/lib/logger/format/asHumanReadable.js +15 -14
- package/lib/logger/format/asJson.js +10 -10
- package/lib/logger/format/index.js +3 -3
- package/lib/logger/index.js +28 -25
- package/lib/logger/levels.js +23 -22
- package/lib/logger/tools.js +17 -13
- package/lib/logger/utils/colorize.js +23 -23
- package/lib/logger/utils/format.js +89 -65
- package/lib/metrics/common.js +47 -47
- package/lib/metrics/constants.js +44 -44
- package/lib/metrics/exporter/base.js +8 -8
- package/lib/metrics/exporter/event.js +20 -20
- package/lib/metrics/exporter/index.js +15 -15
- package/lib/metrics/index.js +2 -2
- package/lib/metrics/types/base.js +20 -20
- package/lib/metrics/types/counter.js +6 -6
- package/lib/metrics/types/gauge.js +24 -24
- package/lib/metrics/types/histogram.js +26 -26
- package/lib/metrics/types/index.js +6 -6
- package/lib/metrics/types/info.js +17 -17
- package/lib/middlewares/action-hooks/index.js +82 -34
- package/lib/middlewares/bulkhead/index.js +34 -33
- package/lib/middlewares/cache/index.js +106 -0
- package/lib/middlewares/circuit-breaker/index.js +85 -60
- package/lib/middlewares/context-tracker/index.js +39 -39
- package/lib/middlewares/error-handler/index.js +14 -14
- package/lib/middlewares/index.js +3 -2
- package/lib/middlewares/metrics/getMiddlewareWrapper.js +17 -17
- package/lib/middlewares/metrics/index.js +29 -29
- package/lib/middlewares/retry/index.js +15 -15
- package/lib/middlewares/timeout/index.js +18 -18
- package/lib/middlewares/tracing/index.js +50 -37
- package/lib/middlewares/tracing/tags.js +43 -0
- package/lib/middlewares/validator/index.js +32 -32
- package/lib/registry/{action-endpoint.js → actionEndpoint.js} +8 -8
- package/lib/registry/collections/{action-collection.js → actionCollection.js} +39 -35
- package/lib/registry/collections/{endpoint-collection.js → endpointCollection.js} +64 -65
- package/lib/registry/collections/{event-collection.js → eventCollection.js} +65 -69
- package/lib/registry/collections/{node-collection.js → nodeCollection.js} +45 -45
- package/lib/registry/collections/{service-collection.js → serviceCollection.js} +61 -55
- package/lib/registry/eventEndpoint.js +26 -0
- package/lib/registry/load-balancer/base.js +3 -3
- package/lib/registry/load-balancer/index.js +7 -7
- package/lib/registry/node.js +27 -27
- package/lib/registry/registry.js +147 -163
- package/lib/registry/service/parseAction.js +16 -16
- package/lib/registry/service/parseEvent.js +18 -18
- package/lib/registry/service/reduceMixins.js +10 -10
- package/lib/registry/service/service.js +72 -72
- package/lib/registry/{service-item.js → serviceItem.js} +21 -21
- package/lib/runtime/{init-action-invoker.js → initActionInvoker.js} +21 -21
- package/lib/runtime/initCache.js +19 -0
- package/lib/runtime/{init-context-factory.js → initContextFactory.js} +22 -22
- package/lib/runtime/{init-eventbus.js → initEventbus.js} +54 -53
- package/lib/runtime/{init-logger.js → initLogger.js} +11 -11
- package/lib/runtime/{init-metrics.js → initMetrics.js} +55 -54
- package/lib/runtime/{init-middleware-manager.js → initMiddlewareManager.js} +21 -21
- package/lib/runtime/{init-registry.js → initRegistry.js} +6 -6
- package/lib/runtime/initServiceManager.js +145 -0
- package/lib/runtime/{init-tracing.js → initTracing.js} +25 -24
- package/lib/runtime/{init-transport.js → initTransport.js} +5 -5
- package/lib/runtime/{init-uuid-factory.js → initUuidFactory.js} +4 -4
- package/lib/runtime/{init-validator.js → initValidator.js} +5 -5
- package/lib/tracing/collectors/base.js +29 -37
- package/lib/tracing/collectors/event.js +33 -33
- package/lib/tracing/collectors/index.js +16 -16
- package/lib/tracing/span.js +34 -32
- package/lib/tracing/time.js +8 -8
- package/lib/transport/InboundTransformStream.js +75 -0
- package/lib/transport/adapters/adapteBase.js +107 -0
- package/lib/transport/adapters/adapters.js +4 -4
- package/lib/transport/adapters/dummy/index.js +19 -19
- package/lib/transport/adapters/fromURI.js +13 -13
- package/lib/transport/adapters/getAdapterByName.js +5 -5
- package/lib/transport/adapters/index.js +12 -12
- package/lib/transport/adapters/tcp/discovery/codec.js +4 -4
- package/lib/transport/adapters/tcp/discovery/index.js +90 -76
- package/lib/transport/adapters/tcp/index.js +180 -175
- package/lib/transport/adapters/tcp/tcp-messagetypes.js +7 -7
- package/lib/transport/adapters/tcp/tcpReader.js +39 -38
- package/lib/transport/adapters/tcp/tcpWriteStream.js +26 -26
- package/lib/transport/adapters/tcp/tcpWriter.js +58 -58
- package/lib/transport/adapters/tcp/utils.js +12 -12
- package/lib/transport/createMessage.js +11 -0
- package/lib/transport/createTransport.js +377 -334
- package/lib/transport/errorPayloadFactory.js +15 -0
- package/lib/transport/messageHandlers.js +517 -0
- package/lib/transport/messageTypes.js +23 -0
- package/lib/types.js +95 -71
- package/lib/utils/index.js +2 -2
- package/lib/utils/options.js +47 -45
- package/lib/utils/{restore-error.js → restoreError.js} +4 -4
- package/package.json +6 -12
- package/CHANGELOG.md +0 -1334
- package/lib/build-runtime.js +0 -70
- package/lib/cache/base.js +0 -142
- package/lib/cache/index.js +0 -48
- package/lib/cache/memory.js +0 -121
- package/lib/middlewares/tracing/buildTags.js +0 -17
- package/lib/new-errors.js +0 -25
- package/lib/registry/event-endpoint.js +0 -26
- package/lib/runtime/init-cache.js +0 -10
- package/lib/runtime/init-service-manager.js +0 -128
- package/lib/tracing/collectors/console.js +0 -34
- package/lib/tracing/index.js +0 -3
- package/lib/tracing/tracer.js +0 -64
- package/lib/transport/adapters/adapter-base.js +0 -92
- package/lib/transport/message-handlers.js +0 -448
- package/lib/transport/message-types.js +0 -59
- package/lib/transport/message.js +0 -16
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const errorPayloadFactory =
|
|
2
|
+
(runtime) =>
|
|
3
|
+
(error) => {
|
|
4
|
+
return {
|
|
5
|
+
name: error.name,
|
|
6
|
+
message: error.message,
|
|
7
|
+
nodeId: error.nodeId || runtime.nodeId,
|
|
8
|
+
code: error.code,
|
|
9
|
+
type: error.type,
|
|
10
|
+
stack: error.stack,
|
|
11
|
+
data: error.data
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
module.exports = { errorPayloadFactory };
|
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Author: Kevin Ries (kevin.ries@fachwerk.io)
|
|
3
|
+
* -----
|
|
4
|
+
* Copyright 2021 Fachwerk
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { InboundTransformStream } = require('./InboundTransformStream');
|
|
8
|
+
const { WeaveError, restoreError } = require('../errors');
|
|
9
|
+
const { createContext } = require('../broker/context');
|
|
10
|
+
const { createMessage } = require('./createMessage');
|
|
11
|
+
const MessageTypes = require('./messageTypes');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {import('../types').Transport} Transport
|
|
15
|
+
* @typedef {import('../types').Runtime} Runtime
|
|
16
|
+
* @typedef {import('../types').TransportMessageHandler} TransportMessageHandler
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {Runtime} runtime - Runtime reference
|
|
21
|
+
* @param {Transport} transport - Transport refence
|
|
22
|
+
* @returns {TransportMessageHandler} - Message handler
|
|
23
|
+
*/
|
|
24
|
+
module.exports = (runtime, transport) => {
|
|
25
|
+
const registry = runtime.registry;
|
|
26
|
+
|
|
27
|
+
const getRequestTimeout = (payload) => {
|
|
28
|
+
return payload.timeout || runtime.options.registry.requestTimeout || 0;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const localRequestProxy = (context) => {
|
|
32
|
+
const actionName = context.action.name;
|
|
33
|
+
|
|
34
|
+
// Get available endpoints
|
|
35
|
+
const endpointList = registry.getActionEndpoints(actionName);
|
|
36
|
+
|
|
37
|
+
// Reject the request if no local endpoint can be found.
|
|
38
|
+
if (endpointList == null || !endpointList.hasLocal()) {
|
|
39
|
+
transport.log.warn(`Service ${actionName} not found localy.`);
|
|
40
|
+
return Promise.reject('Service not found');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// From all available local endpoints - get one.
|
|
44
|
+
const endpoint = endpointList.getNextLocalEndpoint();
|
|
45
|
+
|
|
46
|
+
// if there is no endpoint, reject
|
|
47
|
+
if (!endpoint) {
|
|
48
|
+
transport.log.warn(`Service ${actionName} is not available localy.`);
|
|
49
|
+
return Promise.reject('Service not found');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Call the local action handler with context
|
|
53
|
+
const promise = endpoint.action.handler(context);
|
|
54
|
+
promise.context = context;
|
|
55
|
+
|
|
56
|
+
return promise;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const handleIncomingRequestStream = (payload) => {
|
|
60
|
+
// check for open stream.
|
|
61
|
+
let stream = transport.pending.requestStreams.get(payload.id);
|
|
62
|
+
let isNew = false;
|
|
63
|
+
|
|
64
|
+
if (!payload.isStream && !stream) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!stream) {
|
|
69
|
+
isNew = true;
|
|
70
|
+
stream = new InboundTransformStream(
|
|
71
|
+
payload.sender,
|
|
72
|
+
payload.id, {
|
|
73
|
+
objectMode: payload.meta && payload.meta.$isObjectModeStream
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// handle backpressure
|
|
78
|
+
if (runtime.options.transport.streams.handleBackpressure) {
|
|
79
|
+
stream.on('backpressure', async ({ sender, requestId }) => {
|
|
80
|
+
const message = createMessage(MessageTypes.MESSAGE_REQUEST_STREAM_BACKPRESSURE, sender, { id: requestId });
|
|
81
|
+
await transport.send(message);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
stream.on('resume_backpressure', async ({ sender, requestId }) => {
|
|
85
|
+
const message = createMessage(MessageTypes.MESSAGE_REQUEST_STREAM_RESUME, sender, { id: requestId });
|
|
86
|
+
await transport.send(message);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
stream.$prevSeq = -1;
|
|
91
|
+
stream.$pool = new Map();
|
|
92
|
+
|
|
93
|
+
transport.pending.requestStreams.set(payload.id, stream);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (payload.sequence > (stream.$prevSeq + 1)) {
|
|
97
|
+
stream.$pool.set(payload.sequence, payload);
|
|
98
|
+
return isNew ? stream : null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
stream.$prevSeq = payload.sequence;
|
|
102
|
+
|
|
103
|
+
if (stream.$prevSeq > 0) {
|
|
104
|
+
if (!payload.isStream) {
|
|
105
|
+
transport.log.debug('Stream ended', payload.sender);
|
|
106
|
+
|
|
107
|
+
// Todo: Handle errors
|
|
108
|
+
|
|
109
|
+
// end of stream
|
|
110
|
+
stream.end();
|
|
111
|
+
transport.pending.requestStreams.delete(payload.id);
|
|
112
|
+
return null;
|
|
113
|
+
} else {
|
|
114
|
+
transport.log.debug('Stream chunk received from ', payload.sender);
|
|
115
|
+
stream.write(payload.chunk.type === 'Buffer' ? Buffer.from(payload.chunk.data) : payload.chunk);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (stream.$pool.size > 0) {
|
|
120
|
+
transport.log.debug(`Stream has stored packages. Size: ${stream.$pool.size}`, payload.sender);
|
|
121
|
+
const nextSequence = stream.$prevSeq + 1;
|
|
122
|
+
const nextChunk = stream.$pool.get(nextSequence);
|
|
123
|
+
if (nextChunk) {
|
|
124
|
+
stream.$pool.delete(nextSequence);
|
|
125
|
+
setImmediate(() => onRequest(nextChunk));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return isNew ? stream : null;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const handleIncomingResponseStream = (payload, request) => {
|
|
133
|
+
let stream = transport.pending.responseStreams.get(payload.id);
|
|
134
|
+
|
|
135
|
+
if (!stream && !payload.isStream) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (!stream) {
|
|
140
|
+
transport.log.debug(`New stream from node ${payload.sender} received. Seq: ${payload.sequence}`);
|
|
141
|
+
|
|
142
|
+
stream = new InboundTransformStream(
|
|
143
|
+
payload.sender,
|
|
144
|
+
payload.id, {
|
|
145
|
+
objectMode: payload.meta && payload.meta.$isObjectModeStream
|
|
146
|
+
}
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
// handle backpressure
|
|
150
|
+
if (runtime.options.transport.streams.handleBackpressure) {
|
|
151
|
+
stream.on('backpressure', async ({ sender, requestId }) => {
|
|
152
|
+
const message = createMessage(MessageTypes.MESSAGE_RESPONSE_STREAM_BACKPRESSURE, sender, { id: requestId });
|
|
153
|
+
await transport.send(message);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
stream.on('resume_backpressure', async ({ sender, requestId }) => {
|
|
157
|
+
const message = createMessage(MessageTypes.MESSAGE_RESPONSE_STREAM_RESUME, sender, { id: requestId });
|
|
158
|
+
await transport.send(message);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
stream.$prevSeq = -1;
|
|
163
|
+
stream.$pool = new Map();
|
|
164
|
+
|
|
165
|
+
transport.pending.responseStreams.set(payload.id, stream);
|
|
166
|
+
request.resolve(stream);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (payload.sequence > (stream.$prevSeq + 1)) {
|
|
170
|
+
transport.log.debug(`Put the chunk into pool (size: ${stream.$pool.size}). Seq: ${payload.sequence}`);
|
|
171
|
+
|
|
172
|
+
stream.$pool.set(payload.sequence, payload);
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
stream.$prevSeq = payload.sequence;
|
|
177
|
+
|
|
178
|
+
if (stream.$prevSeq > 0) {
|
|
179
|
+
if (!payload.isStream) {
|
|
180
|
+
transport.log.debug('Stream ended', payload.sender);
|
|
181
|
+
|
|
182
|
+
// Todo: Handle errors
|
|
183
|
+
|
|
184
|
+
// end of stream
|
|
185
|
+
stream.end();
|
|
186
|
+
transport.pending.responseStreams.delete(payload.id);
|
|
187
|
+
return null;
|
|
188
|
+
} else {
|
|
189
|
+
transport.log.debug('Stream chunk received from ', payload.sender);
|
|
190
|
+
stream.write(payload.chunk.type === 'Buffer' ? Buffer.from(payload.chunk.data) : payload.chunk);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (stream.$pool.size > 0) {
|
|
195
|
+
transport.log.debug(`Stream has stored packages. Size: ${stream.$pool.size}`, payload.sender);
|
|
196
|
+
const nextSequence = stream.$prevSeq + 1;
|
|
197
|
+
const nextChunk = stream.$pool.get(nextSequence);
|
|
198
|
+
if (nextChunk) {
|
|
199
|
+
stream.$pool.delete(nextSequence);
|
|
200
|
+
setImmediate(() => onResponse(nextChunk));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return true;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Discovery handler
|
|
209
|
+
* @param {any} payload - Payload
|
|
210
|
+
* @returns {Promise} Promise
|
|
211
|
+
*/
|
|
212
|
+
const onDiscovery = (payload) => transport.sendNodeInfo(payload.sender);
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Node info handler
|
|
216
|
+
* @param {any} payload - Payload
|
|
217
|
+
* @returns {Promise} Promise
|
|
218
|
+
*/
|
|
219
|
+
const onNodeInfos = (payload) => registry.processNodeInfo(payload);
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Request handler
|
|
223
|
+
* @param {any} payload - Payload
|
|
224
|
+
* @returns {Promise} Promise
|
|
225
|
+
*/
|
|
226
|
+
const onRequest = (payload) => {
|
|
227
|
+
const sender = payload.sender;
|
|
228
|
+
try {
|
|
229
|
+
let stream;
|
|
230
|
+
|
|
231
|
+
// Handle incomming stream
|
|
232
|
+
if (payload.isStream !== undefined) {
|
|
233
|
+
// check for open stream.
|
|
234
|
+
stream = handleIncomingRequestStream(payload);
|
|
235
|
+
if (!stream) {
|
|
236
|
+
return Promise.resolve();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const endpoint = registry.getLocalActionEndpoint(payload.action);
|
|
241
|
+
const context = createContext(runtime);
|
|
242
|
+
|
|
243
|
+
context.setEndpoint(endpoint);
|
|
244
|
+
context.id = payload.id;
|
|
245
|
+
context.setData(payload.data);
|
|
246
|
+
context.parentId = payload.parentId;
|
|
247
|
+
context.requestId = payload.requestId;
|
|
248
|
+
context.meta = payload.meta || {};
|
|
249
|
+
context.metrics = payload.metrics;
|
|
250
|
+
context.level = payload.level;
|
|
251
|
+
context.callerNodeId = payload.sender;
|
|
252
|
+
context.options.timeout = getRequestTimeout(payload);
|
|
253
|
+
|
|
254
|
+
// If payload is a stream, attach stream to context
|
|
255
|
+
if (payload.isStream) {
|
|
256
|
+
context.stream = stream;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return localRequestProxy(context)
|
|
260
|
+
.then(data => transport.sendResponse(sender, payload.id, data, context.meta, null))
|
|
261
|
+
.catch(error => transport.sendResponse(sender, payload.id, null, context.meta, error));
|
|
262
|
+
} catch (error) {
|
|
263
|
+
return transport.sendResponse(sender, payload.id, null, payload.meta, error);
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Response handler
|
|
269
|
+
* @param {any} payload - Payload
|
|
270
|
+
* @returns {Promise} Promise
|
|
271
|
+
*/
|
|
272
|
+
const onResponse = (payload) => {
|
|
273
|
+
const id = payload.id;
|
|
274
|
+
const request = transport.pending.requests.get(id);
|
|
275
|
+
|
|
276
|
+
if (!request) {
|
|
277
|
+
return Promise.resolve();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Merge meta data from response
|
|
281
|
+
Object.assign(request.context.meta, payload.meta);
|
|
282
|
+
|
|
283
|
+
// Handle streams
|
|
284
|
+
if (payload.isStream != null) {
|
|
285
|
+
if (handleIncomingResponseStream(payload, request)) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
transport.pending.requests.delete(payload.id);
|
|
291
|
+
|
|
292
|
+
// Response is an error
|
|
293
|
+
if (!payload.success) {
|
|
294
|
+
let error = restoreError(payload.error);
|
|
295
|
+
|
|
296
|
+
if (!error) {
|
|
297
|
+
error = new Error(payload.error.message);
|
|
298
|
+
error.name = payload.error.name;
|
|
299
|
+
error.code = payload.error.code;
|
|
300
|
+
error.type = payload.error.type;
|
|
301
|
+
error.data = payload.error.data;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
error.retryable = payload.error.retryable;
|
|
305
|
+
error.nodeId = error.nodeId || payload.sender;
|
|
306
|
+
|
|
307
|
+
if (payload.error.stack) {
|
|
308
|
+
error.stack = payload.error.stack;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
request.reject(error);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
request.resolve(payload.data);
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Ping handler
|
|
319
|
+
* @param {any} payload - Payload
|
|
320
|
+
* @returns {Promise} Promise
|
|
321
|
+
*/
|
|
322
|
+
const onPing = payload => {
|
|
323
|
+
const message = createMessage(MessageTypes.MESSAGE_PONG, payload.sender, {
|
|
324
|
+
dispatchTime: payload.dispatchTime,
|
|
325
|
+
arrivalTime: Date.now()
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
return transport.send(message);
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Pong handler
|
|
333
|
+
* @param {any} payload - Payload
|
|
334
|
+
* @returns {void}
|
|
335
|
+
*/
|
|
336
|
+
const onPong = (payload) => {
|
|
337
|
+
const now = Date.now();
|
|
338
|
+
const elapsedTime = now - payload.dispatchTime;
|
|
339
|
+
const timeDiff = Math.round(now - payload.arrivalTime - elapsedTime / 2);
|
|
340
|
+
|
|
341
|
+
runtime.eventBus.broadcastLocal('$node.pong', {
|
|
342
|
+
nodeId: payload.sender,
|
|
343
|
+
elapsedTime,
|
|
344
|
+
timeDiff
|
|
345
|
+
});
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Event handler
|
|
350
|
+
* @param {any} payload - Payload
|
|
351
|
+
* @returns {Promise} Promise
|
|
352
|
+
*/
|
|
353
|
+
const onEvent = (payload) => {
|
|
354
|
+
runtime.log.debug(`Received event "${payload.eventName}"`);
|
|
355
|
+
|
|
356
|
+
if (!runtime.state.isStarted) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// todo: reconstruct event context
|
|
361
|
+
const context = createContext(runtime);
|
|
362
|
+
|
|
363
|
+
// context.setEndpoint(endpoint)
|
|
364
|
+
context.id = payload.id;
|
|
365
|
+
context.setData(payload.data);
|
|
366
|
+
context.parentId = payload.parentId;
|
|
367
|
+
context.requestId = payload.requestId;
|
|
368
|
+
context.meta = payload.meta || {};
|
|
369
|
+
context.metrics = payload.metrics;
|
|
370
|
+
context.level = payload.level;
|
|
371
|
+
context.callerNodeId = payload.sender;
|
|
372
|
+
|
|
373
|
+
if (payload.timeout) {
|
|
374
|
+
context.options.timeout = payload.timeout;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// add event infos
|
|
378
|
+
context.eventName = payload.eventName;
|
|
379
|
+
context.eventType = payload.isBroadcast ? 'broadcast' : 'emit';
|
|
380
|
+
|
|
381
|
+
return registry.eventCollection.emitLocal(context);
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Disconnect handler
|
|
386
|
+
* @param {any} payload - Payload
|
|
387
|
+
* @returns {void}
|
|
388
|
+
*/
|
|
389
|
+
const onDisconnect = (payload) => {
|
|
390
|
+
registry.nodeDisconnected(payload.sender, false);
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Heartbeat handler
|
|
395
|
+
* @param {any} payload - Payload
|
|
396
|
+
* @returns {void}
|
|
397
|
+
*/
|
|
398
|
+
const onHeartbeat = (payload) => {
|
|
399
|
+
transport.log.verbose(`Heartbeat from ${payload.sender}`);
|
|
400
|
+
const node = registry.nodeCollection.get(payload.sender);
|
|
401
|
+
// if node is unknown then request a node info message.
|
|
402
|
+
if (node) {
|
|
403
|
+
if (!node.isAvailable) {
|
|
404
|
+
transport.log.debug('Known node. Propably reconnected.');
|
|
405
|
+
// unknown node. request info message.
|
|
406
|
+
transport.discoverNode(payload.sender);
|
|
407
|
+
} else {
|
|
408
|
+
node.heartbeat(payload);
|
|
409
|
+
}
|
|
410
|
+
} else {
|
|
411
|
+
// unknown node. request info message.
|
|
412
|
+
transport.discoverNode(payload.sender);
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
const onResponseStreamBackpressure = (payload) => {
|
|
417
|
+
const stream = transport.pending.outboundResponseStreams.get(payload.id);
|
|
418
|
+
|
|
419
|
+
if (stream) {
|
|
420
|
+
stream.pause();
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
const onResponseStreamResume = (payload) => {
|
|
425
|
+
const stream = transport.pending.outboundResponseStreams.get(payload.id);
|
|
426
|
+
|
|
427
|
+
if (stream) {
|
|
428
|
+
stream.resume();
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
const onRequestStreamBackpressure = (payload) => {
|
|
433
|
+
const stream = transport.pending.outboundRequestStreams.get(payload.id);
|
|
434
|
+
|
|
435
|
+
if (stream) {
|
|
436
|
+
stream.pause();
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
const onRequestStreamResume = (payload) => {
|
|
441
|
+
const stream = transport.pending.outboundRequestStreams.get(payload.id);
|
|
442
|
+
|
|
443
|
+
if (stream) {
|
|
444
|
+
stream.resume();
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
return (type, data) => {
|
|
449
|
+
try {
|
|
450
|
+
if (data === null) {
|
|
451
|
+
runtime.handleError(new WeaveError('Packet missing!'));
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const payload = data.payload;
|
|
455
|
+
|
|
456
|
+
if (!payload) {
|
|
457
|
+
runtime.handleError(new WeaveError('Message payload missing!'));
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// todo: check protocol version
|
|
461
|
+
// todo: check node ID conflict
|
|
462
|
+
|
|
463
|
+
// if (payload.sender === runtime.nodeId) {
|
|
464
|
+
// if (type === MessageTypes.MESSAGE_INFO && payload.instanceId !== runtime.state.instanceId) {
|
|
465
|
+
// return runtime.fatalError('Weave broker has detected a node ID conflict. "nodeId" of broker needs to be unique. Broker will be stopped.')
|
|
466
|
+
// }
|
|
467
|
+
// }
|
|
468
|
+
|
|
469
|
+
switch (type) {
|
|
470
|
+
case MessageTypes.MESSAGE_DISCOVERY:
|
|
471
|
+
onDiscovery(payload);
|
|
472
|
+
break;
|
|
473
|
+
case MessageTypes.MESSAGE_INFO:
|
|
474
|
+
onNodeInfos(payload);
|
|
475
|
+
break;
|
|
476
|
+
case MessageTypes.MESSAGE_REQUEST:
|
|
477
|
+
onRequest(payload);
|
|
478
|
+
break;
|
|
479
|
+
case MessageTypes.MESSAGE_RESPONSE:
|
|
480
|
+
onResponse(payload);
|
|
481
|
+
break;
|
|
482
|
+
case MessageTypes.MESSAGE_PING:
|
|
483
|
+
onPing(payload);
|
|
484
|
+
break;
|
|
485
|
+
case MessageTypes.MESSAGE_PONG:
|
|
486
|
+
onPong(payload);
|
|
487
|
+
break;
|
|
488
|
+
case MessageTypes.MESSAGE_DISCONNECT:
|
|
489
|
+
onDisconnect(payload);
|
|
490
|
+
break;
|
|
491
|
+
case MessageTypes.MESSAGE_HEARTBEAT:
|
|
492
|
+
onHeartbeat(payload);
|
|
493
|
+
break;
|
|
494
|
+
case MessageTypes.MESSAGE_EVENT:
|
|
495
|
+
onEvent(payload);
|
|
496
|
+
break;
|
|
497
|
+
case MessageTypes.MESSAGE_RESPONSE_STREAM_BACKPRESSURE:
|
|
498
|
+
onResponseStreamBackpressure(payload);
|
|
499
|
+
break;
|
|
500
|
+
case MessageTypes.MESSAGE_RESPONSE_STREAM_RESUME:
|
|
501
|
+
onResponseStreamResume(payload);
|
|
502
|
+
break;
|
|
503
|
+
case MessageTypes.MESSAGE_REQUEST_STREAM_BACKPRESSURE:
|
|
504
|
+
onRequestStreamBackpressure(payload);
|
|
505
|
+
break;
|
|
506
|
+
case MessageTypes.MESSAGE_REQUEST_STREAM_RESUME:
|
|
507
|
+
onRequestStreamResume(payload);
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return true;
|
|
512
|
+
} catch (error) {
|
|
513
|
+
transport.log.error(error, data);
|
|
514
|
+
}
|
|
515
|
+
return false;
|
|
516
|
+
};
|
|
517
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Author: Kevin Ries (kevin.ries@fachwerk.io)
|
|
3
|
+
* -----
|
|
4
|
+
* Copyright 2021 Fachwerk
|
|
5
|
+
*/
|
|
6
|
+
exports.MESSAGE_UNKNOWN = 'unknown';
|
|
7
|
+
exports.MESSAGE_DISCOVERY = 'discovery';
|
|
8
|
+
exports.MESSAGE_INFO = 'info';
|
|
9
|
+
exports.MESSAGE_REQUEST = 'request';
|
|
10
|
+
exports.MESSAGE_RESPONSE = 'response';
|
|
11
|
+
exports.MESSAGE_PING = 'ping';
|
|
12
|
+
exports.MESSAGE_PONG = 'pong';
|
|
13
|
+
exports.MESSAGE_DISCONNECT = 'disconnect';
|
|
14
|
+
exports.MESSAGE_HEARTBEAT = 'heartbeat';
|
|
15
|
+
exports.MESSAGE_EVENT = 'event';
|
|
16
|
+
exports.MESSAGE_GOSSIP_HELLO = 'gossip_hello';
|
|
17
|
+
exports.MESSAGE_GOSSIP_RESPONSE = 'gossip_response';
|
|
18
|
+
exports.MESSAGE_GOSSIP_REQUEST = 'gossip_request';
|
|
19
|
+
exports.MESSAGE_EVENT_ACK = 'event_ack';
|
|
20
|
+
exports.MESSAGE_RESPONSE_STREAM_BACKPRESSURE = 'response_stream_backpressure';
|
|
21
|
+
exports.MESSAGE_RESPONSE_STREAM_RESUME = 'response_stream_resume';
|
|
22
|
+
exports.MESSAGE_REQUEST_STREAM_BACKPRESSURE = 'request_stream_backpressure';
|
|
23
|
+
exports.MESSAGE_REQUEST_STREAM_RESUME = 'request_stream_resume';
|