vrpc 3.13.0 → 3.15.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/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict'
2
- module.exports = {
3
- VrpcNative: require('./vrpc/VrpcNative'),
4
- VrpcClient: require('./vrpc/VrpcClient'),
5
- VrpcAdapter: require('./vrpc/VrpcAdapter'),
6
- VrpcAgent: require('./vrpc/VrpcAgent'),
7
- VrpcPersistor: require('./vrpc/VrpcPersistor')
8
- }
2
+ // one assignment per name: Node detects them as named exports, so
3
+ // `import { VrpcClient } from 'vrpc'` works from ES modules, too
4
+ exports.VrpcNative = require('./vrpc/VrpcNative')
5
+ exports.VrpcClient = require('./vrpc/VrpcClient')
6
+ exports.VrpcAdapter = require('./vrpc/VrpcAdapter')
7
+ exports.VrpcAgent = require('./vrpc/VrpcAgent')
8
+ exports.VrpcPersistor = require('./vrpc/VrpcPersistor')
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vrpc",
3
- "version": "3.13.0",
4
- "description": "Variadic Remote Procedure Calls",
3
+ "version": "3.15.0",
4
+ "description": "Remote objects over MQTT: call classes in other programs as if they were local - Node.js, browser, C++, Python, Arduino",
5
5
  "main": "index.js",
