u8-mqtt 0.5.2 → 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/README.md +23 -6
- package/cjs/basic-v4.cjs +293 -284
- package/cjs/basic-v4.cjs.map +1 -1
- package/cjs/basic-v5.cjs +307 -288
- package/cjs/basic-v5.cjs.map +1 -1
- package/cjs/full-v4.cjs +1538 -0
- package/cjs/full-v4.cjs.map +1 -0
- package/cjs/full-v5.cjs +1812 -0
- package/cjs/full-v5.cjs.map +1 -0
- package/cjs/index.cjs +320 -302
- package/cjs/index.cjs.map +1 -1
- package/cjs/v4.cjs +305 -296
- package/cjs/v4.cjs.map +1 -1
- package/cjs/v5.cjs +319 -300
- 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 +35 -63
- package/code/core.jsy +78 -56
- package/code/full-v4.js +20 -0
- package/code/full-v5.js +29 -0
- package/code/router_path.jsy +2 -1
- package/esm/basic-v4.js +293 -284
- package/esm/basic-v4.js.map +1 -1
- package/esm/basic-v5.js +307 -288
- package/esm/basic-v5.js.map +1 -1
- package/esm/deno/basic-v4.js +297 -288
- package/esm/deno/basic-v4.js.map +1 -1
- package/esm/deno/basic-v5.js +311 -292
- package/esm/deno/basic-v5.js.map +1 -1
- package/esm/deno/full-v4.js +1526 -0
- package/esm/deno/full-v4.js.map +1 -0
- package/esm/deno/full-v5.js +1798 -0
- package/esm/deno/full-v5.js.map +1 -0
- package/esm/deno/index.js +324 -305
- package/esm/deno/index.js.map +1 -1
- package/esm/deno/v4.js +309 -300
- package/esm/deno/v4.js.map +1 -1
- package/esm/deno/v5.js +323 -304
- package/esm/deno/v5.js.map +1 -1
- package/esm/full-v4.js +1526 -0
- package/esm/full-v4.js.map +1 -0
- package/esm/full-v5.js +1798 -0
- package/esm/full-v5.js.map +1 -0
- package/esm/index.js +320 -301
- package/esm/index.js.map +1 -1
- package/esm/node/basic-v4.js +293 -284
- package/esm/node/basic-v4.js.map +1 -1
- package/esm/node/basic-v4.mjs +293 -284
- package/esm/node/basic-v4.mjs.map +1 -1
- package/esm/node/basic-v5.js +307 -288
- package/esm/node/basic-v5.js.map +1 -1
- package/esm/node/basic-v5.mjs +307 -288
- package/esm/node/basic-v5.mjs.map +1 -1
- package/esm/node/full-v4.js +1529 -0
- package/esm/node/full-v4.js.map +1 -0
- package/esm/node/full-v4.mjs +1529 -0
- package/esm/node/full-v4.mjs.map +1 -0
- package/esm/node/full-v5.js +1801 -0
- package/esm/node/full-v5.js.map +1 -0
- package/esm/node/full-v5.mjs +1801 -0
- package/esm/node/full-v5.mjs.map +1 -0
- package/esm/node/index.js +320 -301
- package/esm/node/index.js.map +1 -1
- package/esm/node/index.mjs +320 -301
- package/esm/node/index.mjs.map +1 -1
- package/esm/node/v4.js +305 -296
- package/esm/node/v4.js.map +1 -1
- package/esm/node/v4.mjs +305 -296
- package/esm/node/v4.mjs.map +1 -1
- package/esm/node/v5.js +319 -300
- package/esm/node/v5.js.map +1 -1
- package/esm/node/v5.mjs +319 -300
- package/esm/node/v5.mjs.map +1 -1
- package/esm/v4.js +305 -296
- package/esm/v4.js.map +1 -1
- package/esm/v5.js +319 -300
- package/esm/v5.js.map +1 -1
- package/esm/web/basic-v4.js +293 -284
- 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 +307 -288
- 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 +1526 -0
- package/esm/web/full-v4.js.map +1 -0
- package/esm/web/full-v4.min.js +1 -0
- 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 +1798 -0
- package/esm/web/full-v5.js.map +1 -0
- package/esm/web/full-v5.min.js +1 -0
- 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 +320 -301
- 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 +305 -296
- 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 +319 -300
- package/esm/web/v5.js.map +1 -1
- package/esm/web/v5.min.js +1 -1
- package/esm/web/v5.min.js.br +0 -0
- package/esm/web/v5.min.js.gz +0 -0
- package/package.json +7 -8
package/cjs/v5.cjs
CHANGED
|
@@ -163,10 +163,18 @@ let mqtt_reader_v5$1 = class mqtt_reader_v5 extends mqtt_reader_v4 {
|
|
|
163
163
|
|
|
164
164
|
let res={}, fork = this.of(buf.subarray(vi, step.k|0));
|
|
165
165
|
while (fork.has_more()) {
|
|
166
|
-
let pt = mqtt_props.get(
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
166
|
+
let v, pk = fork.u8(), pt = mqtt_props.get( pk );
|
|
167
|
+
|
|
168
|
+
if (!pt) {
|
|
169
|
+
res.error = `Unknown mqtt_prop enum ${pk}`;
|
|
170
|
+
return res
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
v = fork[pt.type]();
|
|
174
|
+
if (pt.op) // accumulate operation
|
|
175
|
+
v = fork[pt.op](res[pt.name], v);
|
|
176
|
+
|
|
177
|
+
res[pt.name] = v;
|
|
170
178
|
}
|
|
171
179
|
return res
|
|
172
180
|
}
|
|
@@ -300,6 +308,8 @@ class mqtt_writer_v5 extends mqtt_writer_v4 {
|
|
|
300
308
|
let fork = this.of();
|
|
301
309
|
for (let [name, value] of props) {
|
|
302
310
|
let pt = mqtt_props.get(name);
|
|
311
|
+
if (!pt)
|
|
312
|
+
throw new Error(`Unknown mqtt_prop "${name}"`)
|
|
303
313
|
fork[pt.op || 'one'](value, pt);
|
|
304
314
|
}
|
|
305
315
|
this.push(fork.pack());
|
|
@@ -803,6 +813,23 @@ function parse(str, loose) {
|
|
|
803
813
|
};
|
|
804
814
|
}
|
|
805
815
|
|
|
816
|
+
const _isfn = v => typeof v === 'function';
|
|
817
|
+
const _isstr = v => typeof v === 'string';
|
|
818
|
+
|
|
819
|
+
function _interval(fn_callback) {
|
|
820
|
+
let tid;
|
|
821
|
+
return (( td ) => {
|
|
822
|
+
tid = clearInterval(tid);
|
|
823
|
+
if (td) {
|
|
824
|
+
tid = setInterval(fn_callback, 1000 * td);
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
// ensure the interval allows the NodeJS event loop to exit
|
|
830
|
+
tid.unref?.();
|
|
831
|
+
return true} }) }
|
|
832
|
+
|
|
806
833
|
/*
|
|
807
834
|
class AbstractTopicRouter ::
|
|
808
835
|
async invoke(pkt, ctx) ::
|
|
@@ -893,7 +920,7 @@ function mqtt_topic_path_router() {
|
|
|
893
920
|
let fn = args.pop();
|
|
894
921
|
let priority = args.pop();
|
|
895
922
|
|
|
896
|
-
if (
|
|
923
|
+
if (! _isfn(fn)) {
|
|
897
924
|
if (fn) {throw new TypeError()}
|
|
898
925
|
fn = _ignore;}
|
|
899
926
|
|
|
@@ -1043,6 +1070,9 @@ function mqtt_pkt_ctx(mqtt_level, opts, pkt_ctx) {
|
|
|
1043
1070
|
return _encode_by_type[type]( mqtt_level, pkt ) },
|
|
1044
1071
|
|
|
1045
1072
|
decode_pkt(b0, u8_body) {
|
|
1073
|
+
if (b0.map) // Uint8Array in first arg
|
|
1074
|
+
return mqtt_raw_dispatch(this)(b0)[0]
|
|
1075
|
+
|
|
1046
1076
|
let fn_decode = _decode_by_id[b0>>>4] || _decode_by_id[0];
|
|
1047
1077
|
return fn_decode?.({__proto__: this.pkt_ctx, b0}, u8_body) },
|
|
1048
1078
|
|
|
@@ -1055,262 +1085,129 @@ function mqtt_pkt_ctx(mqtt_level, opts, pkt_ctx) {
|
|
|
1055
1085
|
}
|
|
1056
1086
|
}
|
|
1057
1087
|
|
|
1058
|
-
function
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
,
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
_q_ready = ao_defer_v();
|
|
1104
|
-
client.conn_emit('on_ready');}
|
|
1105
|
-
|
|
1106
|
-
return res}
|
|
1107
|
-
|
|
1108
|
-
, is_set: (() =>!! _send_mqtt_pkt)
|
|
1109
|
-
, set(mqtt_ctx, send_u8_pkt) {
|
|
1110
|
-
if (_send_mqtt_pkt) {
|
|
1111
|
-
throw new Error('Already connected')}
|
|
1088
|
+
async function _mqtt_cmd_evt(target, answer, pkt, ctx) {
|
|
1089
|
+
/* target : on_mqtt_type = {
|
|
1090
|
+
mqtt_pkt(pkt, ctx) {}, // generic
|
|
1091
|
+
|
|
1092
|
+
mqtt_auth(pkt, ctx) {},
|
|
1093
|
+
mqtt_connect(pkt, ctx) {},
|
|
1094
|
+
mqtt_connack(pkt, ctx) {},
|
|
1095
|
+
mqtt_disconnect(pkt, ctx) {},
|
|
1096
|
+
|
|
1097
|
+
mqtt_publish(pkt, ctx) {},
|
|
1098
|
+
mqtt_subscribe(pkt, ctx) {},
|
|
1099
|
+
mqtt_unsubscribe(pkt, ctx) {},
|
|
1100
|
+
|
|
1101
|
+
mqtt_pingreq(pkt, ctx) {},
|
|
1102
|
+
mqtt_pingresp(pkt, ctx) {},
|
|
1103
|
+
} */
|
|
1104
|
+
|
|
1105
|
+
let pkt_fn = target[`mqtt_${pkt.type}`] || target.mqtt_pkt;
|
|
1106
|
+
await pkt_fn?.call(target, pkt, ctx);}
|
|
1107
|
+
|
|
1108
|
+
function _mqtt_cmd_type(target, answer, pkt, ctx) {
|
|
1109
|
+
answer(pkt.type, pkt);
|
|
1110
|
+
_mqtt_cmd_evt(target, answer, pkt, ctx);}
|
|
1111
|
+
|
|
1112
|
+
function _mqtt_cmd_id(target, answer, pkt) {
|
|
1113
|
+
answer(pkt.pkt_id, pkt);}
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
const _mqtt_cmdids =[
|
|
1117
|
+
_ => {} // 0x0 reserved
|
|
1118
|
+
, _mqtt_cmd_evt // 0x1 connect
|
|
1119
|
+
, _mqtt_cmd_type // 0x2 connack
|
|
1120
|
+
, _mqtt_cmd_evt // 0x3 publish
|
|
1121
|
+
, _mqtt_cmd_id // 0x4 puback
|
|
1122
|
+
, _mqtt_cmd_id // 0x5 pubrec
|
|
1123
|
+
, _mqtt_cmd_id // 0x6 pubrel
|
|
1124
|
+
, _mqtt_cmd_id // 0x7 pubcomp
|
|
1125
|
+
, _mqtt_cmd_evt // 0x8 subscribe
|
|
1126
|
+
, _mqtt_cmd_id // 0x9 suback
|
|
1127
|
+
, _mqtt_cmd_evt // 0xa unsubscribe
|
|
1128
|
+
, _mqtt_cmd_id // 0xb unsuback
|
|
1129
|
+
, _mqtt_cmd_type // 0xc pingreq
|
|
1130
|
+
, _mqtt_cmd_type // 0xd pingresp
|
|
1131
|
+
, _mqtt_cmd_evt // 0xe disconnect
|
|
1132
|
+
, _mqtt_cmd_type ];// 0xf auth
|
|
1112
1133
|
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
_send_mqtt_pkt = async (type, pkt, key) => {
|
|
1119
|
-
let res = undefined !== key
|
|
1120
|
-
? pkt_future(key) : true;
|
|
1121
|
-
|
|
1122
|
-
await send_u8_pkt(
|
|
1123
|
-
mqtt_ctx.encode_pkt(type, pkt));
|
|
1124
|
-
|
|
1125
|
-
return res};
|
|
1126
|
-
|
|
1127
|
-
_q_init[1](_send_mqtt_pkt); // resolve _q_init with _send_mqtt_pkt closure
|
|
1128
|
-
|
|
1129
|
-
// call client.on_live in next promise microtask
|
|
1130
|
-
client.conn_emit('on_live', _has_connected);
|
|
1131
|
-
return on_mqtt_chunk} } }
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
function _ping_interval(send_ping) {
|
|
1135
|
-
let tid;
|
|
1136
|
-
return (( td ) => {
|
|
1137
|
-
tid = clearInterval(tid);
|
|
1138
|
-
if (td) {
|
|
1139
|
-
tid = setInterval(send_ping, 1000 * td);
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
// ensure the interval allows the NodeJS event loop to exit
|
|
1145
|
-
tid.unref?.();
|
|
1146
|
-
return true} }) }
|
|
1134
|
+
function _mqtt_dispatch(opt, target) {
|
|
1135
|
+
let hashbelt=[], rotate_ts=0;
|
|
1136
|
+
// default rotate at 1s across 5 buckets
|
|
1137
|
+
let { td: rotate_td=1000, n: rotate_n=5 } = opt?.rotate || {};
|
|
1147
1138
|
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1139
|
+
// Promise / future scaffolding
|
|
1140
|
+
let _pkt_id=100, _ftr_key; // use _ftr_key to reuse _by_key closure
|
|
1141
|
+
let _ftr_by_key = fn_answer => hashbelt[0].set(_ftr_key, fn_answer);
|
|
1151
1142
|
|
|
1152
|
-
|
|
1153
|
-
|
|
1143
|
+
on_mqtt([]); // init hashbelt and rotate_ts
|
|
1144
|
+
return [on_mqtt, pkt_future]
|
|
1154
1145
|
|
|
1155
|
-
let _tmp_; // use _tmp_ to reuse _by_key closure
|
|
1156
|
-
let _by_key = answer_monad =>
|
|
1157
|
-
hashbelt[0].set(_tmp_, answer_monad);
|
|
1158
1146
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
_tmp_ = pkt_or_key.pkt_id = _pkt_id;}
|
|
1147
|
+
function pkt_future(pkt_or_key) {
|
|
1148
|
+
if (! _isstr(pkt_or_key)) {
|
|
1149
|
+
_pkt_id = (_pkt_id + 1) & 0xffff; // 16-bit unsigned short
|
|
1150
|
+
_ftr_key = pkt_or_key.pkt_id = _pkt_id;}
|
|
1151
|
+
else _ftr_key = pkt_or_key;
|
|
1165
1152
|
|
|
1166
|
-
|
|
1153
|
+
return new Promise(_ftr_by_key)}
|
|
1167
1154
|
|
|
1168
|
-
|
|
1169
|
-
for (let map of
|
|
1170
|
-
let
|
|
1171
|
-
if (
|
|
1155
|
+
function answer(key, pkt) {
|
|
1156
|
+
for (let map of hashbelt) {
|
|
1157
|
+
let fn_answer = map.get(key);
|
|
1158
|
+
if (fn_answer) {
|
|
1172
1159
|
map.delete(key);
|
|
1173
1160
|
|
|
1174
|
-
|
|
1161
|
+
fn_answer([pkt, /*err*/]); // option/maybe monad
|
|
1175
1162
|
return true} }
|
|
1176
1163
|
return false}
|
|
1177
1164
|
|
|
1178
|
-
, rotate_belt(n) {
|
|
1179
|
-
let {hashbelt} = this;
|
|
1180
|
-
hashbelt.unshift(new Map());
|
|
1181
|
-
for (let old of hashbelt.splice(n || 5)) {
|
|
1182
|
-
for (let answer_monad of old.values()) {
|
|
1183
|
-
answer_monad([/*pkt*/, 'expired']); } } }// option/maybe monad
|
|
1184
|
-
|
|
1185
|
-
, cmdids: ((() => {
|
|
1186
|
-
return [
|
|
1187
|
-
(() =>{} )// 0x0 reserved
|
|
1188
|
-
, by_evt // 0x1 connect
|
|
1189
|
-
, by_type // 0x2 connack
|
|
1190
|
-
, by_evt // 0x3 publish
|
|
1191
|
-
, by_id // 0x4 puback
|
|
1192
|
-
, by_id // 0x5 pubrec
|
|
1193
|
-
, by_id // 0x6 pubrel
|
|
1194
|
-
, by_id // 0x7 pubcomp
|
|
1195
|
-
, by_evt // 0x8 subscribe
|
|
1196
|
-
, by_id // 0x9 suback
|
|
1197
|
-
, by_evt // 0xa unsubscribe
|
|
1198
|
-
, by_id // 0xb unsuback
|
|
1199
|
-
, by_type // 0xc pingreq
|
|
1200
|
-
, by_type // 0xd pingresp
|
|
1201
|
-
, by_evt // 0xe disconnect
|
|
1202
|
-
, by_type ]// 0xf auth
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
function by_id(disp, pkt) {
|
|
1206
|
-
disp.answer(pkt.pkt_id, pkt); }
|
|
1207
|
-
|
|
1208
|
-
function by_type(disp, pkt, ctx) {
|
|
1209
|
-
disp.answer(pkt.type, pkt);
|
|
1210
|
-
by_evt(disp, pkt, ctx);}
|
|
1211
|
-
|
|
1212
|
-
async function by_evt({target}, pkt, ctx) {
|
|
1213
|
-
let fn = target[`mqtt_${pkt.type}`]
|
|
1214
|
-
|| target.mqtt_pkt;
|
|
1215
|
-
|
|
1216
|
-
await fn?.call(target, pkt, ctx);} })()) };
|
|
1217
|
-
|
|
1218
|
-
/*
|
|
1219
|
-
on_mqtt_type = {
|
|
1220
|
-
mqtt_auth(pkt, ctx) ::
|
|
1221
|
-
mqtt_connect(pkt, ctx) ::
|
|
1222
|
-
mqtt_connack(pkt, ctx) ::
|
|
1223
|
-
mqtt_disconnect(pkt, ctx) ::
|
|
1224
|
-
|
|
1225
|
-
mqtt_publish(pkt, ctx)
|
|
1226
|
-
mqtt_subscribe(pkt, ctx) ::
|
|
1227
|
-
mqtt_unsubscribe(pkt, ctx) ::
|
|
1228
|
-
|
|
1229
|
-
mqtt_pingreq(pkt, ctx) ::
|
|
1230
|
-
mqtt_pingresp(pkt, ctx) ::
|
|
1231
|
-
}
|
|
1232
|
-
*/
|
|
1233
|
-
|
|
1234
|
-
function _mqtt_dispatch(opt, target) {
|
|
1235
|
-
let _disp_ = _mqtt_cmdid_dispatch.create(target);
|
|
1236
|
-
let { cmdids } = _disp_;
|
|
1237
|
-
|
|
1238
|
-
// default rotate at 1s across 5 buckets
|
|
1239
|
-
let { td: rotate_td=1000, n: rotate_n=5 } =
|
|
1240
|
-
opt && opt.rotate || {};
|
|
1241
|
-
|
|
1242
|
-
let rotate_ts = rotate_td + Date.now();
|
|
1243
|
-
|
|
1244
|
-
return [on_mqtt,
|
|
1245
|
-
_disp_.bind_pkt_future()]
|
|
1246
|
-
|
|
1247
1165
|
function on_mqtt(pkt_list, ctx) {
|
|
1248
1166
|
for (let pkt of pkt_list) {
|
|
1249
|
-
|
|
1167
|
+
_mqtt_cmdids[pkt.id](target, answer, pkt, ctx);}
|
|
1250
1168
|
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1169
|
+
// rotate after rotate_ts
|
|
1170
|
+
let now = Date.now();
|
|
1171
|
+
if (now > rotate_ts) {
|
|
1172
|
+
rotate_ts = rotate_td + now;
|
|
1173
|
+
hashbelt.unshift(new Map());
|
|
1174
|
+
while (hashbelt.length > rotate_n) {
|
|
1175
|
+
for (let fn_answer of hashbelt.pop().values()) {
|
|
1176
|
+
fn_answer([/*pkt*/, 'expired']); } } } } }// option/maybe monad
|
|
1254
1177
|
|
|
1255
1178
|
class MQTTError extends Error {
|
|
1256
1179
|
constructor(mqtt_pkt, reason=mqtt_pkt.reason) {
|
|
1180
|
+
// use hex-encoded reasons to match MQTT spec documentation
|
|
1257
1181
|
super(`[0x${reason.toString(16)}] ${reason.reason}`);
|
|
1258
1182
|
this.mqtt_pkt = mqtt_pkt;
|
|
1259
1183
|
this.reason = reason;} }
|
|
1260
1184
|
|
|
1261
1185
|
class MQTTBase {
|
|
1262
|
-
constructor(opt={}) {
|
|
1263
|
-
this.with(opt);
|
|
1264
|
-
this._conn_ = _mqtt_conn(this,
|
|
1265
|
-
this._init_dispatch(opt, this)); }
|
|
1266
|
-
|
|
1267
|
-
with(fns_ns) {
|
|
1268
|
-
for (let [k,v] of Object.entries(fns_ns)) {
|
|
1269
|
-
if ('function' === typeof v) {this[k] = v;} }
|
|
1270
|
-
return this}
|
|
1271
|
-
|
|
1272
|
-
async conn_emit(evt, arg, err_arg) {
|
|
1273
|
-
this.log_conn?.(evt, arg, err_arg);
|
|
1274
|
-
try {
|
|
1275
|
-
let fn_evt = this[await evt]; // microtask break using `await evt`
|
|
1276
|
-
if (fn_evt) {
|
|
1277
|
-
await fn_evt.call(this, this, arg, err_arg);}
|
|
1278
|
-
else if (err_arg) {throw err_arg} }
|
|
1279
|
-
catch (err) {
|
|
1280
|
-
this.on_error(err, evt);} }
|
|
1281
|
-
|
|
1282
|
-
on_error(err, evt) {
|
|
1283
|
-
console.warn('[[u8-mqtt error: %s]]', evt, err); }
|
|
1284
|
-
|
|
1285
1186
|
// Handshaking Packets
|
|
1286
|
-
|
|
1287
1187
|
async connect(pkt={}) {
|
|
1288
|
-
let cid = pkt.client_id
|
|
1289
|
-
if (
|
|
1188
|
+
let cid = pkt.client_id;
|
|
1189
|
+
if (! _isstr(cid)) {
|
|
1290
1190
|
// see init_client_id implementation in core.jsy
|
|
1291
|
-
pkt.client_id = cid = this.init_client_id(cid);}
|
|
1191
|
+
pkt.client_id = cid = this.client_id || this.init_client_id(cid);}
|
|
1292
1192
|
this.client_id = cid;
|
|
1293
1193
|
|
|
1294
1194
|
if (null == pkt.keep_alive) {
|
|
1295
1195
|
pkt.keep_alive = 60;}
|
|
1296
1196
|
|
|
1297
|
-
let
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
throw new this.MQTTError(res[0])}
|
|
1302
|
-
|
|
1303
|
-
// TODO: merge with server's keep_alive frequency
|
|
1304
|
-
this._conn_.ping(pkt.keep_alive);
|
|
1305
|
-
return res}
|
|
1197
|
+
let response = await this._send0('connect', pkt, 'connack');
|
|
1198
|
+
if (0 != response[0].reason) {// compare to 0 to coerce to number
|
|
1199
|
+
throw new this.MQTTError(response[0])}
|
|
1200
|
+
return this.conn.on_conn(pkt, response)}
|
|
1306
1201
|
|
|
1307
1202
|
async disconnect(pkt={}) {
|
|
1308
|
-
let
|
|
1309
|
-
this.
|
|
1310
|
-
return res}
|
|
1203
|
+
let response = await this._send0('disconnect', pkt);
|
|
1204
|
+
return this.conn.on_dis(pkt, response)}
|
|
1311
1205
|
|
|
1312
|
-
auth(pkt={}) {
|
|
1313
|
-
|
|
1206
|
+
async auth(pkt={}) {
|
|
1207
|
+
let response = await this._send0('auth', pkt, 'auth');
|
|
1208
|
+
if (response[0].reason) {
|
|
1209
|
+
throw new this.MQTTError(response[0])}
|
|
1210
|
+
return this.conn.on_auth(pkt, response)}
|
|
1314
1211
|
|
|
1315
1212
|
ping() {return this._send('pingreq', null, 'pingresp')}
|
|
1316
1213
|
puback({pkt_id}) {return this._send('puback', {pkt_id})}
|
|
@@ -1347,20 +1244,18 @@ class MQTTBase {
|
|
|
1347
1244
|
// alias: publish -- because 'pub' is shorter for semantic aliases above
|
|
1348
1245
|
async pub(pkt, pub_opt) {
|
|
1349
1246
|
if (undefined === pkt.payload) {
|
|
1350
|
-
if (
|
|
1247
|
+
if (_isfn(pub_opt)) {
|
|
1248
|
+
// pub_opt as a function is fn_encode value
|
|
1351
1249
|
pub_opt = {fn_encode: pub_opt};}
|
|
1352
1250
|
|
|
1353
|
-
let
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
// return a single-value closure to publish packets
|
|
1360
|
-
return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)}
|
|
1251
|
+
let msg = pkt.msg, fn_encode = pub_opt?.fn_encode;
|
|
1252
|
+
if (null == msg || _isfn(msg)) {
|
|
1253
|
+
// when msg is a function, return closure using fn_encode
|
|
1254
|
+
if (msg) {pub_opt = {...pub_opt, fn_encode: msg};}
|
|
1255
|
+
// return a single-value closure to publish packets
|
|
1256
|
+
return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)}
|
|
1361
1257
|
|
|
1362
1258
|
// Encode payload from msg; fn_encode allows alternative to JSON.stringify
|
|
1363
|
-
let {fn_encode} = pub_opt || {};
|
|
1364
1259
|
pkt.payload = fn_encode
|
|
1365
1260
|
? await fn_encode(msg)
|
|
1366
1261
|
: JSON.stringify(msg);}
|
|
@@ -1372,31 +1267,31 @@ class MQTTBase {
|
|
|
1372
1267
|
pkt = pub_opt.xform(pkt) || pkt;} }
|
|
1373
1268
|
|
|
1374
1269
|
return this._send('publish', pkt,
|
|
1375
|
-
pkt.qos ? pkt :
|
|
1270
|
+
pkt.qos ? pkt : null ) }// key
|
|
1376
1271
|
|
|
1377
1272
|
|
|
1378
1273
|
// Internal API
|
|
1379
1274
|
|
|
1380
|
-
/* async
|
|
1275
|
+
/* async _send0(type, pkt) -- provided by conn and transport */
|
|
1276
|
+
/* async _send(type, pkt) -- provided by conn and transport */
|
|
1381
1277
|
|
|
1382
1278
|
_init_dispatch(opt) {
|
|
1383
1279
|
this.constructor?._once_();
|
|
1384
1280
|
let target ={__proto__: opt.on_mqtt_type};
|
|
1385
1281
|
target.mqtt_publish ||=
|
|
1386
1282
|
this._init_router?.(opt, this, target);
|
|
1387
|
-
return _mqtt_dispatch(
|
|
1283
|
+
return _mqtt_dispatch(opt, target)}
|
|
1388
1284
|
|
|
1389
1285
|
static _aliases() {
|
|
1390
1286
|
return ' publish:pub sub:subscribe unsub:unsubscribe json_post:obj_post json_send:obj_send json_store:obj_store'}
|
|
1391
1287
|
|
|
1392
|
-
static _once_(
|
|
1393
|
-
|
|
1394
|
-
|
|
1288
|
+
static _once_(klass=this) {
|
|
1289
|
+
klass._once_ = _=>0;
|
|
1290
|
+
var alias, name, p = klass.prototype;
|
|
1395
1291
|
p.MQTTError = MQTTError;
|
|
1396
|
-
for (
|
|
1397
|
-
alias = alias.split(':');
|
|
1398
|
-
|
|
1399
|
-
if (fn) {p[alias[0]] = fn;} } } }
|
|
1292
|
+
for (alias of klass._aliases().split(/\s+/)) {
|
|
1293
|
+
[alias, name] = alias.split(':');
|
|
1294
|
+
p[alias] = p[name];} } }
|
|
1400
1295
|
|
|
1401
1296
|
|
|
1402
1297
|
function _as_topics(pkt, ex, topic_prefix) {
|
|
@@ -1421,43 +1316,177 @@ function _as_topics(pkt, ex, topic_prefix) {
|
|
|
1421
1316
|
pkt.topics = pkt.topics.map(_prefix_topics);}
|
|
1422
1317
|
return pkt}
|
|
1423
1318
|
|
|
1424
|
-
const
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1319
|
+
const _defer_obj = o =>(
|
|
1320
|
+
o.p = new Promise((a,e) => { o.a=a; o.e=e; })
|
|
1321
|
+
, o);
|
|
1322
|
+
|
|
1323
|
+
function _dfn_reset(client, attr, fn_after) {
|
|
1324
|
+
// a resetable deferred for a function
|
|
1325
|
+
let self = {set}, afn = async (...args) => (await self.p)(...args);
|
|
1326
|
+
return set()
|
|
1327
|
+
|
|
1328
|
+
function set() {
|
|
1329
|
+
if (afn !== client[attr]) {
|
|
1330
|
+
_defer_obj(self).p.then(fn_after, _=>0);
|
|
1331
|
+
client[attr] = afn;}
|
|
1332
|
+
return self} }
|
|
1333
|
+
|
|
1334
|
+
function _mqtt_conn(opt, client, [on_mqtt, pkt_future]) {
|
|
1335
|
+
let _abort;
|
|
1336
|
+
let _dfn_send0 = _dfn_reset(client, '_send0', // client._send0 getter/setter
|
|
1337
|
+
_=> client.conn_emit('on_live', conn.has_connected));
|
|
1338
|
+
let _dfn_ready = _dfn_reset(client, '_send', // client._send getter/setter
|
|
1339
|
+
_=> client.conn_emit('on_ready'));
|
|
1340
|
+
let _keep_alive_ival = _interval (() =>client._send0('pingreq') );// resettable interval for keep_alive ping
|
|
1341
|
+
|
|
1342
|
+
let conn = Object.create({
|
|
1343
|
+
ping: (td=conn.keep_alive) => _keep_alive_ival(td)
|
|
1344
|
+
|
|
1345
|
+
, on_conn(pkt, response) {
|
|
1346
|
+
conn.has_connected = true;
|
|
1347
|
+
conn.keep_alive = opt.keep_alive || response[0].props?.server_keep_alive || pkt.keep_alive;
|
|
1348
|
+
client.conn_emit('on_conn');
|
|
1349
|
+
return opt.use_auth
|
|
1350
|
+
? response // wait on enhanced authentication step
|
|
1351
|
+
: conn.on_auth(null, response) }// otherwise, connect is also auth
|
|
1352
|
+
|
|
1353
|
+
, on_auth(pkt, response) {
|
|
1354
|
+
_dfn_ready.a(_dfn_send0.p);
|
|
1355
|
+
if (0 != opt.keep_alive) {
|
|
1356
|
+
conn.ping();}
|
|
1357
|
+
client.conn_emit('on_auth', !pkt);
|
|
1358
|
+
return response}
|
|
1359
|
+
|
|
1360
|
+
, on_dis(pkt, response) {
|
|
1361
|
+
conn.reset(false);
|
|
1362
|
+
return response}
|
|
1363
|
+
|
|
1364
|
+
, reset(err) {
|
|
1365
|
+
if (err) {
|
|
1366
|
+
_dfn_send0.e(err); }// send error to uses of _send0 (connect, auth)
|
|
1367
|
+
_abort.e(err); // abort in-progress connections
|
|
1368
|
+
|
|
1369
|
+
delete conn.is_set;
|
|
1370
|
+
conn.ready = handshake();
|
|
1371
|
+
client.conn_emit('on_disconnect', false===err, err);}
|
|
1372
|
+
|
|
1373
|
+
, abort() {
|
|
1374
|
+
_dfn_ready.e(err); // abort all messages awaiting ready state
|
|
1375
|
+
return conn.reset(err)}
|
|
1376
|
+
|
|
1377
|
+
, async setup(gate, send_u8_pkt, init_msg_loop) {
|
|
1378
|
+
if (conn.is_set) {
|
|
1379
|
+
throw new Error() }// already in-progress
|
|
1380
|
+
|
|
1381
|
+
conn.is_set = true;
|
|
1382
|
+
await gate;
|
|
1383
|
+
|
|
1384
|
+
// setup send/recv MQTT parsing context
|
|
1385
|
+
let mqtt_ctx = client.mqtt_ctx.mqtt_stream();
|
|
1386
|
+
|
|
1387
|
+
{// setup inbound message loop
|
|
1388
|
+
let sess_ctx = {mqtt: client}; // mutable session context
|
|
1389
|
+
let on_mqtt_chunk = u8 => on_mqtt(mqtt_ctx.decode(u8), sess_ctx);
|
|
1390
|
+
init_msg_loop(on_mqtt_chunk, conn);}
|
|
1391
|
+
|
|
1392
|
+
// setup outbound message path and transport connection
|
|
1393
|
+
send_u8_pkt = await send_u8_pkt;
|
|
1394
|
+
_dfn_send0.a(
|
|
1395
|
+
async (type, pkt, key) => {
|
|
1396
|
+
let res = undefined !== key
|
|
1397
|
+
? pkt_future(key) : true;
|
|
1398
|
+
|
|
1399
|
+
await send_u8_pkt(
|
|
1400
|
+
mqtt_ctx.encode_pkt(type, pkt));
|
|
1401
|
+
return res} ); } });
|
|
1402
|
+
|
|
1403
|
+
conn.ready = handshake();
|
|
1404
|
+
return conn
|
|
1405
|
+
|
|
1406
|
+
async function handshake() {
|
|
1407
|
+
_abort = _defer_obj({});
|
|
1408
|
+
|
|
1409
|
+
_keep_alive_ival(0); // clearInterval on keep alive ping
|
|
1410
|
+
_dfn_send0.set(); // reset client._send0 if necessary
|
|
1411
|
+
_dfn_ready.set(); // reset client._send if necessary
|
|
1412
|
+
|
|
1413
|
+
try {
|
|
1414
|
+
// set client._send0 as passtrhough after transport connection
|
|
1415
|
+
client._send0 = await Promise.race([_dfn_send0.p, _abort.p]);
|
|
1416
|
+
|
|
1417
|
+
// set client._send as passtrhough after ready
|
|
1418
|
+
client._send = await Promise.race([_dfn_ready.p, _abort.p]);
|
|
1419
|
+
return true}
|
|
1420
|
+
catch (err) {
|
|
1421
|
+
return false} } }
|
|
1422
|
+
|
|
1423
|
+
const pkt_api ={
|
|
1424
|
+
utf8(u8) {return new TextDecoder('utf-8').decode(u8 || this.payload )}
|
|
1425
|
+
, json(u8) {return JSON.parse( this.utf8(u8) || null )}
|
|
1426
|
+
, text(u8) {return this.utf8(u8)} };
|
|
1427
|
+
|
|
1428
|
+
const opt_default ={
|
|
1429
|
+
sess_stg: globalThis.sessionStorage};
|
|
1429
1430
|
|
|
1430
1431
|
class MQTTCore extends MQTTBase {
|
|
1432
|
+
constructor(opt) {
|
|
1433
|
+
super();
|
|
1434
|
+
this.with(opt);
|
|
1435
|
+
opt ={...opt_default, ...opt};
|
|
1436
|
+
// settings for MQTTCore
|
|
1437
|
+
this.sess_stg = opt.sess_stg;
|
|
1438
|
+
// setup connection and dispatch
|
|
1439
|
+
this.conn = _mqtt_conn(opt, this,
|
|
1440
|
+
this._init_dispatch(opt)); }
|
|
1441
|
+
|
|
1442
|
+
with(fns_ns) {
|
|
1443
|
+
for (let [k,v] of Object.entries(fns_ns)) {
|
|
1444
|
+
if (_isfn(v)) {this[k] = v;} }
|
|
1445
|
+
return this}
|
|
1446
|
+
|
|
1447
|
+
|
|
1431
1448
|
static mqtt_ctx(mqtt_level, mqtt_opts, pkt_ctx=pkt_api) {
|
|
1432
|
-
let
|
|
1433
|
-
|
|
1449
|
+
let klass = class extends this {};
|
|
1450
|
+
klass.prototype.mqtt_ctx =
|
|
1434
1451
|
mqtt_pkt_ctx(mqtt_level, mqtt_opts, pkt_ctx);
|
|
1435
|
-
return
|
|
1452
|
+
return klass}
|
|
1453
|
+
|
|
1454
|
+
|
|
1455
|
+
async conn_emit(evt, arg, err_arg) {
|
|
1456
|
+
this.log_conn?.(evt, arg, err_arg);
|
|
1457
|
+
try {
|
|
1458
|
+
let fn_evt = this[await evt]; // microtask break using `await evt`
|
|
1459
|
+
if (fn_evt) {
|
|
1460
|
+
await fn_evt.call(this, this, arg, err_arg);}
|
|
1461
|
+
else if (err_arg) {throw err_arg} }
|
|
1462
|
+
catch (err) {
|
|
1463
|
+
this.on_error(err, evt);} }
|
|
1464
|
+
|
|
1465
|
+
on_error(err, evt) {
|
|
1466
|
+
console.warn('[[u8-mqtt error: %s]]', evt, err); }
|
|
1467
|
+
log_conn(evt, arg, err_arg) {
|
|
1468
|
+
console.info('[[u8-mqtt conn: %s]]', evt, arg, err_arg); }
|
|
1436
1469
|
|
|
1437
1470
|
|
|
1438
1471
|
// automatic Client Id for connect()
|
|
1439
1472
|
init_client_id(parts=['u8-mqtt--','']) {
|
|
1440
|
-
let sess_stg=this.sess_stg;
|
|
1473
|
+
let sess_stg = this.sess_stg;
|
|
1441
1474
|
let key, cid = sess_stg?.getItem(key=parts.join(' '));
|
|
1442
1475
|
if (! cid) {
|
|
1443
1476
|
cid = parts.join(Math.random().toString(36).slice(2));
|
|
1444
1477
|
sess_stg?.setItem(key, cid);}
|
|
1445
1478
|
return cid}
|
|
1446
1479
|
|
|
1447
|
-
get sess_stg() {return globalThis.sessionStorage}
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
//on_error(err, evt) ::
|
|
1451
|
-
// console.warn @ '[[u8-mqtt error: %s]]', evt, err
|
|
1452
|
-
|
|
1453
|
-
//log_conn(evt, arg, err_arg) ::
|
|
1454
|
-
// console.info @ '[[u8-mqtt log: %s]]', evt, arg, err_arg
|
|
1455
1480
|
|
|
1456
1481
|
on_live(client, is_reconnect) {
|
|
1457
1482
|
if (is_reconnect) {
|
|
1458
1483
|
return client.connect()} }
|
|
1459
1484
|
|
|
1460
|
-
//
|
|
1485
|
+
// on_ready(client) ::
|
|
1486
|
+
// on_reconnect(client) ::
|
|
1487
|
+
on_disconnect(client, intentional) {
|
|
1488
|
+
if (! intentional) {
|
|
1489
|
+
return client.on_reconnect?.()} }
|
|
1461
1490
|
|
|
1462
1491
|
_use_conn(fn_reconnect) {
|
|
1463
1492
|
return (this.reconnect = fn_reconnect)?.()}
|
|
@@ -1469,27 +1498,20 @@ class MQTTCore extends MQTTBase {
|
|
|
1469
1498
|
.then(this.reconnect)
|
|
1470
1499
|
.then(opt.reconnect, opt.error);} }) }
|
|
1471
1500
|
|
|
1472
|
-
on_disconnect(client, intentional) {
|
|
1473
|
-
if (! intentional) {
|
|
1474
|
-
return client.on_reconnect?.()} }
|
|
1475
|
-
|
|
1476
1501
|
delay(ms) {
|
|
1477
1502
|
return new Promise(done => setTimeout(done, ms)) }
|
|
1478
1503
|
|
|
1479
1504
|
with_async_iter(async_iter, write_u8_pkt) {
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
catch (err) {
|
|
1491
|
-
this._conn_.reset(err);} })());
|
|
1492
|
-
|
|
1505
|
+
this.conn.setup(async_iter,
|
|
1506
|
+
write_u8_pkt,
|
|
1507
|
+
async (on_mqtt_chunk, conn) => {
|
|
1508
|
+
try {
|
|
1509
|
+
async_iter = await async_iter;
|
|
1510
|
+
for await (let chunk of async_iter)
|
|
1511
|
+
on_mqtt_chunk(chunk);
|
|
1512
|
+
conn.reset();}
|
|
1513
|
+
catch (err) {
|
|
1514
|
+
conn.reset(err);} } );
|
|
1493
1515
|
return this}
|
|
1494
1516
|
|
|
1495
1517
|
|
|
@@ -1560,33 +1582,30 @@ class MQTTCore extends MQTTBase {
|
|
|
1560
1582
|
|
|
1561
1583
|
websock.binaryType = 'arraybuffer';
|
|
1562
1584
|
|
|
1563
|
-
let
|
|
1585
|
+
let ws_ready, readyState = websock.readyState;
|
|
1564
1586
|
if (1 !== readyState) {
|
|
1565
1587
|
if (0 !== readyState) {
|
|
1566
|
-
throw new Error('
|
|
1567
|
-
|
|
1568
|
-
ready = new Promise(fn => websock.onopen = fn); }
|
|
1588
|
+
throw new Error('WS readyState') }
|
|
1569
1589
|
|
|
1590
|
+
ws_ready = new Promise(ready => websock.onopen = ready); }
|
|
1570
1591
|
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
, websock.send(u8_pkt)) );
|
|
1592
|
+
this.conn.setup(ws_ready,
|
|
1593
|
+
u8_pkt => websock.send(u8_pkt),
|
|
1594
|
+
(on_mqtt_chunk, conn) => {
|
|
1595
|
+
websock.onmessage = evt =>(
|
|
1596
|
+
on_mqtt_chunk(new Uint8Array(evt.data)) );
|
|
1577
1597
|
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
err.reason = evt.reason;}
|
|
1598
|
+
websock.onclose = evt => {
|
|
1599
|
+
if (! evt.wasClean) {
|
|
1600
|
+
var err = new Error('websocket close');
|
|
1601
|
+
err.code = evt.code;
|
|
1602
|
+
err.reason = evt.reason;}
|
|
1584
1603
|
|
|
1585
|
-
|
|
1604
|
+
conn.reset(err);}; } );
|
|
1586
1605
|
|
|
1587
1606
|
return this} }
|
|
1588
1607
|
|
|
1589
|
-
const version = '0.
|
|
1608
|
+
const version = '0.6.0-node';
|
|
1590
1609
|
|
|
1591
1610
|
const MQTTClient_v4 = /* #__PURE__ */
|
|
1592
1611
|
with_topic_path_router(
|