@yuneta/gobj-js 7.26.26 → 7.26.28
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 +38 -8
- package/dist/gobj-js.cjs.js +251 -60
- package/dist/gobj-js.cjs.js.map +1 -1
- package/dist/gobj-js.cjs.min.js +802 -692
- package/dist/gobj-js.cjs.min.js.map +1 -1
- package/dist/gobj-js.es.js +251 -61
- package/dist/gobj-js.es.js.map +1 -1
- package/dist/gobj-js.es.min.js +460 -351
- package/dist/gobj-js.es.min.js.map +1 -1
- package/dist/gobj-js.iife.js +251 -60
- package/dist/gobj-js.iife.js.map +1 -1
- package/dist/gobj-js.iife.min.js +795 -685
- package/dist/gobj-js.iife.min.js.map +1 -1
- package/dist/gobj-js.umd.js +251 -60
- package/dist/gobj-js.umd.js.map +1 -1
- package/dist/gobj-js.umd.min.js +795 -685
- package/dist/gobj-js.umd.min.js.map +1 -1
- package/package.json +1 -1
package/dist/gobj-js.es.js
CHANGED
|
@@ -1948,6 +1948,31 @@ function gobj_destroy_children(gobj) {
|
|
|
1948
1948
|
}
|
|
1949
1949
|
}
|
|
1950
1950
|
/************************************************************
|
|
1951
|
+
* The SDF_REQUIRED attributes with no value, or null when there
|
|
1952
|
+
* is none: what is empty is asked type by type, as in C.
|
|
1953
|
+
************************************************************/
|
|
1954
|
+
function gobj_check_required_attrs(gobj) {
|
|
1955
|
+
const hs = gobj_hsdata(gobj);
|
|
1956
|
+
const missing = [];
|
|
1957
|
+
if (!is_array(gobj.gclass.attrs_table)) return null;
|
|
1958
|
+
for (const it of gobj.gclass.attrs_table) {
|
|
1959
|
+
if (!it.name || !(it.flag & sdata_flag_t.SDF_REQUIRED)) continue;
|
|
1960
|
+
const value = hs[it.name];
|
|
1961
|
+
switch (it.type) {
|
|
1962
|
+
case data_type_t.DTP_STRING:
|
|
1963
|
+
if (!is_string(value) || empty_string(value)) missing.push(it.name);
|
|
1964
|
+
break;
|
|
1965
|
+
case data_type_t.DTP_LIST:
|
|
1966
|
+
case data_type_t.DTP_DICT:
|
|
1967
|
+
case data_type_t.DTP_JSON:
|
|
1968
|
+
if (empty_json(value)) missing.push(it.name);
|
|
1969
|
+
break;
|
|
1970
|
+
case data_type_t.DTP_POINTER: if (!value) missing.push(it.name);
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
return missing.length ? missing : null;
|
|
1974
|
+
}
|
|
1975
|
+
/************************************************************
|
|
1951
1976
|
*
|
|
1952
1977
|
************************************************************/
|
|
1953
1978
|
function gobj_start(gobj) {
|
|
@@ -1963,6 +1988,11 @@ function gobj_start(gobj) {
|
|
|
1963
1988
|
log_error(`${gobj_short_name(gobj)}: GObj DISABLED`);
|
|
1964
1989
|
return -1;
|
|
1965
1990
|
}
|
|
1991
|
+
const required_attrs = gobj_check_required_attrs(gobj);
|
|
1992
|
+
if (required_attrs) {
|
|
1993
|
+
log_error(`${gobj_short_name(gobj)}: Cannot start without all required attributes: ` + JSON.stringify(required_attrs));
|
|
1994
|
+
return -1;
|
|
1995
|
+
}
|
|
1966
1996
|
if (__trace_gobj_start_stop__(gobj)) trace_machine(sprintf("⏺ ⏺ start: %s", gobj_full_name(gobj)));
|
|
1967
1997
|
gobj.running = true;
|
|
1968
1998
|
let ret = 0;
|
|
@@ -2349,7 +2379,7 @@ function gobj_walk_gobj_children(gobj, walk_type, cb_walking, user_data, user_da
|
|
|
2349
2379
|
log_error(`gobj NULL, destroying, or bad type`);
|
|
2350
2380
|
return 0;
|
|
2351
2381
|
}
|
|
2352
|
-
return rc_walk_by_list(gobj
|
|
2382
|
+
return rc_walk_by_list(gobj, /* @__PURE__ */ new Set(), walk_type, cb_walking, user_data, user_data2);
|
|
2353
2383
|
}
|
|
2354
2384
|
/***************************************************************************
|
|
2355
2385
|
*
|
|
@@ -2359,7 +2389,7 @@ function gobj_walk_gobj_children_tree(gobj, walk_type, cb_walking, user_data, us
|
|
|
2359
2389
|
log_error(`gobj NULL, destroying, or bad type`);
|
|
2360
2390
|
return 0;
|
|
2361
2391
|
}
|
|
2362
|
-
return rc_walk_by_tree(gobj
|
|
2392
|
+
return rc_walk_by_tree(gobj, /* @__PURE__ */ new Set(), walk_type, cb_walking, user_data, user_data2);
|
|
2363
2393
|
}
|
|
2364
2394
|
/***************************************************************
|
|
2365
2395
|
* Walking
|
|
@@ -2386,16 +2416,33 @@ function walk_ret(ret) {
|
|
|
2386
2416
|
log_error(`walk callback must return a NUMBER (-1 stop, 0 descend, >0 skip children), got ${typeof ret}: taken as 0`);
|
|
2387
2417
|
return 0;
|
|
2388
2418
|
}
|
|
2389
|
-
|
|
2390
|
-
|
|
2419
|
+
/***************************************************************
|
|
2420
|
+
* Whether a walk steps over this gobj of the list of `owner`.
|
|
2421
|
+
*
|
|
2422
|
+
* Each list is walked over a COPY of it, because a callback may destroy
|
|
2423
|
+
* any gobj of the list, the current one included, or move one with
|
|
2424
|
+
* gobj_change_parent(). One it destroyed is stepped over, as the C walk
|
|
2425
|
+
* does; one it moved is no longer in this list, and is handed where the
|
|
2426
|
+
* walk finds it now (7.26.27 handed it here AND there); and a gobj is
|
|
2427
|
+
* never handed twice in one walk (`seen`), wherever it was moved.
|
|
2428
|
+
***************************************************************/
|
|
2429
|
+
function walk_steps_over(child, owner, seen) {
|
|
2430
|
+
return gobj_is_destroying(child) || child.parent !== owner || seen.has(child);
|
|
2431
|
+
}
|
|
2432
|
+
function rc_walk_by_list(owner, seen, walk_type, cb_walking, user_data, user_data2) {
|
|
2433
|
+
let iter = [...owner.dl_children];
|
|
2391
2434
|
let child;
|
|
2392
2435
|
if (walk_type & walk_type_t.WALK_LAST2FIRST) for (let i = iter.length; i > 0; i--) {
|
|
2393
2436
|
child = iter[i - 1];
|
|
2437
|
+
if (walk_steps_over(child, owner, seen)) continue;
|
|
2438
|
+
seen.add(child);
|
|
2394
2439
|
let ret = walk_ret(cb_walking(child, user_data, user_data2));
|
|
2395
2440
|
if (ret < 0) return ret;
|
|
2396
2441
|
}
|
|
2397
2442
|
else for (let i = 0; i < iter.length; i++) {
|
|
2398
2443
|
child = iter[i];
|
|
2444
|
+
if (walk_steps_over(child, owner, seen)) continue;
|
|
2445
|
+
seen.add(child);
|
|
2399
2446
|
let ret = walk_ret(cb_walking(child, user_data, user_data2));
|
|
2400
2447
|
if (ret < 0) return ret;
|
|
2401
2448
|
}
|
|
@@ -2410,21 +2457,23 @@ function rc_walk_by_list(iter_, walk_type, cb_walking, user_data, user_data2) {
|
|
|
2410
2457
|
* or
|
|
2411
2458
|
* WALK_LAST2FIRST
|
|
2412
2459
|
***************************************************************/
|
|
2413
|
-
function rc_walk_by_level(
|
|
2414
|
-
let
|
|
2415
|
-
if (
|
|
2416
|
-
let
|
|
2417
|
-
|
|
2418
|
-
child
|
|
2419
|
-
|
|
2460
|
+
function rc_walk_by_level(owner, seen, walk_type, cb_walking, user_data, user_data2) {
|
|
2461
|
+
let iter = [...owner.dl_children];
|
|
2462
|
+
if (walk_type & walk_type_t.WALK_LAST2FIRST) iter.reverse();
|
|
2463
|
+
let handed = [];
|
|
2464
|
+
for (const child of iter) {
|
|
2465
|
+
if (walk_steps_over(child, owner, seen)) continue;
|
|
2466
|
+
seen.add(child);
|
|
2467
|
+
handed.push(child);
|
|
2468
|
+
let ret = walk_ret(cb_walking(child, user_data, user_data2));
|
|
2420
2469
|
if (ret < 0) return ret;
|
|
2421
2470
|
}
|
|
2422
|
-
|
|
2423
|
-
child
|
|
2424
|
-
ret = rc_walk_by_level(
|
|
2471
|
+
for (const child of handed) {
|
|
2472
|
+
if (gobj_is_destroying(child)) continue;
|
|
2473
|
+
let ret = rc_walk_by_level(child, seen, walk_type, cb_walking, user_data, user_data2);
|
|
2425
2474
|
if (ret < 0) return ret;
|
|
2426
2475
|
}
|
|
2427
|
-
return
|
|
2476
|
+
return 0;
|
|
2428
2477
|
}
|
|
2429
2478
|
/***************************************************************
|
|
2430
2479
|
* Walking
|
|
@@ -2441,23 +2490,29 @@ function rc_walk_by_level(iter, walk_type, cb_walking, user_data, user_data2) {
|
|
|
2441
2490
|
* or
|
|
2442
2491
|
* WALK_LAST2FIRST
|
|
2443
2492
|
***************************************************************/
|
|
2444
|
-
function rc_walk_by_tree(
|
|
2445
|
-
if (walk_type & walk_type_t.WALK_BYLEVEL) return rc_walk_by_level(
|
|
2493
|
+
function rc_walk_by_tree(owner, seen, walk_type, cb_walking, user_data, user_data2) {
|
|
2494
|
+
if (walk_type & walk_type_t.WALK_BYLEVEL) return rc_walk_by_level(owner, seen, walk_type, cb_walking, user_data, user_data2);
|
|
2495
|
+
let iter = [...owner.dl_children];
|
|
2446
2496
|
let ret;
|
|
2447
2497
|
let child;
|
|
2448
2498
|
if (walk_type & walk_type_t.WALK_BOTTOM2TOP) for (let i = iter.length; i > 0; i--) {
|
|
2449
2499
|
child = iter[i - 1];
|
|
2450
|
-
|
|
2500
|
+
if (walk_steps_over(child, owner, seen)) continue;
|
|
2501
|
+
ret = rc_walk_by_tree(child, seen, walk_type, cb_walking, user_data, user_data2);
|
|
2451
2502
|
if (ret < 0) return ret;
|
|
2503
|
+
if (gobj_is_destroying(child)) continue;
|
|
2504
|
+
seen.add(child);
|
|
2452
2505
|
ret = walk_ret(cb_walking(child, user_data, user_data2));
|
|
2453
2506
|
if (ret < 0) return ret;
|
|
2454
2507
|
}
|
|
2455
2508
|
else for (let i = 0; i < iter.length; i++) {
|
|
2456
2509
|
child = iter[i];
|
|
2510
|
+
if (walk_steps_over(child, owner, seen)) continue;
|
|
2511
|
+
seen.add(child);
|
|
2457
2512
|
ret = walk_ret(cb_walking(child, user_data, user_data2));
|
|
2458
2513
|
if (ret < 0) return ret;
|
|
2459
|
-
else if (ret === 0) {
|
|
2460
|
-
ret = rc_walk_by_tree(
|
|
2514
|
+
else if (ret === 0 && !gobj_is_destroying(child)) {
|
|
2515
|
+
ret = rc_walk_by_tree(child, seen, walk_type, cb_walking, user_data, user_data2);
|
|
2461
2516
|
if (ret < 0) return ret;
|
|
2462
2517
|
}
|
|
2463
2518
|
}
|
|
@@ -6042,44 +6097,99 @@ function kw_clone_by_not_keys(gobj, kw, keys, verbose) {
|
|
|
6042
6097
|
return kw_clone;
|
|
6043
6098
|
}
|
|
6044
6099
|
/********************************************
|
|
6100
|
+
* The browser's localStorage, or null when there is none (outside a
|
|
6101
|
+
* browser).
|
|
6102
|
+
*
|
|
6103
|
+
* With the site's data blocked (Chrome with cookies blocked, a sandboxed
|
|
6104
|
+
* iframe), READING the window.localStorage property already throws a
|
|
6105
|
+
* SecurityError, not only its getItem(): every app reads its locale at
|
|
6106
|
+
* start, so the app did not start. Such a store is answered as one whose
|
|
6107
|
+
* every call throws that error, so each helper fails as it fails for any
|
|
6108
|
+
* store that refuses it: a read gives the default, a write -1.
|
|
6109
|
+
********************************************/
|
|
6110
|
+
function local_store() {
|
|
6111
|
+
if (typeof window === "undefined") return null;
|
|
6112
|
+
let store;
|
|
6113
|
+
try {
|
|
6114
|
+
store = window.localStorage;
|
|
6115
|
+
} catch (e) {
|
|
6116
|
+
const refuse = () => {
|
|
6117
|
+
throw e;
|
|
6118
|
+
};
|
|
6119
|
+
return {
|
|
6120
|
+
getItem: refuse,
|
|
6121
|
+
setItem: refuse,
|
|
6122
|
+
removeItem: refuse
|
|
6123
|
+
};
|
|
6124
|
+
}
|
|
6125
|
+
return store || null;
|
|
6126
|
+
}
|
|
6127
|
+
/********************************************
|
|
6128
|
+
* A failure of the store that would repeat on every read is warned
|
|
6129
|
+
* once per key, until a read of the key goes well again.
|
|
6130
|
+
********************************************/
|
|
6131
|
+
var local_storage_warned = /* @__PURE__ */ new Set();
|
|
6132
|
+
function warn_local_storage_once(key, msg) {
|
|
6133
|
+
if (local_storage_warned.has(key)) return;
|
|
6134
|
+
local_storage_warned.add(key);
|
|
6135
|
+
log_warning(msg);
|
|
6136
|
+
}
|
|
6137
|
+
/********************************************
|
|
6045
6138
|
* Get a local attribute
|
|
6046
6139
|
*
|
|
6047
6140
|
* The json the entry holds, or `default_value` when there is none
|
|
6048
6141
|
* (written there too with `create`). A json null is no value, as
|
|
6049
6142
|
* json_absent() in C: the default. An entry that is not json (a
|
|
6050
|
-
* corrupt or foreign write) is
|
|
6143
|
+
* corrupt or foreign write) is a WARNING and is REMOVED, so the
|
|
6051
6144
|
* next read finds no entry: it used to console.warn on every read,
|
|
6052
|
-
* for ever
|
|
6053
|
-
* error, and an entry can hold a
|
|
6054
|
-
*
|
|
6145
|
+
* for ever; a new corrupt entry is a new WARNING. Its text is never
|
|
6146
|
+
* shown (JSON.parse() quotes it in its error, and an entry can hold a
|
|
6147
|
+
* token). A store that cannot be read (blocked) is warned once per
|
|
6148
|
+
* key, and the default is NOT written there; one that cannot be
|
|
6149
|
+
* written (full) is warned once per key too: with `create` it was an
|
|
6150
|
+
* ERROR on every read, the default tried again each time. A key is
|
|
6151
|
+
* warned again after a read that goes well. Outside a browser: the
|
|
6152
|
+
* default.
|
|
6055
6153
|
********************************************/
|
|
6056
|
-
var local_storage_warned = /* @__PURE__ */ new Set();
|
|
6057
|
-
function warn_local_storage_once(key, what) {
|
|
6058
|
-
if (local_storage_warned.has(key)) return;
|
|
6059
|
-
local_storage_warned.add(key);
|
|
6060
|
-
log_warning(`kw_get_local_storage_value(): localStorage key "${key}" ${what}`);
|
|
6061
|
-
}
|
|
6062
6154
|
function kw_get_local_storage_value(key, default_value, create = false) {
|
|
6063
|
-
|
|
6155
|
+
const store = local_store();
|
|
6156
|
+
if (!store) return default_value;
|
|
6157
|
+
const where = `kw_get_local_storage_value(): localStorage key "${key}"`;
|
|
6064
6158
|
let text;
|
|
6065
6159
|
try {
|
|
6066
|
-
text =
|
|
6160
|
+
text = store.getItem(key);
|
|
6067
6161
|
} catch (e) {
|
|
6068
|
-
warn_local_storage_once(key,
|
|
6162
|
+
warn_local_storage_once(key, `${where} cannot be read (storage blocked?): the default is used`);
|
|
6069
6163
|
return default_value;
|
|
6070
6164
|
}
|
|
6165
|
+
let went_well = true;
|
|
6071
6166
|
let value = null;
|
|
6072
6167
|
if (text !== null) try {
|
|
6073
6168
|
value = JSON.parse(text);
|
|
6074
6169
|
} catch (e) {
|
|
6075
|
-
warn_local_storage_once(key, "does not hold json: removed, the default is used");
|
|
6076
|
-
kw_remove_local_storage_value(key);
|
|
6077
6170
|
value = null;
|
|
6171
|
+
try {
|
|
6172
|
+
store.removeItem(key);
|
|
6173
|
+
log_warning(`${where} does not hold json: removed, the default is used`);
|
|
6174
|
+
} catch (e2) {
|
|
6175
|
+
went_well = false;
|
|
6176
|
+
warn_local_storage_once(key, `${where} does not hold json and cannot be removed: the default is used`);
|
|
6177
|
+
}
|
|
6078
6178
|
}
|
|
6079
6179
|
if (value === null) {
|
|
6080
|
-
|
|
6081
|
-
|
|
6180
|
+
value = default_value;
|
|
6181
|
+
if (create) {
|
|
6182
|
+
const default_text = json_text_of(default_value);
|
|
6183
|
+
if (default_text === void 0) log_error(`${where}: cannot write the default: a value with no json text`);
|
|
6184
|
+
else try {
|
|
6185
|
+
store.setItem(key, default_text);
|
|
6186
|
+
} catch (e) {
|
|
6187
|
+
went_well = false;
|
|
6188
|
+
warn_local_storage_once(key, `${where} cannot be written (storage full or blocked?): the default is used, not kept`);
|
|
6189
|
+
}
|
|
6190
|
+
}
|
|
6082
6191
|
}
|
|
6192
|
+
if (went_well) local_storage_warned.delete(key);
|
|
6083
6193
|
return value;
|
|
6084
6194
|
}
|
|
6085
6195
|
/********************************************
|
|
@@ -6091,15 +6201,26 @@ function kw_get_local_storage_value(key, default_value, create = false) {
|
|
|
6091
6201
|
* reported success on a store that had rejected the write: a full or blocked
|
|
6092
6202
|
* localStorage (quota, private mode) silently discarded the change while the
|
|
6093
6203
|
* UI showed it as saved.
|
|
6204
|
+
*
|
|
6205
|
+
* A value with no json text is refused with an ERROR, as a typed writer
|
|
6206
|
+
* refuses it (json_text_of()): a function was stored as the text
|
|
6207
|
+
* "undefined", and a NaN, a Date or a Map as a text that reads back as
|
|
6208
|
+
* another value. Checked in Node.js too, where there is no store.
|
|
6094
6209
|
********************************************/
|
|
6095
6210
|
function kw_set_local_storage_value(key, value) {
|
|
6096
|
-
if (
|
|
6097
|
-
|
|
6098
|
-
|
|
6211
|
+
if (!key) {
|
|
6212
|
+
log_error(`kw_set_local_storage_value(): invalid key: key=${key}`);
|
|
6213
|
+
return -1;
|
|
6214
|
+
}
|
|
6215
|
+
const text = json_text_of(value);
|
|
6216
|
+
if (text === void 0) {
|
|
6217
|
+
log_error(`kw_set_local_storage_value(): cannot save "${key}": a value with no json text`);
|
|
6099
6218
|
return -1;
|
|
6100
6219
|
}
|
|
6220
|
+
const store = local_store();
|
|
6221
|
+
if (!store) return 0;
|
|
6101
6222
|
try {
|
|
6102
|
-
|
|
6223
|
+
store.setItem(key, text);
|
|
6103
6224
|
return 0;
|
|
6104
6225
|
} catch (e) {
|
|
6105
6226
|
log_error(`kw_set_local_storage_value(): cannot save "${key}" (storage full or blocked?): ${e && e.message ? e.message : e}`);
|
|
@@ -6110,15 +6231,16 @@ function kw_set_local_storage_value(key, value) {
|
|
|
6110
6231
|
* Remove local attribute
|
|
6111
6232
|
********************************************/
|
|
6112
6233
|
function kw_remove_local_storage_value(key) {
|
|
6113
|
-
|
|
6234
|
+
const store = local_store();
|
|
6235
|
+
if (!store) return;
|
|
6114
6236
|
if (!key) {
|
|
6115
|
-
|
|
6237
|
+
log_error(`kw_remove_local_storage_value(): invalid key: key=${key}`);
|
|
6116
6238
|
return;
|
|
6117
6239
|
}
|
|
6118
6240
|
try {
|
|
6119
|
-
|
|
6241
|
+
store.removeItem(key);
|
|
6120
6242
|
} catch (e) {
|
|
6121
|
-
|
|
6243
|
+
log_warning(`kw_remove_local_storage_value(): cannot remove "${key}" (storage blocked?): ${e && e.message ? e.message : e}`);
|
|
6122
6244
|
}
|
|
6123
6245
|
}
|
|
6124
6246
|
/*************************************************************
|
|
@@ -7307,19 +7429,62 @@ function index_in_list(list, elm) {
|
|
|
7307
7429
|
return -1;
|
|
7308
7430
|
}
|
|
7309
7431
|
/************************************************************
|
|
7432
|
+
* A new uuid v4 (RFC 9562).
|
|
7310
7433
|
*
|
|
7434
|
+
* crypto.randomUUID() exists only in a secure context, so a page
|
|
7435
|
+
* served over http without TLS has none; crypto.getRandomValues()
|
|
7436
|
+
* exists there too. With no crypto at all, Math.random(): not fit
|
|
7437
|
+
* for a secret, and a uuid that names a node is not one.
|
|
7311
7438
|
************************************************************/
|
|
7439
|
+
function new_uuid() {
|
|
7440
|
+
const c = typeof window !== "undefined" && window.crypto || globalThis.crypto;
|
|
7441
|
+
if (c && typeof c.randomUUID === "function") return c.randomUUID();
|
|
7442
|
+
const b = /* @__PURE__ */ new Uint8Array(16);
|
|
7443
|
+
if (c && typeof c.getRandomValues === "function") c.getRandomValues(b);
|
|
7444
|
+
else for (let i = 0; i < b.length; i++) b[i] = Math.floor(Math.random() * 256);
|
|
7445
|
+
b[6] = b[6] & 15 | 64;
|
|
7446
|
+
b[8] = b[8] & 63 | 128;
|
|
7447
|
+
const h = Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
|
|
7448
|
+
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;
|
|
7449
|
+
}
|
|
7450
|
+
/************************************************************
|
|
7451
|
+
* The uuid of this node: ONE for the life of the page.
|
|
7452
|
+
*
|
|
7453
|
+
* The one the store keeps ("host_uuid"), made and written there when
|
|
7454
|
+
* there is none. When the store cannot keep it (blocked, full, no
|
|
7455
|
+
* localStorage, outside a browser) the one this page made, warned
|
|
7456
|
+
* once. It goes in the node_uuid attribute of the yuno, the id of the
|
|
7457
|
+
* identity card and the `host` of every message the client sends, so
|
|
7458
|
+
* the first answer is kept and answered again: 7.26.27 made a new
|
|
7459
|
+
* uuid on every call when the store could not keep it, and answered
|
|
7460
|
+
* null without crypto.randomUUID().
|
|
7461
|
+
************************************************************/
|
|
7462
|
+
var uuid_of_this_page = null;
|
|
7312
7463
|
function node_uuid() {
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
|
|
7317
|
-
|
|
7318
|
-
|
|
7464
|
+
if (uuid_of_this_page) return uuid_of_this_page;
|
|
7465
|
+
const store = local_store();
|
|
7466
|
+
if (!store) {
|
|
7467
|
+
uuid_of_this_page = new_uuid();
|
|
7468
|
+
return uuid_of_this_page;
|
|
7469
|
+
}
|
|
7470
|
+
let uuid = null;
|
|
7471
|
+
try {
|
|
7472
|
+
uuid = store.getItem("host_uuid");
|
|
7473
|
+
} catch (e) {
|
|
7474
|
+
warn_local_storage_once("host_uuid", "node_uuid(): localStorage cannot be read (storage blocked?): a uuid of this page only");
|
|
7475
|
+
uuid_of_this_page = new_uuid();
|
|
7476
|
+
return uuid_of_this_page;
|
|
7477
|
+
}
|
|
7478
|
+
if (!uuid) {
|
|
7479
|
+
uuid = new_uuid();
|
|
7480
|
+
try {
|
|
7481
|
+
store.setItem("host_uuid", uuid);
|
|
7482
|
+
} catch (e) {
|
|
7483
|
+
warn_local_storage_once("host_uuid", "node_uuid(): localStorage cannot be written (storage full or blocked?): a uuid of this page only");
|
|
7319
7484
|
}
|
|
7320
|
-
}
|
|
7321
|
-
|
|
7322
|
-
return
|
|
7485
|
+
}
|
|
7486
|
+
uuid_of_this_page = uuid;
|
|
7487
|
+
return uuid_of_this_page;
|
|
7323
7488
|
}
|
|
7324
7489
|
/************************************************************
|
|
7325
7490
|
* Build a cleaned name
|
|
@@ -8604,7 +8769,7 @@ var attrs_table = [
|
|
|
8604
8769
|
SDATA(data_type_t.DTP_STRING, "cert_pem", sdata_flag_t.SDF_PERSIST, "", "SSL server certification, PEM str format"),
|
|
8605
8770
|
SDATA(data_type_t.DTP_JSON, "extra_info", sdata_flag_t.SDF_RD, "{}", "dict data set by user, added to the identity card msg."),
|
|
8606
8771
|
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."),
|
|
8607
|
-
SDATA(data_type_t.DTP_INTEGER, "timeout_retry", sdata_flag_t.SDF_RD, "5000", "
|
|
8772
|
+
SDATA(data_type_t.DTP_INTEGER, "timeout_retry", sdata_flag_t.SDF_RD, "5000", "Base of the first reconnect delay (ms, ±20% jitter), at least 1000. It BACKS OFF from here, doubling up to timeout_retry_max, and resets when a session is reached"),
|
|
8608
8773
|
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"),
|
|
8609
8774
|
SDATA(data_type_t.DTP_INTEGER, "timeout_idack", sdata_flag_t.SDF_RD, "5000", "timeout waiting idAck"),
|
|
8610
8775
|
SDATA(data_type_t.DTP_POINTER, "subscriber", 0, 0, "subscriber of output-events. If null then subscriber is the parent"),
|
|
@@ -8629,7 +8794,8 @@ var PRIVATE_DATA = {
|
|
|
8629
8794
|
inside_on_open: false,
|
|
8630
8795
|
retry_ms: 0,
|
|
8631
8796
|
retry_ms_before_session: 0,
|
|
8632
|
-
session_since: 0
|
|
8797
|
+
session_since: 0,
|
|
8798
|
+
retry_floor_warned: false
|
|
8633
8799
|
};
|
|
8634
8800
|
var __gclass__ = null;
|
|
8635
8801
|
/******************************
|
|
@@ -8901,7 +9067,7 @@ var CLOSE_PEER_FAULT = 4002;
|
|
|
8901
9067
|
function close_for_peer_fault(gobj, reason) {
|
|
8902
9068
|
let priv = gobj.priv;
|
|
8903
9069
|
if (gobj_current_state(gobj) === "ST_SESSION") {
|
|
8904
|
-
if (performance.now() - priv.session_since <
|
|
9070
|
+
if (performance.now() - priv.session_since < retry_bounds(gobj).max) priv.retry_ms = priv.retry_ms_before_session;
|
|
8905
9071
|
priv.retry_ms_before_session = 0;
|
|
8906
9072
|
}
|
|
8907
9073
|
close_websocket(gobj, CLOSE_PEER_FAULT, reason);
|
|
@@ -9173,6 +9339,32 @@ function ac_on_close(gobj, event, kw, src) {
|
|
|
9173
9339
|
return 0;
|
|
9174
9340
|
}
|
|
9175
9341
|
/***************************************************************
|
|
9342
|
+
* The first delay of the backoff and its cap.
|
|
9343
|
+
*
|
|
9344
|
+
* A first delay below RETRY_FLOOR_MS is raised to it, with a WARNING
|
|
9345
|
+
* once: `timeout_retry` 0 never left 0 (0 doubled is 0), so a server
|
|
9346
|
+
* that closed before the ack was reconnected in a loop with no wait,
|
|
9347
|
+
* hundreds of connections a second.
|
|
9348
|
+
***************************************************************/
|
|
9349
|
+
var RETRY_FLOOR_MS = 1e3;
|
|
9350
|
+
function retry_bounds(gobj) {
|
|
9351
|
+
let priv = gobj.priv;
|
|
9352
|
+
let base = gobj_read_integer_attr(gobj, "timeout_retry");
|
|
9353
|
+
let max = gobj_read_integer_attr(gobj, "timeout_retry_max");
|
|
9354
|
+
if (!(base >= RETRY_FLOOR_MS)) {
|
|
9355
|
+
if (!priv.retry_floor_warned) {
|
|
9356
|
+
priv.retry_floor_warned = true;
|
|
9357
|
+
log_warning(`${gobj_short_name(gobj)}: timeout_retry ${base} ms is below ${RETRY_FLOOR_MS} ms: ${RETRY_FLOOR_MS} ms is used`);
|
|
9358
|
+
}
|
|
9359
|
+
base = RETRY_FLOOR_MS;
|
|
9360
|
+
}
|
|
9361
|
+
if (!(max >= base)) max = base;
|
|
9362
|
+
return {
|
|
9363
|
+
base,
|
|
9364
|
+
max
|
|
9365
|
+
};
|
|
9366
|
+
}
|
|
9367
|
+
/***************************************************************
|
|
9176
9368
|
* How long to wait before the next reconnect attempt.
|
|
9177
9369
|
*
|
|
9178
9370
|
* The delay used to be a constant (`timeout_retry`, 5s), for ever. A
|
|
@@ -9193,9 +9385,7 @@ function ac_on_close(gobj, event, kw, src) {
|
|
|
9193
9385
|
***************************************************************/
|
|
9194
9386
|
function next_retry(gobj) {
|
|
9195
9387
|
let priv = gobj.priv;
|
|
9196
|
-
|
|
9197
|
-
let max = gobj_read_integer_attr(gobj, "timeout_retry_max");
|
|
9198
|
-
if (max < base) max = base;
|
|
9388
|
+
const { base, max } = retry_bounds(gobj);
|
|
9199
9389
|
priv.retry_ms = priv.retry_ms ? Math.min(priv.retry_ms * 2, max) : base;
|
|
9200
9390
|
let jitter = priv.retry_ms * .2;
|
|
9201
9391
|
let ms = priv.retry_ms - jitter + Math.random() * 2 * jitter;
|
|
@@ -9488,6 +9678,6 @@ function register_c_ievent_cli() {
|
|
|
9488
9678
|
return create_gclass(GCLASS_NAME);
|
|
9489
9679
|
}
|
|
9490
9680
|
//#endregion
|
|
9491
|
-
export { GObj, SDATA, SDATAAUTHZ, SDATACM, SDATACM2, SDATADF, SDATAPM, SDATAPM0, SDATA_END, SDataDesc, YUNETA_VERSION, __yuno__, build_command_response, build_path, build_stats_response, clean_name, clear_timeout, cmp_two_simple_json, command_parameter_from_json, command_parameter_from_text, command_parser, createElement2, createOneHtml, create_json_record, create_template_record, current_timestamp, data_type_t, db_list_persistent_attrs, db_load_persistent_attrs, db_remove_persistent_attrs, db_save_persistent_attrs, debounce, delete_from_list, duplicate_objects, empty_json, empty_string, escapeHtml, event_flag_t, flat2json, flat_apply, flat_diff, flat_key_join, flat_key_split, gclass_add_ev_action, gclass_add_event_type, gclass_add_state, gclass_check_fsm, gclass_create, gclass_event_type, gclass_find_by_name, gclass_flag_t, gclass_unregister, getPositionRelativeToBody, get_function_name, get_now, gobj_bottom_gobj, gobj_change_parent, gobj_change_state, gobj_command, gobj_create, gobj_create2, gobj_create_default_service, gobj_create_pure_child, gobj_create_service, gobj_create_volatil, gobj_create_yuno, gobj_current_state, gobj_default_service, gobj_deliver_posted_events, gobj_destroy, gobj_find_child, gobj_find_event_type, gobj_find_gobj, gobj_find_service, gobj_find_subscribings, gobj_find_subscriptions, gobj_flag_t, gobj_full_name, gobj_gclass_name, gobj_get_gclass_trace_level, gobj_get_gclass_trace_level2, gobj_get_gclass_trace_no_level, gobj_get_global_trace_level, gobj_get_global_trace_no_level, gobj_global_trace_level, gobj_global_trace_no_level, gobj_has_attr, gobj_has_event, gobj_has_output_event, gobj_hsdata, gobj_is_destroying, gobj_is_playing, gobj_is_pure_child, gobj_is_running, gobj_is_service, gobj_is_volatil, gobj_list_persistent_attrs, gobj_list_subscriptions, gobj_load_persistent_attrs, gobj_match_children, gobj_match_children_tree, gobj_match_gobj, gobj_name, gobj_parent, gobj_pause, gobj_play, gobj_post_event, gobj_posted_events_size, gobj_publish_event, gobj_read_attr, gobj_read_attrs, gobj_read_bool_attr, gobj_read_integer_attr, gobj_read_pointer_attr, gobj_read_str_attr, gobj_remove_persistent_attrs, gobj_repr_global_trace_levels, gobj_reset_volatil_attrs, gobj_save_persistent_attrs, gobj_search_path, gobj_send_event, gobj_services, gobj_set_bottom_gobj, gobj_set_deep_trace, gobj_set_gclass_no_trace, gobj_set_gclass_trace, gobj_set_global_no_trace, gobj_set_global_no_trace2, gobj_set_global_trace, gobj_set_global_trace2, gobj_set_gobj_no_trace, gobj_set_gobj_trace, gobj_set_trace_machine_format, gobj_short_name, gobj_start, gobj_start_children, gobj_start_tree, gobj_start_up, gobj_stats, gobj_stop, gobj_stop_children, gobj_stop_tree, gobj_subscribe_event, gobj_trace_level, gobj_trace_machine_format, gobj_trace_no_level, gobj_unsubscribe_event, gobj_unsubscribe_list, gobj_walk_gobj_children, gobj_walk_gobj_children_tree, gobj_write_attr, gobj_write_attrs, gobj_write_bool_attr, gobj_write_integer_attr, gobj_write_str_attr, gobj_yuno, gobj_yuno_id, gobj_yuno_name, gobj_yuno_role, html_markup, id_index_in_obj_list, index_in_list, is_array, is_boolean, is_date, is_function, is_gobj, is_html_markup, is_metadata_key, is_null, is_number, is_object, is_private_key, is_pure_number, is_secret_name, is_string, jdb_delete, jdb_get, jdb_get_by_idx, jdb_get_topic, jdb_init, jdb_update, json2flat, json_array_append, json_array_append_new, json_array_extend, json_array_remove, json_array_size, json_deep_copy, json_is_identical, json_mask_secrets, json_object_del, json_object_get, json_object_set, json_object_set_new, json_object_size, json_object_update, json_object_update_existing, json_object_update_missing, json_size, jwt2json, jwtDecode, kw_clone_by_keys, kw_clone_by_not_keys, kw_collect, kw_delete, kw_find_json_in_list, kw_find_path, kw_flag_t, kw_get_bool, kw_get_dict, kw_get_dict_value, kw_get_int, kw_get_list, kw_get_local_storage_value, kw_get_pointer, kw_get_real, kw_get_str, kw_has_key, kw_match_simple, kw_pop, kw_remove_local_storage_value, kw_select, kw_set_dict_value, kw_set_local_storage_value, kw_set_subdict_value, kwid_collect, kwid_find_one_record, kwid_get_ids, kwid_match_id, kwid_new_dict, kwid_new_list, list2options, load_json_file, log_debug, log_error, log_info, log_warning, mask_secrets_inline, msg_iev_get_msg_type, msg_iev_get_stack, msg_iev_push_stack, msg_iev_read_key, msg_iev_set_msg_type, msg_iev_write_key, node_uuid, parseBoolean, parseSVG, refresh_language, register_c_ievent_cli, register_c_timer, register_c_yuno, safeSrc, sdata_flag_t, send_http_json_post, set_console_log_enabled, set_console_log_filter, set_log_callback, set_remote_log_functions, set_strings_are_text, set_timeout, set_timeout_periodic, sprintf, stats_parser, str_in_list, strcasecmp, strcmp, strings_are_text, strncmp, strs_in_list, strstr, template_get_field_desc, timeTracker, trace_json, trace_json_masked, trace_level_t, trace_msg, treedb_decoder_fkey, treedb_decoder_hook, treedb_encoder_fkey, treedb_get_field_desc, treedb_hook_data_size, vsprintf, walk_type_t };
|
|
9681
|
+
export { GObj, SDATA, SDATAAUTHZ, SDATACM, SDATACM2, SDATADF, SDATAPM, SDATAPM0, SDATA_END, SDataDesc, YUNETA_VERSION, __yuno__, build_command_response, build_path, build_stats_response, clean_name, clear_timeout, cmp_two_simple_json, command_parameter_from_json, command_parameter_from_text, command_parser, createElement2, createOneHtml, create_json_record, create_template_record, current_timestamp, data_type_t, db_list_persistent_attrs, db_load_persistent_attrs, db_remove_persistent_attrs, db_save_persistent_attrs, debounce, delete_from_list, duplicate_objects, empty_json, empty_string, escapeHtml, event_flag_t, flat2json, flat_apply, flat_diff, flat_key_join, flat_key_split, gclass_add_ev_action, gclass_add_event_type, gclass_add_state, gclass_check_fsm, gclass_create, gclass_event_type, gclass_find_by_name, gclass_flag_t, gclass_unregister, getPositionRelativeToBody, get_function_name, get_now, gobj_bottom_gobj, gobj_change_parent, gobj_change_state, gobj_command, gobj_create, gobj_create2, gobj_create_default_service, gobj_create_pure_child, gobj_create_service, gobj_create_volatil, gobj_create_yuno, gobj_current_state, gobj_default_service, gobj_deliver_posted_events, gobj_destroy, gobj_find_child, gobj_find_event_type, gobj_find_gobj, gobj_find_service, gobj_find_subscribings, gobj_find_subscriptions, gobj_flag_t, gobj_full_name, gobj_gclass_name, gobj_get_gclass_trace_level, gobj_get_gclass_trace_level2, gobj_get_gclass_trace_no_level, gobj_get_global_trace_level, gobj_get_global_trace_no_level, gobj_global_trace_level, gobj_global_trace_no_level, gobj_has_attr, gobj_has_event, gobj_has_output_event, gobj_hsdata, gobj_is_destroying, gobj_is_playing, gobj_is_pure_child, gobj_is_running, gobj_is_service, gobj_is_volatil, gobj_list_persistent_attrs, gobj_list_subscriptions, gobj_load_persistent_attrs, gobj_match_children, gobj_match_children_tree, gobj_match_gobj, gobj_name, gobj_parent, gobj_pause, gobj_play, gobj_post_event, gobj_posted_events_size, gobj_publish_event, gobj_read_attr, gobj_read_attrs, gobj_read_bool_attr, gobj_read_integer_attr, gobj_read_pointer_attr, gobj_read_str_attr, gobj_remove_persistent_attrs, gobj_repr_global_trace_levels, gobj_reset_volatil_attrs, gobj_save_persistent_attrs, gobj_search_path, gobj_send_event, gobj_services, gobj_set_bottom_gobj, gobj_set_deep_trace, gobj_set_gclass_no_trace, gobj_set_gclass_trace, gobj_set_global_no_trace, gobj_set_global_no_trace2, gobj_set_global_trace, gobj_set_global_trace2, gobj_set_gobj_no_trace, gobj_set_gobj_trace, gobj_set_trace_machine_format, gobj_short_name, gobj_start, gobj_start_children, gobj_start_tree, gobj_start_up, gobj_stats, gobj_stop, gobj_stop_children, gobj_stop_tree, gobj_subscribe_event, gobj_trace_level, gobj_trace_machine_format, gobj_trace_no_level, gobj_unsubscribe_event, gobj_unsubscribe_list, gobj_walk_gobj_children, gobj_walk_gobj_children_tree, gobj_write_attr, gobj_write_attrs, gobj_write_bool_attr, gobj_write_integer_attr, gobj_write_str_attr, gobj_yuno, gobj_yuno_id, gobj_yuno_name, gobj_yuno_role, html_markup, id_index_in_obj_list, index_in_list, is_array, is_boolean, is_date, is_function, is_gobj, is_html_markup, is_metadata_key, is_null, is_number, is_object, is_private_key, is_pure_number, is_secret_name, is_string, jdb_delete, jdb_get, jdb_get_by_idx, jdb_get_topic, jdb_init, jdb_update, json2flat, json_array_append, json_array_append_new, json_array_extend, json_array_remove, json_array_size, json_deep_copy, json_is_identical, json_mask_secrets, json_object_del, json_object_get, json_object_set, json_object_set_new, json_object_size, json_object_update, json_object_update_existing, json_object_update_missing, json_size, json_text_of, jwt2json, jwtDecode, kw_clone_by_keys, kw_clone_by_not_keys, kw_collect, kw_delete, kw_find_json_in_list, kw_find_path, kw_flag_t, kw_get_bool, kw_get_dict, kw_get_dict_value, kw_get_int, kw_get_list, kw_get_local_storage_value, kw_get_pointer, kw_get_real, kw_get_str, kw_has_key, kw_match_simple, kw_pop, kw_remove_local_storage_value, kw_select, kw_set_dict_value, kw_set_local_storage_value, kw_set_subdict_value, kwid_collect, kwid_find_one_record, kwid_get_ids, kwid_match_id, kwid_new_dict, kwid_new_list, list2options, load_json_file, log_debug, log_error, log_info, log_warning, mask_secrets_inline, msg_iev_get_msg_type, msg_iev_get_stack, msg_iev_push_stack, msg_iev_read_key, msg_iev_set_msg_type, msg_iev_write_key, node_uuid, parseBoolean, parseSVG, refresh_language, register_c_ievent_cli, register_c_timer, register_c_yuno, safeSrc, sdata_flag_t, send_http_json_post, set_console_log_enabled, set_console_log_filter, set_log_callback, set_remote_log_functions, set_strings_are_text, set_timeout, set_timeout_periodic, sprintf, stats_parser, str_in_list, strcasecmp, strcmp, strings_are_text, strncmp, strs_in_list, strstr, template_get_field_desc, timeTracker, trace_json, trace_json_masked, trace_level_t, trace_msg, treedb_decoder_fkey, treedb_decoder_hook, treedb_encoder_fkey, treedb_get_field_desc, treedb_hook_data_size, vsprintf, walk_type_t };
|
|
9492
9682
|
|
|
9493
9683
|
//# sourceMappingURL=gobj-js.es.js.map
|