u8-mqtt 0.4.0 → 0.5.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 +3 -3
- package/cjs/basic-v4.cjs +107 -146
- package/cjs/basic-v4.cjs.map +1 -1
- package/cjs/basic-v5.cjs +106 -145
- package/cjs/basic-v5.cjs.map +1 -1
- package/cjs/index.cjs +163 -206
- package/cjs/index.cjs.map +1 -1
- package/cjs/v4.cjs +164 -207
- package/cjs/v4.cjs.map +1 -1
- package/cjs/v5.cjs +163 -206
- package/cjs/v5.cjs.map +1 -1
- package/code/_dispatch.jsy +16 -0
- package/code/base.jsy +72 -133
- package/code/core.jsy +15 -9
- package/code/router_path.jsy +38 -51
- package/code/with_topic_router.jsy +20 -11
- package/esm/basic-v4.js +1154 -0
- package/esm/basic-v4.js.map +1 -0
- package/esm/basic-v5.js +1416 -0
- package/esm/basic-v5.js.map +1 -0
- package/esm/deno/basic-v4.js +107 -146
- package/esm/deno/basic-v4.js.map +1 -1
- package/esm/deno/basic-v5.js +106 -145
- package/esm/deno/basic-v5.js.map +1 -1
- package/esm/deno/index.js +163 -206
- package/esm/deno/index.js.map +1 -1
- package/esm/deno/v4.js +164 -207
- package/esm/deno/v4.js.map +1 -1
- package/esm/deno/v5.js +163 -206
- package/esm/deno/v5.js.map +1 -1
- package/esm/index.js +1599 -0
- package/esm/index.js.map +1 -0
- package/esm/node/basic-v4.js +107 -146
- package/esm/node/basic-v4.js.map +1 -1
- package/esm/node/basic-v4.mjs +107 -146
- package/esm/node/basic-v4.mjs.map +1 -1
- package/esm/node/basic-v5.js +106 -145
- package/esm/node/basic-v5.js.map +1 -1
- package/esm/node/basic-v5.mjs +106 -145
- package/esm/node/basic-v5.mjs.map +1 -1
- package/esm/node/index.js +163 -206
- package/esm/node/index.js.map +1 -1
- package/esm/node/index.mjs +163 -206
- package/esm/node/index.mjs.map +1 -1
- package/esm/node/v4.js +164 -207
- package/esm/node/v4.js.map +1 -1
- package/esm/node/v4.mjs +164 -207
- package/esm/node/v4.mjs.map +1 -1
- package/esm/node/v5.js +163 -206
- package/esm/node/v5.js.map +1 -1
- package/esm/node/v5.mjs +163 -206
- package/esm/node/v5.mjs.map +1 -1
- package/esm/v4.js +1336 -0
- package/esm/v4.js.map +1 -0
- package/esm/v5.js +1599 -0
- package/esm/v5.js.map +1 -0
- package/esm/web/basic-v4.js +107 -146
- 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 +106 -145
- 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/index.js +163 -206
- 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 +164 -207
- 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 +163 -206
- 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/base.jsy
CHANGED
|
@@ -9,28 +9,34 @@ export class MQTTError extends Error ::
|
|
|
9
9
|
|
|
10
10
|
export class MQTTBase ::
|
|
11
11
|
constructor(opt={}) ::
|
|
12
|
+
this.with(opt)
|
|
12
13
|
this._conn_ = _mqtt_conn @ this,
|
|
13
14
|
this._init_dispatch(opt, this)
|
|
14
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
|
+
|
|
15
21
|
async conn_emit(evt, arg, err_arg) ::
|
|
16
22
|
this.log_conn?.(evt, arg, err_arg)
|
|
17
23
|
try ::
|
|
18
|
-
let fn_evt = this[await evt] // microtask break
|
|
24
|
+
let fn_evt = this[await evt] // microtask break using `await evt`
|
|
19
25
|
if fn_evt ::
|
|
20
26
|
await fn_evt.call(this, this, arg, err_arg)
|
|
21
|
-
else if err_arg ::
|
|
22
|
-
await this.on_error(err_arg, evt)
|
|
27
|
+
else if err_arg :: throw err_arg
|
|
23
28
|
catch err ::
|
|
24
29
|
this.on_error(err, evt)
|
|
25
30
|
|
|
26
|
-
on_error(err,
|
|
27
|
-
console.warn @ '[[u8-mqtt error: %s]]',
|
|
31
|
+
on_error(err, evt) ::
|
|
32
|
+
console.warn @ '[[u8-mqtt error: %s]]', evt, err
|
|
28
33
|
|
|
29
34
|
// Handshaking Packets
|
|
30
35
|
|
|
31
36
|
async connect(pkt={}) ::
|
|
32
|
-
let cid = pkt.client_id ||
|
|
33
|
-
if
|
|
37
|
+
let cid = pkt.client_id || this.client_id
|
|
38
|
+
if 'string' !== typeof cid ::
|
|
39
|
+
// see init_client_id implementation in core.jsy
|
|
34
40
|
pkt.client_id = cid = this.init_client_id(cid)
|
|
35
41
|
this.client_id = cid
|
|
36
42
|
|
|
@@ -56,12 +62,13 @@ export class MQTTBase ::
|
|
|
56
62
|
return this._send('auth', pkt, 'auth')
|
|
57
63
|
|
|
58
64
|
ping() :: return this._send('pingreq', null, 'pingresp')
|
|
59
|
-
|
|
65
|
+
puback({pkt_id}) :: return this._send('puback', {pkt_id})
|
|
60
66
|
|
|
61
67
|
// alias: sub
|
|
62
68
|
subscribe(pkt, ex, topic_prefix) ::
|
|
63
69
|
pkt = _as_topics(pkt, ex, topic_prefix)
|
|
64
|
-
|
|
70
|
+
let suback = this._send('subscribe', pkt, pkt)
|
|
71
|
+
return this.on_sub?.(suback, pkt) ?? suback
|
|
65
72
|
|
|
66
73
|
// alias: unsub
|
|
67
74
|
unsubscribe(pkt, ex, topic_prefix) ::
|
|
@@ -69,48 +76,52 @@ export class MQTTBase ::
|
|
|
69
76
|
return this._send('unsubscribe', pkt, pkt)
|
|
70
77
|
|
|
71
78
|
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
store(topic, payload, pub_opt) ::
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
obj_send(topic, msg, pub_opt) ::
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
79
|
+
post(topic, payload, pub_opt) :: // qos:0
|
|
80
|
+
return this.pub({topic, payload, qos:0}, pub_opt)
|
|
81
|
+
send(topic, payload, pub_opt) :: // qos:1
|
|
82
|
+
return this.pub({topic, payload, qos:1}, pub_opt)
|
|
83
|
+
store(topic, payload, pub_opt) :: // qos:1, retain: 1
|
|
84
|
+
return this.pub({topic, payload, qos:1, retain: 1}, pub_opt)
|
|
85
|
+
|
|
86
|
+
// alias: json_post
|
|
87
|
+
obj_post(topic, msg, pub_opt) :: // qos:0
|
|
88
|
+
return this.pub({topic, msg, arg: 'msg', qos:0}, pub_opt)
|
|
89
|
+
// alias: json_send
|
|
90
|
+
obj_send(topic, msg, pub_opt) :: // qos:1
|
|
91
|
+
return this.pub({topic, msg, arg: 'msg', qos:1}, pub_opt)
|
|
92
|
+
// alias: json_store
|
|
93
|
+
obj_store(topic, msg, pub_opt) :: // qos:1, retain: 1
|
|
94
|
+
return this.pub({topic, msg, arg: 'msg', qos:1, retain: 1}, pub_opt)
|
|
95
|
+
|
|
96
|
+
// alias: publish -- because 'pub' is shorter for semantic aliases above
|
|
97
|
+
async pub(pkt, pub_opt) ::
|
|
98
|
+
if undefined === pkt.payload ::
|
|
99
|
+
if 'function' === typeof pub_opt ::
|
|
100
|
+
pub_opt = {fn_encode: pub_opt}
|
|
101
|
+
|
|
102
|
+
let {msg} = pkt
|
|
103
|
+
switch typeof msg ::
|
|
104
|
+
case 'function':
|
|
105
|
+
pub_opt = {...pub_opt, fn_encode: msg}
|
|
106
|
+
// flow into 'undefined' case
|
|
107
|
+
case 'undefined':
|
|
108
|
+
// return a single-value closure to publish packets
|
|
109
|
+
return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)
|
|
110
|
+
|
|
111
|
+
// Encode payload from msg; fn_encode allows alternative to JSON.stringify
|
|
112
|
+
let {fn_encode} = pub_opt || {}
|
|
113
|
+
pkt.payload = fn_encode
|
|
114
|
+
? await fn_encode(msg)
|
|
115
|
+
: JSON.stringify(msg)
|
|
116
|
+
|
|
117
|
+
if pub_opt ::
|
|
118
|
+
if pub_opt.props ::
|
|
119
|
+
pkt.props = pub_opt.props
|
|
120
|
+
if pub_opt.xform ::
|
|
121
|
+
pkt = pub_opt.xform(pkt) || pkt
|
|
122
|
+
|
|
123
|
+
return this._send @ 'publish', pkt,
|
|
124
|
+
pkt.qos ? pkt : void 0 // key
|
|
114
125
|
|
|
115
126
|
|
|
116
127
|
// Internal API
|
|
@@ -119,52 +130,24 @@ export class MQTTBase ::
|
|
|
119
130
|
|
|
120
131
|
_init_dispatch(opt) ::
|
|
121
132
|
this.constructor?._once_()
|
|
122
|
-
let
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
__proto__: opt.on_mqtt_type || {}
|
|
127
|
-
router
|
|
128
|
-
|
|
129
|
-
tgt.mqtt_publish ||= router?.invoke
|
|
130
|
-
return _mqtt_dispatch(this, tgt)
|
|
133
|
+
let target = @{} __proto__: opt.on_mqtt_type
|
|
134
|
+
target.mqtt_publish ||=
|
|
135
|
+
this._init_router?.(opt, this, target)
|
|
136
|
+
return _mqtt_dispatch(this, target)
|
|
131
137
|
|
|
132
138
|
static _aliases() ::
|
|
133
|
-
return ' pub
|
|
139
|
+
return ' publish:pub sub:subscribe unsub:unsubscribe json_post:obj_post json_send:obj_send json_store:obj_store'
|
|
134
140
|
|
|
135
141
|
static _once_(self=this) ::
|
|
136
142
|
self._once_ = _=>0
|
|
137
|
-
self.MQTTError = MQTTError
|
|
138
143
|
let p = self.prototype
|
|
144
|
+
p.MQTTError = MQTTError
|
|
139
145
|
for let alias of self._aliases().split(/\s+/) ::
|
|
140
146
|
alias = alias.split(':')
|
|
141
147
|
let fn = alias[1] && p[alias[1]]
|
|
142
148
|
if fn :: p[alias[0]] = fn
|
|
143
149
|
|
|
144
150
|
|
|
145
|
-
/*
|
|
146
|
-
on_mqtt_type = {
|
|
147
|
-
mqtt_auth(pkt, ctx) ::
|
|
148
|
-
mqtt_connect(pkt, ctx) ::
|
|
149
|
-
mqtt_connack(pkt, ctx) ::
|
|
150
|
-
mqtt_disconnect(pkt, ctx) ::
|
|
151
|
-
|
|
152
|
-
mqtt_publish(pkt, ctx)
|
|
153
|
-
mqtt_subscribe(pkt, ctx) ::
|
|
154
|
-
mqtt_unsubscribe(pkt, ctx) ::
|
|
155
|
-
|
|
156
|
-
mqtt_pingreq(pkt, ctx) ::
|
|
157
|
-
mqtt_pingresp(pkt, ctx) ::
|
|
158
|
-
}
|
|
159
|
-
*/
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const _prefix_topics = (topic_prefix, iterable) =>
|
|
163
|
-
Array.from @ iterable, value => @
|
|
164
|
-
value.trim // string
|
|
165
|
-
? _prefix_topics(topic_prefix, value)
|
|
166
|
-
: topic_prefix + value
|
|
167
|
-
|
|
168
151
|
function _as_topics(pkt, ex, topic_prefix) ::
|
|
169
152
|
if ex?.trim :: // string
|
|
170
153
|
topic_prefix = ex
|
|
@@ -181,53 +164,9 @@ function _as_topics(pkt, ex, topic_prefix) ::
|
|
|
181
164
|
if topic_prefix ::
|
|
182
165
|
// particularly useful with shared queues, e.g.
|
|
183
166
|
// topic_prefix = '$share/some-queue-name/'
|
|
184
|
-
|
|
185
|
-
|
|
167
|
+
let _prefix_topics = v =>
|
|
168
|
+
v.trim ? topic_prefix+v : v.map(_prefix_topics)
|
|
186
169
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if undefined === pkt.payload ::
|
|
190
|
-
if 'function' === typeof pub_opt ::
|
|
191
|
-
pub_opt = {fn_encode: pub_opt}
|
|
192
|
-
|
|
193
|
-
let {msg} = pkt
|
|
194
|
-
switch typeof msg ::
|
|
195
|
-
case 'function':
|
|
196
|
-
pub_opt = {...pub_opt, fn_encode: msg}
|
|
197
|
-
// flow into 'undefined' case
|
|
198
|
-
case 'undefined':
|
|
199
|
-
// return a single-value closure to publish packets
|
|
200
|
-
return v => _pub(self, {...pkt, [pkt.arg || 'payload']: v}, pub_opt)
|
|
201
|
-
|
|
202
|
-
default:
|
|
203
|
-
// Encode payload from msg; fn_encode allows alternative to JSON.stringify
|
|
204
|
-
let {fn_encode} = pub_opt || {}
|
|
205
|
-
pkt.payload = fn_encode
|
|
206
|
-
? await fn_encode(msg)
|
|
207
|
-
: JSON.stringify(msg)
|
|
208
|
-
|
|
209
|
-
if pub_opt ::
|
|
210
|
-
if pub_opt.props ::
|
|
211
|
-
pkt.props = pub_opt.props
|
|
212
|
-
if pub_opt.xform ::
|
|
213
|
-
pkt = pub_opt.xform(pkt) || pkt
|
|
214
|
-
|
|
215
|
-
return self._send @ 'publish', pkt,
|
|
216
|
-
pkt.qos ? pkt : void 0 // key
|
|
217
|
-
|
|
218
|
-
::
|
|
219
|
-
Object.assign @ _pub, @{}
|
|
220
|
-
m: (self, topic, payload, pub_opt) =>
|
|
221
|
-
_pub(self, {topic, payload, qos:0}, pub_opt)
|
|
222
|
-
mq: (self, topic, payload, pub_opt) =>
|
|
223
|
-
_pub(self, {topic, payload, qos:1}, pub_opt)
|
|
224
|
-
mqr: (self, topic, payload, pub_opt) =>
|
|
225
|
-
_pub(self, {topic, payload, qos:1, retain: 1}, pub_opt)
|
|
226
|
-
|
|
227
|
-
o: (self, topic, msg, pub_opt) =>
|
|
228
|
-
_pub(self, {topic, msg, arg: 'msg', qos:0}, pub_opt)
|
|
229
|
-
oq: (self, topic, msg, pub_opt) =>
|
|
230
|
-
_pub(self, {topic, msg, arg: 'msg', qos:1}, pub_opt)
|
|
231
|
-
oqr: (self, topic, msg, pub_opt) =>
|
|
232
|
-
_pub(self, {topic, msg, arg: 'msg', qos:1, retain: 1}, pub_opt)
|
|
170
|
+
pkt.topics = pkt.topics.map(_prefix_topics)
|
|
171
|
+
return pkt
|
|
233
172
|
|
package/code/core.jsy
CHANGED
|
@@ -12,20 +12,27 @@ const pkt_api = {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export class MQTTCore extends MQTTBase ::
|
|
15
|
-
constructor(opt={}) ::
|
|
16
|
-
super(opt)
|
|
17
|
-
this.with(opt)
|
|
18
|
-
|
|
19
15
|
static mqtt_ctx(mqtt_level, mqtt_opts, pkt_ctx=pkt_api) ::
|
|
20
16
|
let self = class extends this {}
|
|
21
17
|
self.prototype.mqtt_ctx =
|
|
22
18
|
mqtt_pkt_ctx(mqtt_level, mqtt_opts, pkt_ctx)
|
|
23
19
|
return self
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
|
|
22
|
+
// automatic Client Id for connect()
|
|
23
|
+
init_client_id(parts=['u8-mqtt--','']) ::
|
|
24
|
+
let sess_stg=this.sess_stg
|
|
25
|
+
let key, cid = sess_stg?.getItem(key=parts.join(' '))
|
|
26
|
+
if ! cid ::
|
|
27
|
+
cid = parts.join @ Math.random().toString(36).slice(2)
|
|
28
|
+
sess_stg?.setItem(key, cid)
|
|
29
|
+
return cid
|
|
30
|
+
|
|
31
|
+
get sess_stg() :: return globalThis.sessionStorage
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
//on_error(err, evt) ::
|
|
35
|
+
// console.warn @ '[[u8-mqtt error: %s]]', evt, err
|
|
29
36
|
|
|
30
37
|
//log_conn(evt, arg, err_arg) ::
|
|
31
38
|
// console.info @ '[[u8-mqtt log: %s]]', evt, arg, err_arg
|
|
@@ -102,7 +109,6 @@ export class MQTTCore extends MQTTBase ::
|
|
|
102
109
|
#IF PLAT_NODEJS
|
|
103
110
|
with_tcp(...opt) ::
|
|
104
111
|
opt = this._conn_opt(opt)
|
|
105
|
-
console.log @: opt
|
|
106
112
|
return this._use_conn @=>
|
|
107
113
|
this.with_stream @
|
|
108
114
|
tcp_connect(opt)
|
package/code/router_path.jsy
CHANGED
|
@@ -10,17 +10,23 @@ export const with_topic_path_router = /* #__PURE__ */
|
|
|
10
10
|
|
|
11
11
|
const mqtt_topic = topic_route =>
|
|
12
12
|
topic_route
|
|
13
|
-
.replace
|
|
14
|
-
.replace
|
|
13
|
+
.replace @ /[*].*$/, '#'
|
|
14
|
+
.replace @ /:\w[^\/]*/g, '+'
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
/* From the [MQTT v5 Spec](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Topic_Names_and)
|
|
17
|
+
4.7.1.2 Multi-level wildcard -- (‘#’ U+0023)
|
|
18
|
+
... MUST be specified either on its own or following a topic level separator.
|
|
19
|
+
In either case it MUST be the last character specified in the Topic Filter
|
|
20
|
+
|
|
21
|
+
4.7.1.3 Single-level wildcard -- (‘+’ U+002B)
|
|
22
|
+
...it MUST occupy an entire level of the filter.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
export const as_topic_path = (topic_route, id) => @
|
|
26
|
+
id=1,
|
|
17
27
|
topic_route
|
|
18
|
-
.replace
|
|
19
|
-
.
|
|
20
|
-
.reduce @\ sz, v, idx => sz + @
|
|
21
|
-
idx & 1 // even entires are body, odd are MQTT + tokens
|
|
22
|
-
? `:$${1 + idx>>1}` // replace with `:$#` sequential ids, using ? for partial entries
|
|
23
|
-
: v // pass through body
|
|
28
|
+
.replace @ /#$/, '*' // replace MQTT '#' multi-level wildcard at end
|
|
29
|
+
.replace @ /\+/g, () => `:$${id++}` // replace MQTT '+' single-level wildcards
|
|
24
30
|
|
|
25
31
|
function _ignore(pkt, params, ctx) :: ctx.done = true
|
|
26
32
|
|
|
@@ -35,9 +41,8 @@ function mqtt_topic_path_router() ::
|
|
|
35
41
|
let priority = args.pop()
|
|
36
42
|
|
|
37
43
|
if 'function' !== typeof fn ::
|
|
38
|
-
if
|
|
39
|
-
|
|
40
|
-
else throw new TypeError()
|
|
44
|
+
if fn :: throw new TypeError()
|
|
45
|
+
fn = _ignore
|
|
41
46
|
|
|
42
47
|
let rte = _rxp_parse @ as_topic_path @ topic_route
|
|
43
48
|
|
|
@@ -53,7 +58,7 @@ function mqtt_topic_path_router() ::
|
|
|
53
58
|
clear(priority) ::
|
|
54
59
|
pri_lsts[priority ? 0 : 1] = []
|
|
55
60
|
if null == priority ::
|
|
56
|
-
pri_lsts[1] = []
|
|
61
|
+
pri_lsts[1] = [] // null clears both lists
|
|
57
62
|
|
|
58
63
|
async invoke(pkt, ctx) ::
|
|
59
64
|
ctx.idx = 0
|
|
@@ -69,51 +74,33 @@ function mqtt_topic_path_router() ::
|
|
|
69
74
|
break
|
|
70
75
|
else ctx.idx++
|
|
71
76
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
await ctx.mqtt._send('puback', {pkt_id})
|
|
77
|
+
if 1 === pkt.qos ::
|
|
78
|
+
await ctx.mqtt.puback(pkt)
|
|
75
79
|
|
|
76
80
|
|
|
77
81
|
function * _routes_iter(all_route_lists, topic) ::
|
|
82
|
+
topic = topic.replace(/^[\/]*/, '/') // ensure '/' prefix for regexparam library
|
|
78
83
|
for let route_list of all_route_lists ::
|
|
79
|
-
for let
|
|
80
|
-
let
|
|
81
|
-
if
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
: pattern.exec(topic)
|
|
89
|
-
|
|
90
|
-
if null === match ::
|
|
91
|
-
return
|
|
92
|
-
|
|
93
|
-
if false === keys ::
|
|
94
|
-
let {groups} = match
|
|
95
|
-
if ! groups ::
|
|
96
|
-
return [tgt]
|
|
97
|
-
|
|
98
|
-
let params = {}
|
|
99
|
-
for let k in groups ::
|
|
100
|
-
params[k] = groups[k]
|
|
101
|
-
|
|
102
|
-
return [tgt, params]
|
|
103
|
-
|
|
104
|
-
if 0 === keys.length ::
|
|
105
|
-
return [tgt]
|
|
106
|
-
|
|
107
|
-
let params = {}
|
|
108
|
-
for let i=0; i<keys.length; i++ ::
|
|
109
|
-
params[ keys[i] ] = match[1+i]
|
|
110
|
-
return [tgt, params]
|
|
84
|
+
for let {keys, pattern, tgt} of route_list ::
|
|
85
|
+
let match = pattern.exec(topic)
|
|
86
|
+
if match ::
|
|
87
|
+
let params = keys
|
|
88
|
+
? keys.reduce @
|
|
89
|
+
(o, k, i) => (o[k] = match[1+i], o)
|
|
90
|
+
{}
|
|
91
|
+
: match.groups ?? match
|
|
92
|
+
yield [tgt, params]
|
|
111
93
|
|
|
112
94
|
|
|
113
95
|
function _route_remove(all_route_lists, query) ::
|
|
114
|
-
let
|
|
96
|
+
let fn_match = route => @
|
|
97
|
+
route===query
|
|
98
|
+
|| route.tgt===query
|
|
99
|
+
|| route.key===query
|
|
115
100
|
for let lst of all_route_lists ::
|
|
116
|
-
let i = lst.findIndex(
|
|
117
|
-
if 0 <= i ::
|
|
101
|
+
let i = lst.findIndex(fn_match)
|
|
102
|
+
if 0 <= i ::
|
|
103
|
+
lst.splice(i,1)
|
|
104
|
+
return true
|
|
118
105
|
return false
|
|
119
106
|
|
|
@@ -14,28 +14,37 @@ export const with_topic_router = mqtt_topic_router =>
|
|
|
14
14
|
return super._aliases() +
|
|
15
15
|
' sub_topic:subscribe_topic unsub_topic:unsubscribe_topic'
|
|
16
16
|
|
|
17
|
-
_init_router(opt) ::
|
|
18
|
-
|
|
17
|
+
_init_router(opt, self, target) ::
|
|
18
|
+
this._subs = []
|
|
19
|
+
let router = this.router = target.router =
|
|
20
|
+
mqtt_topic_router(opt, this, target)
|
|
21
|
+
return router?.invoke
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
on_sub(suback, pkt) ::
|
|
24
|
+
suback.pkt = pkt
|
|
25
|
+
this._subs.push(suback)
|
|
26
|
+
return suback
|
|
27
|
+
subs_settled() ::
|
|
28
|
+
return Promise.allSettled @
|
|
29
|
+
this._subs.splice(0,Infinity)
|
|
27
30
|
|
|
28
31
|
// alias: sub_topic
|
|
29
32
|
subscribe_topic(topic_route, ...args) ::
|
|
30
33
|
let router = this.router
|
|
31
34
|
router.add @ topic_route, true, args.pop() // handler
|
|
32
35
|
let topic = router.mqtt_topic(topic_route)
|
|
33
|
-
|
|
36
|
+
this.subscribe @ topic, ...args // ex, topic_prefix
|
|
37
|
+
return this // fluent api -- return this and track side effects
|
|
34
38
|
|
|
35
39
|
// alias: unsub_topic
|
|
36
40
|
unsubscribe_topic(topic_route, ...args) ::
|
|
37
41
|
let router = this.router
|
|
38
42
|
router.remove @ topic_route, true
|
|
39
43
|
let topic = router.mqtt_topic(topic_route)
|
|
40
|
-
return this.unsubscribe @
|
|
44
|
+
return this.unsubscribe @ topic, ...args // topic_prefix
|
|
45
|
+
|
|
46
|
+
// add topic handlers without corresponding subscribe packet
|
|
47
|
+
on_topic(...args) ::
|
|
48
|
+
this.router.add(...args)
|
|
49
|
+
return this
|
|
41
50
|
|