UNPKG

rocket.chat.mqtt

Version:

It's a MQTT Server, using redis to scale horizontally.

193 lines (165 loc) 4.49 kB
'use strict' var retimer = require('retimer') var pump = require('pump') var write = require('../write') var QoSPacket = require('../qos-packet') var through = require('through2') var handleSubscribe = require('./subscribe') var uuid = require('uuid') function ClientPacketStatus (client, packet) { this.client = client this.packet = packet } var connectActions = [ authenticate, fetchSubs, restoreSubs, storeWill, doConnack, emptyQueue ] var errorMessages = [ '', 'unacceptable protocol version', 'identifier rejected', 'Server unavailable', 'bad user name or password', 'not authorized' ] function handleConnect (client, packet, done) { client.connected = true client.clean = packet.clean if (!packet.clientId && packet.protocolVersion === 3) { client.emit('error', new Error('Empty clientIds are supported only on MQTT 3.1.1')) return done() } client.id = packet.clientId || uuid.v4() client.will = packet.will clearTimeout(client._connectTimer) client._connectTimer = null if (packet.keepalive > 0) { client._keepaliveInterval = (packet.keepalive * 1500) + 1 client._keepaliveTimer = retimer(function keepaliveTimeout () { client.broker.emit('keepaliveTimeout', client) client.emit('error', new Error('keep alive timeout')) }, client._keepaliveInterval) } client.broker._series( new ClientPacketStatus(client, packet), connectActions, {}, done) } function authenticate (arg, done) { var client = this.client client.pause() client.broker.authenticate( client, this.packet.username, this.packet.password, negate) function negate (err, successful) { var errCode if (!err && successful) { client.broker.registerClient(client) return done() } else if (err) { if (err.returnCode && (err.returnCode >= 1 && err.returnCode <= 3)) { errCode = err.returnCode write(client, { cmd: 'connack', returnCode: err.returnCode }, client.close.bind(client, done)) } else { // If errorCode is 4 or not a number errCode = 4 write(client, { cmd: 'connack', returnCode: 4 }, client.close.bind(client, done)) } } else { errCode = 5 write(client, { cmd: 'connack', returnCode: 5 }, client.close.bind(client, done)) } var error = new Error(errorMessages[errCode]) error.errorCode = errCode client.broker.emit('clientError', client, error) } } function fetchSubs (arg, done) { if (!this.packet.clean) { this.client.broker.persistence.subscriptionsByClient({ id: this.client.id, done: done, arg: arg }, gotSubs) } else { this.client.broker.persistence.cleanSubscriptions( this.client, done) } } function gotSubs (err, subs, client) { if (err) { return client.done(err) } client.arg.subs = subs client.done() } function restoreSubs (arg, done) { if (arg.subs) { handleSubscribe(this.client, { subscriptions: arg.subs, restore: true }, done) } else { done() } } function storeWill (arg, done) { if (this.client.will) { this.client.broker.persistence.putWill( this.client, this.client.will, done) } else { done() } } function Connack (arg) { this.cmd = 'connack' this.returnCode = 0 this.sessionPresent = !!arg.subs // cast to boolean } function doConnack (arg, done) { write(this.client, new Connack(arg), done) this.client.broker.emit('connackSent', this.client) } function emptyQueue (arg, done) { var client = this.client var persistence = client.broker.persistence var outgoing = persistence.outgoingStream(client) client.resume() pump(outgoing, through.obj(function clearQueue (data, enc, next) { var packet = new QoSPacket(data, client) packet.writeCallback = next persistence.outgoingUpdate(client, packet, emptyQueueFilter) }), done) } function emptyQueueFilter (err, client, packet) { var next = packet.writeCallback var persistence = client.broker.persistence if (err) { client.emit('error', err) return next() } var authorized = true if (packet.cmd === 'publish') { authorized = client.broker.authorizeForward(client, packet) } if (client.clean || !authorized) { persistence.outgoingClearMessageId(client, packet, next) } else { write(client, packet, next) } } module.exports = handleConnect