@flowfuse/flowfuse
Version:
An open source low-code development platform
113 lines (104 loc) • 4.93 kB
JavaScript
const fp = require('fastify-plugin')
const ACLManager = require('./aclManager')
const { CommsClient } = require('./commsClient')
const { DeviceCommsHandler } = require('./devices')
const { InstanceCommsHandler } = require('./instances')
const { PlatformAutomationHandler } = require('./platformAutomation.js')
/**
* This module represents the real-time comms component of the platform.
* We depend on an external MQTT broker (mosquitto) and of the runtime configuration
* to include the details needed to connect to it.
*
* This module handles
* - Incoming device status messages
* - Broker ACL requests
*
*/
module.exports = fp(async function (app, _opts) {
// Check the runtime configuration includes the minimum required configuration
// to use the MQTT broker service
if (app.config.broker && app.config.broker.url) {
// Register the authentication routes the broker will be using
await app.register(require('./authRoutes'), { prefix: '/api/comms/auth', logLevel: app.config.logging.http })
await app.register(require('./v2AuthRoutes'), { prefix: '/api/comms/v2', logLevel: app.config.logging.http })
// Ensure we have a BrokerClient object (auth details) for use by the platform
await app.db.controllers.BrokerClient.ensurePlatformClient()
// Create the platform's client for connecting to the broker
const client = new CommsClient(app)
// Create the handler for any device-related messages
const deviceCommsHandler = DeviceCommsHandler(app, client)
const instanceCommsHandler = InstanceCommsHandler(app, client)
const platformAutomationHandler = PlatformAutomationHandler(app, client)
// Not in the current release, but when we handle Launcher status
// via MQTT, it will arrive here. Compare to the status/device handler in `devices.js`
// client.on('status/project', (status) => {
// // console.info(status)
// })
// Setup the platform API for the comms component
app.decorate('comms', {
devices: deviceCommsHandler,
instances: instanceCommsHandler,
aclManager: ACLManager(app),
platformAutomation: platformAutomationHandler,
platform: {
settings: {
sync: function (key) {
const msg = {
key,
srcId: client.platformId
}
client.publish('ff/v1/platform/sync', JSON.stringify(msg))
}
},
housekeeper: {
vote: function (vote) {
const msg = {
vote,
id: client.platformId
}
client.publish('ff/v1/platform/leader', JSON.stringify(msg))
}
}
},
team: {
notify: function (teamHash, reason, srcId) {
if (!teamHash) return
const msg = { reason: reason || null, srcId: srcId || null }
client.publish(`ff/v1/${teamHash}/t/updated`, JSON.stringify(msg))
},
notifyMembership: function (teamHash, userHash, reason, srcId) {
if (!teamHash || !userHash) return
const msg = { reason: reason || null, srcId: srcId || null }
client.publish(`ff/v1/${teamHash}/u/${userHash}/membership`, JSON.stringify(msg))
},
notifyDeviceState: function (teamHash, id, state) {
if (!teamHash || !id) return
client.publish(`ff/v1/${teamHash}/d/${id}/state`, JSON.stringify({ id, meta: { state } }))
},
notifyInstanceState: function (teamHash, id, { state, versions } = {}) {
if (!teamHash || !id) return
const meta = { state }
if (versions) meta.versions = versions
client.publish(`ff/v1/${teamHash}/p/${id}/state`, JSON.stringify({ id, meta }))
}
}
})
app.addHook('onReady', async () => {
try {
await client.init()
} catch (err) {
app.log.info('[comms] problem starting comms client:', err.toString())
}
})
app.addHook('onClose', async (_) => {
app.log.info('Comms shutdown')
await deviceCommsHandler.stopLogWatcher()
client.publish('ff/v1/platform/leader', JSON.stringify({ id: client.platformId, vote: -1 }))
await client.disconnect()
})
} else {
app.log.warn('[comms] Broker not configured - comms unavailable')
}
}, {
name: 'app.comms'
})