u8-mqtt 0.5.3 → 0.6.0
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/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/basic-v5.js
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());
|
|
@@ -873,88 +883,15 @@ function mqtt_pkt_ctx(mqtt_level, opts, pkt_ctx) {
|
|
|
873
883
|
}
|
|
874
884
|
}
|
|
875
885
|
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
return p =>(
|
|
879
|
-
p = new Promise(_pset)
|
|
880
|
-
, as_res(p, y, n)) }
|
|
881
|
-
|
|
882
|
-
const ao_defer_v = /* #__PURE__ */
|
|
883
|
-
ao_defer_ctx();
|
|
884
|
-
|
|
885
|
-
Promise.resolve({type:'init'});
|
|
886
|
-
|
|
887
|
-
function _mqtt_conn(client, [on_mqtt, pkt_future]) {
|
|
888
|
-
let _q_init = ao_defer_v(), _q_ready = ao_defer_v();
|
|
889
|
-
let _send_ready = async (...args) => (await _q_ready[0])(...args);
|
|
890
|
-
let _send_mqtt_pkt, _has_connected;
|
|
891
|
-
client._send = _send_ready;
|
|
892
|
-
|
|
893
|
-
return {
|
|
894
|
-
async when_ready() {await _q_ready[0];}
|
|
895
|
-
|
|
896
|
-
, ping: _ping_interval (() =>_send_mqtt_pkt?.('pingreq'))
|
|
897
|
-
|
|
898
|
-
, reset(err) {
|
|
899
|
-
if (! _send_mqtt_pkt) {return}
|
|
900
|
-
|
|
901
|
-
if (err) {
|
|
902
|
-
_q_init[2](err);}
|
|
903
|
-
|
|
904
|
-
_send_mqtt_pkt = null;
|
|
905
|
-
_q_init = ao_defer_v();
|
|
906
|
-
client._send = _send_ready;
|
|
907
|
-
|
|
908
|
-
// call client.on_conn_reset in next promise microtask
|
|
909
|
-
client.conn_emit('on_disconnect', false===err, err);}
|
|
910
|
-
|
|
911
|
-
, async send_connect(... args) {
|
|
912
|
-
if (! _send_mqtt_pkt) {
|
|
913
|
-
await _q_init[0]; }// _send_mqtt_pkt is set before fulfilled
|
|
914
|
-
|
|
915
|
-
// await connack response
|
|
916
|
-
let res = await _send_mqtt_pkt(...args);
|
|
917
|
-
if (0 == res[0].reason) {
|
|
918
|
-
_has_connected = true;
|
|
919
|
-
// resolve _q_ready[0] with _send_mqtt_pkt closure
|
|
920
|
-
_q_ready[1](client._send = _send_mqtt_pkt);
|
|
921
|
-
_q_ready = ao_defer_v();
|
|
922
|
-
client.conn_emit('on_ready');}
|
|
923
|
-
|
|
924
|
-
return res}
|
|
925
|
-
|
|
926
|
-
, is_set: (() =>!! _send_mqtt_pkt)
|
|
927
|
-
, set(mqtt_ctx, send_u8_pkt) {
|
|
928
|
-
if (_send_mqtt_pkt) {
|
|
929
|
-
throw new Error('Already connected')}
|
|
930
|
-
|
|
931
|
-
mqtt_ctx = mqtt_ctx.mqtt_stream();
|
|
932
|
-
let sess_ctx = {mqtt: client};
|
|
933
|
-
let on_mqtt_chunk = u8_buf =>
|
|
934
|
-
on_mqtt(mqtt_ctx.decode(u8_buf), sess_ctx);
|
|
935
|
-
|
|
936
|
-
_send_mqtt_pkt = async (type, pkt, key) => {
|
|
937
|
-
let res = undefined !== key
|
|
938
|
-
? pkt_future(key) : true;
|
|
939
|
-
|
|
940
|
-
await send_u8_pkt(
|
|
941
|
-
mqtt_ctx.encode_pkt(type, pkt));
|
|
942
|
-
|
|
943
|
-
return res};
|
|
944
|
-
|
|
945
|
-
_q_init[1](_send_mqtt_pkt); // resolve _q_init with _send_mqtt_pkt closure
|
|
946
|
-
|
|
947
|
-
// call client.on_live in next promise microtask
|
|
948
|
-
client.conn_emit('on_live', _has_connected);
|
|
949
|
-
return on_mqtt_chunk} } }
|
|
950
|
-
|
|
886
|
+
const _isfn = v => typeof v === 'function';
|
|
887
|
+
const _isstr = v => typeof v === 'string';
|
|
951
888
|
|
|
952
|
-
function
|
|
889
|
+
function _interval(fn_callback) {
|
|
953
890
|
let tid;
|
|
954
891
|
return (( td ) => {
|
|
955
892
|
tid = clearInterval(tid);
|
|
956
893
|
if (td) {
|
|
957
|
-
tid = setInterval(
|
|
894
|
+
tid = setInterval(fn_callback, 1000 * td);
|
|
958
895
|
|
|
959
896
|
|
|
960
897
|
|
|
@@ -963,148 +900,108 @@ function _ping_interval(send_ping) {
|
|
|
963
900
|
tid.unref?.();
|
|
964
901
|
return true} }) }
|
|
965
902
|
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
903
|
+
async function _mqtt_cmd_evt(target, answer, pkt, ctx) {
|
|
904
|
+
/* target : on_mqtt_type = {
|
|
905
|
+
mqtt_pkt(pkt, ctx) {}, // generic
|
|
906
|
+
|
|
907
|
+
mqtt_auth(pkt, ctx) {},
|
|
908
|
+
mqtt_connect(pkt, ctx) {},
|
|
909
|
+
mqtt_connack(pkt, ctx) {},
|
|
910
|
+
mqtt_disconnect(pkt, ctx) {},
|
|
911
|
+
|
|
912
|
+
mqtt_publish(pkt, ctx) {},
|
|
913
|
+
mqtt_subscribe(pkt, ctx) {},
|
|
914
|
+
mqtt_unsubscribe(pkt, ctx) {},
|
|
915
|
+
|
|
916
|
+
mqtt_pingreq(pkt, ctx) {},
|
|
917
|
+
mqtt_pingresp(pkt, ctx) {},
|
|
918
|
+
} */
|
|
919
|
+
|
|
920
|
+
let pkt_fn = target[`mqtt_${pkt.type}`] || target.mqtt_pkt;
|
|
921
|
+
await pkt_fn?.call(target, pkt, ctx);}
|
|
922
|
+
|
|
923
|
+
function _mqtt_cmd_type(target, answer, pkt, ctx) {
|
|
924
|
+
answer(pkt.type, pkt);
|
|
925
|
+
_mqtt_cmd_evt(target, answer, pkt, ctx);}
|
|
926
|
+
|
|
927
|
+
function _mqtt_cmd_id(target, answer, pkt) {
|
|
928
|
+
answer(pkt.pkt_id, pkt);}
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
const _mqtt_cmdids =[
|
|
932
|
+
_ => {} // 0x0 reserved
|
|
933
|
+
, _mqtt_cmd_evt // 0x1 connect
|
|
934
|
+
, _mqtt_cmd_type // 0x2 connack
|
|
935
|
+
, _mqtt_cmd_evt // 0x3 publish
|
|
936
|
+
, _mqtt_cmd_id // 0x4 puback
|
|
937
|
+
, _mqtt_cmd_id // 0x5 pubrec
|
|
938
|
+
, _mqtt_cmd_id // 0x6 pubrel
|
|
939
|
+
, _mqtt_cmd_id // 0x7 pubcomp
|
|
940
|
+
, _mqtt_cmd_evt // 0x8 subscribe
|
|
941
|
+
, _mqtt_cmd_id // 0x9 suback
|
|
942
|
+
, _mqtt_cmd_evt // 0xa unsubscribe
|
|
943
|
+
, _mqtt_cmd_id // 0xb unsuback
|
|
944
|
+
, _mqtt_cmd_type // 0xc pingreq
|
|
945
|
+
, _mqtt_cmd_type // 0xd pingresp
|
|
946
|
+
, _mqtt_cmd_evt // 0xe disconnect
|
|
947
|
+
, _mqtt_cmd_type ];// 0xf auth
|
|
969
948
|
|
|
970
|
-
,
|
|
971
|
-
|
|
949
|
+
function _mqtt_dispatch(opt, target) {
|
|
950
|
+
let hashbelt=[], rotate_ts=0;
|
|
951
|
+
// default rotate at 1s across 5 buckets
|
|
952
|
+
let { td: rotate_td=1000, n: rotate_n=5 } = opt?.rotate || {};
|
|
953
|
+
|
|
954
|
+
// Promise / future scaffolding
|
|
955
|
+
let _pkt_id=100, _ftr_key; // use _ftr_key to reuse _by_key closure
|
|
956
|
+
let _ftr_by_key = fn_answer => hashbelt[0].set(_ftr_key, fn_answer);
|
|
957
|
+
|
|
958
|
+
on_mqtt([]); // init hashbelt and rotate_ts
|
|
959
|
+
return [on_mqtt, pkt_future]
|
|
972
960
|
|
|
973
|
-
let _tmp_; // use _tmp_ to reuse _by_key closure
|
|
974
|
-
let _by_key = answer_monad =>
|
|
975
|
-
hashbelt[0].set(_tmp_, answer_monad);
|
|
976
961
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
_tmp_ = pkt_or_key.pkt_id = _pkt_id;}
|
|
962
|
+
function pkt_future(pkt_or_key) {
|
|
963
|
+
if (! _isstr(pkt_or_key)) {
|
|
964
|
+
_pkt_id = (_pkt_id + 1) & 0xffff; // 16-bit unsigned short
|
|
965
|
+
_ftr_key = pkt_or_key.pkt_id = _pkt_id;}
|
|
966
|
+
else _ftr_key = pkt_or_key;
|
|
983
967
|
|
|
984
|
-
|
|
968
|
+
return new Promise(_ftr_by_key)}
|
|
985
969
|
|
|
986
|
-
|
|
987
|
-
for (let map of
|
|
988
|
-
let
|
|
989
|
-
if (
|
|
970
|
+
function answer(key, pkt) {
|
|
971
|
+
for (let map of hashbelt) {
|
|
972
|
+
let fn_answer = map.get(key);
|
|
973
|
+
if (fn_answer) {
|
|
990
974
|
map.delete(key);
|
|
991
975
|
|
|
992
|
-
|
|
976
|
+
fn_answer([pkt, /*err*/]); // option/maybe monad
|
|
993
977
|
return true} }
|
|
994
978
|
return false}
|
|
995
979
|
|
|
996
|
-
, rotate_belt(n) {
|
|
997
|
-
let {hashbelt} = this;
|
|
998
|
-
hashbelt.unshift(new Map());
|
|
999
|
-
for (let old of hashbelt.splice(n || 5)) {
|
|
1000
|
-
for (let answer_monad of old.values()) {
|
|
1001
|
-
answer_monad([/*pkt*/, 'expired']); } } }// option/maybe monad
|
|
1002
|
-
|
|
1003
|
-
, cmdids: ((() => {
|
|
1004
|
-
return [
|
|
1005
|
-
(() =>{} )// 0x0 reserved
|
|
1006
|
-
, by_evt // 0x1 connect
|
|
1007
|
-
, by_type // 0x2 connack
|
|
1008
|
-
, by_evt // 0x3 publish
|
|
1009
|
-
, by_id // 0x4 puback
|
|
1010
|
-
, by_id // 0x5 pubrec
|
|
1011
|
-
, by_id // 0x6 pubrel
|
|
1012
|
-
, by_id // 0x7 pubcomp
|
|
1013
|
-
, by_evt // 0x8 subscribe
|
|
1014
|
-
, by_id // 0x9 suback
|
|
1015
|
-
, by_evt // 0xa unsubscribe
|
|
1016
|
-
, by_id // 0xb unsuback
|
|
1017
|
-
, by_type // 0xc pingreq
|
|
1018
|
-
, by_type // 0xd pingresp
|
|
1019
|
-
, by_evt // 0xe disconnect
|
|
1020
|
-
, by_type ]// 0xf auth
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
function by_id(disp, pkt) {
|
|
1024
|
-
disp.answer(pkt.pkt_id, pkt); }
|
|
1025
|
-
|
|
1026
|
-
function by_type(disp, pkt, ctx) {
|
|
1027
|
-
disp.answer(pkt.type, pkt);
|
|
1028
|
-
by_evt(disp, pkt, ctx);}
|
|
1029
|
-
|
|
1030
|
-
async function by_evt({target}, pkt, ctx) {
|
|
1031
|
-
let fn = target[`mqtt_${pkt.type}`]
|
|
1032
|
-
|| target.mqtt_pkt;
|
|
1033
|
-
|
|
1034
|
-
await fn?.call(target, pkt, ctx);} })()) };
|
|
1035
|
-
|
|
1036
|
-
/*
|
|
1037
|
-
on_mqtt_type = {
|
|
1038
|
-
mqtt_auth(pkt, ctx) ::
|
|
1039
|
-
mqtt_connect(pkt, ctx) ::
|
|
1040
|
-
mqtt_connack(pkt, ctx) ::
|
|
1041
|
-
mqtt_disconnect(pkt, ctx) ::
|
|
1042
|
-
|
|
1043
|
-
mqtt_publish(pkt, ctx)
|
|
1044
|
-
mqtt_subscribe(pkt, ctx) ::
|
|
1045
|
-
mqtt_unsubscribe(pkt, ctx) ::
|
|
1046
|
-
|
|
1047
|
-
mqtt_pingreq(pkt, ctx) ::
|
|
1048
|
-
mqtt_pingresp(pkt, ctx) ::
|
|
1049
|
-
}
|
|
1050
|
-
*/
|
|
1051
|
-
|
|
1052
|
-
function _mqtt_dispatch(opt, target) {
|
|
1053
|
-
let _disp_ = _mqtt_cmdid_dispatch.create(target);
|
|
1054
|
-
let { cmdids } = _disp_;
|
|
1055
|
-
|
|
1056
|
-
// default rotate at 1s across 5 buckets
|
|
1057
|
-
let { td: rotate_td=1000, n: rotate_n=5 } =
|
|
1058
|
-
opt && opt.rotate || {};
|
|
1059
|
-
|
|
1060
|
-
let rotate_ts = rotate_td + Date.now();
|
|
1061
|
-
|
|
1062
|
-
return [on_mqtt,
|
|
1063
|
-
_disp_.bind_pkt_future()]
|
|
1064
|
-
|
|
1065
980
|
function on_mqtt(pkt_list, ctx) {
|
|
1066
981
|
for (let pkt of pkt_list) {
|
|
1067
|
-
|
|
982
|
+
_mqtt_cmdids[pkt.id](target, answer, pkt, ctx);}
|
|
1068
983
|
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
984
|
+
// rotate after rotate_ts
|
|
985
|
+
let now = Date.now();
|
|
986
|
+
if (now > rotate_ts) {
|
|
987
|
+
rotate_ts = rotate_td + now;
|
|
988
|
+
hashbelt.unshift(new Map());
|
|
989
|
+
while (hashbelt.length > rotate_n) {
|
|
990
|
+
for (let fn_answer of hashbelt.pop().values()) {
|
|
991
|
+
fn_answer([/*pkt*/, 'expired']); } } } } }// option/maybe monad
|
|
1072
992
|
|
|
1073
993
|
class MQTTError extends Error {
|
|
1074
994
|
constructor(mqtt_pkt, reason=mqtt_pkt.reason) {
|
|
995
|
+
// use hex-encoded reasons to match MQTT spec documentation
|
|
1075
996
|
super(`[0x${reason.toString(16)}] ${reason.reason}`);
|
|
1076
997
|
this.mqtt_pkt = mqtt_pkt;
|
|
1077
998
|
this.reason = reason;} }
|
|
1078
999
|
|
|
1079
1000
|
class MQTTBase {
|
|
1080
|
-
constructor(opt={}) {
|
|
1081
|
-
this.with(opt);
|
|
1082
|
-
this._conn_ = _mqtt_conn(this,
|
|
1083
|
-
this._init_dispatch(opt, this)); }
|
|
1084
|
-
|
|
1085
|
-
with(fns_ns) {
|
|
1086
|
-
for (let [k,v] of Object.entries(fns_ns)) {
|
|
1087
|
-
if ('function' === typeof v) {this[k] = v;} }
|
|
1088
|
-
return this}
|
|
1089
|
-
|
|
1090
|
-
async conn_emit(evt, arg, err_arg) {
|
|
1091
|
-
this.log_conn?.(evt, arg, err_arg);
|
|
1092
|
-
try {
|
|
1093
|
-
let fn_evt = this[await evt]; // microtask break using `await evt`
|
|
1094
|
-
if (fn_evt) {
|
|
1095
|
-
await fn_evt.call(this, this, arg, err_arg);}
|
|
1096
|
-
else if (err_arg) {throw err_arg} }
|
|
1097
|
-
catch (err) {
|
|
1098
|
-
this.on_error(err, evt);} }
|
|
1099
|
-
|
|
1100
|
-
on_error(err, evt) {
|
|
1101
|
-
console.warn('[[u8-mqtt error: %s]]', evt, err); }
|
|
1102
|
-
|
|
1103
1001
|
// Handshaking Packets
|
|
1104
|
-
|
|
1105
1002
|
async connect(pkt={}) {
|
|
1106
1003
|
let cid = pkt.client_id;
|
|
1107
|
-
if (
|
|
1004
|
+
if (! _isstr(cid)) {
|
|
1108
1005
|
// see init_client_id implementation in core.jsy
|
|
1109
1006
|
pkt.client_id = cid = this.client_id || this.init_client_id(cid);}
|
|
1110
1007
|
this.client_id = cid;
|
|
@@ -1112,23 +1009,20 @@ class MQTTBase {
|
|
|
1112
1009
|
if (null == pkt.keep_alive) {
|
|
1113
1010
|
pkt.keep_alive = 60;}
|
|
1114
1011
|
|
|
1115
|
-
let
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
throw new this.MQTTError(res[0])}
|
|
1120
|
-
|
|
1121
|
-
// TODO: merge with server's keep_alive frequency
|
|
1122
|
-
this._conn_.ping(pkt.keep_alive);
|
|
1123
|
-
return res}
|
|
1012
|
+
let response = await this._send0('connect', pkt, 'connack');
|
|
1013
|
+
if (0 != response[0].reason) {// compare to 0 to coerce to number
|
|
1014
|
+
throw new this.MQTTError(response[0])}
|
|
1015
|
+
return this.conn.on_conn(pkt, response)}
|
|
1124
1016
|
|
|
1125
1017
|
async disconnect(pkt={}) {
|
|
1126
|
-
let
|
|
1127
|
-
this.
|
|
1128
|
-
return res}
|
|
1018
|
+
let response = await this._send0('disconnect', pkt);
|
|
1019
|
+
return this.conn.on_dis(pkt, response)}
|
|
1129
1020
|
|
|
1130
|
-
auth(pkt={}) {
|
|
1131
|
-
|
|
1021
|
+
async auth(pkt={}) {
|
|
1022
|
+
let response = await this._send0('auth', pkt, 'auth');
|
|
1023
|
+
if (response[0].reason) {
|
|
1024
|
+
throw new this.MQTTError(response[0])}
|
|
1025
|
+
return this.conn.on_auth(pkt, response)}
|
|
1132
1026
|
|
|
1133
1027
|
ping() {return this._send('pingreq', null, 'pingresp')}
|
|
1134
1028
|
puback({pkt_id}) {return this._send('puback', {pkt_id})}
|
|
@@ -1165,20 +1059,18 @@ class MQTTBase {
|
|
|
1165
1059
|
// alias: publish -- because 'pub' is shorter for semantic aliases above
|
|
1166
1060
|
async pub(pkt, pub_opt) {
|
|
1167
1061
|
if (undefined === pkt.payload) {
|
|
1168
|
-
if (
|
|
1062
|
+
if (_isfn(pub_opt)) {
|
|
1063
|
+
// pub_opt as a function is fn_encode value
|
|
1169
1064
|
pub_opt = {fn_encode: pub_opt};}
|
|
1170
1065
|
|
|
1171
|
-
let
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
// return a single-value closure to publish packets
|
|
1178
|
-
return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)}
|
|
1066
|
+
let msg = pkt.msg, fn_encode = pub_opt?.fn_encode;
|
|
1067
|
+
if (null == msg || _isfn(msg)) {
|
|
1068
|
+
// when msg is a function, return closure using fn_encode
|
|
1069
|
+
if (msg) {pub_opt = {...pub_opt, fn_encode: msg};}
|
|
1070
|
+
// return a single-value closure to publish packets
|
|
1071
|
+
return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)}
|
|
1179
1072
|
|
|
1180
1073
|
// Encode payload from msg; fn_encode allows alternative to JSON.stringify
|
|
1181
|
-
let {fn_encode} = pub_opt || {};
|
|
1182
1074
|
pkt.payload = fn_encode
|
|
1183
1075
|
? await fn_encode(msg)
|
|
1184
1076
|
: JSON.stringify(msg);}
|
|
@@ -1190,31 +1082,31 @@ class MQTTBase {
|
|
|
1190
1082
|
pkt = pub_opt.xform(pkt) || pkt;} }
|
|
1191
1083
|
|
|
1192
1084
|
return this._send('publish', pkt,
|
|
1193
|
-
pkt.qos ? pkt :
|
|
1085
|
+
pkt.qos ? pkt : null ) }// key
|
|
1194
1086
|
|
|
1195
1087
|
|
|
1196
1088
|
// Internal API
|
|
1197
1089
|
|
|
1198
|
-
/* async
|
|
1090
|
+
/* async _send0(type, pkt) -- provided by conn and transport */
|
|
1091
|
+
/* async _send(type, pkt) -- provided by conn and transport */
|
|
1199
1092
|
|
|
1200
1093
|
_init_dispatch(opt) {
|
|
1201
1094
|
this.constructor?._once_();
|
|
1202
1095
|
let target ={__proto__: opt.on_mqtt_type};
|
|
1203
1096
|
target.mqtt_publish ||=
|
|
1204
1097
|
this._init_router?.(opt, this, target);
|
|
1205
|
-
return _mqtt_dispatch(
|
|
1098
|
+
return _mqtt_dispatch(opt, target)}
|
|
1206
1099
|
|
|
1207
1100
|
static _aliases() {
|
|
1208
1101
|
return ' publish:pub sub:subscribe unsub:unsubscribe json_post:obj_post json_send:obj_send json_store:obj_store'}
|
|
1209
1102
|
|
|
1210
|
-
static _once_(
|
|
1211
|
-
|
|
1212
|
-
|
|
1103
|
+
static _once_(klass=this) {
|
|
1104
|
+
klass._once_ = _=>0;
|
|
1105
|
+
var alias, name, p = klass.prototype;
|
|
1213
1106
|
p.MQTTError = MQTTError;
|
|
1214
|
-
for (
|
|
1215
|
-
alias = alias.split(':');
|
|
1216
|
-
|
|
1217
|
-
if (fn) {p[alias[0]] = fn;} } } }
|
|
1107
|
+
for (alias of klass._aliases().split(/\s+/)) {
|
|
1108
|
+
[alias, name] = alias.split(':');
|
|
1109
|
+
p[alias] = p[name];} } }
|
|
1218
1110
|
|
|
1219
1111
|
|
|
1220
1112
|
function _as_topics(pkt, ex, topic_prefix) {
|
|
@@ -1239,37 +1131,167 @@ function _as_topics(pkt, ex, topic_prefix) {
|
|
|
1239
1131
|
pkt.topics = pkt.topics.map(_prefix_topics);}
|
|
1240
1132
|
return pkt}
|
|
1241
1133
|
|
|
1242
|
-
const
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1134
|
+
const _defer_obj = o =>(
|
|
1135
|
+
o.p = new Promise((a,e) => { o.a=a; o.e=e; })
|
|
1136
|
+
, o);
|
|
1137
|
+
|
|
1138
|
+
function _dfn_reset(client, attr, fn_after) {
|
|
1139
|
+
// a resetable deferred for a function
|
|
1140
|
+
let self = {set}, afn = async (...args) => (await self.p)(...args);
|
|
1141
|
+
return set()
|
|
1142
|
+
|
|
1143
|
+
function set() {
|
|
1144
|
+
if (afn !== client[attr]) {
|
|
1145
|
+
_defer_obj(self).p.then(fn_after, _=>0);
|
|
1146
|
+
client[attr] = afn;}
|
|
1147
|
+
return self} }
|
|
1148
|
+
|
|
1149
|
+
function _mqtt_conn(opt, client, [on_mqtt, pkt_future]) {
|
|
1150
|
+
let _abort;
|
|
1151
|
+
let _dfn_send0 = _dfn_reset(client, '_send0', // client._send0 getter/setter
|
|
1152
|
+
_=> client.conn_emit('on_live', conn.has_connected));
|
|
1153
|
+
let _dfn_ready = _dfn_reset(client, '_send', // client._send getter/setter
|
|
1154
|
+
_=> client.conn_emit('on_ready'));
|
|
1155
|
+
let _keep_alive_ival = _interval (() =>client._send0('pingreq') );// resettable interval for keep_alive ping
|
|
1156
|
+
|
|
1157
|
+
let conn = Object.create({
|
|
1158
|
+
ping: (td=conn.keep_alive) => _keep_alive_ival(td)
|
|
1159
|
+
|
|
1160
|
+
, on_conn(pkt, response) {
|
|
1161
|
+
conn.has_connected = true;
|
|
1162
|
+
conn.keep_alive = opt.keep_alive || response[0].props?.server_keep_alive || pkt.keep_alive;
|
|
1163
|
+
client.conn_emit('on_conn');
|
|
1164
|
+
return opt.use_auth
|
|
1165
|
+
? response // wait on enhanced authentication step
|
|
1166
|
+
: conn.on_auth(null, response) }// otherwise, connect is also auth
|
|
1167
|
+
|
|
1168
|
+
, on_auth(pkt, response) {
|
|
1169
|
+
_dfn_ready.a(_dfn_send0.p);
|
|
1170
|
+
if (0 != opt.keep_alive) {
|
|
1171
|
+
conn.ping();}
|
|
1172
|
+
client.conn_emit('on_auth', !pkt);
|
|
1173
|
+
return response}
|
|
1174
|
+
|
|
1175
|
+
, on_dis(pkt, response) {
|
|
1176
|
+
conn.reset(false);
|
|
1177
|
+
return response}
|
|
1178
|
+
|
|
1179
|
+
, reset(err) {
|
|
1180
|
+
if (err) {
|
|
1181
|
+
_dfn_send0.e(err); }// send error to uses of _send0 (connect, auth)
|
|
1182
|
+
_abort.e(err); // abort in-progress connections
|
|
1183
|
+
|
|
1184
|
+
delete conn.is_set;
|
|
1185
|
+
conn.ready = handshake();
|
|
1186
|
+
client.conn_emit('on_disconnect', false===err, err);}
|
|
1187
|
+
|
|
1188
|
+
, abort() {
|
|
1189
|
+
_dfn_ready.e(err); // abort all messages awaiting ready state
|
|
1190
|
+
return conn.reset(err)}
|
|
1191
|
+
|
|
1192
|
+
, async setup(gate, send_u8_pkt, init_msg_loop) {
|
|
1193
|
+
if (conn.is_set) {
|
|
1194
|
+
throw new Error() }// already in-progress
|
|
1195
|
+
|
|
1196
|
+
conn.is_set = true;
|
|
1197
|
+
await gate;
|
|
1198
|
+
|
|
1199
|
+
// setup send/recv MQTT parsing context
|
|
1200
|
+
let mqtt_ctx = client.mqtt_ctx.mqtt_stream();
|
|
1201
|
+
|
|
1202
|
+
{// setup inbound message loop
|
|
1203
|
+
let sess_ctx = {mqtt: client}; // mutable session context
|
|
1204
|
+
let on_mqtt_chunk = u8 => on_mqtt(mqtt_ctx.decode(u8), sess_ctx);
|
|
1205
|
+
init_msg_loop(on_mqtt_chunk, conn);}
|
|
1206
|
+
|
|
1207
|
+
// setup outbound message path and transport connection
|
|
1208
|
+
send_u8_pkt = await send_u8_pkt;
|
|
1209
|
+
_dfn_send0.a(
|
|
1210
|
+
async (type, pkt, key) => {
|
|
1211
|
+
let res = undefined !== key
|
|
1212
|
+
? pkt_future(key) : true;
|
|
1213
|
+
|
|
1214
|
+
await send_u8_pkt(
|
|
1215
|
+
mqtt_ctx.encode_pkt(type, pkt));
|
|
1216
|
+
return res} ); } });
|
|
1217
|
+
|
|
1218
|
+
conn.ready = handshake();
|
|
1219
|
+
return conn
|
|
1220
|
+
|
|
1221
|
+
async function handshake() {
|
|
1222
|
+
_abort = _defer_obj({});
|
|
1223
|
+
|
|
1224
|
+
_keep_alive_ival(0); // clearInterval on keep alive ping
|
|
1225
|
+
_dfn_send0.set(); // reset client._send0 if necessary
|
|
1226
|
+
_dfn_ready.set(); // reset client._send if necessary
|
|
1227
|
+
|
|
1228
|
+
try {
|
|
1229
|
+
// set client._send0 as passtrhough after transport connection
|
|
1230
|
+
client._send0 = await Promise.race([_dfn_send0.p, _abort.p]);
|
|
1231
|
+
|
|
1232
|
+
// set client._send as passtrhough after ready
|
|
1233
|
+
client._send = await Promise.race([_dfn_ready.p, _abort.p]);
|
|
1234
|
+
return true}
|
|
1235
|
+
catch (err) {
|
|
1236
|
+
return false} } }
|
|
1237
|
+
|
|
1238
|
+
const pkt_api ={
|
|
1239
|
+
utf8(u8) {return new TextDecoder('utf-8').decode(u8 || this.payload )}
|
|
1240
|
+
, json(u8) {return JSON.parse( this.utf8(u8) || null )}
|
|
1241
|
+
, text(u8) {return this.utf8(u8)} };
|
|
1242
|
+
|
|
1243
|
+
const opt_default ={
|
|
1244
|
+
sess_stg: globalThis.sessionStorage};
|
|
1247
1245
|
|
|
1248
1246
|
class MQTTCore extends MQTTBase {
|
|
1247
|
+
constructor(opt) {
|
|
1248
|
+
super();
|
|
1249
|
+
this.with(opt);
|
|
1250
|
+
opt ={...opt_default, ...opt};
|
|
1251
|
+
// settings for MQTTCore
|
|
1252
|
+
this.sess_stg = opt.sess_stg;
|
|
1253
|
+
// setup connection and dispatch
|
|
1254
|
+
this.conn = _mqtt_conn(opt, this,
|
|
1255
|
+
this._init_dispatch(opt)); }
|
|
1256
|
+
|
|
1257
|
+
with(fns_ns) {
|
|
1258
|
+
for (let [k,v] of Object.entries(fns_ns)) {
|
|
1259
|
+
if (_isfn(v)) {this[k] = v;} }
|
|
1260
|
+
return this}
|
|
1261
|
+
|
|
1262
|
+
|
|
1249
1263
|
static mqtt_ctx(mqtt_level, mqtt_opts, pkt_ctx=pkt_api) {
|
|
1250
|
-
let
|
|
1251
|
-
|
|
1264
|
+
let klass = class extends this {};
|
|
1265
|
+
klass.prototype.mqtt_ctx =
|
|
1252
1266
|
mqtt_pkt_ctx(mqtt_level, mqtt_opts, pkt_ctx);
|
|
1253
|
-
return
|
|
1267
|
+
return klass}
|
|
1268
|
+
|
|
1269
|
+
|
|
1270
|
+
async conn_emit(evt, arg, err_arg) {
|
|
1271
|
+
this.log_conn?.(evt, arg, err_arg);
|
|
1272
|
+
try {
|
|
1273
|
+
let fn_evt = this[await evt]; // microtask break using `await evt`
|
|
1274
|
+
if (fn_evt) {
|
|
1275
|
+
await fn_evt.call(this, this, arg, err_arg);}
|
|
1276
|
+
else if (err_arg) {throw err_arg} }
|
|
1277
|
+
catch (err) {
|
|
1278
|
+
this.on_error(err, evt);} }
|
|
1279
|
+
|
|
1280
|
+
on_error(err, evt) {
|
|
1281
|
+
console.warn('[[u8-mqtt error: %s]]', evt, err); }
|
|
1282
|
+
log_conn(evt, arg, err_arg) {
|
|
1283
|
+
console.info('[[u8-mqtt conn: %s]]', evt, arg, err_arg); }
|
|
1254
1284
|
|
|
1255
1285
|
|
|
1256
1286
|
// automatic Client Id for connect()
|
|
1257
1287
|
init_client_id(parts=['u8-mqtt--','']) {
|
|
1258
|
-
let sess_stg=this.sess_stg;
|
|
1288
|
+
let sess_stg = this.sess_stg;
|
|
1259
1289
|
let key, cid = sess_stg?.getItem(key=parts.join(' '));
|
|
1260
1290
|
if (! cid) {
|
|
1261
1291
|
cid = parts.join(Math.random().toString(36).slice(2));
|
|
1262
1292
|
sess_stg?.setItem(key, cid);}
|
|
1263
1293
|
return cid}
|
|
1264
1294
|
|
|
1265
|
-
get sess_stg() {return globalThis.sessionStorage}
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
//on_error(err, evt) ::
|
|
1269
|
-
// console.warn @ '[[u8-mqtt error: %s]]', evt, err
|
|
1270
|
-
|
|
1271
|
-
//log_conn(evt, arg, err_arg) ::
|
|
1272
|
-
// console.info @ '[[u8-mqtt log: %s]]', evt, arg, err_arg
|
|
1273
1295
|
|
|
1274
1296
|
on_live(client, is_reconnect) {
|
|
1275
1297
|
if (is_reconnect) {
|
|
@@ -1295,19 +1317,16 @@ class MQTTCore extends MQTTBase {
|
|
|
1295
1317
|
return new Promise(done => setTimeout(done, ms)) }
|
|
1296
1318
|
|
|
1297
1319
|
with_async_iter(async_iter, write_u8_pkt) {
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
catch (err) {
|
|
1309
|
-
this._conn_.reset(err);} })());
|
|
1310
|
-
|
|
1320
|
+
this.conn.setup(async_iter,
|
|
1321
|
+
write_u8_pkt,
|
|
1322
|
+
async (on_mqtt_chunk, conn) => {
|
|
1323
|
+
try {
|
|
1324
|
+
async_iter = await async_iter;
|
|
1325
|
+
for await (let chunk of async_iter)
|
|
1326
|
+
on_mqtt_chunk(chunk);
|
|
1327
|
+
conn.reset();}
|
|
1328
|
+
catch (err) {
|
|
1329
|
+
conn.reset(err);} } );
|
|
1311
1330
|
return this}
|
|
1312
1331
|
|
|
1313
1332
|
|
|
@@ -1378,33 +1397,30 @@ class MQTTCore extends MQTTBase {
|
|
|
1378
1397
|
|
|
1379
1398
|
websock.binaryType = 'arraybuffer';
|
|
1380
1399
|
|
|
1381
|
-
let
|
|
1400
|
+
let ws_ready, readyState = websock.readyState;
|
|
1382
1401
|
if (1 !== readyState) {
|
|
1383
1402
|
if (0 !== readyState) {
|
|
1384
|
-
throw new Error('
|
|
1385
|
-
|
|
1386
|
-
ready = new Promise(fn => websock.onopen = fn); }
|
|
1403
|
+
throw new Error('WS readyState') }
|
|
1387
1404
|
|
|
1405
|
+
ws_ready = new Promise(ready => websock.onopen = ready); }
|
|
1388
1406
|
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
, websock.send(u8_pkt)) );
|
|
1407
|
+
this.conn.setup(ws_ready,
|
|
1408
|
+
u8_pkt => websock.send(u8_pkt),
|
|
1409
|
+
(on_mqtt_chunk, conn) => {
|
|
1410
|
+
websock.onmessage = evt =>(
|
|
1411
|
+
on_mqtt_chunk(new Uint8Array(evt.data)) );
|
|
1395
1412
|
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
err.reason = evt.reason;}
|
|
1413
|
+
websock.onclose = evt => {
|
|
1414
|
+
if (! evt.wasClean) {
|
|
1415
|
+
var err = new Error('websocket close');
|
|
1416
|
+
err.code = evt.code;
|
|
1417
|
+
err.reason = evt.reason;}
|
|
1402
1418
|
|
|
1403
|
-
|
|
1419
|
+
conn.reset(err);}; } );
|
|
1404
1420
|
|
|
1405
1421
|
return this} }
|
|
1406
1422
|
|
|
1407
|
-
const version = '0.
|
|
1423
|
+
const version = '0.6.0-node';
|
|
1408
1424
|
|
|
1409
1425
|
const MQTTClient_v4 = /* #__PURE__ */
|
|
1410
1426
|
MQTTCore.mqtt_ctx(4, mqtt_opts_v5);
|