@brimble/consul 2.0.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.
package/lib/watch.js ADDED
@@ -0,0 +1,183 @@
1
+ const events = require("events");
2
+
3
+ const errors = require("./errors");
4
+ const utils = require("./utils");
5
+
6
+ /**
7
+ * Initialize a new `Watch` instance.
8
+ */
9
+
10
+ class Watch extends events.EventEmitter {
11
+ constructor(consul, opts) {
12
+ super();
13
+
14
+ this.consul = consul;
15
+
16
+ opts = utils.normalizeKeys(opts);
17
+
18
+ let options = utils.normalizeKeys(opts.options || {});
19
+ options = utils.defaults(options, consul._defaults);
20
+ options.wait = options.wait || "30s";
21
+ options.index = utils.safeBigInt(options.index || "0");
22
+
23
+ if (
24
+ typeof options.timeout !== "string" &&
25
+ typeof options.timeout !== "number"
26
+ ) {
27
+ const wait = utils.parseDuration(options.wait);
28
+ // A small random amount of additional wait time is added to the supplied
29
+ // maximum wait time to spread out the wake up time of any concurrent
30
+ // requests. This adds up to wait / 16 additional time to the maximum duration.
31
+ options.timeout = Math.ceil(wait + Math.max(wait * 0.1, 500));
32
+ }
33
+
34
+ let backoffFactor = 100;
35
+ if (
36
+ opts.hasOwnProperty("backofffactor") &&
37
+ typeof opts.backofffactor === "number"
38
+ ) {
39
+ backoffFactor = opts.backofffactor;
40
+ }
41
+ let backoffMax = 30 * 1000;
42
+ if (
43
+ opts.hasOwnProperty("backoffmax") &&
44
+ typeof opts.backoffmax === "number"
45
+ ) {
46
+ backoffMax = opts.backoffmax;
47
+ }
48
+ let maxAttempts = -1;
49
+ if (
50
+ opts.hasOwnProperty("maxattempts") &&
51
+ typeof opts.maxattempts === "number"
52
+ ) {
53
+ maxAttempts = opts.maxattempts;
54
+ }
55
+
56
+ this._context = { consul: consul };
57
+ this._options = options;
58
+ this._attempts = 0;
59
+ this._maxAttempts = maxAttempts;
60
+ this._backoffMax = backoffMax;
61
+ this._backoffFactor = backoffFactor;
62
+ this._method = opts.method;
63
+ this.includeResponse = true;
64
+
65
+ if (typeof opts.method !== "function") {
66
+ throw errors.Validation("method required");
67
+ }
68
+
69
+ process.nextTick(() => this._run());
70
+ }
71
+
72
+ /**
73
+ * Is running
74
+ */
75
+ isRunning() {
76
+ return !this._end;
77
+ }
78
+
79
+ /**
80
+ * Update time
81
+ */
82
+ updateTime() {
83
+ return this._updateTime;
84
+ }
85
+
86
+ /**
87
+ * End watch
88
+ */
89
+ end() {
90
+ if (this._end) return;
91
+ this._end = true;
92
+
93
+ this.emit("cancel");
94
+ this.emit("end");
95
+ }
96
+
97
+ /**
98
+ * Wait
99
+ */
100
+ _wait() {
101
+ this._attempts += 1;
102
+ if (this._attemptsMaxed) {
103
+ return this._backoffMax;
104
+ }
105
+ const timeout = Math.pow(2, this._attempts) * this._backoffFactor;
106
+ if (timeout < this._backoffMax) {
107
+ return timeout;
108
+ } else {
109
+ this._attemptsMaxed = true;
110
+ return this._backoffMax;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Error helper
116
+ */
117
+ _err(err, res) {
118
+ if (this._end) return;
119
+
120
+ this.emit("error", err, res);
121
+
122
+ if (err && err.isValidation) return this.end();
123
+ if (res && res.statusCode === 400) return this.end();
124
+ if (this._maxAttempts >= 0 && this._attempts >= this._maxAttempts)
125
+ return this.end();
126
+
127
+ utils.setTimeoutContext(
128
+ () => {
129
+ this._run();
130
+ },
131
+ this,
132
+ this._wait(),
133
+ );
134
+ }
135
+
136
+ /**
137
+ * Run
138
+ */
139
+ _run() {
140
+ if (this._end) return;
141
+
142
+ const opts = utils.clone(this._options);
143
+ opts.ctx = this;
144
+
145
+ this._method
146
+ .call(this._context, opts)
147
+ .then(([res, data]) => {
148
+ this._updateTime = +new Date();
149
+
150
+ this._attempts = 0;
151
+ this._attemptsMaxed = false;
152
+
153
+ const newIndex = utils.safeBigInt(res.headers["x-consul-index"]);
154
+ if (newIndex === undefined) {
155
+ return this._err(errors.Validation("Watch not supported"), res);
156
+ }
157
+ if (newIndex === 0n) {
158
+ return this._err(
159
+ errors.Consul("Consul returned zero index value"),
160
+ res,
161
+ );
162
+ }
163
+
164
+ const prevIndex = this._options.index;
165
+ const reset = prevIndex !== undefined && newIndex < prevIndex;
166
+
167
+ if (reset || utils.hasIndexChanged(newIndex, prevIndex)) {
168
+ this._options.index = reset ? 0n : newIndex;
169
+
170
+ this.emit("change", data, res);
171
+ }
172
+
173
+ process.nextTick(() => {
174
+ this._run();
175
+ });
176
+ })
177
+ .catch((err) => {
178
+ this._err(err, err.response);
179
+ });
180
+ }
181
+ }
182
+
183
+ exports.Watch = Watch;
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@brimble/consul",
3
+ "version": "2.0.1",
4
+ "description": "Consul client",
5
+ "main": "./lib",
6
+ "types": "./lib/index.d.ts",
7
+ "files": [
8
+ "./lib"
9
+ ],
10
+ "dependencies": {
11
+ "papi": "^1.1.0"
12
+ },
13
+ "devDependencies": {
14
+ "@types/node": "^22.7.6",
15
+ "async": "^3.2.0",
16
+ "debug": "^4.3.1",
17
+ "jshint": "^2.5.5",
18
+ "mocha": "^10.7.3",
19
+ "nock": "^13.0.7",
20
+ "nyc": "^17.1.0",
21
+ "prettier": "^3.3.3",
22
+ "should": "^13.2.1",
23
+ "sinon": "^19.0.2",
24
+ "temp": "^0.9.4",
25
+ "tsd": "^0.31.2",
26
+ "uuid": "^10.0.0"
27
+ },
28
+ "keywords": [
29
+ "consul"
30
+ ],
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/silas/node-consul.git"
34
+ },
35
+ "bugs": {
36
+ "url": "https://github.com/silas/node-consul/issues"
37
+ },
38
+ "author": "Silas Sewell <silas@sewell.org>",
39
+ "contributors": [
40
+ "Muritala David"
41
+ ],
42
+ "license": "MIT",
43
+ "scripts": {
44
+ "format": "prettier -w .",
45
+ "test": "jshint lib test && prettier -c . && nyc mocha -- --recursive --check-leaks && nyc check-coverage --statements 100 --functions 100 --branches 100 --lines 100",
46
+ "types": "tsd",
47
+ "acceptance": "ACCEPTANCE=true nyc mocha -- test/acceptance --recursive --check-leaks --timeout 30000",
48
+ "acceptanceSetupMacOS": "sudo ifconfig lo0 alias 127.0.0.2 up && sudo ifconfig lo0 alias 127.0.0.3 up"
49
+ }
50
+ }