Merge pull request #1691 from siiky/feat/lam-1062/save-unsuccessful-qr-scans
LAM-1062 Save frames from unsuccessful QR scanning attempts
This commit is contained in:
commit
8381b3d9ec
4 changed files with 108 additions and 10 deletions
|
|
@ -487,11 +487,18 @@ function updateDiagnostics (deviceId, images) {
|
||||||
const directory = `${OPERATOR_DATA_DIR}/diagnostics/${deviceId}/`
|
const directory = `${OPERATOR_DATA_DIR}/diagnostics/${deviceId}/`
|
||||||
const { scan, front } = images
|
const { scan, front } = images
|
||||||
|
|
||||||
return updatePhotos(scan, front, directory)
|
return updatePhotos(directory, [['scan.jpg', scan], ['front.jpg', front]])
|
||||||
.then(() => db.none(sql, [deviceId, !!scan, !!front]))
|
.then(() => db.none(sql, [deviceId, !!scan, !!front]))
|
||||||
.catch(err => logger.error('while running machine diagnostics: ', err))
|
.catch(err => logger.error('while running machine diagnostics: ', err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateFailedQRScans = (deviceId, frames) => {
|
||||||
|
const timestamp = (new Date()).toISOString()
|
||||||
|
const directory = `${OPERATOR_DATA_DIR}/failedQRScans/${deviceId}/`
|
||||||
|
const filenames = _.map(no => `${timestamp}-${no}.jpg`, _.range(0, _.size(frames)))
|
||||||
|
return updatePhotos(directory, _.zip(filenames, frames))
|
||||||
|
}
|
||||||
|
|
||||||
function createPhoto (name, data, dir) {
|
function createPhoto (name, data, dir) {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
logger.error(`Diagnostics error: No data to save for ${name} photo`)
|
logger.error(`Diagnostics error: No data to save for ${name} photo`)
|
||||||
|
|
@ -503,16 +510,12 @@ function createPhoto (name, data, dir) {
|
||||||
return fsPromises.writeFile(filename, decodedImageData)
|
return fsPromises.writeFile(filename, decodedImageData)
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePhotos (scan, front, dir) {
|
function updatePhotos (dir, photoPairs) {
|
||||||
const dirname = path.join(dir)
|
const dirname = path.join(dir)
|
||||||
_.attempt(() => makeDir.sync(dirname))
|
_.attempt(() => makeDir.sync(dirname))
|
||||||
|
return Promise.all(photoPairs.map(
|
||||||
const promises = [
|
([filename, data]) => createPhoto(filename, data, dirname)
|
||||||
createPhoto('scan.jpg', scan, dirname),
|
))
|
||||||
createPhoto('front.jpg', front, dirname)
|
|
||||||
]
|
|
||||||
|
|
||||||
return Promise.all(promises)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
@ -530,5 +533,6 @@ module.exports = {
|
||||||
getMachineIds,
|
getMachineIds,
|
||||||
emptyMachineUnits,
|
emptyMachineUnits,
|
||||||
refillMachineUnits,
|
refillMachineUnits,
|
||||||
updateDiagnostics
|
updateDiagnostics,
|
||||||
|
updateFailedQRScans
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
const fs = require('fs/promises')
|
||||||
|
const path = require('path')
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
const Queue = require('queue-promise')
|
const Queue = require('queue-promise')
|
||||||
const plugins = require('./plugins')
|
const plugins = require('./plugins')
|
||||||
|
|
@ -32,6 +34,7 @@ const RADAR_UPDATE_INTERVAL = 5 * T.minutes
|
||||||
const PRUNE_MACHINES_HEARTBEAT = 1 * T.day
|
const PRUNE_MACHINES_HEARTBEAT = 1 * T.day
|
||||||
const TRANSACTION_BATCH_LIFECYCLE = 20 * T.minutes
|
const TRANSACTION_BATCH_LIFECYCLE = 20 * T.minutes
|
||||||
const TICKER_RATES_INTERVAL = 59 * T.seconds
|
const TICKER_RATES_INTERVAL = 59 * T.seconds
|
||||||
|
const FAILED_SCANS_INTERVAL = 1 * T.day
|
||||||
const EXTERNAL_COMPLIANCE_INTERVAL = 1 * T.minutes
|
const EXTERNAL_COMPLIANCE_INTERVAL = 1 * T.minutes
|
||||||
|
|
||||||
const CHECK_NOTIFICATION_INTERVAL = 20 * T.seconds
|
const CHECK_NOTIFICATION_INTERVAL = 20 * T.seconds
|
||||||
|
|
@ -41,6 +44,8 @@ const CACHE_ENTRY_TTL = 3600 // seconds
|
||||||
const FAST_QUEUE_WAIT = 1 * T.seconds
|
const FAST_QUEUE_WAIT = 1 * T.seconds
|
||||||
const SLOW_QUEUE_WAIT = 10 * T.seconds
|
const SLOW_QUEUE_WAIT = 10 * T.seconds
|
||||||
|
|
||||||
|
const OPERATOR_DATA_DIR = process.env.OPERATOR_DATA_DIR
|
||||||
|
|
||||||
const FAST_QUEUE = new Queue({
|
const FAST_QUEUE = new Queue({
|
||||||
concurrent: 600,
|
concurrent: 600,
|
||||||
interval: FAST_QUEUE_WAIT
|
interval: FAST_QUEUE_WAIT
|
||||||
|
|
@ -129,6 +134,77 @@ function updateCoinAtmRadar () {
|
||||||
.then(rates => coinAtmRadar.update(rates, settings()))
|
.then(rates => coinAtmRadar.update(rates, settings()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const readdir = dirpath =>
|
||||||
|
fs.readdir(dirpath, { withFileTypes: true })
|
||||||
|
.then(_.map(entry => _.set('path', path.join(dirpath, entry.name), entry)))
|
||||||
|
|
||||||
|
const readdirRec = rootPath =>
|
||||||
|
readdir(rootPath)
|
||||||
|
.then(entries => Promise.all(
|
||||||
|
entries.map(entry => entry.isDirectory() ? readdirRec(entry.path) : [entry])
|
||||||
|
))
|
||||||
|
.then(_.flatten)
|
||||||
|
|
||||||
|
const stat = path => fs.stat(path).then(_.set('path', path))
|
||||||
|
const pathComponents = p => path.normalize(p).split(path.sep)
|
||||||
|
|
||||||
|
// @see lib/customers.js:updateIdCardData()
|
||||||
|
const cleanOldFailedPDF417Scans = () => {
|
||||||
|
const matcher = (c, pat) => typeof pat === 'function' ? pat(c) : c === pat
|
||||||
|
const PDF417ScanPathPattern = _.concat(
|
||||||
|
pathComponents(OPERATOR_DATA_DIR),
|
||||||
|
["id-operator", s => /* customerid*/ true, "idcarddata", fname => path.extname(fname) === 'jpg']
|
||||||
|
)
|
||||||
|
const isPDF417Scan = entry => {
|
||||||
|
entry = pathComponents(entry.path)
|
||||||
|
return entry.length === PDF417ScanPathPattern.length
|
||||||
|
&& _.isMatchWith(matcher, PDF417ScanPathPattern, pathComponents(entry.path))
|
||||||
|
}
|
||||||
|
|
||||||
|
let old = new Date()
|
||||||
|
old.setDate(old.getDate() - 2) // 2 days ago
|
||||||
|
old = old.getTime()
|
||||||
|
|
||||||
|
/* NOTE: Small caveat to mtime: last time the file was written to. */
|
||||||
|
const isOld = filestat => filestat.mtimeMs < old
|
||||||
|
|
||||||
|
readdirRec(path.join(OPERATOR_DATA_DIR, 'id-operator'))
|
||||||
|
.then(entries => Promise.all(
|
||||||
|
entries
|
||||||
|
.filter(entry => entry.isFile() && isPDF417Scan(entry))
|
||||||
|
.map(entry => stat(entry.path))
|
||||||
|
))
|
||||||
|
.then(filestats => Promise.all(
|
||||||
|
filestats
|
||||||
|
.filter(isOld)
|
||||||
|
.map(_.flow(_.get(['path']), fs.unlink))
|
||||||
|
))
|
||||||
|
.catch(err => {
|
||||||
|
console.log("Error cleaning up failed PDF417 scans:", err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// @see lib/machine-loader.js:updateFailedQRScans()
|
||||||
|
const cleanOldFailedQRScans = () => {
|
||||||
|
const old = new Date()
|
||||||
|
old.setDate(old.getDate() - 2) // 2 days ago
|
||||||
|
|
||||||
|
const isOld = filepath => {
|
||||||
|
const then = new Date(path.basename(filepath).replace(/-[0-9]+\.jpg$/, ''))
|
||||||
|
return then < old
|
||||||
|
}
|
||||||
|
|
||||||
|
readdirRec(path.join(OPERATOR_DATA_DIR, 'failedQRScans'))
|
||||||
|
.then(entries => Promise.all(
|
||||||
|
entries
|
||||||
|
.filter(entry => entry.isFile() && isOld(entry.path))
|
||||||
|
.map(entry => fs.unlink(entry.path))
|
||||||
|
))
|
||||||
|
.catch(err => {
|
||||||
|
console.log("Error cleaning up failed QR scans:", err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// function checkExternalCompliance (settings) {
|
// function checkExternalCompliance (settings) {
|
||||||
// return customers.checkExternalCompliance(settings)
|
// return customers.checkExternalCompliance(settings)
|
||||||
// }
|
// }
|
||||||
|
|
@ -213,6 +289,8 @@ function doPolling (schema) {
|
||||||
addToQueue(updateAndLoadSanctions, SANCTIONS_UPDATE_INTERVAL, schema, QUEUE.SLOW)
|
addToQueue(updateAndLoadSanctions, SANCTIONS_UPDATE_INTERVAL, schema, QUEUE.SLOW)
|
||||||
addToQueue(updateCoinAtmRadar, RADAR_UPDATE_INTERVAL, schema, QUEUE.SLOW)
|
addToQueue(updateCoinAtmRadar, RADAR_UPDATE_INTERVAL, schema, QUEUE.SLOW)
|
||||||
addToQueue(pi().pruneMachinesHeartbeat, PRUNE_MACHINES_HEARTBEAT, schema, QUEUE.SLOW, settings)
|
addToQueue(pi().pruneMachinesHeartbeat, PRUNE_MACHINES_HEARTBEAT, schema, QUEUE.SLOW, settings)
|
||||||
|
addToQueue(cleanOldFailedQRScans, FAILED_SCANS_INTERVAL, schema, QUEUE.SLOW, settings)
|
||||||
|
addToQueue(cleanOldFailedPDF417Scans, FAILED_SCANS_INTERVAL, schema, QUEUE.SLOW, settings)
|
||||||
// addToQueue(checkExternalCompliance, EXTERNAL_COMPLIANCE_INTERVAL, schema, QUEUE.SLOW, settings)
|
// addToQueue(checkExternalCompliance, EXTERNAL_COMPLIANCE_INTERVAL, schema, QUEUE.SLOW, settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ const verifyUserRoutes = require('./routes/verifyUserRoutes')
|
||||||
const verifyTxRoutes = require('./routes/verifyTxRoutes')
|
const verifyTxRoutes = require('./routes/verifyTxRoutes')
|
||||||
const verifyPromoCodeRoutes = require('./routes/verifyPromoCodeRoutes')
|
const verifyPromoCodeRoutes = require('./routes/verifyPromoCodeRoutes')
|
||||||
const probeRoutes = require('./routes/probeLnRoutes')
|
const probeRoutes = require('./routes/probeLnRoutes')
|
||||||
|
const failedQRScansRoutes = require('./routes/failedQRScans')
|
||||||
|
|
||||||
const graphQLServer = require('./graphql/server')
|
const graphQLServer = require('./graphql/server')
|
||||||
|
|
||||||
|
|
@ -75,6 +76,7 @@ app.use('/cashbox', cashboxRoutes)
|
||||||
|
|
||||||
app.use('/network', performanceRoutes)
|
app.use('/network', performanceRoutes)
|
||||||
app.use('/diagnostics', diagnosticsRoutes)
|
app.use('/diagnostics', diagnosticsRoutes)
|
||||||
|
app.use('/failedqrscans', failedQRScansRoutes)
|
||||||
|
|
||||||
app.use('/verify_user', verifyUserRoutes)
|
app.use('/verify_user', verifyUserRoutes)
|
||||||
app.use('/verify_transaction', verifyTxRoutes)
|
app.use('/verify_transaction', verifyTxRoutes)
|
||||||
|
|
|
||||||
14
lib/routes/failedQRScans.js
Normal file
14
lib/routes/failedQRScans.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
const express = require('express')
|
||||||
|
const router = express.Router()
|
||||||
|
|
||||||
|
const { updateFailedQRScans } = require('../machine-loader')
|
||||||
|
|
||||||
|
function failedQRScans (req, res, next) {
|
||||||
|
return updateFailedQRScans(req.deviceId, req.body)
|
||||||
|
.then(() => res.status(200).send({ status: 'OK' }))
|
||||||
|
.catch(next)
|
||||||
|
}
|
||||||
|
|
||||||
|
router.post('/', failedQRScans)
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
Loading…
Add table
Add a link
Reference in a new issue