0.1.13 add back keeping payload as is when passed in a packet

emit consumer-connection events
master
David Kebler 2019-09-08 19:53:51 -07:00
parent ec953c0123
commit a1a9eb0822
3 changed files with 24 additions and 11 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@uci/mqtt", "name": "@uci/mqtt",
"version": "0.1.12", "version": "0.1.13",
"description": "mqtt client with UCI json packet payloads", "description": "mqtt client with UCI json packet payloads",
"main": "src", "main": "src",
"scripts": { "scripts": {
@ -28,7 +28,7 @@
}, },
"homepage": "https://github.com/uCOMmandIt/uci-changeme#readme", "homepage": "https://github.com/uCOMmandIt/uci-changeme#readme",
"dependencies": { "dependencies": {
"@uci-utils/logger": "^0.0.15", "@uci-utils/logger": "^0.0.16",
"better-try-catch": "0.6.2", "better-try-catch": "0.6.2",
"is-plain-object": "^3.0.0", "is-plain-object": "^3.0.0",
"lodash.union": "^4.6.0", "lodash.union": "^4.6.0",
@ -40,7 +40,7 @@
"chai": "^4.2.0", "chai": "^4.2.0",
"delay": "^4.3.0", "delay": "^4.3.0",
"esm": "^3.2.25", "esm": "^3.2.25",
"mocha": "^6.2.0", "mocha": "^6.2.2",
"nodemon": "^1.19.1" "nodemon": "^2.0.0"
} }
} }

View File

@ -2,4 +2,7 @@
This module integrates MQTT messaging with UCI Packet Messaging. This module integrates MQTT messaging with UCI Packet Messaging.
One can use it as a standard mqtt pub/sub but also provides a transport and functionality for UCI packets via send and push METHODS
In which case they instance can act like a consumer/client (send) or server/socket (push) based on client option
One can `send` a UCI JSON packet and by default the command will be translated into the MQTT Topic and the remainder into the payload and vice versa a listener waits for incoming MQTT messages translates them to UCI packages One can `send` a UCI JSON packet and by default the command will be translated into the MQTT Topic and the remainder into the payload and vice versa a listener waits for incoming MQTT messages translates them to UCI packages

View File

