lamassu-server/packages/server/lib/middlewares/populateSettings.js
2025-07-10 10:10:59 +01:00

150 lines
4.8 KiB
JavaScript

const db = require('../db')
const state = require('./state')
const newSettingsLoader = require('../new-settings-loader')
const logger = require('../logger')
db.connect({ direct: true })
.then(sco => {
sco.client.on('notification', data => {
const parsedData = JSON.parse(data.payload)
return reload(parsedData.operatorId)
})
return sco.none('LISTEN $1:name', 'reload')
})
.catch(console.error)
db.connect({ direct: true })
.then(sco => {
sco.client.on('notification', data => {
const parsedData = JSON.parse(data.payload)
return machineAction(parsedData.action, parsedData.value)
})
return sco.none('LISTEN $1:name', 'machineAction')
})
.catch(console.error)
function machineAction(type, value) {
const deviceId = value.deviceId
const operatorId = value.operatorId
const pid = state.pids?.[operatorId]?.[deviceId]?.pid
switch (type) {
case 'reboot':
logger.debug(
`Rebooting machine '${deviceId}' from operator ${operatorId}`,
)
if (!state.reboots[operatorId]) state.reboots[operatorId] = {}
state.reboots[operatorId][deviceId] = pid
break
case 'shutdown':
logger.debug(
`Shutting down machine '${deviceId}' from operator ${operatorId}`,
)
if (!state.shutdowns[operatorId]) state.shutdowns[operatorId] = {}
state.shutdowns[operatorId][deviceId] = pid
break
case 'restartServices':
logger.debug(
`Restarting services of machine '${deviceId}' from operator ${operatorId}`,
)
if (!state.restartServicesMap[operatorId])
state.restartServicesMap[operatorId] = {}
state.restartServicesMap[operatorId][deviceId] = pid
break
case 'emptyUnit':
logger.debug(
`Emptying units from machine '${deviceId}' from operator ${operatorId}`,
)
if (!state.emptyUnit[operatorId]) state.emptyUnit[operatorId] = {}
state.emptyUnit[operatorId][deviceId] = pid
break
case 'refillUnit':
logger.debug(
`Refilling recyclers from machine '${deviceId}' from operator ${operatorId}`,
)
if (!state.refillUnit[operatorId]) state.refillUnit[operatorId] = {}
state.refillUnit[operatorId][deviceId] = pid
break
case 'diagnostics':
logger.debug(
`Running diagnostics on machine '${deviceId}' from operator ${operatorId}`,
)
if (!state.diagnostics[operatorId]) state.diagnostics[operatorId] = {}
state.diagnostics[operatorId][deviceId] = pid
break
default:
break
}
}
function reload(operatorId) {
state.needsSettingsReload[operatorId] = true
}
const populateSettings = function (req, res, next) {
const { needsSettingsReload, settingsCache } = state
const operatorId = res.locals.operatorId
const versionId = req.headers['config-version']
try {
// Priority of configs to retrieve
// 1. Machine is in the middle of a transaction and has the config-version header set, fetch that config from cache or database, depending on whether it exists in cache
// 2. The operator settings changed, so we must update the cache
// 3. There's a cached config, send the cached value
// 4. There's no cached config, cache and send the latest config
if (versionId) {
const cachedVersionedSettings = settingsCache.get(
`${operatorId}-v${versionId}`,
)
if (!cachedVersionedSettings) {
logger.debug('Fetching a specific config version cached value')
return newSettingsLoader
.load(versionId)
.then(settings => {
settingsCache.set(`${operatorId}-v${versionId}`, settings)
req.settings = settings
})
.then(() => next())
.catch(next)
}
logger.debug('Fetching a cached specific config version')
req.settings = cachedVersionedSettings
return next()
}
const operatorSettings = settingsCache.get(`${operatorId}-latest`)
if (needsSettingsReload[operatorId] || !operatorSettings) {
needsSettingsReload[operatorId]
? logger.debug(
'Fetching and caching a new latest config value, as a reload was requested',
)
: logger.debug(
"Fetching the latest config version because there's no cached value",
)
return newSettingsLoader
.loadLatest()
.then(settings => {
const versionId = settings.version
settingsCache.set(`${operatorId}-latest`, settings)
settingsCache.set(`${operatorId}-v${versionId}`, settings)
delete needsSettingsReload[operatorId]
req.settings = settings
})
.then(() => next())
.catch(next)
}
logger.debug('Fetching the latest config value from cache')
req.settings = operatorSettings
return next()
} catch (e) {
logger.error(e)
}
}
module.exports = populateSettings