@yuneta/gobj-js 7.26.26 → 7.26.27
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/README.md +24 -6
- package/dist/gobj-js.cjs.js +140 -40
- package/dist/gobj-js.cjs.js.map +1 -1
- package/dist/gobj-js.cjs.min.js +329 -273
- package/dist/gobj-js.cjs.min.js.map +1 -1
- package/dist/gobj-js.es.js +140 -41
- package/dist/gobj-js.es.js.map +1 -1
- package/dist/gobj-js.es.min.js +380 -324
- package/dist/gobj-js.es.min.js.map +1 -1
- package/dist/gobj-js.iife.js +140 -40
- package/dist/gobj-js.iife.js.map +1 -1
- package/dist/gobj-js.iife.min.js +329 -273
- package/dist/gobj-js.iife.min.js.map +1 -1
- package/dist/gobj-js.umd.js +140 -40
- package/dist/gobj-js.umd.js.map +1 -1
- package/dist/gobj-js.umd.min.js +329 -273
- package/dist/gobj-js.umd.min.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -308,10 +308,12 @@ string, a `DTP_DICT` or a `DTP_LIST` (7.26.25): a cycle anywhere inside, a
|
|
|
308
308
|
of a class. They were written, and burst (or turned into `"{}"`) when the value
|
|
309
309
|
was serialized, far from the write. And so is a value whose text would say
|
|
310
310
|
another value (7.26.26): an object with a `toJSON()`, `NaN` or `Infinity` inside
|
|
311
|
-
(the text says `null`; jansson holds no such real), a function, `undefined
|
|
312
|
-
symbol inside an array (the text says `null`), and a value
|
|
313
|
-
2048 levels (a scalar is a level too), which C would not read
|
|
314
|
-
bursts `JSON.stringify()` a little further on.
|
|
311
|
+
(the text says `null`; jansson holds no such real), a function, `undefined`, a
|
|
312
|
+
symbol or a hole inside an array (`[1, , 3]`: the text says `null`), and a value
|
|
313
|
+
nested deeper than 2048 levels (a scalar is a level too), which C would not read
|
|
314
|
+
back and which bursts `JSON.stringify()` a little further on. Every version
|
|
315
|
+
before 7.26.26 wrote them, so this is a BREAKING change for a caller that wrote
|
|
316
|
+
one. A getter or a `Proxy` trap that
|
|
315
317
|
throws is a refusal too, never an exception (7.26.26). A key whose value is
|
|
316
318
|
`undefined`, a function or a symbol is dropped, as `JSON.stringify()` drops it:
|
|
317
319
|
an absent key. A plain object of another realm (a `vm` context, an iframe) is a
|
|
@@ -324,6 +326,7 @@ gobj_write_attr(gobj, "settings", new Map([["a", 1]])); // -1, ERROR "a valu
|
|
|
324
326
|
gobj_write_str_attr(gobj, "name", new Map()); // -1: it was the text "{}"
|
|
325
327
|
gobj_write_attr(gobj, "settings", {ratio: NaN}); // -1: it was the text {"ratio":null}
|
|
326
328
|
gobj_write_attr(gobj, "items", [1, undefined]); // -1: it was the text [1,null]
|
|
329
|
+
gobj_write_attr(gobj, "items", [1, , 3]); // -1: a hole, it was the text [1,null,3]
|
|
327
330
|
gobj_write_str_attr(gobj, "name", NaN); // -1: it was the text "null"
|
|
328
331
|
```
|
|
329
332
|
|
|
@@ -723,8 +726,20 @@ kw_clone_by_not_keys(gobj, kw, keys, verbose)
|
|
|
723
726
|
|
|
724
727
|
// Local storage helpers (browser localStorage, no "store" parameter)
|
|
725
728
|
kw_get_local_storage_value(key, default_value, create) // create=false
|
|
726
|
-
kw_set_local_storage_value(key, value)
|
|
729
|
+
kw_set_local_storage_value(key, value) // 0, or -1 logged
|
|
727
730
|
kw_remove_local_storage_value(key)
|
|
731
|
+
// BREAKING in 7.26.26: kw_get_local_storage_value() answers default_value
|
|
732
|
+
// where it answered null (an absent entry, a json null) or undefined (no
|
|
733
|
+
// browser), and an entry that is not json is REMOVED, with one WARNING
|
|
734
|
+
// that never shows its text. A store the browser blocks (cookies blocked,
|
|
735
|
+
// a sandboxed iframe: reading window.localStorage throws) answers the
|
|
736
|
+
// default, warned once per key, and a write to it is -1 (7.26.27: before,
|
|
737
|
+
// every helper and node_uuid() threw). A value with no json text is
|
|
738
|
+
// refused by the writer, -1 with an ERROR, as a typed writer refuses it
|
|
739
|
+
// (7.26.27; a function was stored as the text "undefined"):
|
|
740
|
+
// kw_set_local_storage_value("k", () => 1) → -1
|
|
741
|
+
// kw_set_local_storage_value("k", {w: NaN}) → -1 (it was {"w":null})
|
|
742
|
+
// kw_set_local_storage_value("k", [1, , 3]) → -1 (a hole: [1,null,3])
|
|
728
743
|
|
|
729
744
|
// Misc utilities
|
|
730
745
|
current_timestamp() // ISO string
|
|
@@ -1091,7 +1106,10 @@ count as reached: the backoff goes on from where it was (7.26.25), so a server
|
|
|
1091
1106
|
that breaks every session is not reconnected at the first delay for ever -- unless
|
|
1092
1107
|
the session outlived `timeout_retry_max`: a session that long was served, and its
|
|
1093
1108
|
fault starts the backoff over, as a clean end does (7.26.26). For the old fixed-interval behaviour set `timeout_retry_max` equal to
|
|
1094
|
-
`timeout_retry`.
|
|
1109
|
+
`timeout_retry`. The first delay is **at least 1000 ms** (7.26.27): a lower
|
|
1110
|
+
`timeout_retry` is raised to 1000 with one WARNING, because 0 never doubled
|
|
1111
|
+
away from 0 and a server that closes before the ack was reconnected in a loop
|
|
1112
|
+
with no wait, hundreds of times a second.
|
|
1095
1113
|
|
|
1096
1114
|
**A refused identity card** (`result < 0` in its ack) publishes `EV_ON_ID_NAK`
|
|
1097
1115
|
and closes the channel with 1000; no session was reached, so the close is then
|
package/dist/gobj-js.cjs.js
CHANGED
|
@@ -2392,11 +2392,13 @@ function rc_walk_by_list(iter_, walk_type, cb_walking, user_data, user_data2) {
|
|
|
2392
2392
|
let child;
|
|
2393
2393
|
if (walk_type & walk_type_t.WALK_LAST2FIRST) for (let i = iter.length; i > 0; i--) {
|
|
2394
2394
|
child = iter[i - 1];
|
|
2395
|
+
if (gobj_is_destroying(child)) continue;
|
|
2395
2396
|
let ret = walk_ret(cb_walking(child, user_data, user_data2));
|
|
2396
2397
|
if (ret < 0) return ret;
|
|
2397
2398
|
}
|
|
2398
2399
|
else for (let i = 0; i < iter.length; i++) {
|
|
2399
2400
|
child = iter[i];
|
|
2401
|
+
if (gobj_is_destroying(child)) continue;
|
|
2400
2402
|
let ret = walk_ret(cb_walking(child, user_data, user_data2));
|
|
2401
2403
|
if (ret < 0) return ret;
|
|
2402
2404
|
}
|
|
@@ -2411,18 +2413,21 @@ function rc_walk_by_list(iter_, walk_type, cb_walking, user_data, user_data2) {
|
|
|
2411
2413
|
* or
|
|
2412
2414
|
* WALK_LAST2FIRST
|
|
2413
2415
|
***************************************************************/
|
|
2414
|
-
function rc_walk_by_level(
|
|
2416
|
+
function rc_walk_by_level(iter_, walk_type, cb_walking, user_data, user_data2) {
|
|
2417
|
+
let iter = [...iter_];
|
|
2415
2418
|
let ret = rc_walk_by_list(iter, walk_type, cb_walking, user_data, user_data2);
|
|
2416
2419
|
if (ret < 0) return ret;
|
|
2417
2420
|
let child;
|
|
2418
2421
|
if (walk_type & walk_type_t.WALK_LAST2FIRST) for (let i = iter.length; i > 0; i--) {
|
|
2419
2422
|
child = iter[i - 1];
|
|
2420
|
-
|
|
2423
|
+
if (gobj_is_destroying(child)) continue;
|
|
2424
|
+
ret = rc_walk_by_level(child.dl_children, walk_type, cb_walking, user_data, user_data2);
|
|
2421
2425
|
if (ret < 0) return ret;
|
|
2422
2426
|
}
|
|
2423
2427
|
else for (let i = 0; i < iter.length; i++) {
|
|
2424
2428
|
child = iter[i];
|
|
2425
|
-
|
|
2429
|
+
if (gobj_is_destroying(child)) continue;
|
|
2430
|
+
ret = rc_walk_by_level(child.dl_children, walk_type, cb_walking, user_data, user_data2);
|
|
2426
2431
|
if (ret < 0) return ret;
|
|
2427
2432
|
}
|
|
2428
2433
|
return ret;
|
|
@@ -2442,23 +2447,27 @@ function rc_walk_by_level(iter, walk_type, cb_walking, user_data, user_data2) {
|
|
|
2442
2447
|
* or
|
|
2443
2448
|
* WALK_LAST2FIRST
|
|
2444
2449
|
***************************************************************/
|
|
2445
|
-
function rc_walk_by_tree(
|
|
2446
|
-
if (walk_type & walk_type_t.WALK_BYLEVEL) return rc_walk_by_level(
|
|
2450
|
+
function rc_walk_by_tree(iter_, walk_type, cb_walking, user_data, user_data2) {
|
|
2451
|
+
if (walk_type & walk_type_t.WALK_BYLEVEL) return rc_walk_by_level(iter_, walk_type, cb_walking, user_data, user_data2);
|
|
2452
|
+
let iter = [...iter_];
|
|
2447
2453
|
let ret;
|
|
2448
2454
|
let child;
|
|
2449
2455
|
if (walk_type & walk_type_t.WALK_BOTTOM2TOP) for (let i = iter.length; i > 0; i--) {
|
|
2450
2456
|
child = iter[i - 1];
|
|
2451
|
-
|
|
2457
|
+
if (gobj_is_destroying(child)) continue;
|
|
2458
|
+
ret = rc_walk_by_tree(child.dl_children, walk_type, cb_walking, user_data, user_data2);
|
|
2452
2459
|
if (ret < 0) return ret;
|
|
2460
|
+
if (gobj_is_destroying(child)) continue;
|
|
2453
2461
|
ret = walk_ret(cb_walking(child, user_data, user_data2));
|
|
2454
2462
|
if (ret < 0) return ret;
|
|
2455
2463
|
}
|
|
2456
2464
|
else for (let i = 0; i < iter.length; i++) {
|
|
2457
2465
|
child = iter[i];
|
|
2466
|
+
if (gobj_is_destroying(child)) continue;
|
|
2458
2467
|
ret = walk_ret(cb_walking(child, user_data, user_data2));
|
|
2459
2468
|
if (ret < 0) return ret;
|
|
2460
|
-
else if (ret === 0) {
|
|
2461
|
-
ret = rc_walk_by_tree(
|
|
2469
|
+
else if (ret === 0 && !gobj_is_destroying(child)) {
|
|
2470
|
+
ret = rc_walk_by_tree(child.dl_children, walk_type, cb_walking, user_data, user_data2);
|
|
2462
2471
|
if (ret < 0) return ret;
|
|
2463
2472
|
}
|
|
2464
2473
|
}
|
|
@@ -6043,40 +6052,83 @@ function kw_clone_by_not_keys(gobj, kw, keys, verbose) {
|
|
|
6043
6052
|
return kw_clone;
|
|
6044
6053
|
}
|
|
6045
6054
|
/********************************************
|
|
6055
|
+
* The browser's localStorage, or null when there is none (outside a
|
|
6056
|
+
* browser).
|
|
6057
|
+
*
|
|
6058
|
+
* With the site's data blocked (Chrome with cookies blocked, a sandboxed
|
|
6059
|
+
* iframe), READING the window.localStorage property already throws a
|
|
6060
|
+
* SecurityError, not only its getItem(): every app reads its locale at
|
|
6061
|
+
* start, so the app did not start. Such a store is answered as one whose
|
|
6062
|
+
* every call throws that error, so each helper fails as it fails for any
|
|
6063
|
+
* store that refuses it: a read gives the default, a write -1.
|
|
6064
|
+
********************************************/
|
|
6065
|
+
function local_store() {
|
|
6066
|
+
if (typeof window === "undefined") return null;
|
|
6067
|
+
let store;
|
|
6068
|
+
try {
|
|
6069
|
+
store = window.localStorage;
|
|
6070
|
+
} catch (e) {
|
|
6071
|
+
const refuse = () => {
|
|
6072
|
+
throw e;
|
|
6073
|
+
};
|
|
6074
|
+
return {
|
|
6075
|
+
getItem: refuse,
|
|
6076
|
+
setItem: refuse,
|
|
6077
|
+
removeItem: refuse
|
|
6078
|
+
};
|
|
6079
|
+
}
|
|
6080
|
+
return store || null;
|
|
6081
|
+
}
|
|
6082
|
+
/********************************************
|
|
6083
|
+
* A failure of the store that would repeat on every read is warned
|
|
6084
|
+
* once per key, until a read of the key goes well again.
|
|
6085
|
+
********************************************/
|
|
6086
|
+
var local_storage_warned = /* @__PURE__ */ new Set();
|
|
6087
|
+
function warn_local_storage_once(key, msg) {
|
|
6088
|
+
if (local_storage_warned.has(key)) return;
|
|
6089
|
+
local_storage_warned.add(key);
|
|
6090
|
+
log_warning(msg);
|
|
6091
|
+
}
|
|
6092
|
+
/********************************************
|
|
6046
6093
|
* Get a local attribute
|
|
6047
6094
|
*
|
|
6048
6095
|
* The json the entry holds, or `default_value` when there is none
|
|
6049
6096
|
* (written there too with `create`). A json null is no value, as
|
|
6050
6097
|
* json_absent() in C: the default. An entry that is not json (a
|
|
6051
|
-
* corrupt or foreign write) is
|
|
6098
|
+
* corrupt or foreign write) is a WARNING and is REMOVED, so the
|
|
6052
6099
|
* next read finds no entry: it used to console.warn on every read,
|
|
6053
|
-
* for ever
|
|
6054
|
-
* error, and an entry can hold a
|
|
6055
|
-
*
|
|
6100
|
+
* for ever; a new corrupt entry is a new WARNING. Its text is never
|
|
6101
|
+
* shown (JSON.parse() quotes it in its error, and an entry can hold a
|
|
6102
|
+
* token). A store that cannot be read (blocked) is warned once per
|
|
6103
|
+
* key, and the default is NOT written there. Outside a browser: the
|
|
6104
|
+
* default.
|
|
6056
6105
|
********************************************/
|
|
6057
|
-
var local_storage_warned = /* @__PURE__ */ new Set();
|
|
6058
|
-
function warn_local_storage_once(key, what) {
|
|
6059
|
-
if (local_storage_warned.has(key)) return;
|
|
6060
|
-
local_storage_warned.add(key);
|
|
6061
|
-
log_warning(`kw_get_local_storage_value(): localStorage key "${key}" ${what}`);
|
|
6062
|
-
}
|
|
6063
6106
|
function kw_get_local_storage_value(key, default_value, create = false) {
|
|
6064
|
-
|
|
6107
|
+
const store = local_store();
|
|
6108
|
+
if (!store) return default_value;
|
|
6109
|
+
const where = `kw_get_local_storage_value(): localStorage key "${key}"`;
|
|
6065
6110
|
let text;
|
|
6066
6111
|
try {
|
|
6067
|
-
text =
|
|
6112
|
+
text = store.getItem(key);
|
|
6068
6113
|
} catch (e) {
|
|
6069
|
-
warn_local_storage_once(key,
|
|
6114
|
+
warn_local_storage_once(key, `${where} cannot be read (storage blocked?): the default is used`);
|
|
6070
6115
|
return default_value;
|
|
6071
6116
|
}
|
|
6072
6117
|
let value = null;
|
|
6073
6118
|
if (text !== null) try {
|
|
6074
6119
|
value = JSON.parse(text);
|
|
6075
6120
|
} catch (e) {
|
|
6076
|
-
warn_local_storage_once(key, "does not hold json: removed, the default is used");
|
|
6077
|
-
kw_remove_local_storage_value(key);
|
|
6078
6121
|
value = null;
|
|
6122
|
+
try {
|
|
6123
|
+
store.removeItem(key);
|
|
6124
|
+
log_warning(`${where} does not hold json: removed, the default is used`);
|
|
6125
|
+
local_storage_warned.delete(key);
|
|
6126
|
+
} catch (e2) {
|
|
6127
|
+
warn_local_storage_once(key, `${where} does not hold json and cannot be removed: the default is used`);
|
|
6128
|
+
}
|
|
6129
|
+
text = void 0;
|
|
6079
6130
|
}
|
|
6131
|
+
if (text !== void 0) local_storage_warned.delete(key);
|
|
6080
6132
|
if (value === null) {
|
|
6081
6133
|
if (create) kw_set_local_storage_value(key, default_value);
|
|
6082
6134
|
return default_value;
|
|
@@ -6092,15 +6144,26 @@ function kw_get_local_storage_value(key, default_value, create = false) {
|
|
|
6092
6144
|
* reported success on a store that had rejected the write: a full or blocked
|
|
6093
6145
|
* localStorage (quota, private mode) silently discarded the change while the
|
|
6094
6146
|
* UI showed it as saved.
|
|
6147
|
+
*
|
|
6148
|
+
* A value with no json text is refused with an ERROR, as a typed writer
|
|
6149
|
+
* refuses it (json_text_of()): a function was stored as the text
|
|
6150
|
+
* "undefined", and a NaN, a Date or a Map as a text that reads back as
|
|
6151
|
+
* another value. Checked in Node.js too, where there is no store.
|
|
6095
6152
|
********************************************/
|
|
6096
6153
|
function kw_set_local_storage_value(key, value) {
|
|
6097
|
-
if (
|
|
6098
|
-
|
|
6099
|
-
log_error(`kw_set_local_storage_value(): invalid key or value: key=${key}`);
|
|
6154
|
+
if (!key) {
|
|
6155
|
+
log_error(`kw_set_local_storage_value(): invalid key: key=${key}`);
|
|
6100
6156
|
return -1;
|
|
6101
6157
|
}
|
|
6158
|
+
const text = json_text_of(value);
|
|
6159
|
+
if (text === void 0) {
|
|
6160
|
+
log_error(`kw_set_local_storage_value(): cannot save "${key}": a value with no json text`);
|
|
6161
|
+
return -1;
|
|
6162
|
+
}
|
|
6163
|
+
const store = local_store();
|
|
6164
|
+
if (!store) return 0;
|
|
6102
6165
|
try {
|
|
6103
|
-
|
|
6166
|
+
store.setItem(key, text);
|
|
6104
6167
|
return 0;
|
|
6105
6168
|
} catch (e) {
|
|
6106
6169
|
log_error(`kw_set_local_storage_value(): cannot save "${key}" (storage full or blocked?): ${e && e.message ? e.message : e}`);
|
|
@@ -6111,15 +6174,16 @@ function kw_set_local_storage_value(key, value) {
|
|
|
6111
6174
|
* Remove local attribute
|
|
6112
6175
|
********************************************/
|
|
6113
6176
|
function kw_remove_local_storage_value(key) {
|
|
6114
|
-
|
|
6177
|
+
const store = local_store();
|
|
6178
|
+
if (!store) return;
|
|
6115
6179
|
if (!key) {
|
|
6116
|
-
|
|
6180
|
+
log_error(`kw_remove_local_storage_value(): invalid key: key=${key}`);
|
|
6117
6181
|
return;
|
|
6118
6182
|
}
|
|
6119
6183
|
try {
|
|
6120
|
-
|
|
6184
|
+
store.removeItem(key);
|
|
6121
6185
|
} catch (e) {
|
|
6122
|
-
|
|
6186
|
+
log_warning(`kw_remove_local_storage_value(): cannot remove "${key}" (storage blocked?): ${e && e.message ? e.message : e}`);
|
|
6123
6187
|
}
|
|
6124
6188
|
}
|
|
6125
6189
|
/*************************************************************
|
|
@@ -7312,11 +7376,21 @@ function index_in_list(list, elm) {
|
|
|
7312
7376
|
************************************************************/
|
|
7313
7377
|
function node_uuid() {
|
|
7314
7378
|
let uuid = "";
|
|
7315
|
-
|
|
7316
|
-
|
|
7379
|
+
const store = local_store();
|
|
7380
|
+
if (store) {
|
|
7381
|
+
try {
|
|
7382
|
+
uuid = store.getItem("host_uuid");
|
|
7383
|
+
} catch (e) {
|
|
7384
|
+
uuid = null;
|
|
7385
|
+
warn_local_storage_once("host_uuid", "node_uuid(): localStorage cannot be read (storage blocked?): a uuid of this page only");
|
|
7386
|
+
}
|
|
7317
7387
|
if (!uuid && window.crypto?.randomUUID) {
|
|
7318
7388
|
uuid = window.crypto.randomUUID();
|
|
7319
|
-
|
|
7389
|
+
try {
|
|
7390
|
+
store.setItem("host_uuid", uuid);
|
|
7391
|
+
} catch (e) {
|
|
7392
|
+
warn_local_storage_once("host_uuid", "node_uuid(): localStorage cannot be written (storage full or blocked?): a uuid of this page only");
|
|
7393
|
+
}
|
|
7320
7394
|
}
|
|
7321
7395
|
} else if (typeof globalThis !== "undefined" && globalThis.crypto?.randomUUID) uuid = globalThis.crypto.randomUUID();
|
|
7322
7396
|
else uuid = "00000000-0000-0000-0000-000000000000";
|
|
@@ -8605,7 +8679,7 @@ var attrs_table = [
|
|
|
8605
8679
|
SDATA(data_type_t.DTP_STRING, "cert_pem", sdata_flag_t.SDF_PERSIST, "", "SSL server certification, PEM str format"),
|
|
8606
8680
|
SDATA(data_type_t.DTP_JSON, "extra_info", sdata_flag_t.SDF_RD, "{}", "dict data set by user, added to the identity card msg."),
|
|
8607
8681
|
SDATA(data_type_t.DTP_LIST, "required_services", sdata_flag_t.SDF_RD, "[]", "Services this LINK requires (identity card). Empty = the yuno's `required_services`, as before. A yuno with several links to DIFFERENT backends must set it per link: the yuno-wide list is the union, so every backend is told the service names of all the others."),
|
|
8608
|
-
SDATA(data_type_t.DTP_INTEGER, "timeout_retry", sdata_flag_t.SDF_RD, "5000", "First reconnect delay (ms). It BACKS OFF from here, doubling up to timeout_retry_max, and resets when a session is reached"),
|
|
8682
|
+
SDATA(data_type_t.DTP_INTEGER, "timeout_retry", sdata_flag_t.SDF_RD, "5000", "First reconnect delay (ms), at least 1000. It BACKS OFF from here, doubling up to timeout_retry_max, and resets when a session is reached"),
|
|
8609
8683
|
SDATA(data_type_t.DTP_INTEGER, "timeout_retry_max", sdata_flag_t.SDF_RD, "60000", "Cap of the reconnect backoff (ms). Set it equal to timeout_retry for the old fixed-interval behaviour"),
|
|
8610
8684
|
SDATA(data_type_t.DTP_INTEGER, "timeout_idack", sdata_flag_t.SDF_RD, "5000", "timeout waiting idAck"),
|
|
8611
8685
|
SDATA(data_type_t.DTP_POINTER, "subscriber", 0, 0, "subscriber of output-events. If null then subscriber is the parent"),
|
|
@@ -8630,7 +8704,8 @@ var PRIVATE_DATA = {
|
|
|
8630
8704
|
inside_on_open: false,
|
|
8631
8705
|
retry_ms: 0,
|
|
8632
8706
|
retry_ms_before_session: 0,
|
|
8633
|
-
session_since: 0
|
|
8707
|
+
session_since: 0,
|
|
8708
|
+
retry_floor_warned: false
|
|
8634
8709
|
};
|
|
8635
8710
|
var __gclass__ = null;
|
|
8636
8711
|
/******************************
|
|
@@ -8902,7 +8977,7 @@ var CLOSE_PEER_FAULT = 4002;
|
|
|
8902
8977
|
function close_for_peer_fault(gobj, reason) {
|
|
8903
8978
|
let priv = gobj.priv;
|
|
8904
8979
|
if (gobj_current_state(gobj) === "ST_SESSION") {
|
|
8905
|
-
if (performance.now() - priv.session_since <
|
|
8980
|
+
if (performance.now() - priv.session_since < retry_bounds(gobj).max) priv.retry_ms = priv.retry_ms_before_session;
|
|
8906
8981
|
priv.retry_ms_before_session = 0;
|
|
8907
8982
|
}
|
|
8908
8983
|
close_websocket(gobj, CLOSE_PEER_FAULT, reason);
|
|
@@ -9174,6 +9249,32 @@ function ac_on_close(gobj, event, kw, src) {
|
|
|
9174
9249
|
return 0;
|
|
9175
9250
|
}
|
|
9176
9251
|
/***************************************************************
|
|
9252
|
+
* The first delay of the backoff and its cap.
|
|
9253
|
+
*
|
|
9254
|
+
* A first delay below RETRY_FLOOR_MS is raised to it, with a WARNING
|
|
9255
|
+
* once: `timeout_retry` 0 never left 0 (0 doubled is 0), so a server
|
|
9256
|
+
* that closed before the ack was reconnected in a loop with no wait,
|
|
9257
|
+
* hundreds of connections a second.
|
|
9258
|
+
***************************************************************/
|
|
9259
|
+
var RETRY_FLOOR_MS = 1e3;
|
|
9260
|
+
function retry_bounds(gobj) {
|
|
9261
|
+
let priv = gobj.priv;
|
|
9262
|
+
let base = gobj_read_integer_attr(gobj, "timeout_retry");
|
|
9263
|
+
let max = gobj_read_integer_attr(gobj, "timeout_retry_max");
|
|
9264
|
+
if (!(base >= RETRY_FLOOR_MS)) {
|
|
9265
|
+
if (!priv.retry_floor_warned) {
|
|
9266
|
+
priv.retry_floor_warned = true;
|
|
9267
|
+
log_warning(`${gobj_short_name(gobj)}: timeout_retry ${base} ms is below ${RETRY_FLOOR_MS} ms: ${RETRY_FLOOR_MS} ms is used`);
|
|
9268
|
+
}
|
|
9269
|
+
base = RETRY_FLOOR_MS;
|
|
9270
|
+
}
|
|
9271
|
+
if (!(max >= base)) max = base;
|
|
9272
|
+
return {
|
|
9273
|
+
base,
|
|
9274
|
+
max
|
|
9275
|
+
};
|
|
9276
|
+
}
|
|
9277
|
+
/***************************************************************
|
|
9177
9278
|
* How long to wait before the next reconnect attempt.
|
|
9178
9279
|
*
|
|
9179
9280
|
* The delay used to be a constant (`timeout_retry`, 5s), for ever. A
|
|
@@ -9194,9 +9295,7 @@ function ac_on_close(gobj, event, kw, src) {
|
|
|
9194
9295
|
***************************************************************/
|
|
9195
9296
|
function next_retry(gobj) {
|
|
9196
9297
|
let priv = gobj.priv;
|
|
9197
|
-
|
|
9198
|
-
let max = gobj_read_integer_attr(gobj, "timeout_retry_max");
|
|
9199
|
-
if (max < base) max = base;
|
|
9298
|
+
const { base, max } = retry_bounds(gobj);
|
|
9200
9299
|
priv.retry_ms = priv.retry_ms ? Math.min(priv.retry_ms * 2, max) : base;
|
|
9201
9300
|
let jitter = priv.retry_ms * .2;
|
|
9202
9301
|
let ms = priv.retry_ms - jitter + Math.random() * 2 * jitter;
|
|
@@ -9694,6 +9793,7 @@ exports.json_object_update = json_object_update;
|
|
|
9694
9793
|
exports.json_object_update_existing = json_object_update_existing;
|
|
9695
9794
|
exports.json_object_update_missing = json_object_update_missing;
|
|
9696
9795
|
exports.json_size = json_size;
|
|
9796
|
+
exports.json_text_of = json_text_of;
|
|
9697
9797
|
exports.jwt2json = jwt2json;
|
|
9698
9798
|
exports.jwtDecode = jwtDecode;
|
|
9699
9799
|
exports.kw_clone_by_keys = kw_clone_by_keys;
|