u8-mqtt 0.5.3 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/cjs/basic-v4.cjs +283 -277
- package/cjs/basic-v4.cjs.map +1 -1
- package/cjs/basic-v5.cjs +297 -281
- package/cjs/basic-v5.cjs.map +1 -1
- package/cjs/full-v4.cjs +295 -289
- package/cjs/full-v4.cjs.map +1 -1
- package/cjs/full-v5.cjs +309 -293
- package/cjs/full-v5.cjs.map +1 -1
- package/cjs/index.cjs +310 -295
- package/cjs/index.cjs.map +1 -1
- package/cjs/v4.cjs +295 -289
- package/cjs/v4.cjs.map +1 -1
- package/cjs/v5.cjs +309 -293
- package/cjs/v5.cjs.map +1 -1
- package/code/_cmdid_dispatch.jsy +45 -69
- package/code/_conn.jsy +96 -72
- package/code/_dispatch.jsy +36 -28
- package/code/_utils.jsy +17 -0
- package/code/base.jsy +33 -61
- package/code/core.jsy +73 -51
- package/code/router_path.jsy +2 -1
- package/esm/basic-v4.js +283 -277
- package/esm/basic-v4.js.map +1 -1
- package/esm/basic-v5.js +297 -281
- package/esm/basic-v5.js.map +1 -1
- package/esm/deno/basic-v4.js +287 -281
- package/esm/deno/basic-v4.js.map +1 -1
- package/esm/deno/basic-v5.js +301 -285
- package/esm/deno/basic-v5.js.map +1 -1
- package/esm/deno/full-v4.js +299 -293
- package/esm/deno/full-v4.js.map +1 -1
- package/esm/deno/full-v5.js +313 -297
- package/esm/deno/full-v5.js.map +1 -1
- package/esm/deno/index.js +314 -298
- package/esm/deno/index.js.map +1 -1
- package/esm/deno/v4.js +299 -293
- package/esm/deno/v4.js.map +1 -1
- package/esm/deno/v5.js +313 -297
- package/esm/deno/v5.js.map +1 -1
- package/esm/full-v4.js +295 -289
- package/esm/full-v4.js.map +1 -1
- package/esm/full-v5.js +309 -293
- package/esm/full-v5.js.map +1 -1
- package/esm/index.js +310 -294
- package/esm/index.js.map +1 -1
- package/esm/node/basic-v4.js +283 -277
- package/esm/node/basic-v4.js.map +1 -1
- package/esm/node/basic-v4.mjs +283 -277
- package/esm/node/basic-v4.mjs.map +1 -1
- package/esm/node/basic-v5.js +297 -281
- package/esm/node/basic-v5.js.map +1 -1
- package/esm/node/basic-v5.mjs +297 -281
- package/esm/node/basic-v5.mjs.map +1 -1
- package/esm/node/full-v4.js +295 -289
- package/esm/node/full-v4.js.map +1 -1
- package/esm/node/full-v4.mjs +295 -289
- package/esm/node/full-v4.mjs.map +1 -1
- package/esm/node/full-v5.js +309 -293
- package/esm/node/full-v5.js.map +1 -1
- package/esm/node/full-v5.mjs +309 -293
- package/esm/node/full-v5.mjs.map +1 -1
- package/esm/node/index.js +310 -294
- package/esm/node/index.js.map +1 -1
- package/esm/node/index.mjs +310 -294
- package/esm/node/index.mjs.map +1 -1
- package/esm/node/v4.js +295 -289
- package/esm/node/v4.js.map +1 -1
- package/esm/node/v4.mjs +295 -289
- package/esm/node/v4.mjs.map +1 -1
- package/esm/node/v5.js +309 -293
- package/esm/node/v5.js.map +1 -1
- package/esm/node/v5.mjs +309 -293
- package/esm/node/v5.mjs.map +1 -1
- package/esm/v4.js +295 -289
- package/esm/v4.js.map +1 -1
- package/esm/v5.js +309 -293
- package/esm/v5.js.map +1 -1
- package/esm/web/basic-v4.js +283 -277
- package/esm/web/basic-v4.js.map +1 -1
- package/esm/web/basic-v4.min.js +1 -1
- package/esm/web/basic-v4.min.js.br +0 -0
- package/esm/web/basic-v4.min.js.gz +0 -0
- package/esm/web/basic-v5.js +297 -281
- package/esm/web/basic-v5.js.map +1 -1
- package/esm/web/basic-v5.min.js +1 -1
- package/esm/web/basic-v5.min.js.br +0 -0
- package/esm/web/basic-v5.min.js.gz +0 -0
- package/esm/web/full-v4.js +295 -289
- package/esm/web/full-v4.js.map +1 -1
- package/esm/web/full-v4.min.js +1 -1
- package/esm/web/full-v4.min.js.br +0 -0
- package/esm/web/full-v4.min.js.gz +0 -0
- package/esm/web/full-v5.js +309 -293
- package/esm/web/full-v5.js.map +1 -1
- package/esm/web/full-v5.min.js +1 -1
- package/esm/web/full-v5.min.js.br +0 -0
- package/esm/web/full-v5.min.js.gz +0 -0
- package/esm/web/index.js +310 -294
- package/esm/web/index.js.map +1 -1
- package/esm/web/index.min.js +1 -1
- package/esm/web/index.min.js.br +0 -0
- package/esm/web/index.min.js.gz +0 -0
- package/esm/web/v4.js +295 -289
- package/esm/web/v4.js.map +1 -1
- package/esm/web/v4.min.js +1 -1
- package/esm/web/v4.min.js.br +0 -0
- package/esm/web/v4.min.js.gz +0 -0
- package/esm/web/v5.js +309 -293
- package/esm/web/v5.js.map +1 -1
- package/esm/web/v5.min.js +1 -1
- package/esm/web/v5.min.js.br +0 -0
- package/esm/web/v5.min.js.gz +0 -0
- package/package.json +7 -8
package/code/_cmdid_dispatch.jsy
CHANGED
|
@@ -1,71 +1,47 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
by_id // 0x6 pubrel
|
|
48
|
-
by_id // 0x7 pubcomp
|
|
49
|
-
by_evt // 0x8 subscribe
|
|
50
|
-
by_id // 0x9 suback
|
|
51
|
-
by_evt // 0xa unsubscribe
|
|
52
|
-
by_id // 0xb unsuback
|
|
53
|
-
by_type // 0xc pingreq
|
|
54
|
-
by_type // 0xd pingresp
|
|
55
|
-
by_evt // 0xe disconnect
|
|
56
|
-
by_type // 0xf auth
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
function by_id(disp, pkt) ::
|
|
60
|
-
disp.answer @ pkt.pkt_id, pkt
|
|
61
|
-
|
|
62
|
-
function by_type(disp, pkt, ctx) ::
|
|
63
|
-
disp.answer @ pkt.type, pkt
|
|
64
|
-
by_evt(disp, pkt, ctx)
|
|
65
|
-
|
|
66
|
-
async function by_evt({target}, pkt, ctx) ::
|
|
67
|
-
let fn = target[`mqtt_${pkt.type}`]
|
|
68
|
-
|| target.mqtt_pkt
|
|
69
|
-
|
|
70
|
-
await fn?.call(target, pkt, ctx)
|
|
2
|
+
async function _mqtt_cmd_evt(target, answer, pkt, ctx) ::
|
|
3
|
+
/* target : on_mqtt_type = {
|
|
4
|
+
mqtt_pkt(pkt, ctx) {}, // generic
|
|
5
|
+
|
|
6
|
+
mqtt_auth(pkt, ctx) {},
|
|
7
|
+
mqtt_connect(pkt, ctx) {},
|
|
8
|
+
mqtt_connack(pkt, ctx) {},
|
|
9
|
+
mqtt_disconnect(pkt, ctx) {},
|
|
10
|
+
|
|
11
|
+
mqtt_publish(pkt, ctx) {},
|
|
12
|
+
mqtt_subscribe(pkt, ctx) {},
|
|
13
|
+
mqtt_unsubscribe(pkt, ctx) {},
|
|
14
|
+
|
|
15
|
+
mqtt_pingreq(pkt, ctx) {},
|
|
16
|
+
mqtt_pingresp(pkt, ctx) {},
|
|
17
|
+
} */
|
|
18
|
+
|
|
19
|
+
let pkt_fn = target[`mqtt_${pkt.type}`] || target.mqtt_pkt
|
|
20
|
+
await pkt_fn?.call(target, pkt, ctx)
|
|
21
|
+
|
|
22
|
+
function _mqtt_cmd_type(target, answer, pkt, ctx) ::
|
|
23
|
+
answer(pkt.type, pkt)
|
|
24
|
+
_mqtt_cmd_evt(target, answer, pkt, ctx)
|
|
25
|
+
|
|
26
|
+
function _mqtt_cmd_id(target, answer, pkt) ::
|
|
27
|
+
answer(pkt.pkt_id, pkt)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
export const _mqtt_cmdids = @[]
|
|
31
|
+
_ => {} // 0x0 reserved
|
|
32
|
+
_mqtt_cmd_evt // 0x1 connect
|
|
33
|
+
_mqtt_cmd_type // 0x2 connack
|
|
34
|
+
_mqtt_cmd_evt // 0x3 publish
|
|
35
|
+
_mqtt_cmd_id // 0x4 puback
|
|
36
|
+
_mqtt_cmd_id // 0x5 pubrec
|
|
37
|
+
_mqtt_cmd_id // 0x6 pubrel
|
|
38
|
+
_mqtt_cmd_id // 0x7 pubcomp
|
|
39
|
+
_mqtt_cmd_evt // 0x8 subscribe
|
|
40
|
+
_mqtt_cmd_id // 0x9 suback
|
|
41
|
+
_mqtt_cmd_evt // 0xa unsubscribe
|
|
42
|
+
_mqtt_cmd_id // 0xb unsuback
|
|
43
|
+
_mqtt_cmd_type // 0xc pingreq
|
|
44
|
+
_mqtt_cmd_type // 0xd pingresp
|
|
45
|
+
_mqtt_cmd_evt // 0xe disconnect
|
|
46
|
+
_mqtt_cmd_type // 0xf auth
|
|
71
47
|
|
package/code/_conn.jsy
CHANGED
|
@@ -1,82 +1,106 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { _interval } from './_utils.jsy'
|
|
2
|
+
|
|
3
|
+
const _defer_obj = o => @
|
|
4
|
+
o.p = new Promise @ (a,e) => { o.a=a; o.e=e }
|
|
5
|
+
, o
|
|
6
|
+
|
|
7
|
+
function _dfn_reset(client, attr, fn_after) ::
|
|
8
|
+
// a resetable deferred for a function
|
|
9
|
+
let self = {set}, afn = async (...args) => (await self.p)(...args)
|
|
10
|
+
return set()
|
|
11
|
+
|
|
12
|
+
function set() ::
|
|
13
|
+
if afn !== client[attr] ::
|
|
14
|
+
_defer_obj(self).p.then(fn_after, _=>0)
|
|
15
|
+
client[attr] = afn
|
|
16
|
+
return self
|
|
17
|
+
|
|
18
|
+
export function _mqtt_conn(opt, client, [on_mqtt, pkt_future]) ::
|
|
19
|
+
let _abort
|
|
20
|
+
let _dfn_send0 = _dfn_reset @ client, '_send0', // client._send0 getter/setter
|
|
21
|
+
_=> client.conn_emit('on_live', conn.has_connected)
|
|
22
|
+
let _dfn_ready = _dfn_reset @ client, '_send', // client._send getter/setter
|
|
23
|
+
_=> client.conn_emit('on_ready')
|
|
24
|
+
let _keep_alive_ival = _interval @=> client._send0('pingreq') // resettable interval for keep_alive ping
|
|
25
|
+
|
|
26
|
+
let conn = Object.create @:
|
|
27
|
+
ping: (td=conn.keep_alive) => _keep_alive_ival(td)
|
|
28
|
+
|
|
29
|
+
on_conn(pkt, response) ::
|
|
30
|
+
conn.has_connected = true
|
|
31
|
+
conn.keep_alive = opt.keep_alive || response[0].props?.server_keep_alive || pkt.keep_alive
|
|
32
|
+
client.conn_emit('on_conn')
|
|
33
|
+
return opt.use_auth
|
|
34
|
+
? response // wait on enhanced authentication step
|
|
35
|
+
: conn.on_auth(null, response) // otherwise, connect is also auth
|
|
36
|
+
|
|
37
|
+
on_auth(pkt, response) ::
|
|
38
|
+
_dfn_ready.a(_dfn_send0.p)
|
|
39
|
+
if 0 != opt.keep_alive ::
|
|
40
|
+
conn.ping()
|
|
41
|
+
client.conn_emit('on_auth', !pkt)
|
|
42
|
+
return response
|
|
43
|
+
|
|
44
|
+
on_dis(pkt, response) ::
|
|
45
|
+
conn.reset(false)
|
|
46
|
+
return response
|
|
3
47
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
client._send = _send_ready
|
|
48
|
+
reset(err) ::
|
|
49
|
+
if err ::
|
|
50
|
+
_dfn_send0.e(err) // send error to uses of _send0 (connect, auth)
|
|
51
|
+
_abort.e(err) // abort in-progress connections
|
|
9
52
|
|
|
10
|
-
|
|
11
|
-
|
|
53
|
+
delete conn.is_set
|
|
54
|
+
conn.ready = handshake()
|
|
55
|
+
client.conn_emit('on_disconnect', false===err, err)
|
|
12
56
|
|
|
13
|
-
|
|
57
|
+
abort() ::
|
|
58
|
+
_dfn_ready.e(err) // abort all messages awaiting ready state
|
|
59
|
+
return conn.reset(err)
|
|
14
60
|
|
|
15
|
-
|
|
16
|
-
if
|
|
61
|
+
async setup(gate, send_u8_pkt, init_msg_loop) ::
|
|
62
|
+
if conn.is_set ::
|
|
63
|
+
throw new Error() // already in-progress
|
|
17
64
|
|
|
18
|
-
|
|
19
|
-
|
|
65
|
+
conn.is_set = true
|
|
66
|
+
await gate
|
|
20
67
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
client._send = _send_ready
|
|
68
|
+
// setup send/recv MQTT parsing context
|
|
69
|
+
let mqtt_ctx = client.mqtt_ctx.mqtt_stream()
|
|
24
70
|
|
|
25
|
-
//
|
|
26
|
-
|
|
71
|
+
:: // setup inbound message loop
|
|
72
|
+
let sess_ctx = {mqtt: client} // mutable session context
|
|
73
|
+
let on_mqtt_chunk = u8 => on_mqtt(mqtt_ctx.decode(u8), sess_ctx)
|
|
74
|
+
init_msg_loop(on_mqtt_chunk, conn)
|
|
75
|
+
|
|
76
|
+
// setup outbound message path and transport connection
|
|
77
|
+
send_u8_pkt = await send_u8_pkt
|
|
78
|
+
_dfn_send0.a @
|
|
79
|
+
async (type, pkt, key) => ::
|
|
80
|
+
let res = undefined !== key
|
|
81
|
+
? pkt_future(key) : true
|
|
82
|
+
|
|
83
|
+
await send_u8_pkt @
|
|
84
|
+
mqtt_ctx.encode_pkt(type, pkt)
|
|
85
|
+
return res
|
|
86
|
+
|
|
87
|
+
conn.ready = handshake()
|
|
88
|
+
return conn
|
|
89
|
+
|
|
90
|
+
async function handshake() ::
|
|
91
|
+
_abort = _defer_obj({})
|
|
92
|
+
|
|
93
|
+
_keep_alive_ival(0) // clearInterval on keep alive ping
|
|
94
|
+
_dfn_send0.set() // reset client._send0 if necessary
|
|
95
|
+
_dfn_ready.set() // reset client._send if necessary
|
|
96
|
+
|
|
97
|
+
try ::
|
|
98
|
+
// set client._send0 as passtrhough after transport connection
|
|
99
|
+
client._send0 = await Promise.race @# _dfn_send0.p, _abort.p
|
|
27
100
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
await _q_init[0] // _send_mqtt_pkt is set before fulfilled
|
|
31
|
-
|
|
32
|
-
// await connack response
|
|
33
|
-
let res = await _send_mqtt_pkt(...args)
|
|
34
|
-
if 0 == res[0].reason ::
|
|
35
|
-
_has_connected = true
|
|
36
|
-
// resolve _q_ready[0] with _send_mqtt_pkt closure
|
|
37
|
-
_q_ready[1](client._send = _send_mqtt_pkt)
|
|
38
|
-
_q_ready = ao_defer_v()
|
|
39
|
-
client.conn_emit('on_ready')
|
|
40
|
-
|
|
41
|
-
return res
|
|
42
|
-
|
|
43
|
-
is_set: @=> !! _send_mqtt_pkt
|
|
44
|
-
set(mqtt_ctx, send_u8_pkt) ::
|
|
45
|
-
if _send_mqtt_pkt ::
|
|
46
|
-
throw new Error('Already connected')
|
|
47
|
-
|
|
48
|
-
mqtt_ctx = mqtt_ctx.mqtt_stream()
|
|
49
|
-
let sess_ctx = {mqtt: client}
|
|
50
|
-
let on_mqtt_chunk = u8_buf =>
|
|
51
|
-
on_mqtt(mqtt_ctx.decode(u8_buf), sess_ctx)
|
|
52
|
-
|
|
53
|
-
_send_mqtt_pkt = async (type, pkt, key) => ::
|
|
54
|
-
let res = undefined !== key
|
|
55
|
-
? pkt_future(key) : true
|
|
56
|
-
|
|
57
|
-
await send_u8_pkt @
|
|
58
|
-
mqtt_ctx.encode_pkt(type, pkt)
|
|
59
|
-
|
|
60
|
-
return res
|
|
61
|
-
|
|
62
|
-
_q_init[1](_send_mqtt_pkt) // resolve _q_init with _send_mqtt_pkt closure
|
|
63
|
-
|
|
64
|
-
// call client.on_live in next promise microtask
|
|
65
|
-
client.conn_emit('on_live', _has_connected)
|
|
66
|
-
return on_mqtt_chunk
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
function _ping_interval(send_ping) ::
|
|
70
|
-
let tid
|
|
71
|
-
return @\ td ::
|
|
72
|
-
tid = clearInterval(tid)
|
|
73
|
-
if td ::
|
|
74
|
-
tid = setInterval(send_ping, 1000 * td)
|
|
75
|
-
#IF PLAT_DENO
|
|
76
|
-
// ensure the interval allows the Deno event loop to exit
|
|
77
|
-
Deno.unrefTimer(tid)
|
|
78
|
-
#ELSE
|
|
79
|
-
// ensure the interval allows the NodeJS event loop to exit
|
|
80
|
-
tid.unref?.()
|
|
101
|
+
// set client._send as passtrhough after ready
|
|
102
|
+
client._send = await Promise.race @# _dfn_ready.p, _abort.p
|
|
81
103
|
return true
|
|
104
|
+
catch err ::
|
|
105
|
+
return false
|
|
82
106
|
|
package/code/_dispatch.jsy
CHANGED
|
@@ -1,39 +1,47 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _isstr } from './_utils.jsy'
|
|
2
|
+
import {_mqtt_cmdids} from './_cmdid_dispatch.jsy'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
mqtt_connack(pkt, ctx) ::
|
|
8
|
-
mqtt_disconnect(pkt, ctx) ::
|
|
4
|
+
export function _mqtt_dispatch(opt, target) ::
|
|
5
|
+
let hashbelt=[], rotate_ts=0
|
|
6
|
+
// default rotate at 1s across 5 buckets
|
|
7
|
+
let { td: rotate_td=1000, n: rotate_n=5 } = opt?.rotate || {}
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
// Promise / future scaffolding
|
|
10
|
+
let _pkt_id=100, _ftr_key // use _ftr_key to reuse _by_key closure
|
|
11
|
+
let _ftr_by_key = fn_answer => hashbelt[0].set(_ftr_key, fn_answer)
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
*/
|
|
13
|
+
on_mqtt([]) // init hashbelt and rotate_ts
|
|
14
|
+
return [on_mqtt, pkt_future]
|
|
18
15
|
|
|
19
|
-
export function _mqtt_dispatch(opt, target) ::
|
|
20
|
-
let _disp_ = _mqtt_cmdid_dispatch.create(target)
|
|
21
|
-
let { cmdids } = _disp_
|
|
22
16
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
function pkt_future(pkt_or_key) ::
|
|
18
|
+
if ! _isstr(pkt_or_key) ::
|
|
19
|
+
_pkt_id = (_pkt_id + 1) & 0xffff // 16-bit unsigned short
|
|
20
|
+
_ftr_key = pkt_or_key.pkt_id = _pkt_id
|
|
21
|
+
else _ftr_key = pkt_or_key
|
|
22
|
+
|
|
23
|
+
return new Promise(_ftr_by_key)
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
function answer(key, pkt) ::
|
|
26
|
+
for let map of hashbelt ::
|
|
27
|
+
let fn_answer = map.get(key)
|
|
28
|
+
if fn_answer ::
|
|
29
|
+
map.delete(key)
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
fn_answer([pkt, /*err*/]) // option/maybe monad
|
|
32
|
+
return true
|
|
33
|
+
return false
|
|
31
34
|
|
|
32
35
|
function on_mqtt(pkt_list, ctx) ::
|
|
33
36
|
for let pkt of pkt_list ::
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
_mqtt_cmdids[pkt.id](target, answer, pkt, ctx)
|
|
38
|
+
|
|
39
|
+
// rotate after rotate_ts
|
|
40
|
+
let now = Date.now()
|
|
41
|
+
if now > rotate_ts ::
|
|
42
|
+
rotate_ts = rotate_td + now
|
|
43
|
+
hashbelt.unshift(new Map())
|
|
44
|
+
while hashbelt.length > rotate_n ::
|
|
45
|
+
for let fn_answer of hashbelt.pop().values() ::
|
|
46
|
+
fn_answer([/*pkt*/, 'expired']) // option/maybe monad
|
|
39
47
|
|
package/code/_utils.jsy
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const _isfn = v => typeof v === 'function'
|
|
2
|
+
export const _isstr = v => typeof v === 'string'
|
|
3
|
+
|
|
4
|
+
export function _interval(fn_callback) ::
|
|
5
|
+
let tid
|
|
6
|
+
return @\ td ::
|
|
7
|
+
tid = clearInterval(tid)
|
|
8
|
+
if td ::
|
|
9
|
+
tid = setInterval(fn_callback, 1000 * td)
|
|
10
|
+
#IF PLAT_DENO
|
|
11
|
+
// ensure the interval allows the Deno event loop to exit
|
|
12
|
+
Deno.unrefTimer(tid)
|
|
13
|
+
#ELSE
|
|
14
|
+
// ensure the interval allows the NodeJS event loop to exit
|
|
15
|
+
tid.unref?.()
|
|
16
|
+
return true
|
|
17
|
+
|
package/code/base.jsy
CHANGED
|
@@ -1,41 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {_mqtt_dispatch} from './_dispatch.jsy'
|
|
1
|
+
import { _isfn, _isstr } from './_utils.jsy'
|
|
2
|
+
import { _mqtt_dispatch } from './_dispatch.jsy'
|
|
3
3
|
|
|
4
4
|
export class MQTTError extends Error ::
|
|
5
5
|
constructor(mqtt_pkt, reason=mqtt_pkt.reason) ::
|
|
6
|
+
// use hex-encoded reasons to match MQTT spec documentation
|
|
6
7
|
super(`[0x${reason.toString(16)}] ${reason.reason}`)
|
|
7
8
|
this.mqtt_pkt = mqtt_pkt
|
|
8
9
|
this.reason = reason
|
|
9
10
|
|
|
10
11
|
export class MQTTBase ::
|
|
11
|
-
constructor(opt={}) ::
|
|
12
|
-
this.with(opt)
|
|
13
|
-
this._conn_ = _mqtt_conn @ this,
|
|
14
|
-
this._init_dispatch(opt, this)
|
|
15
|
-
|
|
16
|
-
with(fns_ns) ::
|
|
17
|
-
for let [k,v] of Object.entries(fns_ns) ::
|
|
18
|
-
if 'function' === typeof v :: this[k] = v
|
|
19
|
-
return this
|
|
20
|
-
|
|
21
|
-
async conn_emit(evt, arg, err_arg) ::
|
|
22
|
-
this.log_conn?.(evt, arg, err_arg)
|
|
23
|
-
try ::
|
|
24
|
-
let fn_evt = this[await evt] // microtask break using `await evt`
|
|
25
|
-
if fn_evt ::
|
|
26
|
-
await fn_evt.call(this, this, arg, err_arg)
|
|
27
|
-
else if err_arg :: throw err_arg
|
|
28
|
-
catch err ::
|
|
29
|
-
this.on_error(err, evt)
|
|
30
|
-
|
|
31
|
-
on_error(err, evt) ::
|
|
32
|
-
console.warn @ '[[u8-mqtt error: %s]]', evt, err
|
|
33
|
-
|
|
34
12
|
// Handshaking Packets
|
|
35
|
-
|
|
36
13
|
async connect(pkt={}) ::
|
|
37
14
|
let cid = pkt.client_id
|
|
38
|
-
if
|
|
15
|
+
if ! _isstr(cid) ::
|
|
39
16
|
// see init_client_id implementation in core.jsy
|
|
40
17
|
pkt.client_id = cid = this.client_id || this.init_client_id(cid)
|
|
41
18
|
this.client_id = cid
|
|
@@ -43,23 +20,20 @@ export class MQTTBase ::
|
|
|
43
20
|
if null == pkt.keep_alive ::
|
|
44
21
|
pkt.keep_alive = 60
|
|
45
22
|
|
|
46
|
-
let
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
throw new this.MQTTError(res[0])
|
|
51
|
-
|
|
52
|
-
// TODO: merge with server's keep_alive frequency
|
|
53
|
-
this._conn_.ping(pkt.keep_alive)
|
|
54
|
-
return res
|
|
23
|
+
let response = await this._send0('connect', pkt, 'connack')
|
|
24
|
+
if 0 != response[0].reason :: // compare to 0 to coerce to number
|
|
25
|
+
throw new this.MQTTError(response[0])
|
|
26
|
+
return this.conn.on_conn(pkt, response)
|
|
55
27
|
|
|
56
28
|
async disconnect(pkt={}) ::
|
|
57
|
-
let
|
|
58
|
-
this.
|
|
59
|
-
return res
|
|
29
|
+
let response = await this._send0('disconnect', pkt)
|
|
30
|
+
return this.conn.on_dis(pkt, response)
|
|
60
31
|
|
|
61
|
-
auth(pkt={}) ::
|
|
62
|
-
|
|
32
|
+
async auth(pkt={}) ::
|
|
33
|
+
let response = await this._send0('auth', pkt, 'auth')
|
|
34
|
+
if response[0].reason ::
|
|
35
|
+
throw new this.MQTTError(response[0])
|
|
36
|
+
return this.conn.on_auth(pkt, response)
|
|
63
37
|
|
|
64
38
|
ping() :: return this._send('pingreq', null, 'pingresp')
|
|
65
39
|
puback({pkt_id}) :: return this._send('puback', {pkt_id})
|
|
@@ -96,20 +70,18 @@ export class MQTTBase ::
|
|
|
96
70
|
// alias: publish -- because 'pub' is shorter for semantic aliases above
|
|
97
71
|
async pub(pkt, pub_opt) ::
|
|
98
72
|
if undefined === pkt.payload ::
|
|
99
|
-
if
|
|
73
|
+
if _isfn(pub_opt) ::
|
|
74
|
+
// pub_opt as a function is fn_encode value
|
|
100
75
|
pub_opt = {fn_encode: pub_opt}
|
|
101
76
|
|
|
102
|
-
let
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
// return a single-value closure to publish packets
|
|
109
|
-
return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)
|
|
77
|
+
let msg = pkt.msg, fn_encode = pub_opt?.fn_encode
|
|
78
|
+
if null == msg || _isfn(msg) ::
|
|
79
|
+
// when msg is a function, return closure using fn_encode
|
|
80
|
+
if msg :: pub_opt = {...pub_opt, fn_encode: msg}
|
|
81
|
+
// return a single-value closure to publish packets
|
|
82
|
+
return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)
|
|
110
83
|
|
|
111
84
|
// Encode payload from msg; fn_encode allows alternative to JSON.stringify
|
|
112
|
-
let {fn_encode} = pub_opt || {}
|
|
113
85
|
pkt.payload = fn_encode
|
|
114
86
|
? await fn_encode(msg)
|
|
115
87
|
: JSON.stringify(msg)
|
|
@@ -121,31 +93,31 @@ export class MQTTBase ::
|
|
|
121
93
|
pkt = pub_opt.xform(pkt) || pkt
|
|
122
94
|
|
|
123
95
|
return this._send @ 'publish', pkt,
|
|
124
|
-
pkt.qos ? pkt :
|
|
96
|
+
pkt.qos ? pkt : null // key
|
|
125
97
|
|
|
126
98
|
|
|
127
99
|
// Internal API
|
|
128
100
|
|
|
129
|
-
/* async
|
|
101
|
+
/* async _send0(type, pkt) -- provided by conn and transport */
|
|
102
|
+
/* async _send(type, pkt) -- provided by conn and transport */
|
|
130
103
|
|
|
131
104
|
_init_dispatch(opt) ::
|
|
132
105
|
this.constructor?._once_()
|
|
133
106
|
let target = @{} __proto__: opt.on_mqtt_type
|
|
134
107
|
target.mqtt_publish ||=
|
|
135
108
|
this._init_router?.(opt, this, target)
|
|
136
|
-
return _mqtt_dispatch(
|
|
109
|
+
return _mqtt_dispatch(opt, target)
|
|
137
110
|
|
|
138
111
|
static _aliases() ::
|
|
139
112
|
return ' publish:pub sub:subscribe unsub:unsubscribe json_post:obj_post json_send:obj_send json_store:obj_store'
|
|
140
113
|
|
|
141
|
-
static _once_(
|
|
142
|
-
|
|
143
|
-
|
|
114
|
+
static _once_(klass=this) ::
|
|
115
|
+
klass._once_ = _=>0
|
|
116
|
+
var alias, name, p = klass.prototype
|
|
144
117
|
p.MQTTError = MQTTError
|
|
145
|
-
for
|
|
146
|
-
alias = alias.split(':')
|
|
147
|
-
|
|
148
|
-
if fn :: p[alias[0]] = fn
|
|
118
|
+
for alias of klass._aliases().split(/\s+/) ::
|
|
119
|
+
[alias, name] = alias.split(':')
|
|
120
|
+
p[alias] = p[name]
|
|
149
121
|
|
|
150
122
|
|
|
151
123
|
function _as_topics(pkt, ex, topic_prefix) ::
|