@weave-js/core 0.10.0 → 0.11.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/lib/ExtendableError.js +33 -0
- package/lib/broker/context.js +12 -0
- package/lib/broker/{default-options.js → defaultOptions.js} +22 -4
- package/lib/broker/index.js +218 -192
- package/lib/{build-runtime.js → buildRuntime.js} +16 -16
- package/lib/cache/base.js +33 -28
- package/lib/cache/inMemory.js +140 -0
- package/lib/cache/index.js +1 -1
- package/lib/cache/lock.js +21 -4
- package/lib/constants.js +7 -4
- package/lib/{error-handler.js → errorHandler.js} +0 -0
- package/lib/errors.js +16 -9
- package/lib/helper/{define-action.js → defineAction.js} +3 -1
- package/lib/helper/{define-broker-options.js → defineBrokerOptions.js} +2 -0
- package/lib/helper/{define-service.js → defineService.js} +4 -1
- package/lib/index.js +13 -9
- package/lib/logger/format/asHumanReadable.js +4 -3
- package/lib/logger/index.js +4 -1
- package/lib/logger/levels.js +2 -1
- package/lib/logger/tools.js +4 -0
- package/lib/logger/utils/format.js +18 -4
- package/lib/metrics/constants.js +1 -1
- package/lib/metrics/types/gauge.js +1 -1
- package/lib/middlewares/action-hooks/index.js +59 -11
- package/lib/middlewares/bulkhead/index.js +2 -1
- package/lib/middlewares/cache/index.js +80 -0
- package/lib/middlewares/circuit-breaker/index.js +38 -13
- package/lib/middlewares/index.js +1 -0
- package/lib/middlewares/metrics/index.js +1 -1
- package/lib/middlewares/timeout/index.js +2 -2
- package/lib/middlewares/tracing/index.js +24 -11
- package/lib/middlewares/tracing/tags.js +43 -0
- package/lib/middlewares/validator/index.js +1 -1
- package/lib/registry/{action-endpoint.js → actionEndpoint.js} +0 -0
- package/lib/registry/collections/{action-collection.js → actionCollection.js} +1 -1
- package/lib/registry/collections/{endpoint-collection.js → endpointCollection.js} +2 -3
- package/lib/registry/collections/{event-collection.js → eventCollection.js} +4 -8
- package/lib/registry/collections/{node-collection.js → nodeCollection.js} +0 -0
- package/lib/registry/collections/{service-collection.js → serviceCollection.js} +1 -1
- package/lib/registry/{event-endpoint.js → eventEndpoint.js} +0 -0
- package/lib/registry/registry.js +9 -22
- package/lib/registry/service/service.js +2 -2
- package/lib/registry/{service-item.js → serviceItem.js} +0 -0
- package/lib/runtime/{init-action-invoker.js → initActionInvoker.js} +1 -1
- package/lib/runtime/{init-cache.js → initCache.js} +0 -0
- package/lib/runtime/{init-context-factory.js → initContextFactory.js} +0 -0
- package/lib/runtime/{init-eventbus.js → initEventbus.js} +8 -7
- package/lib/runtime/{init-logger.js → initLogger.js} +0 -0
- package/lib/runtime/{init-metrics.js → initMetrics.js} +11 -10
- package/lib/runtime/{init-middleware-manager.js → initMiddlewareManager.js} +0 -0
- package/lib/runtime/{init-registry.js → initRegistry.js} +0 -0
- package/lib/runtime/{init-service-manager.js → initServiceManager.js} +0 -0
- package/lib/runtime/{init-tracing.js → initTracing.js} +2 -1
- package/lib/runtime/{init-transport.js → initTransport.js} +0 -0
- package/lib/runtime/{init-uuid-factory.js → initUuidFactory.js} +0 -0
- package/lib/runtime/{init-validator.js → initValidator.js} +0 -0
- package/lib/tracing/collectors/base.js +11 -19
- package/lib/tracing/collectors/event.js +2 -2
- package/lib/tracing/collectors/index.js +2 -2
- package/lib/tracing/span.js +8 -6
- package/lib/transport/InboundTransformStream.js +75 -0
- package/lib/transport/adapters/{adapter-base.js → adapteBase.js} +15 -0
- package/lib/transport/adapters/adapters.js +1 -1
- package/lib/transport/adapters/dummy/index.js +2 -2
- package/lib/transport/adapters/tcp/discovery/index.js +45 -31
- package/lib/transport/adapters/tcp/index.js +20 -13
- package/lib/transport/adapters/tcp/tcpReader.js +1 -0
- package/lib/transport/adapters/tcp/tcpWriteStream.js +1 -1
- package/lib/transport/adapters/tcp/tcpWriter.js +2 -2
- package/lib/transport/createMessage.js +11 -0
- package/lib/transport/createTransport.js +214 -171
- package/lib/transport/errorPayloadFactory.js +18 -0
- package/lib/transport/{message-handlers.js → messageHandlers.js} +91 -22
- package/lib/transport/messageTypes.js +23 -0
- package/lib/types.js +49 -49
- package/lib/utils/options.js +4 -2
- package/lib/utils/{restore-error.js → restoreError.js} +1 -1
- package/package.json +6 -12
- package/CHANGELOG.md +0 -1334
- package/lib/cache/memory.js +0 -121
- package/lib/middlewares/tracing/buildTags.js +0 -17
- package/lib/new-errors.js +0 -25
- 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/message-types.js +0 -59
- package/lib/transport/message.js +0 -16
|
@@ -9,7 +9,7 @@ const { WeaveError } = require('../../errors')
|
|
|
9
9
|
const { parseAction } = require('./parseAction')
|
|
10
10
|
const { parseEvent } = require('./parseEvent')
|
|
11
11
|
const { reduceMixins } = require('./reduceMixins')
|
|
12
|
-
const { createEventEndpoint } = require('../
|
|
12
|
+
const { createEventEndpoint } = require('../eventEndpoint')
|
|
13
13
|
/**
|
|
14
14
|
* Service factory
|
|
15
15
|
* @param {Runtime} runtime Broker instance
|
|
@@ -133,7 +133,7 @@ exports.createServiceFromSchema = (runtime, schema) => {
|
|
|
133
133
|
context = runtime.contextFactory.create(endpoint, data, options || {})
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
return wrappedAction(context, { service, runtime, errors: {}
|
|
136
|
+
return wrappedAction(context, { service, runtime, errors: {}})
|
|
137
137
|
}
|
|
138
138
|
})
|
|
139
139
|
}
|
|
File without changes
|
|
@@ -36,7 +36,7 @@ exports.initActionInvoker = (runtime) => {
|
|
|
36
36
|
log.debug({ action: context.action.name, nodeId, requestId: context.requestId }, 'Call action on remote node.')
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const p = action.handler(context, { service:
|
|
39
|
+
const p = action.handler(context, { service: context.action.service, runtime, errors })
|
|
40
40
|
p.context = context
|
|
41
41
|
|
|
42
42
|
return p
|
|
File without changes
|
|
File without changes
|
|
@@ -15,7 +15,11 @@ exports.initEventbus = (runtime) => {
|
|
|
15
15
|
options = {}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
// Emit local events
|
|
19
|
+
if (/^\$/.test(eventName)) {
|
|
20
|
+
bus.emit(eventName, payload)
|
|
21
|
+
}
|
|
22
|
+
|
|
19
23
|
// todo: create an event context object
|
|
20
24
|
const context = contextFactory.create(null, payload, options)
|
|
21
25
|
|
|
@@ -23,18 +27,15 @@ exports.initEventbus = (runtime) => {
|
|
|
23
27
|
context.eventName = eventName
|
|
24
28
|
context.eventGroups = options.groups
|
|
25
29
|
|
|
26
|
-
// Emit system events
|
|
27
|
-
if (/^\$/.test(eventName)) {
|
|
28
|
-
bus.emit(eventName, payload)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
30
|
const endpoints = registry.eventCollection.getBalancedEndpoints(eventName, options.groups)
|
|
32
31
|
const groupedEndpoints = {}
|
|
32
|
+
const promises = []
|
|
33
33
|
|
|
34
34
|
endpoints.map(([endpoint, groupName]) => {
|
|
35
35
|
if (endpoint) {
|
|
36
36
|
if (endpoint.node.id === brokerOptions.nodeId) {
|
|
37
37
|
// Local event. Call handler
|
|
38
|
+
context.setEndpoint(endpoint)
|
|
38
39
|
promises.push(endpoint.action.handler(context))
|
|
39
40
|
} else {
|
|
40
41
|
const e = groupedEndpoints[endpoint.node.id]
|
|
@@ -50,7 +51,7 @@ exports.initEventbus = (runtime) => {
|
|
|
50
51
|
}
|
|
51
52
|
})
|
|
52
53
|
|
|
53
|
-
//
|
|
54
|
+
// Send remote events
|
|
54
55
|
if (runtime.transport) {
|
|
55
56
|
Object.values(groupedEndpoints)
|
|
56
57
|
.forEach(groupedEndpoint => {
|
|
File without changes
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { isPlainObject, isFunction } = require('@weave-js/utils')
|
|
2
|
+
const { WeaveError } = require('../errors')
|
|
2
3
|
const { registerCommonMetrics, updateCommonMetrics } = require('../metrics/common')
|
|
3
4
|
const MetricTypes = require('../metrics/types')
|
|
4
5
|
|
|
@@ -32,7 +33,7 @@ exports.initMetrics = (runtime) => {
|
|
|
32
33
|
// Load adapters
|
|
33
34
|
if (metricOptions.adapters) {
|
|
34
35
|
if (!Array.isArray(metricOptions.adapters)) {
|
|
35
|
-
runtime.handleError(new
|
|
36
|
+
runtime.handleError(new WeaveError('Metic adapter needs to be an Array.'))
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
this.adapters = metricOptions.adapters.map(adapter => {
|
|
@@ -50,21 +51,21 @@ exports.initMetrics = (runtime) => {
|
|
|
50
51
|
},
|
|
51
52
|
register (obj) {
|
|
52
53
|
if (!isPlainObject(obj)) {
|
|
53
|
-
runtime.handleError(new
|
|
54
|
+
runtime.handleError(new WeaveError('Param needs to be an object.'))
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
if (!obj.type) {
|
|
57
|
-
runtime.handleError(new
|
|
58
|
+
runtime.handleError(new WeaveError('Type is missing.'))
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
if (!obj.name) {
|
|
61
|
-
runtime.handleError(new
|
|
62
|
+
runtime.handleError(new WeaveError('Name is missing.'))
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
const createMetricType = MetricTypes.resolve(obj.type)
|
|
65
66
|
|
|
66
67
|
if (!createMetricType) {
|
|
67
|
-
runtime.handleError(new
|
|
68
|
+
runtime.handleError(new WeaveError('Unknown metric type.'))
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
const type = createMetricType(this, obj)
|
|
@@ -81,7 +82,7 @@ exports.initMetrics = (runtime) => {
|
|
|
81
82
|
const item = this.storage.get(name)
|
|
82
83
|
|
|
83
84
|
if (!item) {
|
|
84
|
-
runtime.handleError(new
|
|
85
|
+
runtime.handleError(new WeaveError('Item not found.'))
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
item.increment(labels, value, timestamp)
|
|
@@ -94,7 +95,7 @@ exports.initMetrics = (runtime) => {
|
|
|
94
95
|
const item = this.storage.get(name)
|
|
95
96
|
|
|
96
97
|
if (!item) {
|
|
97
|
-
runtime.handleError(new
|
|
98
|
+
runtime.handleError(new WeaveError('Item not found.'))
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
item.decrement(labels, value, timestamp)
|
|
@@ -107,7 +108,7 @@ exports.initMetrics = (runtime) => {
|
|
|
107
108
|
const item = this.storage.get(name)
|
|
108
109
|
|
|
109
110
|
if (!isFunction(item.set)) {
|
|
110
|
-
runtime.handleError(new
|
|
111
|
+
runtime.handleError(new WeaveError('Invalid metric type'))
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
item.set(value, labels, timestamp)
|
|
@@ -137,12 +138,12 @@ exports.initMetrics = (runtime) => {
|
|
|
137
138
|
const item = this.storage.get(name)
|
|
138
139
|
|
|
139
140
|
if (!item) {
|
|
140
|
-
runtime.handleError(new
|
|
141
|
+
runtime.handleError(new WeaveError('Item not found.'))
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
return item
|
|
144
145
|
},
|
|
145
|
-
list (options = {}) {
|
|
146
|
+
list (/* options = {} */) {
|
|
146
147
|
const results = []
|
|
147
148
|
|
|
148
149
|
this.storage.forEach(metric => {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -9,6 +9,8 @@ exports.initTracer = (runtime) => {
|
|
|
9
9
|
|
|
10
10
|
Object.defineProperty(runtime, 'tracer', {
|
|
11
11
|
value: {
|
|
12
|
+
runtime,
|
|
13
|
+
options,
|
|
12
14
|
log,
|
|
13
15
|
async stop () {
|
|
14
16
|
if (collectors.length > 0) {
|
|
@@ -55,7 +57,6 @@ exports.initTracer = (runtime) => {
|
|
|
55
57
|
collectors = options.collectors
|
|
56
58
|
.map(entry => {
|
|
57
59
|
const initCollector = resolveCollector(runtime, entry, this)
|
|
58
|
-
// collector.init(this)
|
|
59
60
|
initCollector.init(runtime)
|
|
60
61
|
return initCollector
|
|
61
62
|
})
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,26 +1,25 @@
|
|
|
1
|
-
const { isObject } = require('@weave-js/utils')
|
|
2
|
-
const { WeaveError } = require('../../errors')
|
|
1
|
+
const { isObject, pick } = require('@weave-js/utils')
|
|
3
2
|
|
|
4
|
-
exports.createBaseTracingCollector = (
|
|
3
|
+
exports.createBaseTracingCollector = (runtime) => {
|
|
5
4
|
const baseTracingCollector = Object.create(null)
|
|
6
5
|
|
|
7
|
-
baseTracingCollector.options = options
|
|
6
|
+
baseTracingCollector.options = runtime.tracer.options
|
|
8
7
|
|
|
9
|
-
baseTracingCollector.init = (runtime
|
|
8
|
+
baseTracingCollector.init = (runtime) => {
|
|
10
9
|
baseTracingCollector.runtime = runtime
|
|
11
|
-
baseTracingCollector.tracer = tracer
|
|
10
|
+
baseTracingCollector.tracer = runtime.tracer
|
|
12
11
|
}
|
|
13
12
|
|
|
14
13
|
baseTracingCollector.startedSpan = () => {
|
|
15
|
-
throw new WeaveError('not implemented.')
|
|
14
|
+
// throw new WeaveError('not implemented.')
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
baseTracingCollector.finishedSpan = () => {
|
|
19
|
-
throw new WeaveError('not implemented.')
|
|
18
|
+
// throw new WeaveError('not implemented.')
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
baseTracingCollector.stop = () => {
|
|
23
|
-
throw new WeaveError('not implemented.')
|
|
22
|
+
// throw new WeaveError('not implemented.')
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
baseTracingCollector.flattenTags = (obj, convertToString = false, path = '') => {
|
|
@@ -42,18 +41,11 @@ exports.createBaseTracingCollector = (options) => {
|
|
|
42
41
|
}, {})
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
baseTracingCollector.getErrorFields = (
|
|
46
|
-
if (!
|
|
44
|
+
baseTracingCollector.getErrorFields = (err, fields) => {
|
|
45
|
+
if (!err) {
|
|
47
46
|
return null
|
|
48
47
|
}
|
|
49
|
-
|
|
50
|
-
const picked = {}
|
|
51
|
-
|
|
52
|
-
for (const field of fields) {
|
|
53
|
-
picked[field] = error[field]
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return picked
|
|
48
|
+
return pick(err, fields)
|
|
57
49
|
}
|
|
58
50
|
|
|
59
51
|
return baseTracingCollector
|
|
@@ -13,7 +13,7 @@ const mergeDefaultOptions = (options) => {
|
|
|
13
13
|
module.exports = (options) => (runtime, tracer) => {
|
|
14
14
|
options = mergeDefaultOptions(options)
|
|
15
15
|
|
|
16
|
-
const exporter = createBaseTracingCollector(
|
|
16
|
+
const exporter = createBaseTracingCollector(runtime)
|
|
17
17
|
|
|
18
18
|
exporter.init(runtime, tracer)
|
|
19
19
|
|
|
@@ -28,7 +28,7 @@ module.exports = (options) => (runtime, tracer) => {
|
|
|
28
28
|
const newSpan = Object.assign({}, span)
|
|
29
29
|
|
|
30
30
|
if (newSpan.error) {
|
|
31
|
-
newSpan.error = exporter.getErrorFields(newSpan.error)
|
|
31
|
+
newSpan.error = exporter.getErrorFields(newSpan.error, exporter.options.errors.fields)
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
return newSpan
|
|
@@ -11,14 +11,14 @@ const getByName = name => {
|
|
|
11
11
|
return collectors[n]
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
exports.resolveCollector = (runtime, collector
|
|
14
|
+
exports.resolveCollector = (runtime, collector) => {
|
|
15
15
|
let CollectorClass
|
|
16
16
|
if (typeof collector === 'string') {
|
|
17
17
|
CollectorClass = getByName(collector)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
if (isFunction(collector)) {
|
|
21
|
-
return collector(runtime
|
|
21
|
+
return collector(runtime)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
if (typeof collector === 'object') {
|
package/lib/tracing/span.js
CHANGED
|
@@ -3,8 +3,8 @@ const hrTime = require('./time')
|
|
|
3
3
|
exports.createSpan = (tracer, name, options) => {
|
|
4
4
|
const span = Object.assign({}, {
|
|
5
5
|
name,
|
|
6
|
-
id: options.id || tracer.
|
|
7
|
-
traceId: options.traceId || tracer.
|
|
6
|
+
id: options.id || tracer.runtime.generateUUID(),
|
|
7
|
+
traceId: options.traceId || tracer.runtime.generateUUID(),
|
|
8
8
|
parentId: options.parentId,
|
|
9
9
|
type: options.type,
|
|
10
10
|
sampled: options.sampled || tracer.shouldSample(),
|
|
@@ -12,10 +12,12 @@ exports.createSpan = (tracer, name, options) => {
|
|
|
12
12
|
tags: {}
|
|
13
13
|
})
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
if (options.service) {
|
|
16
|
+
span.service = {
|
|
17
|
+
name: options.service.name,
|
|
18
|
+
version: options.service.version,
|
|
19
|
+
fullyQualifiedName: options.service.fullyQualifiedName
|
|
20
|
+
}
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
span.addTags = (tags) => {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const { Transform } = require('stream')
|
|
2
|
+
|
|
3
|
+
const pushWithBackpressure = (stream, chunks, encoding, callback = null, $index = 0) => {
|
|
4
|
+
if (!(stream instanceof Transform)) {
|
|
5
|
+
throw new TypeError('Argument "stream" must be an instance of Duplex')
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
chunks = [].concat(chunks).filter(x => x !== undefined)
|
|
9
|
+
|
|
10
|
+
if (typeof encoding === 'function') {
|
|
11
|
+
callback = encoding
|
|
12
|
+
encoding = undefined
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if ($index >= chunks.length) {
|
|
16
|
+
if (typeof callback === 'function') {
|
|
17
|
+
callback()
|
|
18
|
+
}
|
|
19
|
+
return stream
|
|
20
|
+
} else if (!stream.push(chunks[$index], ...([encoding].filter(Boolean)))) {
|
|
21
|
+
stream.emit('backpressure', {
|
|
22
|
+
sender: stream.sender,
|
|
23
|
+
requestId: stream.requestId
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const pipedStreams = [].concat(
|
|
27
|
+
(stream._readableState || {}).pipes || stream
|
|
28
|
+
).filter(Boolean)
|
|
29
|
+
|
|
30
|
+
let listenerCalled = false
|
|
31
|
+
|
|
32
|
+
const drainListener = () => {
|
|
33
|
+
stream.emit('resume_backpressure', {
|
|
34
|
+
sender: stream.sender,
|
|
35
|
+
requestId: stream.requestId
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
if (listenerCalled) {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
listenerCalled = true
|
|
43
|
+
|
|
44
|
+
for (const stream of pipedStreams) {
|
|
45
|
+
stream.removeListener('drain', drainListener)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
pushWithBackpressure(stream, chunks, encoding, callback, $index + 1)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
for (const stream of pipedStreams) {
|
|
52
|
+
stream.once('drain', drainListener)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return stream
|
|
56
|
+
}
|
|
57
|
+
return pushWithBackpressure(stream, chunks, encoding, callback, $index + 1)
|
|
58
|
+
}
|
|
59
|
+
class InboundTransformStream extends Transform {
|
|
60
|
+
constructor (sender, requestId, options) {
|
|
61
|
+
super(options)
|
|
62
|
+
this.sender = sender
|
|
63
|
+
this.requestId = requestId
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
_transform (chunk, encoding, callback) {
|
|
67
|
+
pushWithBackpressure(this, chunk, encoding, callback)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
_flush (callback) {
|
|
71
|
+
return callback()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = { InboundTransformStream }
|
|
@@ -6,6 +6,21 @@
|
|
|
6
6
|
|
|
7
7
|
const EventEmitter = require('events').EventEmitter
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {Object} AdapterBase
|
|
11
|
+
* @property {string} name Name
|
|
12
|
+
* @property {EventEmitter} bus Event bus.
|
|
13
|
+
* @property {function():Promise<any>} afterInit After init callback.
|
|
14
|
+
* @property {boolean} isConnected Is connected state.
|
|
15
|
+
* @property {number} interruptCounter Interruption counter.
|
|
16
|
+
* @property {number} repeatAttemptCounter Repeat attempt counter
|
|
17
|
+
* @property {function(Object, Object, Object):Promise<any>} init Repeat attempt counter
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Create a adapter base object.
|
|
22
|
+
* @returns {AdapterBase} Adapter base object
|
|
23
|
+
*/
|
|
9
24
|
const createTransportBase = () => {
|
|
10
25
|
let prefix = 'weave'
|
|
11
26
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Copyright 2021 Fachwerk
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const TransportBase = require('../
|
|
7
|
+
const TransportBase = require('../adapteBase')
|
|
8
8
|
const EventEmitter = require('eventemitter2').EventEmitter2
|
|
9
9
|
|
|
10
10
|
// create a global eventbus to pass messages between weave service brokers.
|
|
@@ -18,7 +18,7 @@ const DummyTransportAdapter = (adapterOptions) => {
|
|
|
18
18
|
|
|
19
19
|
return Object.assign(TransportBase(adapterOptions), {
|
|
20
20
|
name: 'Dummy',
|
|
21
|
-
connect (
|
|
21
|
+
connect () {
|
|
22
22
|
this.bus.emit('$adapter.connected', false)
|
|
23
23
|
this.log.info('Dummy transport client connected.')
|
|
24
24
|
return Promise.resolve()
|
|
@@ -12,7 +12,7 @@ const createDiscoveryService = (adapter, options) => {
|
|
|
12
12
|
const codec = Codec(options)
|
|
13
13
|
const bus = new EventEmitter()
|
|
14
14
|
const ips = getIpList(false)
|
|
15
|
-
const
|
|
15
|
+
const MESSAGE_TYPE_LENGTH = 1
|
|
16
16
|
|
|
17
17
|
let servers = []
|
|
18
18
|
let discoverTimer
|
|
@@ -20,32 +20,29 @@ const createDiscoveryService = (adapter, options) => {
|
|
|
20
20
|
const startServer = (host, port, multicastAddress) => {
|
|
21
21
|
return new Promise((resolve, reject) => {
|
|
22
22
|
try {
|
|
23
|
-
const socket = dgram.createSocket({
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const messageType = Buffer.prototype.readUInt8.call(message, 0)
|
|
27
|
-
const payload = message.slice(MESSAGE_TYPE_LENGHT)
|
|
28
|
-
|
|
29
|
-
switch (messageType) {
|
|
30
|
-
case messageTypes.HELLO:
|
|
31
|
-
onMessage(payload, info)
|
|
32
|
-
break
|
|
33
|
-
default:
|
|
34
|
-
onUnknown(payload, info)
|
|
35
|
-
}
|
|
23
|
+
const socket = dgram.createSocket({
|
|
24
|
+
type: options.discovery.type,
|
|
25
|
+
reuseAddr: options.discovery.udpReuseAddress
|
|
36
26
|
})
|
|
37
27
|
|
|
38
|
-
socket.
|
|
28
|
+
socket.on('message', onMessage)
|
|
29
|
+
|
|
30
|
+
socket.bind({ port, exclusive: true }, () => {
|
|
39
31
|
try {
|
|
40
32
|
if (multicastAddress) {
|
|
41
33
|
socket.setMulticastInterface(host)
|
|
42
34
|
socket.addMembership(multicastAddress, host)
|
|
43
35
|
socket.setMulticastTTL(1)
|
|
44
|
-
socket
|
|
36
|
+
// Add destination to socket object
|
|
37
|
+
Object.defineProperty(socket, 'destinations', {
|
|
38
|
+
value: [multicastAddress]
|
|
39
|
+
})
|
|
45
40
|
adapter.log.info(`UDP Server is listening on ${host}:${port}. Membership: ${multicastAddress}`)
|
|
46
41
|
} else {
|
|
47
42
|
socket.setBroadcast(true)
|
|
48
|
-
socket
|
|
43
|
+
Object.defineProperty(socket, 'destinations', {
|
|
44
|
+
value: getBroadcastAddresses()
|
|
45
|
+
})
|
|
49
46
|
}
|
|
50
47
|
} catch (error) {
|
|
51
48
|
adapter.log.info(`UDP Multicast membership error: ${error.message}`)
|
|
@@ -62,20 +59,25 @@ const createDiscoveryService = (adapter, options) => {
|
|
|
62
59
|
}
|
|
63
60
|
|
|
64
61
|
const onMessage = (buffer, info) => {
|
|
65
|
-
const
|
|
66
|
-
|
|
62
|
+
const messageType = Buffer.prototype.readUInt8.call(buffer, 0)
|
|
63
|
+
const payload = buffer.slice(MESSAGE_TYPE_LENGTH)
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
switch (messageType) {
|
|
66
|
+
case messageTypes.HELLO:
|
|
67
|
+
const message = codec.decode(payload)
|
|
68
|
+
message.host = info.address
|
|
72
69
|
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
if (message.namespace === namespace) {
|
|
71
|
+
bus.emit('message', message)
|
|
72
|
+
}
|
|
73
|
+
break
|
|
74
|
+
default:
|
|
75
|
+
adapter.log.debug(`Received an unknown data package from host "${info.address}"`)
|
|
76
|
+
}
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
function sendMessage (payload) {
|
|
78
|
-
const header = Buffer.alloc(
|
|
80
|
+
const header = Buffer.alloc(MESSAGE_TYPE_LENGTH)
|
|
79
81
|
Buffer.prototype.writeUInt8.call(header, messageTypes.HELLO, 0)
|
|
80
82
|
|
|
81
83
|
const message = Buffer.concat([header, codec.encode(payload)])
|
|
@@ -101,7 +103,6 @@ const createDiscoveryService = (adapter, options) => {
|
|
|
101
103
|
|
|
102
104
|
function startDiscovering (port) {
|
|
103
105
|
discoverTimer = setInterval(() => sendDiscoveryPackage(port), 2000)
|
|
104
|
-
|
|
105
106
|
discoverTimer.unref()
|
|
106
107
|
}
|
|
107
108
|
|
|
@@ -115,14 +116,27 @@ const createDiscoveryService = (adapter, options) => {
|
|
|
115
116
|
|
|
116
117
|
return {
|
|
117
118
|
bus,
|
|
118
|
-
|
|
119
|
+
async start (port) {
|
|
119
120
|
if (!options.discovery.enabled) {
|
|
120
121
|
return Promise.resolve()
|
|
121
122
|
}
|
|
122
123
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
.
|
|
124
|
+
// UDP Multicast
|
|
125
|
+
if (options.discovery.udpMulticast) {
|
|
126
|
+
if (options.discovery.multicastAddress) {
|
|
127
|
+
await Promise.all(ips.map(ip => startServer(ip, options.discovery.port, options.discovery.multicastAddress)))
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// UDP Broadcast
|
|
132
|
+
if (options.discovery.udpBroadcast) {
|
|
133
|
+
await startServer(options.discovery.udpBindAddress, options.discovery.port, options.discovery.multicastAddress)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// send the first dis
|
|
137
|
+
const timeout = Math.floor(Math.random() * 500) + 500
|
|
138
|
+
setTimeout(() => sendDiscoveryPackage(port), timeout)
|
|
139
|
+
startDiscovering(port)
|
|
126
140
|
},
|
|
127
141
|
close () {
|
|
128
142
|
stopDiscovery()
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
|
|
2
2
|
const { defaultsDeep } = require('@weave-js/utils')
|
|
3
|
-
const TransportBase = require('../
|
|
3
|
+
const TransportBase = require('../adapteBase')
|
|
4
4
|
const Swim = require('./discovery/index')
|
|
5
|
-
const MessageTypes = require('../../
|
|
5
|
+
const MessageTypes = require('../../messageTypes')
|
|
6
6
|
const TCPReader = require('./tcpReader')
|
|
7
7
|
const TCPWriter = require('./tcpWriter')
|
|
8
|
+
const { createMessage } = require('../../createMessage')
|
|
9
|
+
|
|
8
10
|
// const TCPMessageTypeHelper = require('./tcp-messagetypes')
|
|
9
11
|
|
|
10
12
|
const defaultOptions = {
|
|
@@ -12,6 +14,7 @@ const defaultOptions = {
|
|
|
12
14
|
discovery: {
|
|
13
15
|
enabled: true,
|
|
14
16
|
type: 'udp4',
|
|
17
|
+
udpMulticast: true,
|
|
15
18
|
multicastAddress: '239.0.0.0',
|
|
16
19
|
port: 54355,
|
|
17
20
|
udpReuseAddress: true
|
|
@@ -59,7 +62,11 @@ module.exports = function SwimTransport (adapterOptions) {
|
|
|
59
62
|
MessageTypes.MESSAGE_RESPONSE,
|
|
60
63
|
MessageTypes.MESSAGE_GOSSIP_HELLO,
|
|
61
64
|
MessageTypes.MESSAGE_GOSSIP_REQUEST,
|
|
62
|
-
MessageTypes.MESSAGE_GOSSIP_RESPONSE
|
|
65
|
+
MessageTypes.MESSAGE_GOSSIP_RESPONSE,
|
|
66
|
+
MessageTypes.MESSAGE_RESPONSE_STREAM_BACKPRESSURE,
|
|
67
|
+
MessageTypes.MESSAGE_RESPONSE_STREAM_RESUME,
|
|
68
|
+
MessageTypes.MESSAGE_REQUEST_STREAM_BACKPRESSURE,
|
|
69
|
+
MessageTypes.MESSAGE_REQUEST_STREAM_RESUME
|
|
63
70
|
].includes(message.type)) {
|
|
64
71
|
if (message.type === MessageTypes.MESSAGE_DISCONNECT) {
|
|
65
72
|
// send a disconnect message to all connected nodes
|
|
@@ -81,7 +88,7 @@ module.exports = function SwimTransport (adapterOptions) {
|
|
|
81
88
|
|
|
82
89
|
const localNode = self.broker.registry.nodeCollection.localNode
|
|
83
90
|
|
|
84
|
-
const message =
|
|
91
|
+
const message = createMessage(MessageTypes.MESSAGE_GOSSIP_HELLO, nodeId, {
|
|
85
92
|
host: localNode.IPList[0],
|
|
86
93
|
port: localNode.port
|
|
87
94
|
})
|
|
@@ -165,7 +172,7 @@ module.exports = function SwimTransport (adapterOptions) {
|
|
|
165
172
|
}
|
|
166
173
|
})
|
|
167
174
|
|
|
168
|
-
self.swim.
|
|
175
|
+
self.swim.start(port)
|
|
169
176
|
}
|
|
170
177
|
|
|
171
178
|
function startTCPServer () {
|
|
@@ -174,19 +181,19 @@ module.exports = function SwimTransport (adapterOptions) {
|
|
|
174
181
|
|
|
175
182
|
tcpReader.on('message', onMessage)
|
|
176
183
|
|
|
177
|
-
tcpWriter.on('error', (error,
|
|
184
|
+
tcpWriter.on('error', (error, nodeId) => {
|
|
178
185
|
self.log.debug('TCP client error on ', error)
|
|
179
|
-
self.broker.registry.nodeDisconnected(
|
|
186
|
+
self.broker.registry.nodeDisconnected(nodeId, false)
|
|
180
187
|
})
|
|
181
188
|
|
|
182
|
-
tcpWriter.on('end',
|
|
189
|
+
tcpWriter.on('end', nodeId => {
|
|
183
190
|
self.log.debug('TCP connection ended with')
|
|
184
|
-
self.broker.registry.nodeDisconnected(
|
|
191
|
+
self.broker.registry.nodeDisconnected(nodeId, false)
|
|
185
192
|
})
|
|
186
193
|
|
|
187
|
-
// tcpWriter.on('error', (_,
|
|
194
|
+
// tcpWriter.on('error', (_, nodeId) => {
|
|
188
195
|
// self.log.debug('TCP server error on ')
|
|
189
|
-
// // this.nodes.disconnected(
|
|
196
|
+
// // this.nodes.disconnected(nodeId, false)
|
|
190
197
|
// })
|
|
191
198
|
|
|
192
199
|
return tcpReader.listen()
|
|
@@ -250,7 +257,7 @@ module.exports = function SwimTransport (adapterOptions) {
|
|
|
250
257
|
|
|
251
258
|
const destinationNode = nodes[Math.floor(Math.random() * nodes.length)]
|
|
252
259
|
if (destinationNode) {
|
|
253
|
-
const message =
|
|
260
|
+
const message = createMessage(MessageTypes.MESSAGE_GOSSIP_REQUEST, destinationNode.id, payload)
|
|
254
261
|
|
|
255
262
|
self.send(message).catch(() => {
|
|
256
263
|
self.log.debug(`Unable to send gossip response to ${destinationNode.id}`)
|
|
@@ -357,7 +364,7 @@ module.exports = function SwimTransport (adapterOptions) {
|
|
|
357
364
|
|
|
358
365
|
if (response.online || response.offline) {
|
|
359
366
|
const destinationNode = self.broker.registry.nodeCollection.get(payload.sender)
|
|
360
|
-
const message =
|
|
367
|
+
const message = createMessage(MessageTypes.MESSAGE_GOSSIP_RESPONSE, destinationNode.id, response)
|
|
361
368
|
self.send(message).catch(() => {})
|
|
362
369
|
}
|
|
363
370
|
} catch (error) {
|