diff --git a/lib/machine-loader.js b/lib/machine-loader.js index 6818676f..ce62e05c 100644 --- a/lib/machine-loader.js +++ b/lib/machine-loader.js @@ -151,9 +151,8 @@ function unpair (rec) { } function reboot (rec) { - return db.none('NOTIFY $1:name, $2', ['poller', JSON.stringify( + return db.none('NOTIFY $1:name, $2', ['machineAction', JSON.stringify( { - type: 'machineAction', action: 'reboot', value: _.pick(['deviceId', 'operatorId', 'action'], rec) } @@ -161,9 +160,8 @@ function reboot (rec) { } function shutdown (rec) { - return db.none('NOTIFY $1:name, $2', ['poller', JSON.stringify( + return db.none('NOTIFY $1:name, $2', ['machineAction', JSON.stringify( { - type: 'machineAction', action: 'shutdown', value: _.pick(['deviceId', 'operatorId', 'action'], rec) } @@ -171,9 +169,8 @@ function shutdown (rec) { } function restartServices (rec) { - return db.none('NOTIFY $1:name, $2', ['poller', JSON.stringify( + return db.none('NOTIFY $1:name, $2', ['machineAction', JSON.stringify( { - type: 'machineAction', action: 'restartServices', value: _.pick(['deviceId', 'operatorId', 'action'], rec) } diff --git a/lib/middlewares/populateSettings.js b/lib/middlewares/populateSettings.js index 146aafeb..80ccc9a6 100644 --- a/lib/middlewares/populateSettings.js +++ b/lib/middlewares/populateSettings.js @@ -1,11 +1,56 @@ +const _ = require('lodash/fp') + +const db = require('../db') const state = require('./state') const newSettingsLoader = require('../new-settings-loader') const helpers = require('../route-helpers') const logger = require('../logger') -const { settingsCache } = state +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}`) + state.reboots[operatorId] = { [deviceId]: pid } + break + case 'shutdown': + logger.debug(`Shutting down machine '${deviceId}' from operator ${operatorId}`) + state.shutdowns[operatorId] = { [deviceId]: pid } + break + case 'restartServices': + logger.debug(`Restarting services of machine '${deviceId}' from operator ${operatorId}`) + state.restartServicesMap[operatorId] = { [deviceId]: pid } + break + default: + break + } +} + +function reload (operatorId) { + state.needsSettingsReload[operatorId.operatorId] = true +} const populateSettings = function (req, res, next) { + const { needsSettingsReload, settingsCache } = state const operatorId = res.locals.operatorId const versionId = req.headers['config-version'] if (versionId !== state.oldVersionId) { @@ -14,20 +59,21 @@ const populateSettings = function (req, res, next) { try { const operatorSettings = settingsCache.get(operatorId) - if (!versionId && operatorSettings) { - req.settings = operatorSettings - return next() - } - - if (!versionId && !operatorSettings) { + if (!versionId && (!operatorSettings || !!needsSettingsReload[operatorId])) { return newSettingsLoader.loadLatest() .then(settings => { settingsCache.set(operatorId, settings) + delete needsSettingsReload[operatorId] req.settings = settings }) .then(() => next()) .catch(next) } + + if (!versionId && operatorSettings) { + req.settings = operatorSettings + return next() + } } catch (e) { logger.error(e) } diff --git a/lib/middlewares/state.js b/lib/middlewares/state.js index 10267d88..2599e259 100644 --- a/lib/middlewares/state.js +++ b/lib/middlewares/state.js @@ -4,6 +4,7 @@ const SETTINGS_CACHE_REFRESH = 3600 module.exports = (function () { return { oldVersionId: 'unset', + needsSettingsReload: {}, settingsCache: new NodeCache({ stdTTL: SETTINGS_CACHE_REFRESH, checkperiod: SETTINGS_CACHE_REFRESH // Clear cache every hour diff --git a/lib/new-settings-loader.js b/lib/new-settings-loader.js index 18da5c61..d9e838ef 100644 --- a/lib/new-settings-loader.js +++ b/lib/new-settings-loader.js @@ -2,6 +2,7 @@ const _ = require('lodash/fp') const db = require('./db') const migration = require('./config-migration') const { asyncLocalStorage } = require('./async-storage') +const { getOperatorId } = require('./operator') const OLD_SETTINGS_LOADER_SCHEMA_VERSION = 1 const NEW_SETTINGS_LOADER_SCHEMA_VERSION = 2 @@ -71,12 +72,12 @@ function showAccounts (schemaVersion) { const configSql = 'insert into user_config (type, data, valid, schema_version) values ($1, $2, $3, $4)' function saveConfig (config) { - return loadLatestConfigOrNone() - .then(currentConfig => { + return Promise.all([loadLatestConfigOrNone(), getOperatorId('middleware')]) + .then(([currentConfig, operatorId]) => { const newConfig = _.assign(currentConfig, config) return db.tx(t => { return t.none(configSql, ['config', { config: newConfig }, true, NEW_SETTINGS_LOADER_SCHEMA_VERSION]) - .then(() => t.none('NOTIFY $1:name, $2', ['poller', JSON.stringify({ type: 'reload', schema: asyncLocalStorage.getStore().get('schema') })])) + .then(() => t.none('NOTIFY $1:name, $2', ['reload', JSON.stringify({ schema: asyncLocalStorage.getStore().get('schema'), operatorId })])) }).catch(console.error) }) } diff --git a/lib/poller.js b/lib/poller.js index 25011b17..99ea5543 100644 --- a/lib/poller.js +++ b/lib/poller.js @@ -81,16 +81,9 @@ cachedVariables.on('expired', (key, val) => { db.connect({ direct: true }).then(sco => { sco.client.on('notification', data => { const parsedData = JSON.parse(data.payload) - switch (parsedData.type) { - case 'reload': - return reload(parsedData.schema) - case 'machineAction': - return machineAction(parsedData.action, parsedData.value) - default: - break - } + return reload(parsedData.schema) }) - return sco.none('LISTEN $1:name', 'poller') + return sco.none('LISTEN $1:name', 'reload') }).catch(console.error) function reload (schema) { @@ -98,38 +91,16 @@ function reload (schema) { store.set('schema', schema) // set asyncLocalStorage so settingsLoader loads settings for the right schema return asyncLocalStorage.run(store, () => { - return settingsLoader.loadLatest().then(settings => { - const pi = plugins(settings) - cachedVariables.set(schema, { settings, pi, isReloading: false }) - logger.debug(`Settings for schema '${schema}' reloaded in poller`) - return updateAndLoadSanctions() - }) + return settingsLoader.loadLatest() + .then(settings => { + const pi = plugins(settings) + cachedVariables.set(schema, { settings, pi, isReloading: false }) + logger.debug(`Settings for schema '${schema}' reloaded in poller`) + return updateAndLoadSanctions() + }) }) } -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}`) - state.reboots[operatorId] = { [deviceId]: pid } - break - case 'shutdown': - logger.debug(`Shutting down machine '${deviceId}' from operator ${operatorId}`) - state.shutdowns[operatorId] = { [deviceId]: pid } - break - case 'restartServices': - logger.debug(`Restarting services of machine '${deviceId}' from operator ${operatorId}`) - state.restartServicesMap[operatorId] = { [deviceId]: pid } - break - default: - break - } -} - function pi () { return cachedVariables.get(asyncLocalStorage.getStore().get('schema')).pi } function settings () { return cachedVariables.get(asyncLocalStorage.getStore().get('schema')).settings }