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