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:
Rafael Taranto 2024-08-05 13:42:31 +01:00 committed by GitHub
commit 8381b3d9ec
4 changed files with 108 additions and 10 deletions

View file

@ -487,11 +487,18 @@ function updateDiagnostics (deviceId, images) {
const directory = `${OPERATOR_DATA_DIR}/diagnostics/${deviceId}/`
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]))
.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) {
if (!data) {
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)
}
function updatePhotos (scan, front, dir) {
function updatePhotos (dir, photoPairs) {
const dirname = path.join(dir)
_.attempt(() => makeDir.sync(dirname))
const promises = [
createPhoto('scan.jpg', scan, dirname),
createPhoto('front.jpg', front, dirname)
]
return Promise.all(promises)
return Promise.all(photoPairs.map(
([filename, data]) => createPhoto(filename, data, dirname)
))
}
module.exports = {
@ -530,5 +533,6 @@ module.exports = {
getMachineIds,
emptyMachineUnits,
refillMachineUnits,
updateDiagnostics
updateDiagnostics,
updateFailedQRScans
}

View file

@ -1,3 +1,5 @@
const fs = require('fs/promises')
const path = require('path')
const _ = require('lodash/fp')
const Queue = require('queue-promise')
const plugins = require('./plugins')
@ -32,6 +34,7 @@ const RADAR_UPDATE_INTERVAL = 5 * T.minutes
const PRUNE_MACHINES_HEARTBEAT = 1 * T.day
const TRANSACTION_BATCH_LIFECYCLE = 20 * T.minutes
const TICKER_RATES_INTERVAL = 59 * T.seconds
const FAILED_SCANS_INTERVAL = 1 * T.day
const EXTERNAL_COMPLIANCE_INTERVAL = 1 * T.minutes
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 SLOW_QUEUE_WAIT = 10 * T.seconds
const OPERATOR_DATA_DIR = process.env.OPERATOR_DATA_DIR
const FAST_QUEUE = new Queue({
concurrent: 600,
interval: FAST_QUEUE_WAIT
@ -129,6 +134,77 @@ function updateCoinAtmRadar () {
.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) {
// return customers.checkExternalCompliance(settings)
// }
@ -213,6 +289,8 @@ function doPolling (schema) {
addToQueue(updateAndLoadSanctions, SANCTIONS_UPDATE_INTERVAL, schema, QUEUE.SLOW)
addToQueue(updateCoinAtmRadar, RADAR_UPDATE_INTERVAL, schema, QUEUE.SLOW)
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)
}

View file

@ -32,6 +32,7 @@ const verifyUserRoutes = require('./routes/verifyUserRoutes')
const verifyTxRoutes = require('./routes/verifyTxRoutes')
const verifyPromoCodeRoutes = require('./routes/verifyPromoCodeRoutes')
const probeRoutes = require('./routes/probeLnRoutes')
const failedQRScansRoutes = require('./routes/failedQRScans')
const graphQLServer = require('./graphql/server')
@ -75,6 +76,7 @@ app.use('/cashbox', cashboxRoutes)
app.use('/network', performanceRoutes)
app.use('/diagnostics', diagnosticsRoutes)
app.use('/failedqrscans', failedQRScansRoutes)
app.use('/verify_user', verifyUserRoutes)
app.use('/verify_transaction', verifyTxRoutes)

View 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