package/test/connection-v5.js000644 0000001740 3560116604 013266 0ustar00000000 000000 /* global describe, beforeEach, it */ /** * Testing requires */ var stream = require('./util').testStream var should = require('should') /** * Units under test */ var Connection = require('../connection') describe('Connection-v5', function () { beforeEach(function () { this.stream = stream() this.conn = new Connection(this.stream, { protocolVersion: 5 }) this.readFromStream = (stream, length, cb) => { var buf, done stream.on('data', data => { if (done) return buf = buf ? Buffer.concat([ buf, data ]) : data if (buf.length >= length) { cb(buf.slice(0, length)) done = true } }) } }) it('should start piping in the next tick', function (done) { should(this.stream._readableState.flowing).eql(null) process.nextTick(() => { this.stream._readableState.flowing.should.eql(true) done() }) }) describe('transmission-v5', require('./connection.transmit-v5.js')) }) package/connection.js000644 0000005016 3560116604 011757 0ustar00000000 000000 'use strict' var generateStream = require('./lib/generateStream') var parseStream = require('./lib/parseStream') var writeToStream = require('./lib/writeToStream') var Duplexify = require('duplexify') var inherits = require('inherits') function emitPacket (packet) { this.emit(packet.cmd, packet) } function Connection (duplex, opts, cb) { if (!(this instanceof Connection)) { return new Connection(duplex, opts) } if (typeof opts === 'function') { cb = opts opts = {} } opts = opts || {} this._generator = writeToStream(duplex, opts) this._parser = parseStream(opts) // defer piping, so consumer can attach event listeners // otherwise we might lose events process.nextTick(() => { duplex.pipe(this._parser) }) this._generator.on('error', this.emit.bind(this, 'error')) this._parser.on('error', this.emit.bind(this, 'error')) this.stream = duplex duplex.on('error', this.emit.bind(this, 'error')) duplex.on('close', this.emit.bind(this, 'close')) Duplexify.call(this, this._generator, this._parser, { objectMode: true }) // MQTT.js basic default if (opts.notData !== true) { var that = this this.once('data', function (connectPacket) { that.setOptions(connectPacket, opts) that.on('data', emitPacket) if (cb) { cb() } that.emit('data', connectPacket) }) } } inherits(Connection, Duplexify) ;['connect', 'connack', 'publish', 'puback', 'pubrec', 'pubrel', 'pubcomp', 'subscribe', 'suback', 'unsubscribe', 'unsuback', 'pingreq', 'pingresp', 'disconnect', 'auth' ].forEach(function (cmd) { Connection.prototype[cmd] = function (opts, cb) { opts = opts || {} opts.cmd = cmd // Flush the buffer if needed // UGLY hack, we should listen for the 'drain' event // and start writing again, but this works too this.write(opts) if (cb) setImmediate(cb) } }) Connection.prototype.destroy = function () { if (this.stream.destroy) this.stream.destroy() else this.stream.end() } Connection.prototype.setOptions = function (packet, opts) { let options = {} Object.assign(options, packet) // Specifically set the protocol version for client connections if (options.cmd === 'connack') { options.protocolVersion = opts && opts.protocolVersion ? opts.protocolVersion : 4 } this.options = options this._parser.setOptions(options) this._generator.setOptions(options) } module.exports = Connection module.exports.parseStream = parseStream module.exports.generateStream = generateStream package/test/connection.js000644 0000001767 3560116604 012747 0ustar00000000 000000 /* global describe, beforeEach, it */ /** * Testing requires */ var stream = require('./util').testStream var should = require('should') /** * Units under test */ var Connection = require('../connection') describe('Connection', function () { beforeEach(function () { this.stream = stream() this.conn = new Connection(this.stream) this.readFromStream = (stream, length, cb) => { var buf, done stream.on('data', data => { if (done) return buf = buf ? Buffer.concat([ buf, data ]) : data if (buf.length >= length) { cb(buf.slice(0, length)) done = true } }) } }) it('should start piping in the next tick', function (done) { should(this.stream._readableState.flowing).eql(null) process.nextTick(() => { this.stream._readableState.flowing.should.eql(true) done() }) }) describe('parsing', require('./connection.parse.js')) describe('transmission', require('./connection.transmit.js')) }) package/test/connection.parse.js000644 0000037522 3560116604 014056 0ustar00000000 000000 /* global describe, it */ /** * Testing requires */ var Buffer = require('safe-buffer').Buffer var should = require('should') var stream = require('./util').testStream // This is so we can use eql to compare Packet objects with plain objects: should.config.checkProtoEql = false /** * Units under test */ var Connection = require('../connection') module.exports = function () { describe('connect', function () { it('should fire a connect event (minimal)', function (done) { var expected = { cmd: 'connect', retain: false, qos: 0, dup: false, length: 18, protocolId: 'MQIsdp', protocolVersion: 3, clean: false, keepalive: 30, clientId: 'test', topic: null, payload: null } var fixture = [ 16, 18, // Header 0, 6, // Protocol id length 77, 81, 73, 115, 100, 112, // Protocol id 3, // Protocol version 0, // Connect flags 0, 30, // Keepalive 0, 4, // Client id length 116, 101, 115, 116 // Client id ] this.stream.write(Buffer.from(fixture)) this.conn.once('connect', function (packet) { packet.should.eql(expected) done() }) }) it('should fire a connect event (maximal)', function (done) { var expected = { cmd: 'connect', retain: false, qos: 0, dup: false, length: 54, protocolId: 'MQIsdp', protocolVersion: 3, will: { retain: true, qos: 2, topic: 'topic', payload: Buffer.from('payload') }, clean: true, keepalive: 30, clientId: 'test', username: 'username', password: Buffer.from('password'), topic: null, payload: null } var fixture = [ 16, 54, // Header 0, 6, // Protocol id length 77, 81, 73, 115, 100, 112, // Protocol id 3, // Protocol version 246, // Connect flags 0, 30, // Keepalive 0, 4, // Client id length 116, 101, 115, 116, // Client id 0, 5, // Will topic length 116, 111, 112, 105, 99, // Will topic 0, 7, // Will payload length 112, 97, 121, 108, 111, 97, 100, // Will payload 0, 8, // Username length 117, 115, 101, 114, 110, 97, 109, 101, // Username 0, 8, // Password length 112, 97, 115, 115, 119, 111, 114, 100 // Password ] this.stream.write(Buffer.from(fixture)) this.conn.once('connect', function (packet) { packet.should.eql(expected) done() }) }) describe('parse errors', function () { it('should say protocol not parseable', function (done) { var fixture = [ 16, 4, 0, 6, 77, 81 ] this.stream.write(Buffer.from(fixture)) this.conn.once('error', function (err) { err.message.should.match(/cannot parse protocolId/i) done() }) }) }) }) describe('connack', function () { it('should fire a connack event (rc = 0)', function (done) { var expected = { cmd: 'connack', retain: false, qos: 0, dup: false, length: 2, sessionPresent: false, returnCode: 0, topic: null, payload: null } var fixture = [32, 2, 0, 0] this.stream.write(Buffer.from(fixture)) this.conn.once('connack', function (packet) { packet.should.eql(expected) done() }) }) it('should fire a connack event (rc = 5)', function (done) { var expected = { cmd: 'connack', retain: false, qos: 0, dup: false, length: 2, sessionPresent: false, returnCode: 5, topic: null, payload: null } var fixture = [32, 2, 0, 5] this.stream.write(Buffer.from(fixture)) this.conn.once('connack', function (packet) { packet.should.eql(expected) done() }) }) }) describe('publish', function () { it('should fire a publish event (minimal)', function (done) { var expected = { cmd: 'publish', retain: false, qos: 0, dup: false, length: 10, topic: 'test', payload: Buffer.from('test') } var fixture = [ 48, 10, // Header 0, 4, // Topic length 116, 101, 115, 116, // Topic (test) 116, 101, 115, 116 // Payload (test) ] this.stream.write(Buffer.from(fixture)) this.conn.once('publish', function (packet) { packet.should.eql(expected) done() }) }) it('should fire a publish event with 2KB payload', function (done) { var expected = { cmd: 'publish', retain: false, qos: 0, dup: false, length: 2054, topic: 'test', payload: Buffer.allocUnsafe(2048) } var fixture = Buffer.from([ 48, 134, 16, // Header 0, 4, // Topic length 116, 101, 115, 116 // Topic (test) ]) fixture = Buffer.concat([fixture, expected.payload]) var s = stream() var c = new Connection(s) s.write(fixture) c.once('publish', function (packet) { packet.should.eql(expected) done() }) }) it('should fire a publish event with 2MB payload', function (done) { var expected = { cmd: 'publish', retain: false, qos: 0, dup: false, length: 6 + 2 * 1024 * 1024, topic: 'test', payload: Buffer.allocUnsafe(2 * 1024 * 1024) } var fixture = Buffer.from([ 48, 134, 128, 128, 1, // Header 0, 4, // Topic length 116, 101, 115, 116 // Topic (test) ]) fixture = Buffer.concat([fixture, expected.payload]) var s = stream() var c = new Connection(s) s.write(fixture) c.once('publish', function (packet) { // Comparing the whole 2MB buffer is very slow so only check the length packet.length.should.eql(expected.length) done() }) }) it('should fire a publish event (maximal)', function (done) { var expected = { cmd: 'publish', retain: true, qos: 2, length: 12, dup: true, topic: 'test', messageId: 10, payload: Buffer.from('test') } var fixture = [ 61, 12, // Header 0, 4, // Topic length 116, 101, 115, 116, // Topic 0, 10, // Message id 116, 101, 115, 116 // Payload ] this.stream.write(Buffer.from(fixture)) this.conn.once('publish', function (packet) { packet.should.eql(expected) done() }) }) it('should fire an empty publish', function (done) { var expected = { cmd: 'publish', retain: false, qos: 0, dup: false, length: 6, topic: 'test', payload: Buffer.allocUnsafe(0) } var fixture = [ 48, 6, // Header 0, 4, // Topic length 116, 101, 115, 116 // Topic // Empty payload ] this.stream.write(Buffer.from(fixture)) this.conn.once('publish', function (packet) { packet.should.eql(expected) done() }) }) it('should parse a splitted publish', function (done) { var expected = { cmd: 'publish', retain: false, qos: 0, dup: false, length: 10, topic: 'test', payload: Buffer.from('test') } var fixture1 = [ 48, 10, // Header 0, 4, // Topic length 116, 101, 115, 116 // Topic (test) ] var fixture2 = [ 116, 101, 115, 116 // Payload (test) ] this.stream.write(Buffer.from(fixture1)) this.stream.write(Buffer.from(fixture2)) this.conn.once('publish', function (packet) { packet.should.eql(expected) done() }) }) }) describe('puback', function () { it('should fire a puback event', function (done) { var expected = { cmd: 'puback', retain: false, qos: 0, dup: false, length: 2, messageId: 2, topic: null, payload: null } var fixture = [ 64, 2, // Header 0, 2 // Message id ] this.stream.write(Buffer.from(fixture)) this.conn.once('puback', function (packet) { packet.should.eql(expected) done() }) }) }) describe('pubrec', function () { it('should fire a pubrec event', function (done) { var expected = { cmd: 'pubrec', retain: false, qos: 0, dup: false, length: 2, messageId: 3, topic: null, payload: null } var fixture = [ 80, 2, // Header 0, 3 // Message id ] this.stream.write(Buffer.from(fixture)) this.conn.once('pubrec', function (packet) { packet.should.eql(expected) done() }) }) }) describe('pubrel', function () { it('should fire a pubrel event', function (done) { var expected = { cmd: 'pubrel', retain: false, qos: 0, dup: false, length: 2, messageId: 4, topic: null, payload: null } var fixture = [ 96, 2, // Header 0, 4 // Message id ] this.stream.write(Buffer.from(fixture)) this.conn.once('pubrel', function (packet) { packet.should.eql(expected) done() }) }) }) describe('pubcomp', function () { it('should fire a pubcomp event', function (done) { var expected = { cmd: 'pubcomp', retain: false, qos: 0, dup: false, length: 2, messageId: 5, topic: null, payload: null } var fixture = [ 112, 2, // Header 0, 5 // Message id ] this.stream.write(Buffer.from(fixture)) this.conn.once('pubcomp', function (packet) { packet.should.eql(expected) done() }) }) }) describe('subscribe', function () { it('should fire a subscribe event (1 topic)', function (done) { var expected = { cmd: 'subscribe', retain: false, qos: 1, dup: false, length: 9, subscriptions: [ { topic: 'test', qos: 0 } ], messageId: 6, topic: null, payload: null } var fixture = [ 130, 9, // Header (publish, qos=1, length=9) 0, 6, // Message id (6) 0, 4, // Topic length, 116, 101, 115, 116, // Topic (test) 0 // Qos (0) ] this.stream.write(Buffer.from(fixture)) this.conn.once('subscribe', function (packet) { packet.should.eql(expected) done() }) }) it('should fire a subscribe event (3 topic)', function (done) { var expected = { cmd: 'subscribe', retain: false, qos: 1, dup: false, length: 23, subscriptions: [ { topic: 'test', qos: 0 }, { topic: 'uest', qos: 1 }, { topic: 'tfst', qos: 2 } ], messageId: 6, topic: null, payload: null } var fixture = [ 130, 23, // Header (publish, qos=1, length=9) 0, 6, // Message id (6) 0, 4, // Topic length, 116, 101, 115, 116, // Topic (test) 0, // Qos (0) 0, 4, // Topic length 117, 101, 115, 116, // Topic (uest) 1, // Qos (1) 0, 4, // Topic length 116, 102, 115, 116, // Topic (tfst) 2 // Qos (2) ] this.stream.write(Buffer.from(fixture)) this.conn.once('subscribe', function (packet) { packet.should.eql(expected) done() }) }) }) describe('suback', function () { it('should fire a suback event', function (done) { var expected = { cmd: 'suback', retain: false, qos: 0, dup: false, length: 6, granted: [0, 1, 2, 128], messageId: 6, topic: null, payload: null } var fixture = [ 144, 6, // Header 0, 6, // Message id 0, 1, 2, 128 // Granted qos (0, 1, 2) and a rejected being 0x80 ] this.stream.write(Buffer.from(fixture)) this.conn.once('suback', function (packet) { packet.should.eql(expected) done() }) }) }) describe('unsubscribe', function () { it('should fire an unsubscribe event', function (done) { var expected = { cmd: 'unsubscribe', retain: false, qos: 1, dup: false, length: 14, unsubscriptions: [ 'tfst', 'test' ], messageId: 7, topic: null, payload: null } var fixture = [ 162, 14, 0, 7, // Message id (7) 0, 4, // Topic length 116, 102, 115, 116, // Topic (tfst) 0, 4, // Topic length, 116, 101, 115, 116 // Topic (test) ] this.stream.write(Buffer.from(fixture)) this.conn.once('unsubscribe', function (packet) { packet.should.eql(expected) done() }) }) }) describe('unsuback', function () { it('should fire a unsuback event', function (done) { var expected = { cmd: 'unsuback', retain: false, qos: 0, dup: false, length: 2, messageId: 8, topic: null, payload: null } var fixture = [ 176, 2, // Header 0, 8 // Message id ] this.stream.write(Buffer.from(fixture)) this.conn.once('unsuback', function (packet) { packet.should.eql(expected) done() }) }) }) describe('pingreq', function () { it('should fire a pingreq event', function (done) { var expected = { cmd: 'pingreq', retain: false, qos: 0, dup: false, length: 0, topic: null, payload: null } var fixture = [ 192, 0 // Header ] this.stream.write(Buffer.from(fixture)) this.conn.once('pingreq', function (packet) { packet.should.eql(expected) done() }) }) }) describe('pingresp', function () { it('should fire a pingresp event', function (done) { var expected = { cmd: 'pingresp', retain: false, qos: 0, dup: false, length: 0, topic: null, payload: null } var fixture = [ 208, 0 // Header ] this.stream.write(Buffer.from(fixture)) this.conn.once('pingresp', function (packet) { packet.should.eql(expected) done() }) }) }) describe('disconnect', function () { it('should fire a disconnect event', function (done) { var expected = { cmd: 'disconnect', retain: false, qos: 0, dup: false, length: 0, topic: null, payload: null } var fixture = [ 224, 0 // Header ] this.stream.write(Buffer.from(fixture)) this.conn.once('disconnect', function (packet) { packet.should.eql(expected) done() }) }) }) describe('reserverd (15)', function () { it('should emit an error', function (done) { var fixture = [ 240, 0 // Header ] this.stream.write(Buffer.from(fixture)) this.conn.once('error', function () { done() }) }) }) describe('reserverd (0)', function () { it('should emit an error', function (done) { var fixture = [ 0, 0 // Header ] this.stream.write(Buffer.from(fixture)) this.conn.once('error', function () { done() }) }) }) } package/test/connection.transmit-v5.js000644 0000001405 3560116604 015124 0ustar00000000 000000 /* global describe, it */ /** * Testing requires */ /** * Unit under test */ module.exports = function () { describe('#subscribe-5.0', function () { it('should send a 5.0 subscribe packet (single)', function (done) { var expected = Buffer.from([ 130, 10, // Header 0, 7, // Message id 0, // Properties 0, 4, // Topic length 116, 101, 115, 116, // Topic 0 // Qos=0 ]) var fixture = { messageId: 7, subscriptions: [ { topic: 'test', qos: 0 } ] } this.conn.subscribe(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) }) } package/test/connection.transmit.js000644 0000064545 3560116604 014612 0ustar00000000 000000 /* global describe, it */ /** * Testing requires */ var stream = require('./util').testStream /** * Unit under test */ var Connection = require('../connection') module.exports = function () { describe('#connect', function () { it('should send a connect packet (minimal)', function (done) { var expected = Buffer.from([ 16, 18, // Header 0, 6, 77, 81, 73, 115, 100, 112, // Protocol Id 3, // Protocol version 0, // Connect flags 0, 30, // Keepalive 0, 4, // Client id length 116, 101, 115, 116 // Client Id ]) var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: 'test', keepalive: 30, clean: false } this.conn.connect(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should send a connect packet (maximal)', function (done) { var expected = Buffer.from([ 16, 54, // Header 0, 6, 77, 81, 73, 115, 100, 112, // Protocol Id 3, // Protocol version 246, // Connect flags (u=1,p=1,wr=1,wq=2,wf=1,c=1) 0, 30, // Keepalive (30) 0, 4, // Client id length 116, 101, 115, 116, // Client Id 0, 5, // Will topic length 116, 111, 112, 105, 99, // Will topic ('topic') 0, 7, // Will payload length 112, 97, 121, 108, 111, 97, 100, // ('payload') 0, 8, // Username length 117, 115, 101, 114, 110, 97, 109, 101, // ('username') 0, 8, // Password length 112, 97, 115, 115, 119, 111, 114, 100 // ('password') ]) var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: 'test', keepalive: 30, will: { topic: 'topic', payload: 'payload', qos: 2, retain: true }, clean: true, username: 'username', password: 'password' } this.conn.connect(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should send a connect packet with binary username/password', function (done) { var expected = Buffer.from([ 16, 28, // Header 0, 6, 77, 81, 73, 115, 100, 112, // Protocol Id 3, // Protocol version 0x40 | 0x80, // Connect flags 0, 30, // Keepalive 0, 4, // Client id length 116, 101, 115, 116, // Client Id 0, 3, // Username length 12, 13, 14, // Username 0, 3, // Password length 15, 16, 17 // Password ]) var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: 'test', keepalive: 30, clean: false, username: Buffer.from([12, 13, 14]), password: Buffer.from([15, 16, 17]) } var s = stream() var c = new Connection(s, { encoding: 'binary' }) s.removeAllListeners() c.connect(fixture) this.readFromStream(s, expected.length, data => { data.should.eql(expected) done() }) }) it('should send a connect packet with binary will payload', function (done) { var expected = Buffer.from([ 16, 50, // Header 0, 6, 77, 81, 73, 115, 100, 112, // Protocol Id 3, // Protocol version 246, // Connect flags 0, 30, // Keepalive 0, 4, // Client id length 116, 101, 115, 116, // Client Id 0, 5, // Will topic length 116, 111, 112, 105, 99, // Will topic ('topic') 0, 3, // Will payload length 18, 19, 20, // Will payload 0, 8, // Username length 117, 115, 101, 114, 110, 97, 109, 101, // ('username') 0, 8, // Password length 112, 97, 115, 115, 119, 111, 114, 100 // ('password') ]) var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: 'test', keepalive: 30, will: { topic: 'topic', payload: Buffer.from([18, 19, 20]), qos: 2, retain: true }, clean: true, username: 'username', password: 'password' } var s = stream() var c = new Connection(s, { encoding: 'binary' }) s.removeAllListeners() c.connect(fixture) this.readFromStream(s, expected.length, data => { data.should.eql(expected) done() }) }) it('should send a connect packet with unicode will payload', function (done) { var expected = Buffer.from([ 16, 49, // Header 0, 6, 77, 81, 73, 115, 100, 112, // Protocol Id 3, // Protocol version 246, // Connect flags 0, 30, // Keepalive 0, 4, // Client id length 116, 101, 115, 116, // Client Id 0, 5, // Will topic length 116, 111, 112, 105, 99, // Will topic ('topic') 0, 2, // Will payload length 194, 167, // Will payload - '§' 0, 8, // Username length 117, 115, 101, 114, 110, 97, 109, 101, // ('username') 0, 8, // Password length 112, 97, 115, 115, 119, 111, 114, 100 // ('password') ]) var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: 'test', keepalive: 30, will: { topic: 'topic', payload: '§', qos: 2, retain: true }, clean: true, username: 'username', password: 'password' } var s = stream() var c = new Connection(s, { encoding: 'binary' }) s.removeAllListeners() c.connect(fixture) this.readFromStream(s, expected.length, data => { data.should.eql(expected) done() }) }) describe('invalid options', function () { describe('protocol id', function () { it('should reject non-string', function (done) { var fixture = { protocolId: 42, protocolVersion: 3, clientId: 'test', keepalive: 30 } var expectedErr = 'Invalid protocolId' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) }) describe('protocol version', function () { it('should reject non-number', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: [], clientId: 'test', keepalive: 30 } var expectedErr = 'Invalid protocol version' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) it('should reject >255', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: 300, clientId: 'test', keepalive: 30 } var expectedErr = 'Invalid protocol version' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) it('should reject <0', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: -20, clientId: 'test', keepalive: 30 } var expectedErr = 'Invalid protocol version' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) }) describe('client id', function () { it('should reject non-present', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, keepalive: 30 } var expectedErr = 'clientId must be supplied before 3.1.1' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) it('should reject empty', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: '', keepalive: 30 } var expectedErr = 'clientId must be supplied before 3.1.1' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) it('should reject non-string', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: {}, keepalive: 30 } var expectedErr = 'clientId must be supplied before 3.1.1' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) }) describe('keepalive', function () { it('should reject non-number', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: 'test', keepalive: 'blah' } var expectedErr = 'Invalid keepalive' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) it('should reject < 0', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: 'test', keepalive: -2 } var expectedErr = 'Invalid keepalive' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) it('should reject > 65535', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: 'test', keepalive: 65536 } var expectedErr = 'Invalid keepalive' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) }) describe('will', function () { it('should reject non-object', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: 'test', keepalive: 30, will: 'test' } var expectedErr = 'Invalid will' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) it('should reject will without valid topic', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: 'test', keepalive: 30, will: { topic: 0, payload: 'test', qos: 0, retain: false } } var expectedErr = 'Invalid will topic' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) it('should reject will without valid payload', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: 'test', keepalive: 30, will: { topic: 'test', payload: 42, qos: 0, retain: false } } var expectedErr = 'Invalid will payload' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) it.skip('should reject will with invalid qos', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: 'test', keepalive: 30, will: { topic: 'test', payload: 'test', qos: '', retain: false } } var expectedErr = 'Invalid will qos' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) }) describe('username', function () { it('should reject invalid username', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: 'test', keepalive: 30, username: 30 } var expectedErr = 'Invalid username' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) }) describe('password', function () { it('should reject invalid password', function (done) { var fixture = { protocolId: 'MQIsdp', protocolVersion: 3, clientId: 'test', keepalive: 30, password: 30 } var expectedErr = 'Username is required to use password' this.conn.once('error', function (error) { error.message.should.equal(expectedErr) done() }) this.conn.connect(fixture) }) }) }) }) describe('#connack', function () { it('should send a connack packet (rc = 0)', function (done) { var expected = Buffer.from([ 32, 2, // Header 0, 0 // Rc=0 ]) var fixture = { returnCode: 0 } this.conn.connack(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should send a connack packet (rc = 4)', function (done) { var expected = Buffer.from([ 32, 2, // Header 0, 4 // Rc=0 ]) var fixture = { returnCode: 4 } this.conn.connack(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should reject invalid rc', function (done) { this.conn.once('error', function (error) { error.message.should.equal('Invalid return code') done() }) this.conn.connack({returnCode: 'asdf'}) }) }) describe('#publish', function () { it('should send a publish packet (minimal)', function (done) { var expected = Buffer.from([ 48, 10, // Header 0, 4, // Topic length 116, 101, 115, 116, // Topic ('test') 116, 101, 115, 116 // Payload ('test') ]) var fixture = { topic: 'test', payload: 'test' } this.conn.publish(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should send a publish packet (maximal)', function (done) { var expected = Buffer.from([ 61, 12, // Header 0, 4, // Topic length 116, 101, 115, 116, // Topic ('test') 0, 7, // Message id (7) 116, 101, 115, 116 // Payload ('test') ]) var fixture = { topic: 'test', payload: 'test', qos: 2, retain: true, dup: true, messageId: 7 } this.conn.publish(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should send a publish packet (empty)', function (done) { var expected = Buffer.from([ 48, 6, // Header 0, 4, // Topic length 116, 101, 115, 116 // Topic ('test') // Empty payload ]) var fixture = { topic: 'test' } this.conn.publish(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should send a publish packet (buffer)', function (done) { var expected = Buffer.from([ 48, 10, // Header 0, 4, // Topic length 116, 101, 115, 116, // Topic ('test') 0, 0, 0, 0 // Payload ]) var buf = Buffer.allocUnsafe(4) buf.fill(0) var fixture = { topic: 'test', payload: buf } this.conn.publish(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should send a publish packet of 2KB', function (done) { var expected = Buffer.from([ 48, 134, 16, // Header 0, 4, // Topic length 116, 101, 115, 116 // Topic ('test') ]) var payload = Buffer.allocUnsafe(2048) expected = Buffer.concat([expected, payload]) var fixture = { topic: 'test', payload: payload } this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) this.conn.publish(fixture) this.conn.end() }) it('should send a publish packet of 2MB', function (done) { var expected = Buffer.from([ 48, 134, 128, 128, 1, // Header 0, 4, // Topic length 116, 101, 115, 116 // Topic ('test') ]) var payload = Buffer.allocUnsafe(2 * 1024 * 1024) expected = Buffer.concat([expected, payload]) var fixture = { topic: 'test', payload: payload } this.conn.publish(fixture) this.readFromStream(this.stream, expected.length, data => { // Comparing the whole 2MB buffer is very slow so only check the length data.length.should.eql(expected.length) done() }) }) it('should reject invalid topic', function (done) { var error = 'Invalid topic' this.conn.once('error', function (err) { err.message.should.equal(error) done() }) this.conn.publish({topic: 0}) }) it('should reject invalid payloads, maybe') it('should reject invalid mid', function (done) { this.conn.once('error', function (err) { err.message.should.equal('Invalid messageId') done() }) this.conn.publish({topic: 'test', messageId: '', qos: 1}) }) }) describe('#puback', function () { it('should send a puback packet', function (done) { var expected = Buffer.from([ 64, 2, // Header 0, 30 // Mid=30 ]) var fixture = { messageId: 30 } this.conn.puback(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should reject invalid mid', function (done) { this.conn.once('error', function (error) { error.message.should.equal('Invalid messageId') done() }) this.conn.puback({messageId: ''}) }) }) describe('#pubrec', function () { it('should send a pubrec packet', function (done) { var expected = Buffer.from([ 80, 2, // Header 0, 3 // Mid=3 ]) var fixture = { messageId: 3 } this.conn.pubrec(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should reject invalid mid') }) describe('#pubrel', function () { it('should send a pubrel packet', function (done) { var expected = Buffer.from([ 98, 2, // Header 0, 6 // Mid=6 ]) var fixture = { messageId: 6 } this.conn.pubrel(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should reject invalid mid') }) describe('#pubcomp', function () { it('should send a pubcomp packet', function (done) { var expected = Buffer.from([ 112, 2, // Header 0, 9 // Mid=9 ]) var fixture = { messageId: 9 } this.conn.pubcomp(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should reject invalid mid') }) describe('#subscribe', function () { it('should send a subscribe packet (single)', function (done) { var expected = Buffer.from([ 130, 9, // Header 0, 7, // Message id 0, 4, // Topic length 116, 101, 115, 116, // Topic 0 // Qos=0 ]) var fixture = { messageId: 7, subscriptions: [ { topic: 'test', qos: 0 } ] } this.conn.subscribe(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should send a subscribe packet (multiple)', function (done) { var expected = Buffer.from([ 130, 23, // Header 0, 8, // Message id 0, 4, // Topic length 116, 101, 115, 116, // Topic ('test') 0, // Qos=0 0, 4, // Topic length 117, 101, 115, 116, // Topic ('uest') 1, // Qos=1 0, 4, // Topic length 116, 101, 115, 115, // Topic ('tess') 2 // Qos=2 ]) var fixture = { messageId: 8, subscriptions: [ { topic: 'test', qos: 0 }, { topic: 'uest', qos: 1 }, { topic: 'tess', qos: 2 } ] } this.conn.subscribe(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should reject invalid subscriptions', function (done) { this.conn.once('error', function (error) { error.message.should.equal('Invalid subscriptions') done() }) this.conn.subscribe({ messageId: 1, subscriptions: '' }) }) it('should reject invalid subscription objects') it('should reject invalid mid', function (done) { this.conn.once('error', function (error) { error.message.should.equal('Invalid messageId') done() }) this.conn.subscribe({ messageId: '', subscriptions: [{topic: 'test', qos: 1}] }) }) }) describe('#suback', function () { it('should send a suback packet', function (done) { var expected = Buffer.from([ 144, 5, // Length 0, 4, // Mid=4 0, // Qos=0 1, // Qos=1 2 // Qos=2 ]) var fixture = { granted: [0, 1, 2], messageId: 4 } this.conn.suback(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should reject invalid mid') it('should reject invalid qos vector', function (done) { this.conn.on('error', function (error) { error.message.should.equal('Invalid qos vector') done() }) this.conn.suback({granted: '', messageId: 1}) }) }) describe('#unsubscribe', function () { it('should send an unsubscribe packet', function (done) { var expected = Buffer.from([ 162, 14, // Header 0, 6, // Mid=6 0, 4, // Topic length 116, 101, 115, 116, // Topic ('test') 0, 4, // Topic length 116, 115, 101, 116 // Topic ('tset') ]) var fixture = { messageId: 6, unsubscriptions: [ 'test', 'tset' ] } this.conn.unsubscribe(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should reject invalid unsubs', function (done) { this.conn.once('error', function (error) { error.message.should.equal('Invalid unsubscriptions') done() }) this.conn.unsubscribe({ messageId: 1, unsubscriptions: '' }) }) it('should reject invalid mids') }) describe('#unsuback', function () { it('should send a unsuback packet', function (done) { var expected = Buffer.from([ 176, 2, // Header 0, 8 // Mid=8 ]) var fixture = { messageId: 8 } this.conn.unsuback(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should reject invalid mid') }) describe('#pingreq', function () { it('should send a pingreq packet', function (done) { var expected = Buffer.from([ 192, 0 // Header ]) var fixture = { } this.conn.pingreq(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) }) describe('#pingresp', function () { it('should send a pingresp packet', function (done) { var expected = Buffer.from([ 208, 0 // Header ]) var fixture = { } this.conn.pingresp(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) }) describe('#disconnect', function () { it('should send a disconnect packet', function (done) { var expected = Buffer.from([ 224, 0 // Header ]) var fixture = { } this.conn.disconnect(fixture) this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) it('should send a null disconnect packet', function (done) { var expected = Buffer.from([ 224, 0 // Header ]) this.conn.disconnect() this.readFromStream(this.stream, expected.length, data => { data.should.eql(expected) done() }) }) }) } package/lib/generateStream.js000644 0000000775 3560116604 013343 0ustar00000000 000000 'use strict' var Buffer = require('safe-buffer').Buffer var through = require('through2') var generate = require('mqtt-packet').generate var empty = Buffer.allocUnsafe(0) function generateStream (opts) { var stream = through.obj(process) function process (chunk, enc, cb) { var packet = empty try { packet = generate(chunk, opts) } catch (err) { this.emit('error', err) return } this.push(packet) cb() } return stream } module.exports = generateStream package/lib/parseStream.js000644 0000001260 3560116604 012651 0ustar00000000 000000 'use strict' var through = require('through2') var build = require('mqtt-packet').parser function StreamParser (opts) { if (!(this instanceof StreamParser)) return new StreamParser(opts) var that = this var stream = through.obj(process) this.stream = stream createParser(opts) function process (chunk, enc, cb) { that.parser.parse(chunk) cb() } function push (packet) { stream.push(packet) } function createParser (opts) { that.parser = build(opts) that.parser.on('packet', push) that.parser.on('error', that.stream.emit.bind(that.stream, 'error')) } stream.setOptions = createParser return stream } module.exports = StreamParser package/test/util.js000644 0000000513 3560116604 011551 0ustar00000000 000000 var through = require('through2') var setImmediate = global.setImmediate setImmediate = setImmediate || function (func) { setTimeout(func, 0) } module.exports.testStream = function () { return through(function (buf, enc, cb) { var that = this setImmediate(function () { that.push(buf) cb() }) }) } package/lib/writeToStream.js000644 0000001143 3560116604 013174 0ustar00000000 000000 'use strict' var stream = require('stream') var writeToStream = require('mqtt-packet').writeToStream function StreamGenerator (output, opts) { if (!(this instanceof StreamGenerator)) return new StreamGenerator(output, opts) var that = this this.opts = opts || {} var input = new stream.Writable({ objectMode: true, write: write }) function write (chunk, enc, cb) { if (writeToStream(chunk, output, that.opts)) { cb() } else { output.once('drain', cb) } } input.setOptions = function (opts) { that.opts = opts } return input } module.exports = StreamGenerator package/package.json000644 0000002006 3560116604 011544 0ustar00000000 000000 { "name": "mqtt-connection", "version": "4.1.0", "description": "Stream-based Connection object for MQTT, extracted from MQTT.js", "main": "connection.js", "contributors": [ "Matteo Collina (https://github.com/mcollina)", "Adam Rudd ", "Siarhei Buntsevich (https://github.com/scarry1992)" ], "scripts": { "test": "mocha test/ && standard" }, "repository": { "type": "git", "url": "https://github.com/mqttjs/mqtt-connection.git" }, "keywords": [ "mqtt", "connection", "server" ], "license": "MIT", "bugs": { "url": "https://github.com/mqttjs/mqtt-connection/issues" }, "homepage": "https://github.com/mqttjs/mqtt-connection", "dependencies": { "duplexify": "^3.5.1", "inherits": "^2.0.3", "mqtt-packet": "^6.0.0", "safe-buffer": "^5.1.1", "through2": "^2.0.1" }, "devDependencies": { "mocha": "^4.0.0", "should": "^13.0.0", "standard": "^11.0.0" } } package/CONTRIBUTING.md000644 0000002325 3560116604 011513 0ustar00000000 000000 # mqtt-packet is an OPEN Open Source Project ----------------------------------------- ## What? Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project. ## Rules There are a few basic ground-rules for contributors: 1. **No `--force` pushes** or modifying the Git history in any way. 1. **Non-master branches** ought to be used for ongoing work. 1. **External API changes and significant modifications** ought to be subject to an **internal pull-request** to solicit feedback from other contributors. 1. Internal pull-requests to solicit feedback are *encouraged* for any other non-trivial contribution but left to the discretion of the contributor. 1. Contributors should attempt to adhere to the prevailing code-style. ## Releases Declaring formal releases remains the prerogative of the project maintainer. ## Changes to this arrangement This is an experiment and feedback is welcome! This document may also be subject to pull-requests or changes by contributors where you believe you have something valuable to add or change. ----------------------------------------- package/LICENSE.md000644 0000002355 3560116604 010671 0ustar00000000 000000 The MIT License (MIT) ===================== Copyright (c) 2014-2015 mqtt-connection contributors --------------------------------------- *mqtt-connection contributors listed at * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. package/README.md000644 0000044337 3560116604 010552 0ustar00000000 000000 mqtt-connection   [![Build Status](https://travis-ci.org/mqttjs/mqtt-connection.png)](https://travis-ci.org/mqttjs/mqtt-connection) =============== Barebone Connection object for MQTT. Works over any kind of binary Streams, TCP, TLS, WebSocket, ... [![JavaScript Style Guide](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) It uses [mqtt-packet](http://npm.im/mqtt-packet) for generating and parsing MQTT packets. See it for the full documentations on the packet types. * Installation * Usage * API * Contributing * License & copyright This library is tested with node v4, v6 and v7. The last version to support older versions of node was mqtt-connection@2.1.1. Installation ------- ```sh npm install mqtt-connection --save ``` Usage ----- As a client: ```js var net = require('net') var mqttCon = require('mqtt-connection') var stream = net.createConnection(1883, 'localhost') var conn = mqttCon(stream) // conn is your MQTT connection! ``` As a server: ```js var net = require('net') var mqttCon = require('mqtt-connection') var server = new net.Server() server.on('connection', function (stream) { var client = mqttCon(stream) // client connected client.on('connect', function (packet) { // acknowledge the connect packet client.connack({ returnCode: 0 }); }) // client published client.on('publish', function (packet) { // send a puback with messageId (for QoS > 0) client.puback({ messageId: packet.messageId }) }) // client pinged client.on('pingreq', function () { // send a pingresp client.pingresp() }); // client subscribed client.on('subscribe', function (packet) { // send a suback with messageId and granted QoS level client.suback({ granted: [packet.qos], messageId: packet.messageId }) }) // timeout idle streams after 5 minutes stream.setTimeout(1000 * 60 * 5) // connection error handling client.on('close', function () { client.destroy() }) client.on('error', function () { client.destroy() }) client.on('disconnect', function () { client.destroy() }) // stream timeout stream.on('timeout', function () { client.destroy(); }) }) // listen on port 1883 server.listen(1883) ``` As a websocket server: ```js var websocket = require('websocket-stream') var WebSocketServer = require('ws').Server var Connection = require('mqtt-connection') var server = http.createServer() var wss = new WebSocketServer({server: server}) if (handler) { server.on('client', handler) } wss.on('connection', function (ws) { var stream = websocket(ws) var connection = new Connection(stream) handle(connection) }) function handle (conn) { // handle the MQTT connection like // the net example } ``` API --- * mqtt.Connection() * mqtt.parseStream() * mqtt.generateStream() --------------------------------- ### new mqtt.Connection([options]) Creates a new MQTT `Connection`. Options: * `notData`: do not listen to the `'data'` event, so that it can respect backpressure. Pipe the `Connection` to another stream to consume the packets. If this option is passed `true` the object will emit no packet-related events. #### Connection#connect(options, [callback]) Send a MQTT connect packet. `options` supports the following properties: * `protocolId`: Protocol ID, usually `MQIsdp`. `string` * `protocolVersion`: Protocol version, usually 3. `number` * `keepalive`: keepalive period in seconds. `number` * `clientId`: client ID. `string` * `will`: the client's will message options. `object` that supports the following properties: * `topic`: the will topic. `string` * `payload`: the will payload. `string` * `qos`: will qos level. `number` * `retain`: will retain flag. `boolean` * `properties`: properties of will by MQTT 5.0: * `willDelayInterval`: representing the Will Delay Interval in seconds `number`, * `payloadFormatIndicator`: Will Message is UTF-8 Encoded Character Data or not `boolean`, * `messageExpiryInterval`: value is the lifetime of the Will Message in seconds and is sent as the Publication Expiry Interval when the Server publishes the Will Message `number`, * `contentType`: describing the content of the Will Message `string`, * `responseTopic`: String which is used as the Topic Name for a response message `string`, * `correlationData`: The Correlation Data is used by the sender of the Request Message to identify which request the Response Message is for when it is received `binary`, * `userProperties`: The User Property is allowed to appear multiple times to represent multiple name, value pairs `object` * `properties`: properties MQTT 5.0. `object` that supports the following properties: * `sessionExpiryInterval`: representing the Session Expiry Interval in seconds `number`, * `receiveMaximum`: representing the Receive Maximum value `number`, * `maximumPacketSize`: representing the Maximum Packet Size the Client is willing to accept `number`, * `topicAliasMaximum`: representing the Topic Alias Maximum value indicates the highest value that the Client will accept as a Topic Alias sent by the Server `number`, * `requestResponseInformation`: The Client uses this value to request the Server to return Response Information in the CONNACK `boolean`, * `requestProblemInformation`: The Client uses this value to indicate whether the Reason String or User Properties are sent in the case of failures `boolean`, * `userProperties`: The User Property is allowed to appear multiple times to represent multiple name, value pairs `object`, * `authenticationMethod`: the name of the authentication method used for extended authentication `string`, * `authenticationData`: Binary Data containing authentication data `binary` * `clean`: the 'clean start' flag. `boolean` * `username`: username for protocol v3.1. `string` * `password`: password for protocol v3.1. `string` #### Connection#connack(options, [callback]) Send a MQTT connack packet. `options` supports the following properties: * `returnCode`: the return code of the connack, success is for MQTT < 5.0 * `reasonCode`: suback Reason Code `number` MQTT 5.0 * `properties`: properties MQTT 5.0. `object` that supports the following properties: * `sessionExpiryInterval`: representing the Session Expiry Interval in seconds `number`, * `receiveMaximum`: representing the Receive Maximum value `number`, * `maximumQoS`: maximum qos supported by server `number`, * `retainAvailable`: declares whether the Server supports retained messages `boolean`, * `maximumPacketSize`: Maximum Packet Size the Server is willing to accept `number`, * `assignedClientIdentifier`: Assigned Client Identifier `string`, * `topicAliasMaximum`: representing the Topic Alias Maximum value indicates the highest value that the Client will accept as a Topic Alias sent by the Server `number`, * `reasonString`: representing the reason associated with this response `string`, * `userProperties`: The User Property is allowed to appear multiple times to represent multiple name, value pairs `object`, * `wildcardSubscriptionAvailable`: this byte declares whether the Server supports Wildcard Subscriptions `boolean` * `subscriptionIdentifiersAvailable`: declares whether the Server supports Subscription Identifiers `boolean`, * `sharedSubscriptionAvailable`: declares whether the Server supports Shared Subscriptions `boolean`, * `serverKeepAlive`: Keep Alive time assigned by the Server `number`, * `responseInformation`: String which is used as the basis for creating a Response Topic `string`, * `serverReference`: String which can be used by the Client to identify another Server to use `string`, * `authenticationMethod`: the name of the authentication method used for extended authentication `string`, * `authenticationData`: Binary Data containing authentication data `binary` #### Connection#publish(options, [callback]) Send a MQTT publish packet. `options` supports the following properties: * `topic`: the topic to publish to. `string` * `payload`: the payload to publish, defaults to an empty buffer. `string` or `buffer` * `qos`: the quality of service level to publish on. `number` * `messageId`: the message ID of the packet, required if qos > 0. `number` * `retain`: retain flag. `boolean` * `properties`: `object` * `payloadFormatIndicator`: Payload is UTF-8 Encoded Character Data or not `boolean`, * `messageExpiryInterval`: the lifetime of the Application Message in seconds `number`, * `topicAlias`: value that is used to identify the Topic instead of using the Topic Name `number`, * `responseTopic`: String which is used as the Topic Name for a response message `string`, * `correlationData`: used by the sender of the Request Message to identify which request the Response Message is for when it is received `binary`, * `userProperties`: The User Property is allowed to appear multiple times to represent multiple name, value pairs `object`, * `subscriptionIdentifier`: representing the identifier of the subscription `number`, * `contentType`: String describing the content of the Application Message `string` #### Connection#puback #pubrec #pubcomp #unsuback(options, [callback]) Send a MQTT `[puback, pubrec, pubcomp, unsuback]` packet. `options` supports the following properties: * `messageId`: the ID of the packet * `reasonCode`: Reason Code by packet `number` * `properties`: `object` * `reasonString`: representing the reason associated with this response `string`, * `userProperties`: The User Property is allowed to appear multiple times to represent multiple name, value pairs `object` #### Connection#pubrel(options, [callback]) Send a MQTT pubrel packet. `options` supports the following properties: * `dup`: duplicate message flag * `reasonCode`: pubrel Reason Code `number` * `messageId`: the ID of the packet * `properties`: `object` * `reasonString`: representing the reason associated with this response `string`, * `userProperties`: The User Property is allowed to appear multiple times to represent multiple name, value pairs `object` #### Connection#subscribe(options, [callback]) Send a MQTT subscribe packet. `options` supports the following properties: * `dup`: duplicate message flag * `messageId`: the ID of the packet * `properties`: `object` * `subscriptionIdentifier`: representing the identifier of the subscription `number`, * `userProperties`: The User Property is allowed to appear multiple times to represent multiple name, value pairs `object` * `subscriptions`: a list of subscriptions of the form `[{topic: a, qos: 0}, {topic: b, qos: 1}]` `[{topic: a, qos: 0, nl: false, rap: true, rh: 15 }, {topic: b, qos: 1, nl: false, rap: false, rh: 100 }]` MQTT 5.0 Example #### Connection#suback(options, [callback]) Send a MQTT suback packet. `options` supports the following properties: * `granted`: a vector of granted QoS levels, of the form `[0, 1, 2]` * `messageId`: the ID of the packet * `reasonCode`: suback Reason Code `number` * `properties`: `object` * `reasonString`: representing the reason associated with this response `string`, * `userProperties`: The User Property is allowed to appear multiple times to represent multiple name, value pairs `object` #### Connection#unsubscribe(options, [callback]) Send a MQTT unsubscribe packet. `options` supports the following properties: * `messageId`: the ID of the packet * `reasonCode`: unsubscribe Reason Code MQTT 5.0 `number` * `dup`: duplicate message flag * `properties`: `object` * `userProperties`: The User Property is allowed to appear multiple times to represent multiple name, value pairs `object` * `unsubscriptions`: a list of topics to unsubscribe from, of the form `["topic1", "topic2"]` #### Connection#pingreq #pingresp #disconnect(options, [callback]) Send a MQTT `[pingreq, pingresp]` packet. #### Connection#disconnect(options, [callback]) Send a MQTT `disconnect` packet. `options` supports the following properties only MQTT 5.0: * `reasonCode`: Disconnect Reason Code `number` * `properties`: `object` * `sessionExpiryInterval`: representing the Session Expiry Interval in seconds `number`, * `reasonString`: representing the reason for the disconnect `string`, * `userProperties`: The User Property is allowed to appear multiple times to represent multiple name, value pairs `object`, * `serverReference`: String which can be used by the Client to identify another Server to use `string` #### Connection#auth(options, [callback]) Send a MQTT `auth` packet. Only MQTT 5.0 `options` supports the following properties only MQTT 5.0: * `reasonCode`: Auth Reason Code `number` * `properties`: `object` * `authenticationMethod`: the name of the authentication method used for extended authentication `string`, * `authenticationData`: Binary Data containing authentication data `binary`, * `reasonString`: representing the reason for the disconnect `string`, * `userProperties`: The User Property is allowed to appear multiple times to represent multiple name, value pairs `object` #### Event: 'connect' `function(packet) {}` Emitted when a MQTT connect packet is received by the client. `packet` is an object that may have the following properties: * `version`: the protocol version string * `versionNum`: the protocol version number * `keepalive`: the client's keepalive period * `clientId`: the client's ID * `will`: an object with the following keys: * `topic`: the client's will topic * `payload`: the will message * `retain`: will retain flag * `qos`: will qos level * `properties`: properties of will * `properties`: properties of packet * `clean`: clean start flag * `username`: v3.1 username * `password`: v3.1 password #### Event: 'connack' `function(packet) {}` Emitted when a MQTT connack packet is received by the client. `packet` is an object that may have the following properties: * `returnCode`: the return code of the connack packet * `properties`: properties of packet #### Event: 'publish' `function(packet) {}` Emitted when a MQTT publish packet is received by the client. `packet` is an object that may have the following properties: * `topic`: the topic the message is published on * `payload`: the payload of the message * `messageId`: the ID of the packet * `properties`: properties of packet * `qos`: the QoS level to publish at #### Events: \<'puback', 'pubrec', 'pubrel', 'pubcomp', 'unsuback'\> `function(packet) {}` Emitted when a MQTT `[puback, pubrec, pubrel, pubcomp, unsuback]` packet is received by the client. `packet` is an object that may contain the property: * `messageId`: the ID of the packet * `properties`: properties of packet #### Event: 'subscribe' `function(packet) {}` Emitted when a MQTT subscribe packet is received. `packet` is an object that may contain the properties: * `messageId`: the ID of the packet * `properties`: properties of packet * `subscriptions`: an array of objects representing the subscribed topics, containing the following keys * `topic`: the topic subscribed to * `qos`: the qos level of the subscription #### Event: 'suback' `function(packet) {}` Emitted when a MQTT suback packet is received. `packet` is an object that may contain the properties: * `messageId`: the ID of the packet * `properties`: properties of packet * `granted`: a vector of granted QoS levels #### Event: 'unsubscribe' `function(packet) {}` Emitted when a MQTT unsubscribe packet is received. `packet` is an object that may contain the properties: * `messageId`: the ID of the packet * `properties`: properties of packet * `unsubscriptions`: a list of topics the client is unsubscribing from, of the form `[topic1, topic2, ...]` #### Events: \<'pingreq', 'pingresp'\> `function(packet){}` Emitted when a MQTT `[pingreq, pingresp, disconnect]` packet is received. `packet` only includes static header information and can be ignored. #### Event: 'disconnect' `function(packet) {}` Emitted when a MQTT disconnect packet is received. `packet` only includes static header information and can be ignored for MQTT < 5.0. `packet` is an object that may contain the properties for MQTT 5.0: * `reasonCode`: disconnect Reason Code * `properties`: properties of packet #### Event: 'auth' `function(packet) {}` Emitted when a MQTT auth packet is received. `packet` is an object that may contain the properties: * `reasonCode`: Auth Reason Code * `properties`: properties of packet ------------------------------------- ### mqtt.generateStream() Returns a `Transform` stream that calls [`generate()`](https://github.com/mqttjs/mqtt-packet#generate). The stream is configured into object mode. ### mqtt.parseStream(opts) Returns a `Transform` stream that embeds a [`Parser`](https://github.com/mqttjs/mqtt-packet#mqttparser) and calls [`Parser.parse()`](https://github.com/mqttjs/mqtt-packet#parserparsebuffer) for each new `Buffer`. The stream is configured into object mode. It accepts the same options of [`parser(opts)`](#parser). Contributing ------------ mqtt-connection is an **OPEN Open Source Project**. This means that: > Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project. See the [CONTRIBUTING.md](https://github.com/mqttjs/mqtt-connection/blob/master/CONTRIBUTING.md) file for more details. ### Contributors mqtt-connection is only possible due to the excellent work of the following contributors:
Matteo CollinaGitHub/mcollinaTwitter/@matteocollina
Adam RuddGitHub/adamvrTwitter/@adam_vr
Siarhei BuntsevichGitHub/scarry1992
License ------- MIT package/.travis.yml000644 0000000107 3560116604 011367 0ustar00000000 000000 language: node_js node_js: - 10 - 8 - 6 script: - npm run test