@ -33,6 +33,7 @@ class MQTTClient extends EventEmitter {
this.url = opts.url || null this.url = opts.url || null
this.client = opts.client || false this.client = opts.client || false
this.sendTopic = opts.sendTopic || 'uci/send' this.sendTopic = opts.sendTopic || 'uci/send'
this.opts = opts
// these are the "listen" topics to which the instance will subscribe. By default that will include the instance ID // these are the "listen" topics to which the instance will subscribe. By default that will include the instance ID
// default subscription topics can be string of commna delimited or array of strings. If none they by default topic is id // default subscription topics can be string of commna delimited or array of strings. If none they by default topic is id
this.topics = opts.topics ? (Array.isArray(opts.topics) ? opts.topics : opts.topics.split(',')) : [] this.topics = opts.topics ? (Array.isArray(opts.topics) ? opts.topics : opts.topics.split(',')) : []
@ -47,6 +48,8 @@ class MQTTClient extends EventEmitter {
this.client ? this.send = this._send.bind(this) : this.push = this._push.bind(this) this.client ? this.send = this._send.bind(this) : this.push = this._push.bind(this)
} }
// TODO add UCI authentication and MQTT authentication
get connected() { return this._connected } get connected() { return this._connected }
/** /**
@ -73,11 +76,15 @@ class MQTTClient extends EventEmitter {
log.debug({method:'connect', line:71, msg:'mqtt client reconnected to broker'}) log.debug({method:'connect', line:71, msg:'mqtt client reconnected to broker'})
this._connected=true this._connected=true
this._subscribe(this.topics) // resubscribe this._subscribe(this.topics) // resubscribe
this.emit('status',{level:'info', msg:'reconnected', id:this.id, opts:this.opts, connected:this._connected})
this.emit('consumer-connection', {state:'reconnected', id:this.id})
if (this.opts.conPacket) this.send(this.conPacket)
}) })
this.mqtt.on('error', err => { this.mqtt.on('error', err => {
this.emit('status',{level:'fatal', method:'connect', err: err, msg:'connection error to broker'}) this.emit('status',{level:'fatal', method:'connect', err: err, msg:'connection error to broker'})
log.fatal({method:'connect', line:76, err: err, msg:'connection error to broker'}) log.fatal({method:'connect', line:76, err: err, msg:'connection error to broker'})
this.emit('consumer-connection', {state:'disconnected', id:this.id})
this._connected=false this._connected=false
}) })
@ -97,7 +104,12 @@ class MQTTClient extends EventEmitter {
this._connected=true this._connected=true
let [err] = await btc(this._subscribe)(this.topics) // initial subscriptions let [err] = await btc(this._subscribe)(this.topics) // initial subscriptions
if (err) reject({error:'unable to subscribe to topics after connection', err:err}) if (err) reject({error:'unable to subscribe to topics after connection', err:err})
resolve(`mqtt client connected to broker at ${this.mqtt.options.hostname}:${this.mqtt.options.port}`) else{
this.emit('status',{level:'info', msg:'connected', id:this.id, opts:this.opts, connected:this._connected})
this.emit('consumer-connection', {state:'connected', id:this.id})
if (this.opts.conPacket) this.send(this.conPacket)
resolve(`mqtt client connected to broker at ${this.mqtt.options.hostname}:${this.mqtt.options.port}`)
}
}) })
}) //end promise }) //end promise
} }
@ -125,7 +137,7 @@ class MQTTClient extends EventEmitter {
} }
// solely for primary of sending uci packets. Use publish for typical mqtt messaging // solely for primary of sending uci packets. Use publish for typical mqtt messaging
// if topic not passed, nor a severID supplied in the options then it will send to teh topic given by the cmd // if topic not passed then it will send to the topic given by the cmd
async _send(ipacket, topic, options) { // packet is required async _send(ipacket, topic, options) { // packet is required
if (isPlainObject(topic)) { // if neither then assume none and what is passed is options if (isPlainObject(topic)) { // if neither then assume none and what is passed is options
@ -199,7 +211,7 @@ class MQTTClient extends EventEmitter {
// this is internal UCI publish // this is internal UCI publish
async _publish(packet,topic,options) { async _publish(packet,topic,options) {
if(!topic) return {error: 'no topic to which to publish packet'} if(!topic) return {error: 'no topic to which to publish packet'}
let payload = this._serialize(packet) // payload is entire packet let payload = packet.payload ? (typeof packet.payload ==='string' ? packet.payload : this._serialize(packet)) : this._serialize(packet) // payload is entire packet
if (!payload) { if (!payload) {
log.error({method:'send', line:163, msg:'not able to serilaize packet', packet:packet}) log.error({method:'send', line:163, msg:'not able to serilaize packet', packet:packet})
return {error:'not able to serilaize packet', packet:packet} return {error:'not able to serilaize packet', packet:packet}
@ -254,8 +266,6 @@ class MQTTClient extends EventEmitter {
} }
return payload return payload
} }
// TODO if client set up reply subscription with message id and then emit that for resolving send
// if server then take id and send message back with that appended to topic
_listen() { _listen() {
log.debug({method:'_listen', line:147, msg:`listening for incoming mqtt packets from broker on topics ${this.topics}`}) log.debug({method:'_listen', line:147, msg:`listening for incoming mqtt packets from broker on topics ${this.topics}`})
@ -269,8 +279,8 @@ class MQTTClient extends EventEmitter {
this.emit('payload',{topic:topic, payload:payload}) // emit 'payload' event for use for standard mqtt pub/sub this.emit('payload',{topic:topic, payload:payload}) // emit 'payload' event for use for standard mqtt pub/sub
let header = Object.assign({},packet._header) // save the header in case a packet processor deletes it let header = Object.assign({},packet._header) // save the header in case a packet processor deletes it
let res = await this._packetProcess(packet) let res = await this._packetProcess(packet)
if (header && this.client) this.emit(header.id,packet) if (header && this.client) this.emit(header.id,packet) // is acting like a client then emit returned packet
else { else { // act like a server, process and return reply
res._header = header res._header = header
log.info({method:'_listen', line:159, msg:'processed packet - return only if sent not published', processed:res}) log.info({method:'_listen', line:159, msg:'processed packet - return only if sent not published', processed:res})
if (res._header) { if (res._header) {