u8-mqtt 0.5.3 → 0.6.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/README.md +1 -1
- package/cjs/basic-v4.cjs +283 -277
- package/cjs/basic-v4.cjs.map +1 -1
- package/cjs/basic-v5.cjs +297 -281
- package/cjs/basic-v5.cjs.map +1 -1
- package/cjs/full-v4.cjs +295 -289
- package/cjs/full-v4.cjs.map +1 -1
- package/cjs/full-v5.cjs +309 -293
- package/cjs/full-v5.cjs.map +1 -1
- package/cjs/index.cjs +310 -295
- package/cjs/index.cjs.map +1 -1
- package/cjs/v4.cjs +295 -289
- package/cjs/v4.cjs.map +1 -1
- package/cjs/v5.cjs +309 -293
- package/cjs/v5.cjs.map +1 -1
- package/code/_cmdid_dispatch.jsy +45 -69
- package/code/_conn.jsy +96 -72
- package/code/_dispatch.jsy +36 -28
- package/code/_utils.jsy +17 -0
- package/code/base.jsy +33 -61
- package/code/core.jsy +73 -51
- package/code/router_path.jsy +2 -1
- package/esm/basic-v4.js +283 -277
- package/esm/basic-v4.js.map +1 -1
- package/esm/basic-v5.js +297 -281
- package/esm/basic-v5.js.map +1 -1
- package/esm/deno/basic-v4.js +287 -281
- package/esm/deno/basic-v4.js.map +1 -1
- package/esm/deno/basic-v5.js +301 -285
- package/esm/deno/basic-v5.js.map +1 -1
- package/esm/deno/full-v4.js +299 -293
- package/esm/deno/full-v4.js.map +1 -1
- package/esm/deno/full-v5.js +313 -297
- package/esm/deno/full-v5.js.map +1 -1
- package/esm/deno/index.js +314 -298
- package/esm/deno/index.js.map +1 -1
- package/esm/deno/v4.js +299 -293
- package/esm/deno/v4.js.map +1 -1
- package/esm/deno/v5.js +313 -297
- package/esm/deno/v5.js.map +1 -1
- package/esm/full-v4.js +295 -289
- package/esm/full-v4.js.map +1 -1
- package/esm/full-v5.js +309 -293
- package/esm/full-v5.js.map +1 -1
- package/esm/index.js +310 -294
- package/esm/index.js.map +1 -1
- package/esm/node/basic-v4.js +283 -277
- package/esm/node/basic-v4.js.map +1 -1
- package/esm/node/basic-v4.mjs +283 -277
- package/esm/node/basic-v4.mjs.map +1 -1
- package/esm/node/basic-v5.js +297 -281
- package/esm/node/basic-v5.js.map +1 -1
- package/esm/node/basic-v5.mjs +297 -281
- package/esm/node/basic-v5.mjs.map +1 -1
- package/esm/node/full-v4.js +295 -289
- package/esm/node/full-v4.js.map +1 -1
- package/esm/node/full-v4.mjs +295 -289
- package/esm/node/full-v4.mjs.map +1 -1
- package/esm/node/full-v5.js +309 -293
- package/esm/node/full-v5.js.map +1 -1
- package/esm/node/full-v5.mjs +309 -293
- package/esm/node/full-v5.mjs.map +1 -1
- package/esm/node/index.js +310 -294
- package/esm/node/index.js.map +1 -1
- package/esm/node/index.mjs +310 -294
- package/esm/node/index.mjs.map +1 -1
- package/esm/node/v4.js +295 -289
- package/esm/node/v4.js.map +1 -1
- package/esm/node/v4.mjs +295 -289
- package/esm/node/v4.mjs.map +1 -1
- package/esm/node/v5.js +309 -293
- package/esm/node/v5.js.map +1 -1
- package/esm/node/v5.mjs +309 -293
- package/esm/node/v5.mjs.map +1 -1
- package/esm/v4.js +295 -289
- package/esm/v4.js.map +1 -1
- package/esm/v5.js +309 -293
- package/esm/v5.js.map +1 -1
- package/esm/web/basic-v4.js +283 -277
- package/esm/web/basic-v4.js.map +1 -1
- package/esm/web/basic-v4.min.js +1 -1
- package/esm/web/basic-v4.min.js.br +0 -0
- package/esm/web/basic-v4.min.js.gz +0 -0
- package/esm/web/basic-v5.js +297 -281
- package/esm/web/basic-v5.js.map +1 -1
- package/esm/web/basic-v5.min.js +1 -1
- package/esm/web/basic-v5.min.js.br +0 -0
- package/esm/web/basic-v5.min.js.gz +0 -0
- package/esm/web/full-v4.js +295 -289
- package/esm/web/full-v4.js.map +1 -1
- package/esm/web/full-v4.min.js +1 -1
- package/esm/web/full-v4.min.js.br +0 -0
- package/esm/web/full-v4.min.js.gz +0 -0
- package/esm/web/full-v5.js +309 -293
- package/esm/web/full-v5.js.map +1 -1
- package/esm/web/full-v5.min.js +1 -1
- package/esm/web/full-v5.min.js.br +0 -0
- package/esm/web/full-v5.min.js.gz +0 -0
- package/esm/web/index.js +310 -294
- package/esm/web/index.js.map +1 -1
- package/esm/web/index.min.js +1 -1
- package/esm/web/index.min.js.br +0 -0
- package/esm/web/index.min.js.gz +0 -0
- package/esm/web/v4.js +295 -289
- package/esm/web/v4.js.map +1 -1
- package/esm/web/v4.min.js +1 -1
- package/esm/web/v4.min.js.br +0 -0
- package/esm/web/v4.min.js.gz +0 -0
- package/esm/web/v5.js +309 -293
- package/esm/web/v5.js.map +1 -1
- package/esm/web/v5.min.js +1 -1
- package/esm/web/v5.min.js.br +0 -0
- package/esm/web/v5.min.js.gz +0 -0
- package/package.json +7 -8
package/cjs/full-v5.cjs
CHANGED
|
@@ -163,10 +163,18 @@ let mqtt_reader_v5$1 = class mqtt_reader_v5 extends mqtt_reader_v4 {
|
|
|
163
163
|
|
|
164
164
|
let res={}, fork = this.of(buf.subarray(vi, step.k|0));
|
|
165
165
|
while (fork.has_more()) {
|
|
166
|
-
let pt = mqtt_props.get(
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
166
|
+
let v, pk = fork.u8(), pt = mqtt_props.get( pk );
|
|
167
|
+
|
|
168
|
+
if (!pt) {
|
|
169
|
+
res.error = `Unknown mqtt_prop enum ${pk}`;
|
|
170
|
+
return res
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
v = fork[pt.type]();
|
|
174
|
+
if (pt.op) // accumulate operation
|
|
175
|
+
v = fork[pt.op](res[pt.name], v);
|
|
176
|
+
|
|
177
|
+
res[pt.name] = v;
|
|
170
178
|
}
|
|
171
179
|
return res
|
|
172
180
|
}
|
|
@@ -300,6 +308,8 @@ class mqtt_writer_v5 extends mqtt_writer_v4 {
|
|
|
300
308
|
let fork = this.of();
|
|
301
309
|
for (let [name, value] of props) {
|
|
302
310
|
let pt = mqtt_props.get(name);
|
|
311
|
+
if (!pt)
|
|
312
|
+
throw new Error(`Unknown mqtt_prop "${name}"`)
|
|
303
313
|
fork[pt.op || 'one'](value, pt);
|
|
304
314
|
}
|
|
305
315
|
this.push(fork.pack());
|
|
@@ -983,6 +993,23 @@ function parse(str, loose) {
|
|
|
983
993
|
};
|
|
984
994
|
}
|
|
985
995
|
|
|
996
|
+
const _isfn = v => typeof v === 'function';
|
|
997
|
+
const _isstr = v => typeof v === 'string';
|
|
998
|
+
|
|
999
|
+
function _interval(fn_callback) {
|
|
1000
|
+
let tid;
|
|
1001
|
+
return (( td ) => {
|
|
1002
|
+
tid = clearInterval(tid);
|
|
1003
|
+
if (td) {
|
|
1004
|
+
tid = setInterval(fn_callback, 1000 * td);
|
|
1005
|
+
|
|
1006
|
+
|
|
1007
|
+
|
|
1008
|
+
|
|
1009
|
+
// ensure the interval allows the NodeJS event loop to exit
|
|
1010
|
+
tid.unref?.();
|
|
1011
|
+
return true} }) }
|
|
1012
|
+
|
|
986
1013
|
/*
|
|
987
1014
|
class AbstractTopicRouter ::
|
|
988
1015
|
async invoke(pkt, ctx) ::
|
|
@@ -1073,7 +1100,7 @@ function mqtt_topic_path_router() {
|
|
|
1073
1100
|
let fn = args.pop();
|
|
1074
1101
|
let priority = args.pop();
|
|
1075
1102
|
|
|
1076
|
-
if (
|
|
1103
|
+
if (! _isfn(fn)) {
|
|
1077
1104
|
if (fn) {throw new TypeError()}
|
|
1078
1105
|
fn = _ignore;}
|
|
1079
1106
|
|
|
@@ -1238,238 +1265,108 @@ function mqtt_pkt_ctx(mqtt_level, opts, pkt_ctx) {
|
|
|
1238
1265
|
}
|
|
1239
1266
|
}
|
|
1240
1267
|
|
|
1241
|
-
function
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
,
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
_q_ready = ao_defer_v();
|
|
1287
|
-
client.conn_emit('on_ready');}
|
|
1288
|
-
|
|
1289
|
-
return res}
|
|
1268
|
+
async function _mqtt_cmd_evt(target, answer, pkt, ctx) {
|
|
1269
|
+
/* target : on_mqtt_type = {
|
|
1270
|
+
mqtt_pkt(pkt, ctx) {}, // generic
|
|
1271
|
+
|
|
1272
|
+
mqtt_auth(pkt, ctx) {},
|
|
1273
|
+
mqtt_connect(pkt, ctx) {},
|
|
1274
|
+
mqtt_connack(pkt, ctx) {},
|
|
1275
|
+
mqtt_disconnect(pkt, ctx) {},
|
|
1276
|
+
|
|
1277
|
+
mqtt_publish(pkt, ctx) {},
|
|
1278
|
+
mqtt_subscribe(pkt, ctx) {},
|
|
1279
|
+
mqtt_unsubscribe(pkt, ctx) {},
|
|
1280
|
+
|
|
1281
|
+
mqtt_pingreq(pkt, ctx) {},
|
|
1282
|
+
mqtt_pingresp(pkt, ctx) {},
|
|
1283
|
+
} */
|
|
1284
|
+
|
|
1285
|
+
let pkt_fn = target[`mqtt_${pkt.type}`] || target.mqtt_pkt;
|
|
1286
|
+
await pkt_fn?.call(target, pkt, ctx);}
|
|
1287
|
+
|
|
1288
|
+
function _mqtt_cmd_type(target, answer, pkt, ctx) {
|
|
1289
|
+
answer(pkt.type, pkt);
|
|
1290
|
+
_mqtt_cmd_evt(target, answer, pkt, ctx);}
|
|
1291
|
+
|
|
1292
|
+
function _mqtt_cmd_id(target, answer, pkt) {
|
|
1293
|
+
answer(pkt.pkt_id, pkt);}
|
|
1294
|
+
|
|
1295
|
+
|
|
1296
|
+
const _mqtt_cmdids =[
|
|
1297
|
+
_ => {} // 0x0 reserved
|
|
1298
|
+
, _mqtt_cmd_evt // 0x1 connect
|
|
1299
|
+
, _mqtt_cmd_type // 0x2 connack
|
|
1300
|
+
, _mqtt_cmd_evt // 0x3 publish
|
|
1301
|
+
, _mqtt_cmd_id // 0x4 puback
|
|
1302
|
+
, _mqtt_cmd_id // 0x5 pubrec
|
|
1303
|
+
, _mqtt_cmd_id // 0x6 pubrel
|
|
1304
|
+
, _mqtt_cmd_id // 0x7 pubcomp
|
|
1305
|
+
, _mqtt_cmd_evt // 0x8 subscribe
|
|
1306
|
+
, _mqtt_cmd_id // 0x9 suback
|
|
1307
|
+
, _mqtt_cmd_evt // 0xa unsubscribe
|
|
1308
|
+
, _mqtt_cmd_id // 0xb unsuback
|
|
1309
|
+
, _mqtt_cmd_type // 0xc pingreq
|
|
1310
|
+
, _mqtt_cmd_type // 0xd pingresp
|
|
1311
|
+
, _mqtt_cmd_evt // 0xe disconnect
|
|
1312
|
+
, _mqtt_cmd_type ];// 0xf auth
|
|
1290
1313
|
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
mqtt_ctx = mqtt_ctx.mqtt_stream();
|
|
1297
|
-
let sess_ctx = {mqtt: client};
|
|
1298
|
-
let on_mqtt_chunk = u8_buf =>
|
|
1299
|
-
on_mqtt(mqtt_ctx.decode(u8_buf), sess_ctx);
|
|
1300
|
-
|
|
1301
|
-
_send_mqtt_pkt = async (type, pkt, key) => {
|
|
1302
|
-
let res = undefined !== key
|
|
1303
|
-
? pkt_future(key) : true;
|
|
1304
|
-
|
|
1305
|
-
await send_u8_pkt(
|
|
1306
|
-
mqtt_ctx.encode_pkt(type, pkt));
|
|
1307
|
-
|
|
1308
|
-
return res};
|
|
1309
|
-
|
|
1310
|
-
_q_init[1](_send_mqtt_pkt); // resolve _q_init with _send_mqtt_pkt closure
|
|
1311
|
-
|
|
1312
|
-
// call client.on_live in next promise microtask
|
|
1313
|
-
client.conn_emit('on_live', _has_connected);
|
|
1314
|
-
return on_mqtt_chunk} } }
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
function _ping_interval(send_ping) {
|
|
1318
|
-
let tid;
|
|
1319
|
-
return (( td ) => {
|
|
1320
|
-
tid = clearInterval(tid);
|
|
1321
|
-
if (td) {
|
|
1322
|
-
tid = setInterval(send_ping, 1000 * td);
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
// ensure the interval allows the NodeJS event loop to exit
|
|
1328
|
-
tid.unref?.();
|
|
1329
|
-
return true} }) }
|
|
1314
|
+
function _mqtt_dispatch(opt, target) {
|
|
1315
|
+
let hashbelt=[], rotate_ts=0;
|
|
1316
|
+
// default rotate at 1s across 5 buckets
|
|
1317
|
+
let { td: rotate_td=1000, n: rotate_n=5 } = opt?.rotate || {};
|
|
1330
1318
|
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1319
|
+
// Promise / future scaffolding
|
|
1320
|
+
let _pkt_id=100, _ftr_key; // use _ftr_key to reuse _by_key closure
|
|
1321
|
+
let _ftr_by_key = fn_answer => hashbelt[0].set(_ftr_key, fn_answer);
|
|
1334
1322
|
|
|
1335
|
-
|
|
1336
|
-
|
|
1323
|
+
on_mqtt([]); // init hashbelt and rotate_ts
|
|
1324
|
+
return [on_mqtt, pkt_future]
|
|
1337
1325
|
|
|
1338
|
-
let _tmp_; // use _tmp_ to reuse _by_key closure
|
|
1339
|
-
let _by_key = answer_monad =>
|
|
1340
|
-
hashbelt[0].set(_tmp_, answer_monad);
|
|
1341
1326
|
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
_tmp_ = pkt_or_key.pkt_id = _pkt_id;}
|
|
1327
|
+
function pkt_future(pkt_or_key) {
|
|
1328
|
+
if (! _isstr(pkt_or_key)) {
|
|
1329
|
+
_pkt_id = (_pkt_id + 1) & 0xffff; // 16-bit unsigned short
|
|
1330
|
+
_ftr_key = pkt_or_key.pkt_id = _pkt_id;}
|
|
1331
|
+
else _ftr_key = pkt_or_key;
|
|
1348
1332
|
|
|
1349
|
-
|
|
1333
|
+
return new Promise(_ftr_by_key)}
|
|
1350
1334
|
|
|
1351
|
-
|
|
1352
|
-
for (let map of
|
|
1353
|
-
let
|
|
1354
|
-
if (
|
|
1335
|
+
function answer(key, pkt) {
|
|
1336
|
+
for (let map of hashbelt) {
|
|
1337
|
+
let fn_answer = map.get(key);
|
|
1338
|
+
if (fn_answer) {
|
|
1355
1339
|
map.delete(key);
|
|
1356
1340
|
|
|
1357
|
-
|
|
1341
|
+
fn_answer([pkt, /*err*/]); // option/maybe monad
|
|
1358
1342
|
return true} }
|
|
1359
1343
|
return false}
|
|
1360
1344
|
|
|
1361
|
-
, rotate_belt(n) {
|
|
1362
|
-
let {hashbelt} = this;
|
|
1363
|
-
hashbelt.unshift(new Map());
|
|
1364
|
-
for (let old of hashbelt.splice(n || 5)) {
|
|
1365
|
-
for (let answer_monad of old.values()) {
|
|
1366
|
-
answer_monad([/*pkt*/, 'expired']); } } }// option/maybe monad
|
|
1367
|
-
|
|
1368
|
-
, cmdids: ((() => {
|
|
1369
|
-
return [
|
|
1370
|
-
(() =>{} )// 0x0 reserved
|
|
1371
|
-
, by_evt // 0x1 connect
|
|
1372
|
-
, by_type // 0x2 connack
|
|
1373
|
-
, by_evt // 0x3 publish
|
|
1374
|
-
, by_id // 0x4 puback
|
|
1375
|
-
, by_id // 0x5 pubrec
|
|
1376
|
-
, by_id // 0x6 pubrel
|
|
1377
|
-
, by_id // 0x7 pubcomp
|
|
1378
|
-
, by_evt // 0x8 subscribe
|
|
1379
|
-
, by_id // 0x9 suback
|
|
1380
|
-
, by_evt // 0xa unsubscribe
|
|
1381
|
-
, by_id // 0xb unsuback
|
|
1382
|
-
, by_type // 0xc pingreq
|
|
1383
|
-
, by_type // 0xd pingresp
|
|
1384
|
-
, by_evt // 0xe disconnect
|
|
1385
|
-
, by_type ]// 0xf auth
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
function by_id(disp, pkt) {
|
|
1389
|
-
disp.answer(pkt.pkt_id, pkt); }
|
|
1390
|
-
|
|
1391
|
-
function by_type(disp, pkt, ctx) {
|
|
1392
|
-
disp.answer(pkt.type, pkt);
|
|
1393
|
-
by_evt(disp, pkt, ctx);}
|
|
1394
|
-
|
|
1395
|
-
async function by_evt({target}, pkt, ctx) {
|
|
1396
|
-
let fn = target[`mqtt_${pkt.type}`]
|
|
1397
|
-
|| target.mqtt_pkt;
|
|
1398
|
-
|
|
1399
|
-
await fn?.call(target, pkt, ctx);} })()) };
|
|
1400
|
-
|
|
1401
|
-
/*
|
|
1402
|
-
on_mqtt_type = {
|
|
1403
|
-
mqtt_auth(pkt, ctx) ::
|
|
1404
|
-
mqtt_connect(pkt, ctx) ::
|
|
1405
|
-
mqtt_connack(pkt, ctx) ::
|
|
1406
|
-
mqtt_disconnect(pkt, ctx) ::
|
|
1407
|
-
|
|
1408
|
-
mqtt_publish(pkt, ctx)
|
|
1409
|
-
mqtt_subscribe(pkt, ctx) ::
|
|
1410
|
-
mqtt_unsubscribe(pkt, ctx) ::
|
|
1411
|
-
|
|
1412
|
-
mqtt_pingreq(pkt, ctx) ::
|
|
1413
|
-
mqtt_pingresp(pkt, ctx) ::
|
|
1414
|
-
}
|
|
1415
|
-
*/
|
|
1416
|
-
|
|
1417
|
-
function _mqtt_dispatch(opt, target) {
|
|
1418
|
-
let _disp_ = _mqtt_cmdid_dispatch.create(target);
|
|
1419
|
-
let { cmdids } = _disp_;
|
|
1420
|
-
|
|
1421
|
-
// default rotate at 1s across 5 buckets
|
|
1422
|
-
let { td: rotate_td=1000, n: rotate_n=5 } =
|
|
1423
|
-
opt && opt.rotate || {};
|
|
1424
|
-
|
|
1425
|
-
let rotate_ts = rotate_td + Date.now();
|
|
1426
|
-
|
|
1427
|
-
return [on_mqtt,
|
|
1428
|
-
_disp_.bind_pkt_future()]
|
|
1429
|
-
|
|
1430
1345
|
function on_mqtt(pkt_list, ctx) {
|
|
1431
1346
|
for (let pkt of pkt_list) {
|
|
1432
|
-
|
|
1347
|
+
_mqtt_cmdids[pkt.id](target, answer, pkt, ctx);}
|
|
1433
1348
|
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1349
|
+
// rotate after rotate_ts
|
|
1350
|
+
let now = Date.now();
|
|
1351
|
+
if (now > rotate_ts) {
|
|
1352
|
+
rotate_ts = rotate_td + now;
|
|
1353
|
+
hashbelt.unshift(new Map());
|
|
1354
|
+
while (hashbelt.length > rotate_n) {
|
|
1355
|
+
for (let fn_answer of hashbelt.pop().values()) {
|
|
1356
|
+
fn_answer([/*pkt*/, 'expired']); } } } } }// option/maybe monad
|
|
1437
1357
|
|
|
1438
1358
|
class MQTTError extends Error {
|
|
1439
1359
|
constructor(mqtt_pkt, reason=mqtt_pkt.reason) {
|
|
1360
|
+
// use hex-encoded reasons to match MQTT spec documentation
|
|
1440
1361
|
super(`[0x${reason.toString(16)}] ${reason.reason}`);
|
|
1441
1362
|
this.mqtt_pkt = mqtt_pkt;
|
|
1442
1363
|
this.reason = reason;} }
|
|
1443
1364
|
|
|
1444
1365
|
class MQTTBase {
|
|
1445
|
-
constructor(opt={}) {
|
|
1446
|
-
this.with(opt);
|
|
1447
|
-
this._conn_ = _mqtt_conn(this,
|
|
1448
|
-
this._init_dispatch(opt, this)); }
|
|
1449
|
-
|
|
1450
|
-
with(fns_ns) {
|
|
1451
|
-
for (let [k,v] of Object.entries(fns_ns)) {
|
|
1452
|
-
if ('function' === typeof v) {this[k] = v;} }
|
|
1453
|
-
return this}
|
|
1454
|
-
|
|
1455
|
-
async conn_emit(evt, arg, err_arg) {
|
|
1456
|
-
this.log_conn?.(evt, arg, err_arg);
|
|
1457
|
-
try {
|
|
1458
|
-
let fn_evt = this[await evt]; // microtask break using `await evt`
|
|
1459
|
-
if (fn_evt) {
|
|
1460
|
-
await fn_evt.call(this, this, arg, err_arg);}
|
|
1461
|
-
else if (err_arg) {throw err_arg} }
|
|
1462
|
-
catch (err) {
|
|
1463
|
-
this.on_error(err, evt);} }
|
|
1464
|
-
|
|
1465
|
-
on_error(err, evt) {
|
|
1466
|
-
console.warn('[[u8-mqtt error: %s]]', evt, err); }
|
|
1467
|
-
|
|
1468
1366
|
// Handshaking Packets
|
|
1469
|
-
|
|
1470
1367
|
async connect(pkt={}) {
|
|
1471
1368
|
let cid = pkt.client_id;
|
|
1472
|
-
if (
|
|
1369
|
+
if (! _isstr(cid)) {
|
|
1473
1370
|
// see init_client_id implementation in core.jsy
|
|
1474
1371
|
pkt.client_id = cid = this.client_id || this.init_client_id(cid);}
|
|
1475
1372
|
this.client_id = cid;
|
|
@@ -1477,23 +1374,20 @@ class MQTTBase {
|
|
|
1477
1374
|
if (null == pkt.keep_alive) {
|
|
1478
1375
|
pkt.keep_alive = 60;}
|
|
1479
1376
|
|
|
1480
|
-
let
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
throw new this.MQTTError(res[0])}
|
|
1485
|
-
|
|
1486
|
-
// TODO: merge with server's keep_alive frequency
|
|
1487
|
-
this._conn_.ping(pkt.keep_alive);
|
|
1488
|
-
return res}
|
|
1377
|
+
let response = await this._send0('connect', pkt, 'connack');
|
|
1378
|
+
if (0 != response[0].reason) {// compare to 0 to coerce to number
|
|
1379
|
+
throw new this.MQTTError(response[0])}
|
|
1380
|
+
return this.conn.on_conn(pkt, response)}
|
|
1489
1381
|
|
|
1490
1382
|
async disconnect(pkt={}) {
|
|
1491
|
-
let
|
|
1492
|
-
this.
|
|
1493
|
-
return res}
|
|
1383
|
+
let response = await this._send0('disconnect', pkt);
|
|
1384
|
+
return this.conn.on_dis(pkt, response)}
|
|
1494
1385
|
|
|
1495
|
-
auth(pkt={}) {
|
|
1496
|
-
|
|
1386
|
+
async auth(pkt={}) {
|
|
1387
|
+
let response = await this._send0('auth', pkt, 'auth');
|
|
1388
|
+
if (response[0].reason) {
|
|
1389
|
+
throw new this.MQTTError(response[0])}
|
|
1390
|
+
return this.conn.on_auth(pkt, response)}
|
|
1497
1391
|
|
|
1498
1392
|
ping() {return this._send('pingreq', null, 'pingresp')}
|
|
1499
1393
|
puback({pkt_id}) {return this._send('puback', {pkt_id})}
|
|
@@ -1530,20 +1424,18 @@ class MQTTBase {
|
|
|
1530
1424
|
// alias: publish -- because 'pub' is shorter for semantic aliases above
|
|
1531
1425
|
async pub(pkt, pub_opt) {
|
|
1532
1426
|
if (undefined === pkt.payload) {
|
|
1533
|
-
if (
|
|
1427
|
+
if (_isfn(pub_opt)) {
|
|
1428
|
+
// pub_opt as a function is fn_encode value
|
|
1534
1429
|
pub_opt = {fn_encode: pub_opt};}
|
|
1535
1430
|
|
|
1536
|
-
let
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
// return a single-value closure to publish packets
|
|
1543
|
-
return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)}
|
|
1431
|
+
let msg = pkt.msg, fn_encode = pub_opt?.fn_encode;
|
|
1432
|
+
if (null == msg || _isfn(msg)) {
|
|
1433
|
+
// when msg is a function, return closure using fn_encode
|
|
1434
|
+
if (msg) {pub_opt = {...pub_opt, fn_encode: msg};}
|
|
1435
|
+
// return a single-value closure to publish packets
|
|
1436
|
+
return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)}
|
|
1544
1437
|
|
|
1545
1438
|
// Encode payload from msg; fn_encode allows alternative to JSON.stringify
|
|
1546
|
-
let {fn_encode} = pub_opt || {};
|
|
1547
1439
|
pkt.payload = fn_encode
|
|
1548
1440
|
? await fn_encode(msg)
|
|
1549
1441
|
: JSON.stringify(msg);}
|
|
@@ -1555,31 +1447,31 @@ class MQTTBase {
|
|
|
1555
1447
|
pkt = pub_opt.xform(pkt) || pkt;} }
|
|
1556
1448
|
|
|
1557
1449
|
return this._send('publish', pkt,
|
|
1558
|
-
pkt.qos ? pkt :
|
|
1450
|
+
pkt.qos ? pkt : null ) }// key
|
|
1559
1451
|
|
|
1560
1452
|
|
|
1561
1453
|
// Internal API
|
|
1562
1454
|
|
|
1563
|
-
/* async
|
|
1455
|
+
/* async _send0(type, pkt) -- provided by conn and transport */
|
|
1456
|
+
/* async _send(type, pkt) -- provided by conn and transport */
|
|
1564
1457
|
|
|
1565
1458
|
_init_dispatch(opt) {
|
|
1566
1459
|
this.constructor?._once_();
|
|
1567
1460
|
let target ={__proto__: opt.on_mqtt_type};
|
|
1568
1461
|
target.mqtt_publish ||=
|
|
1569
1462
|
this._init_router?.(opt, this, target);
|
|
1570
|
-
return _mqtt_dispatch(
|
|
1463
|
+
return _mqtt_dispatch(opt, target)}
|
|
1571
1464
|
|
|
1572
1465
|
static _aliases() {
|
|
1573
1466
|
return ' publish:pub sub:subscribe unsub:unsubscribe json_post:obj_post json_send:obj_send json_store:obj_store'}
|
|
1574
1467
|
|
|
1575
|
-
static _once_(
|
|
1576
|
-
|
|
1577
|
-
|
|
1468
|
+
static _once_(klass=this) {
|
|
1469
|
+
klass._once_ = _=>0;
|
|
1470
|
+
var alias, name, p = klass.prototype;
|
|
1578
1471
|
p.MQTTError = MQTTError;
|
|
1579
|
-
for (
|
|
1580
|
-
alias = alias.split(':');
|
|
1581
|
-
|
|
1582
|
-
if (fn) {p[alias[0]] = fn;} } } }
|
|
1472
|
+
for (alias of klass._aliases().split(/\s+/)) {
|
|
1473
|
+
[alias, name] = alias.split(':');
|
|
1474
|
+
p[alias] = p[name];} } }
|
|
1583
1475
|
|
|
1584
1476
|
|
|
1585
1477
|
function _as_topics(pkt, ex, topic_prefix) {
|
|
@@ -1604,37 +1496,167 @@ function _as_topics(pkt, ex, topic_prefix) {
|
|
|
1604
1496
|
pkt.topics = pkt.topics.map(_prefix_topics);}
|
|
1605
1497
|
return pkt}
|
|
1606
1498
|
|
|
1607
|
-
const
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1499
|
+
const _defer_obj = o =>(
|
|
1500
|
+
o.p = new Promise((a,e) => { o.a=a; o.e=e; })
|
|
1501
|
+
, o);
|
|
1502
|
+
|
|
1503
|
+
function _dfn_reset(client, attr, fn_after) {
|
|
1504
|
+
// a resetable deferred for a function
|
|
1505
|
+
let self = {set}, afn = async (...args) => (await self.p)(...args);
|
|
1506
|
+
return set()
|
|
1507
|
+
|
|
1508
|
+
function set() {
|
|
1509
|
+
if (afn !== client[attr]) {
|
|
1510
|
+
_defer_obj(self).p.then(fn_after, _=>0);
|
|
1511
|
+
client[attr] = afn;}
|
|
1512
|
+
return self} }
|
|
1513
|
+
|
|
1514
|
+
function _mqtt_conn(opt, client, [on_mqtt, pkt_future]) {
|
|
1515
|
+
let _abort;
|
|
1516
|
+
let _dfn_send0 = _dfn_reset(client, '_send0', // client._send0 getter/setter
|
|
1517
|
+
_=> client.conn_emit('on_live', conn.has_connected));
|
|
1518
|
+
let _dfn_ready = _dfn_reset(client, '_send', // client._send getter/setter
|
|
1519
|
+
_=> client.conn_emit('on_ready'));
|
|
1520
|
+
let _keep_alive_ival = _interval (() =>client._send0('pingreq') );// resettable interval for keep_alive ping
|
|
1521
|
+
|
|
1522
|
+
let conn = Object.create({
|
|
1523
|
+
ping: (td=conn.keep_alive) => _keep_alive_ival(td)
|
|
1524
|
+
|
|
1525
|
+
, on_conn(pkt, response) {
|
|
1526
|
+
conn.has_connected = true;
|
|
1527
|
+
conn.keep_alive = opt.keep_alive || response[0].props?.server_keep_alive || pkt.keep_alive;
|
|
1528
|
+
client.conn_emit('on_conn');
|
|
1529
|
+
return opt.use_auth
|
|
1530
|
+
? response // wait on enhanced authentication step
|
|
1531
|
+
: conn.on_auth(null, response) }// otherwise, connect is also auth
|
|
1532
|
+
|
|
1533
|
+
, on_auth(pkt, response) {
|
|
1534
|
+
_dfn_ready.a(_dfn_send0.p);
|
|
1535
|
+
if (0 != opt.keep_alive) {
|
|
1536
|
+
conn.ping();}
|
|
1537
|
+
client.conn_emit('on_auth', !pkt);
|
|
1538
|
+
return response}
|
|
1539
|
+
|
|
1540
|
+
, on_dis(pkt, response) {
|
|
1541
|
+
conn.reset(false);
|
|
1542
|
+
return response}
|
|
1543
|
+
|
|
1544
|
+
, reset(err) {
|
|
1545
|
+
if (err) {
|
|
1546
|
+
_dfn_send0.e(err); }// send error to uses of _send0 (connect, auth)
|
|
1547
|
+
_abort.e(err); // abort in-progress connections
|
|
1548
|
+
|
|
1549
|
+
delete conn.is_set;
|
|
1550
|
+
conn.ready = handshake();
|
|
1551
|
+
client.conn_emit('on_disconnect', false===err, err);}
|
|
1552
|
+
|
|
1553
|
+
, abort() {
|
|
1554
|
+
_dfn_ready.e(err); // abort all messages awaiting ready state
|
|
1555
|
+
return conn.reset(err)}
|
|
1556
|
+
|
|
1557
|
+
, async setup(gate, send_u8_pkt, init_msg_loop) {
|
|
1558
|
+
if (conn.is_set) {
|
|
1559
|
+
throw new Error() }// already in-progress
|
|
1560
|
+
|
|
1561
|
+
conn.is_set = true;
|
|
1562
|
+
await gate;
|
|
1563
|
+
|
|
1564
|
+
// setup send/recv MQTT parsing context
|
|
1565
|
+
let mqtt_ctx = client.mqtt_ctx.mqtt_stream();
|
|
1566
|
+
|
|
1567
|
+
{// setup inbound message loop
|
|
1568
|
+
let sess_ctx = {mqtt: client}; // mutable session context
|
|
1569
|
+
let on_mqtt_chunk = u8 => on_mqtt(mqtt_ctx.decode(u8), sess_ctx);
|
|
1570
|
+
init_msg_loop(on_mqtt_chunk, conn);}
|
|
1571
|
+
|
|
1572
|
+
// setup outbound message path and transport connection
|
|
1573
|
+
send_u8_pkt = await send_u8_pkt;
|
|
1574
|
+
_dfn_send0.a(
|
|
1575
|
+
async (type, pkt, key) => {
|
|
1576
|
+
let res = undefined !== key
|
|
1577
|
+
? pkt_future(key) : true;
|
|
1578
|
+
|
|
1579
|
+
await send_u8_pkt(
|
|
1580
|
+
mqtt_ctx.encode_pkt(type, pkt));
|
|
1581
|
+
return res} ); } });
|
|
1582
|
+
|
|
1583
|
+
conn.ready = handshake();
|
|
1584
|
+
return conn
|
|
1585
|
+
|
|
1586
|
+
async function handshake() {
|
|
1587
|
+
_abort = _defer_obj({});
|
|
1588
|
+
|
|
1589
|
+
_keep_alive_ival(0); // clearInterval on keep alive ping
|
|
1590
|
+
_dfn_send0.set(); // reset client._send0 if necessary
|
|
1591
|
+
_dfn_ready.set(); // reset client._send if necessary
|
|
1592
|
+
|
|
1593
|
+
try {
|
|
1594
|
+
// set client._send0 as passtrhough after transport connection
|
|
1595
|
+
client._send0 = await Promise.race([_dfn_send0.p, _abort.p]);
|
|
1596
|
+
|
|
1597
|
+
// set client._send as passtrhough after ready
|
|
1598
|
+
client._send = await Promise.race([_dfn_ready.p, _abort.p]);
|
|
1599
|
+
return true}
|
|
1600
|
+
catch (err) {
|
|
1601
|
+
return false} } }
|
|
1602
|
+
|
|
1603
|
+
const pkt_api ={
|
|
1604
|
+
utf8(u8) {return new TextDecoder('utf-8').decode(u8 || this.payload )}
|
|
1605
|
+
, json(u8) {return JSON.parse( this.utf8(u8) || null )}
|
|
1606
|
+
, text(u8) {return this.utf8(u8)} };
|
|
1607
|
+
|
|
1608
|
+
const opt_default ={
|
|
1609
|
+
sess_stg: globalThis.sessionStorage};
|
|
1612
1610
|
|
|
1613
1611
|
class MQTTCore extends MQTTBase {
|
|
1612
|
+
constructor(opt) {
|
|
1613
|
+
opt = {...opt_default, ...opt};
|
|
1614
|
+
super();
|
|
1615
|
+
this.with(opt);
|
|
1616
|
+
// settings for MQTTCore
|
|
1617
|
+
this.sess_stg = opt.sess_stg;
|
|
1618
|
+
// setup connection and dispatch
|
|
1619
|
+
this.conn = _mqtt_conn(opt, this,
|
|
1620
|
+
this._init_dispatch(opt)); }
|
|
1621
|
+
|
|
1622
|
+
with(fns_ns) {
|
|
1623
|
+
for (let [k,v] of Object.entries(fns_ns)) {
|
|
1624
|
+
if (_isfn(v)) {this[k] = v;} }
|
|
1625
|
+
return this}
|
|
1626
|
+
|
|
1627
|
+
|
|
1614
1628
|
static mqtt_ctx(mqtt_level, mqtt_opts, pkt_ctx=pkt_api) {
|
|
1615
|
-
let
|
|
1616
|
-
|
|
1629
|
+
let klass = class extends this {};
|
|
1630
|
+
klass.prototype.mqtt_ctx =
|
|
1617
1631
|
mqtt_pkt_ctx(mqtt_level, mqtt_opts, pkt_ctx);
|
|
1618
|
-
return
|
|
1632
|
+
return klass}
|
|
1633
|
+
|
|
1634
|
+
|
|
1635
|
+
async conn_emit(evt, arg, err_arg) {
|
|
1636
|
+
this.log_conn?.(evt, arg, err_arg);
|
|
1637
|
+
try {
|
|
1638
|
+
let fn_evt = this[await evt]; // microtask break using `await evt`
|
|
1639
|
+
if (fn_evt) {
|
|
1640
|
+
await fn_evt.call(this, this, arg, err_arg);}
|
|
1641
|
+
else if (err_arg) {throw err_arg} }
|
|
1642
|
+
catch (err) {
|
|
1643
|
+
this.on_error(err, evt);} }
|
|
1644
|
+
|
|
1645
|
+
on_error(err, evt) {
|
|
1646
|
+
console.warn('[[u8-mqtt error: %s]]', evt, err); }
|
|
1647
|
+
log_conn(evt, arg, err_arg) {
|
|
1648
|
+
console.info('[[u8-mqtt conn: %s]]', evt, arg, err_arg); }
|
|
1619
1649
|
|
|
1620
1650
|
|
|
1621
1651
|
// automatic Client Id for connect()
|
|
1622
1652
|
init_client_id(parts=['u8-mqtt--','']) {
|
|
1623
|
-
let sess_stg=this.sess_stg;
|
|
1653
|
+
let sess_stg = this.sess_stg;
|
|
1624
1654
|
let key, cid = sess_stg?.getItem(key=parts.join(' '));
|
|
1625
1655
|
if (! cid) {
|
|
1626
1656
|
cid = parts.join(Math.random().toString(36).slice(2));
|
|
1627
1657
|
sess_stg?.setItem(key, cid);}
|
|
1628
1658
|
return cid}
|
|
1629
1659
|
|
|
1630
|
-
get sess_stg() {return globalThis.sessionStorage}
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
//on_error(err, evt) ::
|
|
1634
|
-
// console.warn @ '[[u8-mqtt error: %s]]', evt, err
|
|
1635
|
-
|
|
1636
|
-
//log_conn(evt, arg, err_arg) ::
|
|
1637
|
-
// console.info @ '[[u8-mqtt log: %s]]', evt, arg, err_arg
|
|
1638
1660
|
|
|
1639
1661
|
on_live(client, is_reconnect) {
|
|
1640
1662
|
if (is_reconnect) {
|
|
@@ -1660,19 +1682,16 @@ class MQTTCore extends MQTTBase {
|
|
|
1660
1682
|
return new Promise(done => setTimeout(done, ms)) }
|
|
1661
1683
|
|
|
1662
1684
|
with_async_iter(async_iter, write_u8_pkt) {
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
catch (err) {
|
|
1674
|
-
this._conn_.reset(err);} })());
|
|
1675
|
-
|
|
1685
|
+
this.conn.setup(async_iter,
|
|
1686
|
+
write_u8_pkt,
|
|
1687
|
+
async (on_mqtt_chunk, conn) => {
|
|
1688
|
+
try {
|
|
1689
|
+
async_iter = await async_iter;
|
|
1690
|
+
for await (let chunk of async_iter)
|
|
1691
|
+
on_mqtt_chunk(chunk);
|
|
1692
|
+
conn.reset();}
|
|
1693
|
+
catch (err) {
|
|
1694
|
+
conn.reset(err);} } );
|
|
1676
1695
|
return this}
|
|
1677
1696
|
|
|
1678
1697
|
|
|
@@ -1743,33 +1762,30 @@ class MQTTCore extends MQTTBase {
|
|
|
1743
1762
|
|
|
1744
1763
|
websock.binaryType = 'arraybuffer';
|
|
1745
1764
|
|
|
1746
|
-
let
|
|
1765
|
+
let ws_ready, readyState = websock.readyState;
|
|
1747
1766
|
if (1 !== readyState) {
|
|
1748
1767
|
if (0 !== readyState) {
|
|
1749
|
-
throw new Error('
|
|
1750
|
-
|
|
1751
|
-
ready = new Promise(fn => websock.onopen = fn); }
|
|
1768
|
+
throw new Error('WS readyState') }
|
|
1752
1769
|
|
|
1770
|
+
ws_ready = new Promise(ready => websock.onopen = ready); }
|
|
1753
1771
|
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
, websock.send(u8_pkt)) );
|
|
1772
|
+
this.conn.setup(ws_ready,
|
|
1773
|
+
u8_pkt => websock.send(u8_pkt),
|
|
1774
|
+
(on_mqtt_chunk, conn) => {
|
|
1775
|
+
websock.onmessage = evt =>(
|
|
1776
|
+
on_mqtt_chunk(new Uint8Array(evt.data)) );
|
|
1760
1777
|
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
err.reason = evt.reason;}
|
|
1778
|
+
websock.onclose = evt => {
|
|
1779
|
+
if (! evt.wasClean) {
|
|
1780
|
+
var err = new Error('websocket close');
|
|
1781
|
+
err.code = evt.code;
|
|
1782
|
+
err.reason = evt.reason;}
|
|
1767
1783
|
|
|
1768
|
-
|
|
1784
|
+
conn.reset(err);}; } );
|
|
1769
1785
|
|
|
1770
1786
|
return this} }
|
|
1771
1787
|
|
|
1772
|
-
const version = '0.
|
|
1788
|
+
const version = '0.6.1-node';
|
|
1773
1789
|
|
|
1774
1790
|
const MQTTClient_v4 = /* #__PURE__ */
|
|
1775
1791
|
with_topic_path_router(
|