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