diff --git a/lib/machine-loader.js b/lib/machine-loader.js index 5ce26a5a..f7e19dfa 100644 --- a/lib/machine-loader.js +++ b/lib/machine-loader.js @@ -157,18 +157,37 @@ function unpair (rec) { } function reboot (rec) { - return axios.post(`http://localhost:3030/reboot?device_id=${rec.deviceId}`) + return db.none('NOTIFY $1:name, $2', ['poller', JSON.stringify( + { + type: 'machineAction', + action: 'reboot', + value: _.pick(['deviceId', 'operatorId', 'action'], rec) + } + )]) } function shutdown (rec) { - return axios.post(`http://localhost:3030/shutdown?device_id=${rec.deviceId}`) + return db.none('NOTIFY $1:name, $2', ['poller', JSON.stringify( + { + type: 'machineAction', + action: 'shutdown', + value: _.pick(['deviceId', 'operatorId', 'action'], rec) + } + )]) } function restartServices (rec) { - return axios.post(`http://localhost:3030/restartServices?device_id=${rec.deviceId}`) + return db.none('NOTIFY $1:name, $2', ['poller', JSON.stringify( + { + type: 'machineAction', + action: 'restartServices', + value: _.pick(['deviceId', 'operatorId', 'action'], rec) + } + )]) } -function setMachine (rec) { +function setMachine (rec, operatorId) { + rec.operatorId = operatorId switch (rec.action) { case 'rename': return renameMachine(rec) case 'emptyCashInBills': return emptyCashInBills(rec) diff --git a/lib/new-admin/admin-server.js b/lib/new-admin/admin-server.js index 93cf01ad..8b7938cf 100644 --- a/lib/new-admin/admin-server.js +++ b/lib/new-admin/admin-server.js @@ -18,6 +18,7 @@ const logger = require('../logger') const { AuthDirective } = require('./graphql/directives') const { typeDefs, resolvers } = require('./graphql/schema') +const findOperatorId = require('../middlewares/operatorId') const computeSchema = require('../compute-schema') const { USER_SESSIONS_CLEAR_INTERVAL } = require('../constants') const { session, cleanUserSessions, buildApolloContext } = require('./middlewares') diff --git a/lib/new-admin/graphql/resolvers/machine.resolver.js b/lib/new-admin/graphql/resolvers/machine.resolver.js index c2e5bc2c..771bb479 100644 --- a/lib/new-admin/graphql/resolvers/machine.resolver.js +++ b/lib/new-admin/graphql/resolvers/machine.resolver.js @@ -18,7 +18,7 @@ const resolvers = { machine: (...[, { deviceId }]) => machineLoader.getMachine(deviceId) }, Mutation: { - machineAction: (...[, { deviceId, action, cashbox, cassette1, cassette2, newName }]) => machineAction({ deviceId, action, cashbox, cassette1, cassette2, newName }) + machineAction: (...[, { deviceId, action, cashbox, cassette1, cassette2, newName }, context]) => machineAction({ deviceId, action, cashbox, cassette1, cassette2, newName }, context) } } diff --git a/lib/new-admin/graphql/resolvers/settings.resolver.js b/lib/new-admin/graphql/resolvers/settings.resolver.js index 329be89e..383f9309 100644 --- a/lib/new-admin/graphql/resolvers/settings.resolver.js +++ b/lib/new-admin/graphql/resolvers/settings.resolver.js @@ -1,11 +1,5 @@ -const got = require('got') - -const logger = require('../../../logger') const settingsLoader = require('../../../new-settings-loader') -const notify = () => got.post('http://localhost:3030/dbChange') - .catch(e => logger.error('lamassu-server not responding')) - const resolvers = { Query: { accounts: () => settingsLoader.showAccounts(), @@ -14,10 +8,7 @@ const resolvers = { Mutation: { saveAccounts: (...[, { accounts }]) => settingsLoader.saveAccounts(accounts), // resetAccounts: (...[, { schemaVersion }]) => settingsLoader.resetAccounts(schemaVersion), - saveConfig: (...[, { config }]) => settingsLoader.saveConfig(config).then(it => { - notify() - return it - }), + saveConfig: (...[, { config }]) => settingsLoader.saveConfig(config), // resetConfig: (...[, { schemaVersion }]) => settingsLoader.resetConfig(schemaVersion), // migrateConfigAndAccounts: () => settingsLoader.migrate() } diff --git a/lib/new-admin/services/machines.js b/lib/new-admin/services/machines.js index 9a612935..85796601 100644 --- a/lib/new-admin/services/machines.js +++ b/lib/new-admin/services/machines.js @@ -6,13 +6,14 @@ function getMachine (machineId) { .then(machines => machines.find(({ deviceId }) => deviceId === machineId)) } -function machineAction ({ deviceId, action, cashbox, cassette1, cassette2, newName }) { +function machineAction ({ deviceId, action, cashbox, cassette1, cassette2, newName }, context) { + const operatorId = context.res.locals.operatorId return getMachine(deviceId) .then(machine => { if (!machine) throw new UserInputError(`machine:${deviceId} not found`, { deviceId }) return machine }) - .then(machineLoader.setMachine({ deviceId, action, cashbox, cassettes: [cassette1, cassette2], newName })) + .then(machineLoader.setMachine({ deviceId, action, cashbox, cassettes: [cassette1, cassette2], newName }, operatorId)) .then(getMachine(deviceId)) } diff --git a/lib/new-settings-loader.js b/lib/new-settings-loader.js index d71e171c..18da5c61 100644 --- a/lib/new-settings-loader.js +++ b/lib/new-settings-loader.js @@ -76,7 +76,7 @@ function saveConfig (config) { 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', asyncLocalStorage.getStore().get('schema')])) + .then(() => t.none('NOTIFY $1:name, $2', ['poller', JSON.stringify({ type: 'reload', schema: asyncLocalStorage.getStore().get('schema') })])) }).catch(console.error) }) } diff --git a/lib/poller.js b/lib/poller.js index 943d0054..c3ba3334 100644 --- a/lib/poller.js +++ b/lib/poller.js @@ -16,6 +16,7 @@ const settingsLoader = require('./new-settings-loader') const NodeCache = require('node-cache') const util = require('util') const db = require('./db') +const state = require('./middlewares/state') const INCOMING_TX_INTERVAL = 30 * T.seconds const LIVE_INCOMING_TX_INTERVAL = 5 * T.seconds @@ -77,7 +78,15 @@ cachedVariables.on('expired', (key, val) => { db.connect({ direct: true }).then(sco => { sco.client.on('notification', data => { - return reload(data.payload) + 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 sco.none('LISTEN $1:name', 'poller') }).catch(console.error) @@ -90,12 +99,35 @@ function reload (schema) { 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`) + 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 } diff --git a/lib/routes.js b/lib/routes.js index d2c25a40..4c694fd5 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -30,8 +30,6 @@ const verifyUserRoutes = require('./routes/verifyUserRoutes') const verifyTxRoutes = require('./routes/verifyTxRoutes') const verifyPromoCodeRoutes = require('./routes/verifyPromoCodeRoutes') -const localAppRoutes = require('./routes/localAppRoutes') - const app = express() const localApp = express() @@ -87,7 +85,4 @@ app.use((req, res) => { res.status(404).json({ error: 'No such route' }) }) -// localapp routes -localApp.use('/', localAppRoutes) - module.exports = { app, localApp } diff --git a/lib/routes/cashboxRoutes.js b/lib/routes/cashboxRoutes.js index 6c740c08..1747187a 100644 --- a/lib/routes/cashboxRoutes.js +++ b/lib/routes/cashboxRoutes.js @@ -8,6 +8,7 @@ const { getCashInSettings } = require('../new-config-manager') const { AUTOMATIC } = require('../constants.js') function notifyCashboxRemoval (req, res, next) { + const operatorId = res.locals.operatorId return Promise.all([getMachine(req.deviceId), loadLatestConfig()]) .then(([machine, config]) => { const cashInSettings = getCashInSettings(config) @@ -15,7 +16,7 @@ function notifyCashboxRemoval (req, res, next) { return res.status(200).send({ status: 'OK' }) } return cashbox.createCashboxBatch(req.deviceId, machine.cashbox) - .then(() => setMachine({ deviceId: req.deviceId, action: 'emptyCashInBills' })) + .then(() => setMachine({ deviceId: req.deviceId, action: 'emptyCashInBills' }, operatorId)) .then(() => res.status(200).send({ status: 'OK' })) }) .catch(next) diff --git a/lib/routes/localAppRoutes.js b/lib/routes/localAppRoutes.js deleted file mode 100644 index d235faa8..00000000 --- a/lib/routes/localAppRoutes.js +++ /dev/null @@ -1,48 +0,0 @@ -const express = require('express') -const router = express.Router() - -const state = require('../middlewares/state') - -router.get('/pid', (req, res) => { - const deviceId = req.query.device_id - const pidRec = state.pids[deviceId] - res.json(pidRec) -}) - -router.post('/reboot', (req, res) => { - const deviceId = req.query.device_id - const pid = state.pids[deviceId] && state.pids[deviceId].pid - - if (!deviceId || !pid) { - return res.sendStatus(400) - } - - state.reboots[deviceId] = pid - res.sendStatus(200) -}) - -router.post('/shutdown', (req, res) => { - const deviceId = req.query.device_id - const pid = state.pids[deviceId] && state.pids[deviceId].pid - - if (!deviceId || !pid) { - return res.sendStatus(400) - } - - state.shutdowns[deviceId] = pid - res.sendStatus(200) -}) - -router.post('/restartServices', (req, res) => { - const deviceId = req.query.device_id - const pid = state.pids[deviceId] && state.pids[deviceId].pid - - if (!deviceId || !pid) { - return res.sendStatus(400) - } - - state.restartServicesMap[deviceId] = pid - res.sendStatus(200) -}) - -module.exports = router diff --git a/lib/routes/pollingRoutes.js b/lib/routes/pollingRoutes.js index cd64f6b5..593b0e9e 100644 --- a/lib/routes/pollingRoutes.js +++ b/lib/routes/pollingRoutes.js @@ -31,6 +31,7 @@ function poll (req, res, next) { const serialNumber = req.query.sn const pid = req.query.pid const settings = req.settings + const operatorId = res.locals.operatorId const localeConfig = configManager.getLocale(deviceId, settings.config) const zeroConfLimits = _.reduce((acc, cryptoCode) => { acc[cryptoCode] = configManager.getWalletSettings(cryptoCode, settings.config).zeroConfLimit @@ -48,15 +49,15 @@ function poll (req, res, next) { const receipt = configManager.getReceipt(settings.config) const terms = configManager.getTermsConditions(settings.config) - state.pids[deviceId] = { pid, ts: Date.now() } + state.pids[operatorId] = { [deviceId]: { pid, ts: Date.now() } } return pi.pollQueries(serialNumber, deviceTime, req.query, machineVersion, machineModel) .then(results => { const cassettes = results.cassettes - const reboot = pid && state.reboots[deviceId] && state.reboots[deviceId] === pid - const shutdown = pid && state.shutdowns[deviceId] && state.shutdowns[deviceId] === pid - const restartServices = pid && state.restartServicesMap[deviceId] && state.restartServicesMap[deviceId] === pid + const reboot = pid && state.reboots?.[operatorId]?.[deviceId] === pid + const shutdown = pid && state.shutdowns?.[operatorId]?.[deviceId] === pid + const restartServices = pid && state.restartServicesMap?.[operatorId]?.[deviceId] === pid const langs = localeConfig.languages const locale = {