6
6
  "directories": {
7
7
  "example": "examples",
@@ -11,10 +11,14 @@
11
11
  "scripts": {
12
12
  "build:addon": "ln -sf binding.gyp.no-auto binding.gyp && node-gyp rebuild && rm binding.gyp",
13
13
  "build:browser": "./node_modules/.bin/webpack --stats-error-details",
14
- "build:doc": "./node_modules/.bin/jsdoc2md -f vrpc/VrpcAdapter.js vrpc/VrpcAgent.js vrpc/VrpcClient.js vrpc/VrpcNative.js --param-list-format=list --separators > docs/api.md",
15
- "test": "npm run test:adapter && npm run test:agent && npm run test:client && npm run test:persistor && npm run test:lifecycle && npm run test:legacy-runtime && npm run test:production",
14
+ "build:doc": "node scripts/build-docs.js",
15
+ "check:links": "node scripts/check-links.js",
16
+ "test": "npm run test:adapter && npm run test:subscriptions && npm run test:examples && npm run test:reconnect && npm run test:agent && npm run test:client && npm run test:persistor && npm run test:lifecycle && npm run test:legacy-runtime && npm run test:production",
16
17
  "test:adapter": "./node_modules/.bin/mocha tests/adapter/*.js --exit",
17
18
  "test:native": "./node_modules/.bin/mocha tests/native/*.js --exit",
19
+ "test:reconnect": "./node_modules/.bin/mocha tests/reconnect/*.spec.js --exit",
20
+ "test:subscriptions": "./node_modules/.bin/mocha tests/subscriptions/*.spec.js --exit",
21
+ "test:examples": "./node_modules/.bin/mocha tests/examples/*.spec.js --exit",
18
22
  "test:agent": "tests/agent/test.sh",
19
23
  "test:client": "tests/client/test.sh",
20
24
  "test:performance": "tests/performance/test.sh",
@@ -27,27 +31,32 @@
27
31
  "vrpc-agent-js": "./vrpc/vrpc-agent-js"
28
32
  },
29
33
  "keywords": [
30
- "communication",
31
- "iot",
34
+ "rpc",
32
35
  "mqtt",
36
+ "remote objects",
37
+ "remote procedure call",
38
+ "mqtt-rpc",
39
+ "iot",
33
40
  "edge-to-cloud",
34
- "rpc",
35
- "remote procedural calls",
36
- "language binding",
37
- "C++",
38
- "C++ embedding",
39
- "header-only"
41
+ "events",
42
+ "microservices",
43
+ "browser",
44
+ "react",
45
+ "arduino",
46
+ "esp32",
47
+ "python",
48
+ "c++"
40
49
  ],
41
50
  "repository": {
42
51
  "type": "git",
43
- "url": "git+https://github.com/heisenware/vrpc.git"
52
+ "url": "git+https://github.com/heisenware/vrpc-js.git"
44
53
  },
45
54
  "author": "Burkhard C. Heisen <burkhard.heisen@heisenware.com>",
46
55
  "license": "MIT",
47
56
  "bugs": {
48
- "url": "https://github.com/heisenware/vrpc/issues"
57
+ "url": "https://github.com/heisenware/vrpc-js/issues"
49
58
  },
50
- "homepage": "https://docs.heisenware.com/developers/vrpc",
59
+ "homepage": "https://vrpc.io",
51
60
  "devDependencies": {
52
61
  "@heisenware/storage": "^3.0.2",
53
62
  "assert": "^2.1.0",
@@ -57,6 +66,7 @@
57
66
  "fs-extra": "^11.3.1",
58
67
  "jsdoc-to-markdown": "^7.0.1",
59
68
  "mocha": "^9.2.2",
69
+ "mqtt-packet": "^9.0.2",
60
70
  "os-browserify": "^0.3.0",
61
71
  "sinon": "^21.0.0",
62
72
  "stream-browserify": "^3.0.0",
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Paces the reconnects of an mqtt.js client after refused CONNACKs.
3
+ *
4
+ * mqtt.js retries at a fixed `reconnectPeriod`. A connection the broker
5
+ * refuses - a stale credential, an authorization service that is away -
6
+ * would knock once per period for as long as it lives, and an
7
+ * authorization service may block a client id that knocks too often. So
8
+ * every refusal doubles the wait up to `max`, and a successful connect
9
+ * restores the base. The refusal itself stays visible as the client's
10
+ * 'error' event, so a host can renew its credentials and `hurry()`.
11
+ *
12
+ * mqtt.js reads `reconnectPeriod` only when it arms its reconnect
13
+ * interval, once per outage; re-arming it takes the internal
14
+ * `_clearReconnect` / `_setupReconnect`. Without them (a future mqtt.js)
15
+ * a new period applies from the next outage on.
16
+ */
17
+
18
+ const REFUSED = /^Connection refused/
19
+
20
+ class ReconnectBackoff {
21
+ /**
22
+ * @param {Object} client an mqtt.js client created with
23
+ * `reconnectOnConnackError: true`
24
+ * @param {Object} [options]
25
+ * @param {Number} [options.max=30000] longest wait in ms between attempts
26
+ */
27
+ constructor (client, { max = 30000 } = {}) {
28
+ this._client = client
29
+ this._base = client.options.reconnectPeriod
30
+ this._max = Math.max(max, this._base)
31
+ this._next = this._base
32
+ client.on('error', err => {
33
+ if (ReconnectBackoff.isRefusal(err)) this._slowDown()
34
+ })
35
+ client.on('connect', () => this._restore())
36
+ }
37
+
38
+ /** Whether an mqtt.js error is a refused CONNACK. */
39
+ static isRefusal (err) {
40
+ return (
41
+ !!err && typeof err.code === 'number' && REFUSED.test(err.message || '')
42
+ )
43
+ }
44
+
45
+ /** The wait in ms before the next attempt. */
46
+ get period () {
47
+ return this._client.options.reconnectPeriod
48
+ }
49
+
50
+ /**
51
+ * New credentials: the next attempt follows within the base period
52
+ * instead of waiting out the back-off. A live connection stays as it is.
53
+ */
54
+ hurry () {
55
+ this._restore()
56
+ const client = this._client
57
+ if (client.connected || client.disconnecting || !client.reconnecting) return
58
+ if (typeof client._clearReconnect !== 'function') return
59
+ client._clearReconnect()
60
+ client._setupReconnect()
61
+ }
62
+
63
+ // Runs inside the CONNACK handler's 'error' emit: the handler re-arms
64
+ // the reconnect interval right after (reconnectOnConnackError), with the
65
+ // period set here
66
+ _slowDown () {
67
+ const client = this._client
68
+ client.options.reconnectPeriod = this._next
69
+ this._next = Math.min(this._next * 2, this._max)
70
+ if (typeof client._clearReconnect === 'function') client._clearReconnect()
71
+ }
72
+
73
+ _restore () {
74
+ this._next = this._base
75
+ this._client.options.reconnectPeriod = this._base
76
+ }
77
+ }
78
+
79
+ module.exports = ReconnectBackoff