u8-mqtt 0.3.2-0 → 0.4.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 +5 -5
- package/cjs/basic-v4.cjs +1205 -0
- package/cjs/basic-v4.cjs.map +1 -0
- package/cjs/basic-v5.cjs +1469 -0
- package/cjs/basic-v5.cjs.map +1 -0
- package/cjs/index.cjs +308 -267
- package/cjs/index.cjs.map +1 -1
- package/cjs/v4.cjs +303 -262
- package/cjs/v4.cjs.map +1 -1
- package/cjs/v5.cjs +305 -263
- package/cjs/v5.cjs.map +1 -1
- package/code/_cmdid_dispatch.jsy +1 -3
- package/code/base.jsy +64 -84
- package/code/basic-v4.js +18 -0
- package/code/basic-v5.js +26 -0
- package/code/index.js +2 -1
- package/code/{_router.jsy → router_path.jsy} +30 -12
- package/code/v4.js +3 -1
- package/code/v5.js +5 -2
- package/code/with_topic_router.jsy +41 -0
- package/esm/deno/basic-v4.js +1193 -0
- package/esm/deno/basic-v4.js.map +1 -0
- package/esm/deno/basic-v5.js +1455 -0
- package/esm/deno/basic-v5.js.map +1 -0
- package/esm/deno/index.js +306 -264
- package/esm/deno/index.js.map +1 -1
- package/esm/deno/v4.js +303 -262
- package/esm/deno/v4.js.map +1 -1
- package/esm/deno/v5.js +305 -263
- package/esm/deno/v5.js.map +1 -1
- package/esm/node/basic-v4.js +1196 -0
- package/esm/node/basic-v4.js.map +1 -0
- package/esm/node/basic-v4.mjs +1196 -0
- package/esm/node/basic-v4.mjs.map +1 -0
- package/esm/node/basic-v5.js +1458 -0
- package/esm/node/basic-v5.js.map +1 -0
- package/esm/node/basic-v5.mjs +1458 -0
- package/esm/node/basic-v5.mjs.map +1 -0
- package/esm/node/index.js +306 -264
- package/esm/node/index.js.map +1 -1
- package/esm/node/index.mjs +306 -264
- package/esm/node/index.mjs.map +1 -1
- package/esm/node/v4.js +303 -262
- package/esm/node/v4.js.map +1 -1
- package/esm/node/v4.mjs +303 -262
- package/esm/node/v4.mjs.map +1 -1
- package/esm/node/v5.js +305 -263
- package/esm/node/v5.js.map +1 -1
- package/esm/node/v5.mjs +305 -263
- package/esm/node/v5.mjs.map +1 -1
- package/esm/web/basic-v4.js +1193 -0
- package/esm/web/basic-v4.js.map +1 -0
- package/esm/web/basic-v4.min.js +1 -0
- 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 +1455 -0
- package/esm/web/basic-v5.js.map +1 -0
- package/esm/web/basic-v5.min.js +1 -0
- package/esm/web/basic-v5.min.js.br +0 -0
- package/esm/web/basic-v5.min.js.gz +0 -0
- package/esm/web/index.js +305 -263
- 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 +303 -262
- 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 +304 -262
- 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 +5 -5
|
@@ -0,0 +1,1196 @@
|
|
|
1
|
+
import { connect } from 'node:net';
|
|
2
|
+
import { connect as connect$1 } from 'node:tls';
|
|
3
|
+
|
|
4
|
+
function encode_varint(n, a=[]) {
|
|
5
|
+
do {
|
|
6
|
+
const ni = n & 0x7f;
|
|
7
|
+
n >>>= 7;
|
|
8
|
+
a.push( ni | (0===n ? 0 : 0x80) );
|
|
9
|
+
} while (n > 0)
|
|
10
|
+
return a
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
export function decode_varint_loop(u8, i=0) {
|
|
16
|
+
let i0 = i
|
|
17
|
+
let shift = 0, n = (u8[i] & 0x7f)
|
|
18
|
+
while ( 0x80 & u8[i++] )
|
|
19
|
+
n |= (u8[i] & 0x7f) << (shift += 7)
|
|
20
|
+
|
|
21
|
+
return [n, i, i0]
|
|
22
|
+
}
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
function decode_varint$1(u8, i=0) {
|
|
27
|
+
let i0 = i;
|
|
28
|
+
// unrolled for a max of 4 chains
|
|
29
|
+
let n = (u8[i] & 0x7f) << 0;
|
|
30
|
+
if ( 0x80 & u8[i++] ) {
|
|
31
|
+
n |= (u8[i] & 0x7f) << 7;
|
|
32
|
+
if ( 0x80 & u8[i++] ) {
|
|
33
|
+
n |= (u8[i] & 0x7f) << 14;
|
|
34
|
+
if ( 0x80 & u8[i++] ) {
|
|
35
|
+
n |= (u8[i] & 0x7f) << 21;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return [n, i, i0]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
class U8_Reason extends Number {
|
|
43
|
+
static of(v, pkt_kind, by_kind) {
|
|
44
|
+
let self = new this(v);
|
|
45
|
+
self.reason = by_kind?.[pkt_kind]?.get(v) || pkt_kind;
|
|
46
|
+
return self
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
class mqtt_reader_v4$1 {
|
|
51
|
+
static of(buf) { return this.prototype.of(buf) }
|
|
52
|
+
of(buf) {
|
|
53
|
+
let step = (width, k) => (k=0|step.k, step.k=k+width, k);
|
|
54
|
+
return {__proto__: this, buf, step}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
has_more() {
|
|
58
|
+
return this.buf.byteLength > (this.step.k|0)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
u8() {
|
|
62
|
+
return this.buf[this.step(1)]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
u16() {
|
|
66
|
+
let {buf, step} = this, i = step(2);
|
|
67
|
+
return (buf[i]<<8) | buf[i+1]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
u32() {
|
|
71
|
+
let {buf, step} = this, i = step(4);
|
|
72
|
+
return (buf[i]<<24) | (buf[i+1]<<16) | (buf[i+2]<<8) | buf[i+3]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
vint() {
|
|
76
|
+
let {buf, step} = this;
|
|
77
|
+
let [n, vi, vi0] = decode_varint$1(buf, step.k|0);
|
|
78
|
+
step(vi - vi0);
|
|
79
|
+
return n
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
bin() {
|
|
83
|
+
let {buf, step} = this, i = step(2);
|
|
84
|
+
let len = (buf[i]<<8) | buf[i+1];
|
|
85
|
+
i = step(len);
|
|
86
|
+
return buf.subarray(i, i+len)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
utf8() { return new TextDecoder('utf-8').decode(this.bin()) }
|
|
90
|
+
pair() { return [ this.utf8(), this.utf8() ] }
|
|
91
|
+
|
|
92
|
+
flags(FlagsType) { return new FlagsType(this.buf[this.step(1)]) }
|
|
93
|
+
|
|
94
|
+
reason(pkt_kind) {
|
|
95
|
+
let v = this.buf[this.step(1)];
|
|
96
|
+
if (null != v)
|
|
97
|
+
return U8_Reason.of(v, pkt_kind, this._reasons_by)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
flush() {
|
|
101
|
+
let {buf, step} = this;
|
|
102
|
+
this.step = this.buf = null;
|
|
103
|
+
return buf.subarray(step.k|0)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function mqtt_reader_info(mqtt_reader, ... info_fn_list) {
|
|
109
|
+
mqtt_reader = class extends mqtt_reader {
|
|
110
|
+
static reasons(pkt_type, ...reason_entries) {
|
|
111
|
+
let proto = this.prototype;
|
|
112
|
+
proto._reasons_by = {... proto._reasons_by};
|
|
113
|
+
|
|
114
|
+
let lut = (proto._reasons_by[pkt_type] ||= new Map());
|
|
115
|
+
for (let [u8, reason] of reason_entries)
|
|
116
|
+
lut.set( u8, reason );
|
|
117
|
+
|
|
118
|
+
return this
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
for (let fn_info of info_fn_list)
|
|
123
|
+
fn_info(mqtt_reader);
|
|
124
|
+
|
|
125
|
+
return mqtt_reader
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
class mqtt_writer_v4 {
|
|
129
|
+
static of() { return this.prototype.of() }
|
|
130
|
+
of() { return {__proto__: this, $:[]} }
|
|
131
|
+
|
|
132
|
+
static init() { return this }
|
|
133
|
+
|
|
134
|
+
as_pkt(pkt_id) { return this.pack([pkt_id]) }
|
|
135
|
+
|
|
136
|
+
push(...z) { this.$.push(...z); }
|
|
137
|
+
pack(hdr) {
|
|
138
|
+
let z, i, n=0, parts = this.$;
|
|
139
|
+
this.$ = false;
|
|
140
|
+
for (z of parts) n += z.length;
|
|
141
|
+
|
|
142
|
+
hdr = encode_varint(n, hdr);
|
|
143
|
+
i = hdr.length;
|
|
144
|
+
|
|
145
|
+
let pkt = new Uint8Array(i + n);
|
|
146
|
+
pkt.set(hdr, 0);
|
|
147
|
+
for (z of parts) {
|
|
148
|
+
pkt.set(z, i);
|
|
149
|
+
i += z.length;
|
|
150
|
+
}
|
|
151
|
+
return pkt
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
u8(v) { this.push([ v & 0xff ]); }
|
|
155
|
+
u16(v) { this.push([ (v>>>8) & 0xff, v & 0xff ]); }
|
|
156
|
+
u32(v) { this.push([ (v>>>24) & 0xff, (v>>>16) & 0xff, (v>>>8) & 0xff, v & 0xff ]); }
|
|
157
|
+
vint(v) { this.push( encode_varint(v) );}
|
|
158
|
+
|
|
159
|
+
bin(u8_buf) {
|
|
160
|
+
if (! u8_buf) return this.u16(0)
|
|
161
|
+
if ('string' === typeof u8_buf)
|
|
162
|
+
return this.utf8(u8_buf)
|
|
163
|
+
|
|
164
|
+
if (u8_buf.length !== u8_buf.byteLength)
|
|
165
|
+
u8_buf = new Uint8Array(u8_buf);
|
|
166
|
+
|
|
167
|
+
this.u16(u8_buf.byteLength);
|
|
168
|
+
this.push(u8_buf);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
utf8(v) {
|
|
172
|
+
let u8_buf = new TextEncoder('utf-8').encode(v);
|
|
173
|
+
this.u16(u8_buf.byteLength);
|
|
174
|
+
this.push(u8_buf);
|
|
175
|
+
}
|
|
176
|
+
pair(k,v) { this.utf8(k); this.utf8(v); }
|
|
177
|
+
|
|
178
|
+
flags(v, enc_flags, b0=0) {
|
|
179
|
+
if (undefined !== v && isNaN(+v))
|
|
180
|
+
v = enc_flags(v, 0);
|
|
181
|
+
|
|
182
|
+
v |= b0;
|
|
183
|
+
this.push([v]);
|
|
184
|
+
return v
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
reason(v) { this.push([v | 0]); }
|
|
188
|
+
|
|
189
|
+
flush(buf) {
|
|
190
|
+
if (null != buf)
|
|
191
|
+
this.push(
|
|
192
|
+
'string' === typeof buf
|
|
193
|
+
? new TextEncoder('utf-8').encode(buf)
|
|
194
|
+
: buf );
|
|
195
|
+
|
|
196
|
+
this.push = false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function mqtt_decode_connack(ns, mqtt_reader) {
|
|
201
|
+
class _connack_flags_ extends Number {
|
|
202
|
+
get session_present() { return this & 0x01 !== 0 }
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return ns[0x2] = (pkt, u8_body) => {
|
|
206
|
+
let rdr = mqtt_reader.of(u8_body);
|
|
207
|
+
|
|
208
|
+
pkt.flags =
|
|
209
|
+
rdr.flags(_connack_flags_);
|
|
210
|
+
|
|
211
|
+
pkt.reason = rdr.reason(pkt.type);
|
|
212
|
+
if (5 <= pkt.mqtt_level)
|
|
213
|
+
pkt.props = rdr.props();
|
|
214
|
+
return pkt }
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
function _connack_v4(mqtt_reader) {
|
|
219
|
+
mqtt_reader.reasons('connack',
|
|
220
|
+
// MQTT 3.1.1
|
|
221
|
+
[ 0x00, 'Success'],
|
|
222
|
+
[ 0x01, 'Connection refused, unacceptable protocol version'],
|
|
223
|
+
[ 0x02, 'Connection refused, identifier rejected'],
|
|
224
|
+
[ 0x03, 'Connection refused, server unavailable'],
|
|
225
|
+
[ 0x04, 'Connection refused, bad user name or password'],
|
|
226
|
+
[ 0x05, 'Connection refused, not authorized'],
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function mqtt_decode_publish(ns, mqtt_reader) {
|
|
231
|
+
return ns[0x3] = (pkt, u8_body) => {
|
|
232
|
+
let {hdr} = pkt;
|
|
233
|
+
pkt.dup = Boolean(hdr & 0x8);
|
|
234
|
+
pkt.retain = Boolean(hdr & 0x1);
|
|
235
|
+
let qos = pkt.qos = (hdr>>1) & 0x3;
|
|
236
|
+
|
|
237
|
+
let rdr = mqtt_reader.of(u8_body);
|
|
238
|
+
pkt.topic = rdr.utf8();
|
|
239
|
+
if (0 !== qos)
|
|
240
|
+
pkt.pkt_id = rdr.u16();
|
|
241
|
+
|
|
242
|
+
if (5 <= pkt.mqtt_level)
|
|
243
|
+
pkt.props = rdr.props();
|
|
244
|
+
|
|
245
|
+
pkt.payload = rdr.flush();
|
|
246
|
+
return pkt }
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function mqtt_decode_puback(ns, mqtt_reader) {
|
|
250
|
+
return ns[0x4] = (pkt, u8_body) => {
|
|
251
|
+
let rdr = mqtt_reader.of(u8_body);
|
|
252
|
+
|
|
253
|
+
pkt.pkt_id = rdr.u16();
|
|
254
|
+
if (5 <= pkt.mqtt_level) {
|
|
255
|
+
pkt.reason = rdr.reason(pkt.type);
|
|
256
|
+
pkt.props = rdr.props();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return pkt }
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function _mqtt_decode_suback(mqtt_reader) {
|
|
263
|
+
return (pkt, u8_body) => {
|
|
264
|
+
let rdr = mqtt_reader.of(u8_body);
|
|
265
|
+
|
|
266
|
+
pkt.pkt_id = rdr.u16();
|
|
267
|
+
if (5 <= pkt.mqtt_level)
|
|
268
|
+
pkt.props = rdr.props();
|
|
269
|
+
|
|
270
|
+
let answers = pkt.answers = [];
|
|
271
|
+
while (rdr.has_more())
|
|
272
|
+
answers.push(
|
|
273
|
+
rdr.reason(pkt.type) );
|
|
274
|
+
|
|
275
|
+
return pkt }
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function mqtt_decode_suback(ns, mqtt_reader) {
|
|
279
|
+
return ns[0x9] = _mqtt_decode_suback(mqtt_reader)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function _suback_v4(mqtt_reader) {
|
|
283
|
+
mqtt_reader.reasons('suback',
|
|
284
|
+
// MQTT 3.1.1
|
|
285
|
+
[ 0x00, 'Granted QoS 0'],
|
|
286
|
+
[ 0x01, 'Granted QoS 1'],
|
|
287
|
+
[ 0x02, 'Granted QoS 2'],
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function mqtt_decode_unsuback(ns, mqtt_reader) {
|
|
292
|
+
return ns[0xb] = _mqtt_decode_suback(mqtt_reader)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function _unsuback_v4(mqtt_reader) {
|
|
296
|
+
mqtt_reader.reasons('unsuback',
|
|
297
|
+
// MQTT 3.1.1
|
|
298
|
+
[ 0x00, 'Success'],
|
|
299
|
+
[ 0x11, 'No subscription existed'],
|
|
300
|
+
[ 0x80, 'Unspecified error'],
|
|
301
|
+
[ 0x83, 'Implementation specific error'],
|
|
302
|
+
[ 0x87, 'Not authorized'],
|
|
303
|
+
[ 0x8F, 'Topic Filter invalid'],
|
|
304
|
+
[ 0x91, 'Packet Identifier in use'],
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function mqtt_decode_pingxxx(ns) {
|
|
309
|
+
return ns[0xc] = ns[0xd] = pkt => pkt
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function mqtt_decode_disconnect(ns, mqtt_reader) {
|
|
313
|
+
return ns[0xe] = (pkt, u8_body) => {
|
|
314
|
+
if (u8_body && 5 <= pkt.mqtt_level) {
|
|
315
|
+
let rdr = mqtt_reader.of(u8_body);
|
|
316
|
+
pkt.reason = rdr.reason(pkt.type);
|
|
317
|
+
pkt.props = rdr.props();
|
|
318
|
+
}
|
|
319
|
+
return pkt }
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function mqtt_encode_connect(ns, mqtt_writer) {
|
|
323
|
+
const _c_mqtt_proto = new Uint8Array([
|
|
324
|
+
0, 4, 0x4d, 0x51, 0x54, 0x54 ]);
|
|
325
|
+
|
|
326
|
+
const _enc_flags_connect = flags => 0
|
|
327
|
+
| ( flags.reserved ? 0x01 : 0 )
|
|
328
|
+
| ( (flags.will_qos & 0x3) << 3 )
|
|
329
|
+
| ( flags.clean_start ? 0x02 : 0 )
|
|
330
|
+
| ( flags.will_flag ? 0x04 : 0 )
|
|
331
|
+
| ( flags.will_retain ? 0x20 : 0 )
|
|
332
|
+
| ( flags.password ? 0x40 : 0 )
|
|
333
|
+
| ( flags.username ? 0x80 : 0 );
|
|
334
|
+
|
|
335
|
+
const _enc_flags_will = will => 0x4
|
|
336
|
+
| ( (will.qos & 0x3) << 3 )
|
|
337
|
+
| ( will.retain ? 0x20 : 0 );
|
|
338
|
+
|
|
339
|
+
return ns.connect = ( mqtt_level, pkt ) => {
|
|
340
|
+
let wrt = mqtt_writer.of(pkt);
|
|
341
|
+
|
|
342
|
+
wrt.push(_c_mqtt_proto);
|
|
343
|
+
wrt.u8( mqtt_level );
|
|
344
|
+
|
|
345
|
+
let {will, username, password} = pkt;
|
|
346
|
+
let flags = wrt.flags(
|
|
347
|
+
pkt.flags,
|
|
348
|
+
_enc_flags_connect,
|
|
349
|
+
0 | (username ? 0x80 : 0)
|
|
350
|
+
| (password ? 0x40 : 0)
|
|
351
|
+
| (will ? _enc_flags_will(will) : 0) );
|
|
352
|
+
|
|
353
|
+
wrt.u16(pkt.keep_alive);
|
|
354
|
+
|
|
355
|
+
if (5 <= mqtt_level)
|
|
356
|
+
wrt.props(pkt.props);
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
wrt.utf8(pkt.client_id);
|
|
360
|
+
if (flags & 0x04) { // .will_flag
|
|
361
|
+
if (5 <= mqtt_level)
|
|
362
|
+
wrt.props(will.props);
|
|
363
|
+
|
|
364
|
+
wrt.utf8(will.topic);
|
|
365
|
+
wrt.bin(will.payload);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (flags & 0x80) // .username
|
|
369
|
+
wrt.utf8(username);
|
|
370
|
+
|
|
371
|
+
if (flags & 0x40) // .password
|
|
372
|
+
wrt.bin(password);
|
|
373
|
+
|
|
374
|
+
return wrt.as_pkt(0x10)
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function mqtt_encode_publish(ns, mqtt_writer) {
|
|
379
|
+
return ns.publish = ( mqtt_level, pkt ) => {
|
|
380
|
+
let qos = (pkt.qos & 0x3) << 1;
|
|
381
|
+
let wrt = mqtt_writer.of(pkt);
|
|
382
|
+
|
|
383
|
+
wrt.utf8(pkt.topic);
|
|
384
|
+
if (0 !== qos)
|
|
385
|
+
wrt.u16(pkt.pkt_id);
|
|
386
|
+
|
|
387
|
+
if ( 5 <= mqtt_level) {
|
|
388
|
+
wrt.props(pkt.props);
|
|
389
|
+
wrt.flush(pkt.payload);
|
|
390
|
+
} else {
|
|
391
|
+
wrt.flush(pkt.payload);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return wrt.as_pkt(
|
|
395
|
+
0x30 | qos | (pkt.dup ? 0x8 : 0) | (pkt.retain ? 0x1 : 0) )
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function mqtt_encode_puback(ns, mqtt_writer) {
|
|
400
|
+
return ns.puback = ( mqtt_level, pkt ) => {
|
|
401
|
+
let wrt = mqtt_writer.of(pkt);
|
|
402
|
+
|
|
403
|
+
wrt.u16(pkt.pkt_id);
|
|
404
|
+
if (5 <= mqtt_level) {
|
|
405
|
+
wrt.reason(pkt.reason);
|
|
406
|
+
wrt.props(pkt.props);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return wrt.as_pkt(0x40)
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function mqtt_encode_subscribe(ns, mqtt_writer) {
|
|
414
|
+
const _enc_subscribe_flags = opts => 0
|
|
415
|
+
| ( opts.qos & 0x3 )
|
|
416
|
+
| ( opts.retain ? 0x4 : 0 )
|
|
417
|
+
| ( (opts.retain_handling & 0x3) << 2 );
|
|
418
|
+
|
|
419
|
+
return ns.subscribe = ( mqtt_level, pkt ) => {
|
|
420
|
+
let wrt = mqtt_writer.of(pkt);
|
|
421
|
+
|
|
422
|
+
wrt.u16(pkt.pkt_id);
|
|
423
|
+
if (5 <= mqtt_level)
|
|
424
|
+
wrt.props(pkt.props);
|
|
425
|
+
|
|
426
|
+
let f0 = _enc_subscribe_flags(pkt);
|
|
427
|
+
for (let each of pkt.topics) {
|
|
428
|
+
if ('string' === typeof each) {
|
|
429
|
+
wrt.utf8(each);
|
|
430
|
+
wrt.u8(f0);
|
|
431
|
+
} else {
|
|
432
|
+
let [topic, opts] =
|
|
433
|
+
Array.isArray(each) ? each
|
|
434
|
+
: [each.topic, each.opts];
|
|
435
|
+
|
|
436
|
+
wrt.utf8(topic);
|
|
437
|
+
if (undefined === opts) wrt.u8(f0);
|
|
438
|
+
else wrt.flags(opts, _enc_subscribe_flags);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
return wrt.as_pkt(0x82)
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function mqtt_encode_unsubscribe(ns, mqtt_writer) {
|
|
447
|
+
return ns.unsubscribe = ( mqtt_level, pkt ) => {
|
|
448
|
+
let wrt = mqtt_writer.of(pkt);
|
|
449
|
+
|
|
450
|
+
wrt.u16(pkt.pkt_id);
|
|
451
|
+
if (5 <= mqtt_level)
|
|
452
|
+
wrt.props(pkt.props);
|
|
453
|
+
|
|
454
|
+
for (let topic of pkt.topics)
|
|
455
|
+
wrt.utf8(topic);
|
|
456
|
+
|
|
457
|
+
return wrt.as_pkt(0xa2)
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function mqtt_encode_pingxxx(ns) {
|
|
462
|
+
ns.pingreq = () => new Uint8Array([ 0xc0, 0 ]);
|
|
463
|
+
ns.pingresp = () => new Uint8Array([ 0xd0, 0 ]);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function mqtt_encode_disconnect(ns, mqtt_writer) {
|
|
467
|
+
return ns.disconnect = ( mqtt_level, pkt ) => {
|
|
468
|
+
let wrt = mqtt_writer.of(pkt);
|
|
469
|
+
|
|
470
|
+
if (pkt && 5 <= mqtt_level) {
|
|
471
|
+
if (pkt.reason || pkt.props) {
|
|
472
|
+
wrt.reason(pkt.reason);
|
|
473
|
+
wrt.props(pkt.props);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return wrt.as_pkt(0xe0)
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// not a v4 packet: import { mqtt_encode_auth } from './encode/auth.mjs'
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
const mqtt_decode_v4 = [
|
|
485
|
+
mqtt_decode_connack,
|
|
486
|
+
mqtt_decode_publish,
|
|
487
|
+
mqtt_decode_puback,
|
|
488
|
+
mqtt_decode_suback,
|
|
489
|
+
mqtt_decode_unsuback,
|
|
490
|
+
mqtt_decode_pingxxx,
|
|
491
|
+
mqtt_decode_disconnect,
|
|
492
|
+
];
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
const mqtt_encode_v4 = [
|
|
496
|
+
mqtt_encode_connect,
|
|
497
|
+
mqtt_encode_puback,
|
|
498
|
+
mqtt_encode_publish,
|
|
499
|
+
mqtt_encode_subscribe,
|
|
500
|
+
mqtt_encode_unsubscribe,
|
|
501
|
+
mqtt_encode_pingxxx,
|
|
502
|
+
mqtt_encode_disconnect,
|
|
503
|
+
];
|
|
504
|
+
|
|
505
|
+
const mqtt_reader_v4 = /* #__PURE__ */
|
|
506
|
+
mqtt_reader_info(
|
|
507
|
+
mqtt_reader_v4$1,
|
|
508
|
+
_connack_v4,
|
|
509
|
+
_suback_v4,
|
|
510
|
+
_unsuback_v4,
|
|
511
|
+
);
|
|
512
|
+
|
|
513
|
+
const mqtt_opts_v4 =
|
|
514
|
+
{ decode_fns: mqtt_decode_v4,
|
|
515
|
+
mqtt_reader: mqtt_reader_v4,
|
|
516
|
+
encode_fns: mqtt_encode_v4,
|
|
517
|
+
mqtt_writer: mqtt_writer_v4, };
|
|
518
|
+
|
|
519
|
+
/*
|
|
520
|
+
export function decode_varint_loop(u8, i=0) {
|
|
521
|
+
let i0 = i
|
|
522
|
+
let shift = 0, n = (u8[i] & 0x7f)
|
|
523
|
+
while ( 0x80 & u8[i++] )
|
|
524
|
+
n |= (u8[i] & 0x7f) << (shift += 7)
|
|
525
|
+
|
|
526
|
+
return [n, i, i0]
|
|
527
|
+
}
|
|
528
|
+
*/
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
function decode_varint(u8, i=0) {
|
|
532
|
+
let i0 = i;
|
|
533
|
+
// unrolled for a max of 4 chains
|
|
534
|
+
let n = (u8[i] & 0x7f) << 0;
|
|
535
|
+
if ( 0x80 & u8[i++] ) {
|
|
536
|
+
n |= (u8[i] & 0x7f) << 7;
|
|
537
|
+
if ( 0x80 & u8[i++] ) {
|
|
538
|
+
n |= (u8[i] & 0x7f) << 14;
|
|
539
|
+
if ( 0x80 & u8[i++] ) {
|
|
540
|
+
n |= (u8[i] & 0x7f) << 21;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return [n, i, i0]
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function mqtt_raw_dispatch(opt) {
|
|
548
|
+
let u8 = new Uint8Array(0);
|
|
549
|
+
return u8_buf => {
|
|
550
|
+
u8 = 0 === u8.byteLength
|
|
551
|
+
? u8_buf : _u8_join(u8, u8_buf);
|
|
552
|
+
|
|
553
|
+
let res = [];
|
|
554
|
+
while (1) {
|
|
555
|
+
let [len_body, len_vh] = decode_varint(u8, 1);
|
|
556
|
+
let len_pkt = len_body + len_vh;
|
|
557
|
+
|
|
558
|
+
if ( u8.byteLength < len_pkt )
|
|
559
|
+
return res
|
|
560
|
+
|
|
561
|
+
let b0 = u8[0];
|
|
562
|
+
let u8_body = 0 === len_body ? null
|
|
563
|
+
: u8.subarray(len_vh, len_pkt);
|
|
564
|
+
|
|
565
|
+
u8 = u8.subarray(len_pkt);
|
|
566
|
+
|
|
567
|
+
let pkt = opt.decode_pkt(b0, u8_body, opt);
|
|
568
|
+
if (null != pkt)
|
|
569
|
+
res.push( pkt );
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function _u8_join(a, b) {
|
|
575
|
+
let alen = a.byteLength, r = new Uint8Array(alen + b.byteLength);
|
|
576
|
+
r.set(a, 0);
|
|
577
|
+
r.set(b, alen);
|
|
578
|
+
return r
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const _pkt_types = ['~', 'connect', 'connack', 'publish', 'puback', 'pubrec', 'pubrel', 'pubcomp', 'subscribe', 'suback', 'unsubscribe', 'unsuback', 'pingreq', 'pingresp', 'disconnect', 'auth'];
|
|
582
|
+
|
|
583
|
+
function mqtt_pkt_ctx(mqtt_level, opts, pkt_ctx) {
|
|
584
|
+
pkt_ctx = {
|
|
585
|
+
__proto__: pkt_ctx || opts.pkt_ctx,
|
|
586
|
+
mqtt_level,
|
|
587
|
+
get hdr() { return this.b0 & 0xf },
|
|
588
|
+
get id() { return this.b0 >>> 4 },
|
|
589
|
+
get type() { return _pkt_types[this.b0 >>> 4] },
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
let op, _decode_by_id=[], _encode_by_type={};
|
|
593
|
+
for (op of opts.encode_fns)
|
|
594
|
+
op(_encode_by_type, opts.mqtt_writer);
|
|
595
|
+
for (op of opts.decode_fns)
|
|
596
|
+
op(_decode_by_id, opts.mqtt_reader);
|
|
597
|
+
|
|
598
|
+
return {
|
|
599
|
+
pkt_ctx,
|
|
600
|
+
|
|
601
|
+
encode_pkt(type, pkt) {
|
|
602
|
+
return _encode_by_type[type]( mqtt_level, pkt ) },
|
|
603
|
+
|
|
604
|
+
decode_pkt(b0, u8_body) {
|
|
605
|
+
let fn_decode = _decode_by_id[b0>>>4] || _decode_by_id[0];
|
|
606
|
+
return fn_decode?.({__proto__: this.pkt_ctx, b0}, u8_body) },
|
|
607
|
+
|
|
608
|
+
mqtt_stream() {
|
|
609
|
+
let self = { __proto__: this, pkt_ctx: { __proto__: pkt_ctx } };
|
|
610
|
+
self.pkt_ctx._base_ = self.pkt_ctx;
|
|
611
|
+
self.decode = mqtt_raw_dispatch(self);
|
|
612
|
+
return self
|
|
613
|
+
},
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
function ao_defer_ctx(as_res = (...args) => args) {
|
|
618
|
+
let y,n,_pset = (a,b) => { y=a, n=b; };
|
|
619
|
+
return p =>(
|
|
620
|
+
p = new Promise(_pset)
|
|
621
|
+
, as_res(p, y, n)) }
|
|
622
|
+
|
|
623
|
+
const ao_defer_v = /* #__PURE__ */
|
|
624
|
+
ao_defer_ctx();
|
|
625
|
+
|
|
626
|
+
Promise.resolve({type:'init'});
|
|
627
|
+
|
|
628
|
+
function _mqtt_conn(client, [on_mqtt, pkt_future]) {
|
|
629
|
+
let _q_init = ao_defer_v(), _q_ready = ao_defer_v();
|
|
630
|
+
let _send_ready = async (...args) => (await _q_ready[0])(...args);
|
|
631
|
+
let _send_mqtt_pkt, _has_connected;
|
|
632
|
+
client._send = _send_ready;
|
|
633
|
+
|
|
634
|
+
return {
|
|
635
|
+
async when_ready() {await _q_ready[0];}
|
|
636
|
+
|
|
637
|
+
, ping: _ping_interval (() =>_send_mqtt_pkt?.('pingreq'))
|
|
638
|
+
|
|
639
|
+
, reset(err) {
|
|
640
|
+
if (! _send_mqtt_pkt) {return}
|
|
641
|
+
|
|
642
|
+
if (err) {
|
|
643
|
+
_q_init[2](err);}
|
|
644
|
+
|
|
645
|
+
_send_mqtt_pkt = null;
|
|
646
|
+
_q_init = ao_defer_v();
|
|
647
|
+
client._send = _send_ready;
|
|
648
|
+
|
|
649
|
+
// call client.on_conn_reset in next promise microtask
|
|
650
|
+
client.conn_emit('on_disconnect', false===err, err);}
|
|
651
|
+
|
|
652
|
+
, async send_connect(... args) {
|
|
653
|
+
if (! _send_mqtt_pkt) {
|
|
654
|
+
await _q_init[0]; }// _send_mqtt_pkt is set before fulfilled
|
|
655
|
+
|
|
656
|
+
// await connack response
|
|
657
|
+
let res = await _send_mqtt_pkt(...args);
|
|
658
|
+
if (0 == res[0].reason) {
|
|
659
|
+
_has_connected = true;
|
|
660
|
+
// resolve _q_ready[0] with _send_mqtt_pkt closure
|
|
661
|
+
_q_ready[1](client._send = _send_mqtt_pkt);
|
|
662
|
+
_q_ready = ao_defer_v();
|
|
663
|
+
client.conn_emit('on_ready');}
|
|
664
|
+
|
|
665
|
+
return res}
|
|
666
|
+
|
|
667
|
+
, is_set: (() =>!! _send_mqtt_pkt)
|
|
668
|
+
, set(mqtt_ctx, send_u8_pkt) {
|
|
669
|
+
if (_send_mqtt_pkt) {
|
|
670
|
+
throw new Error('Already connected')}
|
|
671
|
+
|
|
672
|
+
mqtt_ctx = mqtt_ctx.mqtt_stream();
|
|
673
|
+
let sess_ctx = {mqtt: client};
|
|
674
|
+
let on_mqtt_chunk = u8_buf =>
|
|
675
|
+
on_mqtt(mqtt_ctx.decode(u8_buf), sess_ctx);
|
|
676
|
+
|
|
677
|
+
_send_mqtt_pkt = async (type, pkt, key) => {
|
|
678
|
+
let res = undefined !== key
|
|
679
|
+
? pkt_future(key) : true;
|
|
680
|
+
|
|
681
|
+
await send_u8_pkt(
|
|
682
|
+
mqtt_ctx.encode_pkt(type, pkt));
|
|
683
|
+
|
|
684
|
+
return res};
|
|
685
|
+
|
|
686
|
+
_q_init[1](_send_mqtt_pkt); // resolve _q_init with _send_mqtt_pkt closure
|
|
687
|
+
|
|
688
|
+
// call client.on_live in next promise microtask
|
|
689
|
+
client.conn_emit('on_live', _has_connected);
|
|
690
|
+
return on_mqtt_chunk} } }
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
function _ping_interval(send_ping) {
|
|
694
|
+
let tid;
|
|
695
|
+
return (( td ) => {
|
|
696
|
+
tid = clearInterval(tid);
|
|
697
|
+
if (td) {
|
|
698
|
+
tid = setInterval(send_ping, 1000 * td);
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
// ensure the interval allows the NodeJS event loop to exit
|
|
704
|
+
tid.unref?.();
|
|
705
|
+
return true} }) }
|
|
706
|
+
|
|
707
|
+
const _mqtt_cmdid_dispatch ={
|
|
708
|
+
create(target) {
|
|
709
|
+
return {__proto__: this, target, hashbelt: [new Map()]} }
|
|
710
|
+
|
|
711
|
+
, bind_pkt_future(_pkt_id=100) {
|
|
712
|
+
let {hashbelt} = this;
|
|
713
|
+
|
|
714
|
+
let _tmp_; // use _tmp_ to reuse _by_key closure
|
|
715
|
+
let _by_key = answer_monad =>
|
|
716
|
+
hashbelt[0].set(_tmp_, answer_monad);
|
|
717
|
+
|
|
718
|
+
return (( pkt_or_key ) => {
|
|
719
|
+
if ('string' === typeof pkt_or_key) {
|
|
720
|
+
_tmp_ = pkt_or_key;}
|
|
721
|
+
else {
|
|
722
|
+
_pkt_id = (_pkt_id + 1) & 0xffff;
|
|
723
|
+
_tmp_ = pkt_or_key.pkt_id = _pkt_id;}
|
|
724
|
+
|
|
725
|
+
return new Promise(_by_key)}) }
|
|
726
|
+
|
|
727
|
+
, answer(key, pkt) {
|
|
728
|
+
for (let map of this.hashbelt) {
|
|
729
|
+
let answer_monad = map.get(key);
|
|
730
|
+
if (undefined !== answer_monad) {
|
|
731
|
+
map.delete(key);
|
|
732
|
+
|
|
733
|
+
answer_monad([pkt, /*err*/]); // option/maybe monad
|
|
734
|
+
return true} }
|
|
735
|
+
return false}
|
|
736
|
+
|
|
737
|
+
, rotate_belt(n) {
|
|
738
|
+
let {hashbelt} = this;
|
|
739
|
+
hashbelt.unshift(new Map());
|
|
740
|
+
for (let old of hashbelt.splice(n || 5)) {
|
|
741
|
+
for (let answer_monad of old.values()) {
|
|
742
|
+
answer_monad([/*pkt*/, 'expired']); } } }// option/maybe monad
|
|
743
|
+
|
|
744
|
+
, cmdids: ((() => {
|
|
745
|
+
return [
|
|
746
|
+
(() =>{} )// 0x0 reserved
|
|
747
|
+
, by_evt // 0x1 connect
|
|
748
|
+
, by_type // 0x2 connack
|
|
749
|
+
, by_evt // 0x3 publish
|
|
750
|
+
, by_id // 0x4 puback
|
|
751
|
+
, by_id // 0x5 pubrec
|
|
752
|
+
, by_id // 0x6 pubrel
|
|
753
|
+
, by_id // 0x7 pubcomp
|
|
754
|
+
, by_evt // 0x8 subscribe
|
|
755
|
+
, by_id // 0x9 suback
|
|
756
|
+
, by_evt // 0xa unsubscribe
|
|
757
|
+
, by_id // 0xb unsuback
|
|
758
|
+
, by_type // 0xc pingreq
|
|
759
|
+
, by_type // 0xd pingresp
|
|
760
|
+
, by_evt // 0xe disconnect
|
|
761
|
+
, by_type ]// 0xf auth
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
function by_id(disp, pkt) {
|
|
765
|
+
disp.answer(pkt.pkt_id, pkt); }
|
|
766
|
+
|
|
767
|
+
function by_type(disp, pkt, ctx) {
|
|
768
|
+
disp.answer(pkt.type, pkt);
|
|
769
|
+
by_evt(disp, pkt, ctx);}
|
|
770
|
+
|
|
771
|
+
async function by_evt({target}, pkt, ctx) {
|
|
772
|
+
let fn = target[`mqtt_${pkt.type}`]
|
|
773
|
+
|| target.mqtt_pkt;
|
|
774
|
+
|
|
775
|
+
await fn?.call(target, pkt, ctx);} })()) };
|
|
776
|
+
|
|
777
|
+
function _mqtt_dispatch(opt, target) {
|
|
778
|
+
let _disp_ = _mqtt_cmdid_dispatch.create(target);
|
|
779
|
+
let { cmdids } = _disp_;
|
|
780
|
+
|
|
781
|
+
// default rotate at 1s across 5 buckets
|
|
782
|
+
let { td: rotate_td=1000, n: rotate_n=5 } =
|
|
783
|
+
opt && opt.rotate || {};
|
|
784
|
+
|
|
785
|
+
let rotate_ts = rotate_td + Date.now();
|
|
786
|
+
|
|
787
|
+
return [on_mqtt,
|
|
788
|
+
_disp_.bind_pkt_future()]
|
|
789
|
+
|
|
790
|
+
function on_mqtt(pkt_list, ctx) {
|
|
791
|
+
for (let pkt of pkt_list) {
|
|
792
|
+
cmdids[pkt.id](_disp_, pkt, ctx); }
|
|
793
|
+
|
|
794
|
+
if (Date.now() > rotate_ts) {
|
|
795
|
+
_disp_.rotate_belt(rotate_n);
|
|
796
|
+
rotate_ts = rotate_td + Date.now();} } }
|
|
797
|
+
|
|
798
|
+
class MQTTError extends Error {
|
|
799
|
+
constructor(mqtt_pkt, reason=mqtt_pkt.reason) {
|
|
800
|
+
super(`[0x${reason.toString(16)}] ${reason.reason}`);
|
|
801
|
+
this.mqtt_pkt = mqtt_pkt;
|
|
802
|
+
this.reason = reason;} }
|
|
803
|
+
|
|
804
|
+
class MQTTBase {
|
|
805
|
+
constructor(opt={}) {
|
|
806
|
+
this._conn_ = _mqtt_conn(this,
|
|
807
|
+
this._init_dispatch(opt, this)); }
|
|
808
|
+
|
|
809
|
+
async conn_emit(evt, arg, err_arg) {
|
|
810
|
+
this.log_conn?.(evt, arg, err_arg);
|
|
811
|
+
try {
|
|
812
|
+
let fn_evt = this[await evt]; // microtask break
|
|
813
|
+
if (fn_evt) {
|
|
814
|
+
await fn_evt.call(this, this, arg, err_arg);}
|
|
815
|
+
else if (err_arg) {
|
|
816
|
+
await this.on_error(err_arg, evt);} }
|
|
817
|
+
catch (err) {
|
|
818
|
+
this.on_error(err, evt);} }
|
|
819
|
+
|
|
820
|
+
on_error(err, err_path) {
|
|
821
|
+
console.warn('[[u8-mqtt error: %s]]', err_path, err); }
|
|
822
|
+
|
|
823
|
+
// Handshaking Packets
|
|
824
|
+
|
|
825
|
+
async connect(pkt={}) {
|
|
826
|
+
let cid = pkt.client_id || ['u8-mqtt--', ''];
|
|
827
|
+
if (Array.isArray(cid)) {
|
|
828
|
+
pkt.client_id = cid = this.init_client_id(cid);}
|
|
829
|
+
this.client_id = cid;
|
|
830
|
+
|
|
831
|
+
if (null == pkt.keep_alive) {
|
|
832
|
+
pkt.keep_alive = 60;}
|
|
833
|
+
|
|
834
|
+
let res = await this._conn_
|
|
835
|
+
.send_connect('connect', pkt, 'connack');
|
|
836
|
+
|
|
837
|
+
if (0 != res[0].reason) {
|
|
838
|
+
throw new this.MQTTError(res[0])}
|
|
839
|
+
|
|
840
|
+
// TODO: merge with server's keep_alive frequency
|
|
841
|
+
this._conn_.ping(pkt.keep_alive);
|
|
842
|
+
return res}
|
|
843
|
+
|
|
844
|
+
async disconnect(pkt={}) {
|
|
845
|
+
let res = await this._send('disconnect', pkt);
|
|
846
|
+
this._conn_.reset(false);
|
|
847
|
+
return res}
|
|
848
|
+
|
|
849
|
+
auth(pkt={}) {
|
|
850
|
+
return this._send('auth', pkt, 'auth')}
|
|
851
|
+
|
|
852
|
+
ping() {return this._send('pingreq', null, 'pingresp')}
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
// alias: sub
|
|
856
|
+
subscribe(pkt, ex, topic_prefix) {
|
|
857
|
+
pkt = _as_topics(pkt, ex, topic_prefix);
|
|
858
|
+
return this._send('subscribe', pkt, pkt)}
|
|
859
|
+
|
|
860
|
+
// alias: unsub
|
|
861
|
+
unsubscribe(pkt, ex, topic_prefix) {
|
|
862
|
+
pkt = _as_topics(pkt, ex, topic_prefix);
|
|
863
|
+
return this._send('unsubscribe', pkt, pkt)}
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
// alias: pub
|
|
867
|
+
publish(pkt, pub_opt) {return _pub(this, pkt, pub_opt)}
|
|
868
|
+
post(topic, payload, pub_opt) {return _pub.m(this, topic, payload, pub_opt)}
|
|
869
|
+
send(topic, payload, pub_opt) {return _pub.mq(this, topic, payload, pub_opt)}
|
|
870
|
+
store(topic, payload, pub_opt) {return _pub.mqr(this, topic, payload, pub_opt)}
|
|
871
|
+
|
|
872
|
+
json_post(topic, msg, pub_opt) {return _pub.o(this, topic, msg, pub_opt)}
|
|
873
|
+
json_send(topic, msg, pub_opt) {return _pub.oq(this, topic, msg, pub_opt)}
|
|
874
|
+
json_store(topic, msg, pub_opt) {return _pub.oqr(this, topic, msg, pub_opt)}
|
|
875
|
+
|
|
876
|
+
obj_post(topic, msg, pub_opt) {return _pub.o(this, topic, msg, pub_opt)}
|
|
877
|
+
obj_send(topic, msg, pub_opt) {return _pub.oq(this, topic, msg, pub_opt)}
|
|
878
|
+
obj_store(topic, msg, pub_opt) {return _pub.oqr(this, topic, msg, pub_opt)}
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
|
|
882
|
+
// Utility Methods
|
|
883
|
+
|
|
884
|
+
init_client_id(parts) {
|
|
885
|
+
let cid = this.client_id;
|
|
886
|
+
|
|
887
|
+
if (undefined === cid) {
|
|
888
|
+
this.client_id = cid = (
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
|
|
892
|
+
this.new_client_id(parts)
|
|
893
|
+
);}
|
|
894
|
+
|
|
895
|
+
return cid}
|
|
896
|
+
|
|
897
|
+
new_client_id(parts) {
|
|
898
|
+
return [parts[0], Math.random().toString(36).slice(2), parts[1]].join('')}
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
|
|
908
|
+
|
|
909
|
+
|
|
910
|
+
// Internal API
|
|
911
|
+
|
|
912
|
+
/* async _send(type, pkt) -- provided by _conn_ and transport */
|
|
913
|
+
|
|
914
|
+
_init_dispatch(opt) {
|
|
915
|
+
this.constructor?._once_();
|
|
916
|
+
let router = this.router =
|
|
917
|
+
this._init_router?.(opt, this);
|
|
918
|
+
|
|
919
|
+
let tgt ={
|
|
920
|
+
__proto__: opt.on_mqtt_type || {}
|
|
921
|
+
, router};
|
|
922
|
+
|
|
923
|
+
tgt.mqtt_publish ||= router?.invoke;
|
|
924
|
+
return _mqtt_dispatch(this, tgt)}
|
|
925
|
+
|
|
926
|
+
static _aliases() {
|
|
927
|
+
return ' pub:publish sub:subscribe unsub:unsubscribe '}
|
|
928
|
+
|
|
929
|
+
static _once_(self=this) {
|
|
930
|
+
self._once_ = _=>0;
|
|
931
|
+
self.MQTTError = MQTTError;
|
|
932
|
+
let p = self.prototype;
|
|
933
|
+
for (let alias of self._aliases().split(/\s+/)) {
|
|
934
|
+
alias = alias.split(':');
|
|
935
|
+
let fn = alias[1] && p[alias[1]];
|
|
936
|
+
if (fn) {p[alias[0]] = fn;} } } }
|
|
937
|
+
|
|
938
|
+
|
|
939
|
+
/*
|
|
940
|
+
on_mqtt_type = {
|
|
941
|
+
mqtt_auth(pkt, ctx) ::
|
|
942
|
+
mqtt_connect(pkt, ctx) ::
|
|
943
|
+
mqtt_connack(pkt, ctx) ::
|
|
944
|
+
mqtt_disconnect(pkt, ctx) ::
|
|
945
|
+
|
|
946
|
+
mqtt_publish(pkt, ctx)
|
|
947
|
+
mqtt_subscribe(pkt, ctx) ::
|
|
948
|
+
mqtt_unsubscribe(pkt, ctx) ::
|
|
949
|
+
|
|
950
|
+
mqtt_pingreq(pkt, ctx) ::
|
|
951
|
+
mqtt_pingresp(pkt, ctx) ::
|
|
952
|
+
}
|
|
953
|
+
*/
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
const _prefix_topics = (topic_prefix, iterable) =>
|
|
957
|
+
Array.from(iterable, value =>(
|
|
958
|
+
value.trim // string
|
|
959
|
+
? _prefix_topics(topic_prefix, value)
|
|
960
|
+
: topic_prefix + value) );
|
|
961
|
+
|
|
962
|
+
function _as_topics(pkt, ex, topic_prefix) {
|
|
963
|
+
if (ex?.trim) {// string
|
|
964
|
+
topic_prefix = ex;
|
|
965
|
+
ex = null;}
|
|
966
|
+
|
|
967
|
+
pkt =(
|
|
968
|
+
pkt.trim // string
|
|
969
|
+
? {topics:[pkt], ... ex}
|
|
970
|
+
: pkt[Symbol.iterator]
|
|
971
|
+
? {topics:[... pkt], ... ex}
|
|
972
|
+
: ex ? {...pkt, ...ex}
|
|
973
|
+
: pkt);
|
|
974
|
+
|
|
975
|
+
if (topic_prefix) {
|
|
976
|
+
// particularly useful with shared queues, e.g.
|
|
977
|
+
// topic_prefix = '$share/some-queue-name/'
|
|
978
|
+
pkt.topics = _prefix_topics(topic_prefix, pkt.topics);}
|
|
979
|
+
return pkt}
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
async function _pub(self, pkt, pub_opt) {
|
|
983
|
+
if (undefined === pkt.payload) {
|
|
984
|
+
if ('function' === typeof pub_opt) {
|
|
985
|
+
pub_opt = {fn_encode: pub_opt};}
|
|
986
|
+
|
|
987
|
+
let {msg} = pkt;
|
|
988
|
+
switch (typeof msg) {
|
|
989
|
+
case 'function':
|
|
990
|
+
pub_opt = {...pub_opt, fn_encode: msg};
|
|
991
|
+
// flow into 'undefined' case
|
|
992
|
+
case 'undefined':
|
|
993
|
+
// return a single-value closure to publish packets
|
|
994
|
+
return v => _pub(self, {...pkt, [pkt.arg || 'payload']: v}, pub_opt)
|
|
995
|
+
|
|
996
|
+
default:
|
|
997
|
+
// Encode payload from msg; fn_encode allows alternative to JSON.stringify
|
|
998
|
+
let {fn_encode} = pub_opt || {};
|
|
999
|
+
pkt.payload = fn_encode
|
|
1000
|
+
? await fn_encode(msg)
|
|
1001
|
+
: JSON.stringify(msg);} }
|
|
1002
|
+
|
|
1003
|
+
if (pub_opt) {
|
|
1004
|
+
if (pub_opt.props) {
|
|
1005
|
+
pkt.props = pub_opt.props;}
|
|
1006
|
+
if (pub_opt.xform) {
|
|
1007
|
+
pkt = pub_opt.xform(pkt) || pkt;} }
|
|
1008
|
+
|
|
1009
|
+
return self._send('publish', pkt,
|
|
1010
|
+
pkt.qos ? pkt : void 0 ) }// key
|
|
1011
|
+
|
|
1012
|
+
{
|
|
1013
|
+
Object.assign(_pub,{
|
|
1014
|
+
m: (self, topic, payload, pub_opt) =>
|
|
1015
|
+
_pub(self, {topic, payload, qos:0}, pub_opt)
|
|
1016
|
+
, mq: (self, topic, payload, pub_opt) =>
|
|
1017
|
+
_pub(self, {topic, payload, qos:1}, pub_opt)
|
|
1018
|
+
, mqr: (self, topic, payload, pub_opt) =>
|
|
1019
|
+
_pub(self, {topic, payload, qos:1, retain: 1}, pub_opt)
|
|
1020
|
+
|
|
1021
|
+
, o: (self, topic, msg, pub_opt) =>
|
|
1022
|
+
_pub(self, {topic, msg, arg: 'msg', qos:0}, pub_opt)
|
|
1023
|
+
, oq: (self, topic, msg, pub_opt) =>
|
|
1024
|
+
_pub(self, {topic, msg, arg: 'msg', qos:1}, pub_opt)
|
|
1025
|
+
, oqr: (self, topic, msg, pub_opt) =>
|
|
1026
|
+
_pub(self, {topic, msg, arg: 'msg', qos:1, retain: 1}, pub_opt)} ); }
|
|
1027
|
+
|
|
1028
|
+
const pkt_api = {
|
|
1029
|
+
utf8(u8) { return new TextDecoder('utf-8').decode(u8 || this.payload ) },
|
|
1030
|
+
json(u8) { return JSON.parse( this.utf8(u8) || null ) },
|
|
1031
|
+
text(u8) { return this.utf8(u8) },
|
|
1032
|
+
};
|
|
1033
|
+
|
|
1034
|
+
class MQTTCore extends MQTTBase {
|
|
1035
|
+
constructor(opt={}) {
|
|
1036
|
+
super(opt);
|
|
1037
|
+
this.with(opt);}
|
|
1038
|
+
|
|
1039
|
+
static mqtt_ctx(mqtt_level, mqtt_opts, pkt_ctx=pkt_api) {
|
|
1040
|
+
let self = class extends this {};
|
|
1041
|
+
self.prototype.mqtt_ctx =
|
|
1042
|
+
mqtt_pkt_ctx(mqtt_level, mqtt_opts, pkt_ctx);
|
|
1043
|
+
return self}
|
|
1044
|
+
|
|
1045
|
+
with(fns_ns) {
|
|
1046
|
+
for (let [k,v] of Object.entries(fns_ns)) {
|
|
1047
|
+
if ('function' === typeof v) {this[k] = v;} }
|
|
1048
|
+
return this}
|
|
1049
|
+
|
|
1050
|
+
//log_conn(evt, arg, err_arg) ::
|
|
1051
|
+
// console.info @ '[[u8-mqtt log: %s]]', evt, arg, err_arg
|
|
1052
|
+
|
|
1053
|
+
on_live(client, is_reconnect) {
|
|
1054
|
+
if (is_reconnect) {
|
|
1055
|
+
return client.connect()} }
|
|
1056
|
+
|
|
1057
|
+
//on_reconnect(client) ::
|
|
1058
|
+
|
|
1059
|
+
_use_conn(fn_reconnect) {
|
|
1060
|
+
return (this.reconnect = fn_reconnect)?.()}
|
|
1061
|
+
with_autoreconnect(opt=2000) {
|
|
1062
|
+
if (opt.toFixed) {opt ={delay: opt};}
|
|
1063
|
+
return this.with({
|
|
1064
|
+
on_reconnect() {
|
|
1065
|
+
this.delay(opt.delay || 2000)
|
|
1066
|
+
.then(this.reconnect)
|
|
1067
|
+
.then(opt.reconnect, opt.error);} }) }
|
|
1068
|
+
|
|
1069
|
+
on_disconnect(client, intentional) {
|
|
1070
|
+
if (! intentional) {
|
|
1071
|
+
return client.on_reconnect?.()} }
|
|
1072
|
+
|
|
1073
|
+
delay(ms) {
|
|
1074
|
+
return new Promise(done => setTimeout(done, ms)) }
|
|
1075
|
+
|
|
1076
|
+
with_async_iter(async_iter, write_u8_pkt) {
|
|
1077
|
+
let on_mqtt_chunk = this._conn_.set(
|
|
1078
|
+
this.mqtt_ctx,
|
|
1079
|
+
write_u8_pkt);
|
|
1080
|
+
|
|
1081
|
+
this._msg_loop = ((async () => {
|
|
1082
|
+
try {
|
|
1083
|
+
async_iter = await async_iter;
|
|
1084
|
+
for await (let chunk of async_iter)
|
|
1085
|
+
on_mqtt_chunk(chunk);
|
|
1086
|
+
this._conn_.reset();}
|
|
1087
|
+
catch (err) {
|
|
1088
|
+
this._conn_.reset(err);} })());
|
|
1089
|
+
|
|
1090
|
+
return this}
|
|
1091
|
+
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
with_tcp(...opt) {
|
|
1124
|
+
opt = this._conn_opt(opt);
|
|
1125
|
+
console.log({opt});
|
|
1126
|
+
return this._use_conn (() =>
|
|
1127
|
+
this.with_stream(
|
|
1128
|
+
connect(opt)) ) }
|
|
1129
|
+
|
|
1130
|
+
with_tls(...opt) {
|
|
1131
|
+
opt = this._conn_opt(opt);
|
|
1132
|
+
return this._use_conn (() =>
|
|
1133
|
+
this.with_stream(
|
|
1134
|
+
connect$1(opt)) ) }
|
|
1135
|
+
|
|
1136
|
+
_conn_opt([a0, a1, a2]) {
|
|
1137
|
+
// (port, hostname, options) or (url, options)
|
|
1138
|
+
if (Number.isFinite(a0)) {
|
|
1139
|
+
return {...a2, port: a0, host: a1}}
|
|
1140
|
+
a0 = new URL(a0);
|
|
1141
|
+
return {...a1, port: a0.port, host: a0.hostname}}
|
|
1142
|
+
|
|
1143
|
+
|
|
1144
|
+
with_stream(read_stream, write_stream) {
|
|
1145
|
+
if (undefined === write_stream) {
|
|
1146
|
+
write_stream = read_stream;}
|
|
1147
|
+
|
|
1148
|
+
return this.with_async_iter(read_stream,
|
|
1149
|
+
u8_pkt => write_stream.write(u8_pkt)) }
|
|
1150
|
+
|
|
1151
|
+
|
|
1152
|
+
with_websock(websock) {
|
|
1153
|
+
if (! websock?.send) {
|
|
1154
|
+
websock = new URL(websock || 'ws://127.0.0.1:9001');
|
|
1155
|
+
return this._use_conn (() =>
|
|
1156
|
+
this.with_websock(
|
|
1157
|
+
new WebSocket(websock, ['mqtt'])) ) }
|
|
1158
|
+
|
|
1159
|
+
websock.binaryType = 'arraybuffer';
|
|
1160
|
+
|
|
1161
|
+
let ready, {readyState} = websock;
|
|
1162
|
+
if (1 !== readyState) {
|
|
1163
|
+
if (0 !== readyState) {
|
|
1164
|
+
throw new Error('Invalid WebSocket readyState') }
|
|
1165
|
+
|
|
1166
|
+
ready = new Promise(fn => websock.onopen = fn); }
|
|
1167
|
+
|
|
1168
|
+
|
|
1169
|
+
let {_conn_} = this;
|
|
1170
|
+
let on_mqtt_chunk = _conn_.set(
|
|
1171
|
+
this.mqtt_ctx,
|
|
1172
|
+
async u8_pkt =>(
|
|
1173
|
+
await ready
|
|
1174
|
+
, websock.send(u8_pkt)) );
|
|
1175
|
+
|
|
1176
|
+
websock.onmessage = evt =>(on_mqtt_chunk(new Uint8Array(evt.data)));
|
|
1177
|
+
websock.onclose = evt => {
|
|
1178
|
+
if (! evt.wasClean) {
|
|
1179
|
+
var err = new Error('websocket connection close');
|
|
1180
|
+
err.code = evt.code;
|
|
1181
|
+
err.reason = evt.reason;}
|
|
1182
|
+
|
|
1183
|
+
_conn_.reset(err);};
|
|
1184
|
+
|
|
1185
|
+
return this} }
|
|
1186
|
+
|
|
1187
|
+
const version = '0.4.0';
|
|
1188
|
+
|
|
1189
|
+
const MQTTClient_v4 = /* #__PURE__ */
|
|
1190
|
+
MQTTCore.mqtt_ctx(4, mqtt_opts_v4);
|
|
1191
|
+
|
|
1192
|
+
const mqtt_v4 = opt =>
|
|
1193
|
+
new MQTTClient_v4(opt);
|
|
1194
|
+
|
|
1195
|
+
export { MQTTClient_v4 as MQTTClient, MQTTClient_v4, mqtt_v4 as default, mqtt_v4 as mqtt, mqtt_v4, version };
|
|
1196
|
+
//# sourceMappingURL=basic-v4.mjs.map
|