diff --git a/lib/db/api.js b/lib/db/api.js index 8281c7ca..c1a5b372 100644 --- a/lib/db/api.js +++ b/lib/db/api.js @@ -1,5 +1,5 @@ /** -* Copyright © 2019 contains code contributed by Orange SA, authors: Denis Barbaron - Licensed under the Apache license 2.0 +* Copyright © 2019,2023 contains code contributed by Orange SA, authors: Denis Barbaron - Licensed under the Apache license 2.0 **/ var r = require('rethinkdb') @@ -278,6 +278,30 @@ dbapi.lockBookableDevice = function(groups, serial) { , Math.random() * 500 + 50) } +dbapi.lockDeviceByCurrent = function(groups, serial) { + function wrappedlockDeviceByCurrent() { + return db.run(r.table('devices').get(serial).update({group: {lock: + r.branch( + r.row('group')('lock') + .eq(false) + .and(r.expr(groups) + .setIntersection([r.row('group')('id')]) + .isEmpty() + .not()) + , true + , r.row('group')('lock')) + }}, {returnChanges: true})) + .then(function(stats) { + return apiutil.lockDeviceResult(stats, dbapi.loadDeviceByCurrent, groups, serial) + }) + } + + return apiutil.setIntervalWrapper( + wrappedlockDeviceByCurrent + , 10 + , Math.random() * 500 + 50) +} + dbapi.lockDeviceByOrigin = function(groups, serial) { function wrappedlockDeviceByOrigin() { return db.run(r.table('devices').get(serial).update({group: {lock: @@ -1362,6 +1386,15 @@ dbapi.loadBookableDevice = function(groups, serial) { }) } +dbapi.loadDeviceByCurrent = function(groups, serial) { + return db.run(r.table('devices').getAll(serial).filter(function(device) { + return r.expr(groups).contains(device('group')('id')) + })) + .then(function(cursor) { + return cursor.toArray() + }) +} + dbapi.loadDeviceByOrigin = function(groups, serial) { return db.run(r.table('devices').getAll(serial).filter(function(device) { return r.expr(groups).contains(device('group')('origin')) diff --git a/lib/units/api/controllers/user.js b/lib/units/api/controllers/user.js index 2710e4da..97be85db 100644 --- a/lib/units/api/controllers/user.js +++ b/lib/units/api/controllers/user.js @@ -1,5 +1,5 @@ /** -* Copyright © 2019 contains code contributed by Orange SA, authors: Denis Barbaron - Licensed under the Apache license 2.0 +* Copyright © 2019,2023 contains code contributed by Orange SA, authors: Denis Barbaron - Licensed under the Apache license 2.0 **/ var util = require('util') @@ -18,6 +18,7 @@ var wirerouter = require('../../../wire/router') const apiutil = require('../../../util/apiutil') const jwtutil = require('../../../util/jwtutil') +const lockutil = require('../../../util/lockutil') var log = logger.createLogger('api:controllers:user') @@ -128,16 +129,12 @@ function addUserDevice(req, res) { var serial = req.hasOwnProperty('body') ? req.body.serial : req.swagger.params.serial.value var timeout = req.hasOwnProperty('body') ? req.body.timeout || null : req.swagger.params.timeout.value || null + const lock = {} - dbapi.loadDevice(req.user.groups.subscribed, serial) - .then(function(cursor) { - cursor.next(function(err, device) { - if (err) { - return res.status(404).json({ - success: false - , description: 'Device not found' - }) - } + lockutil.lockGenericDevice(req, res, lock, dbapi.lockDeviceByCurrent) + .then(function(lockingSuccessed) { + if (lockingSuccessed) { + const device = lock.device datautil.normalize(device, req.user) if (!deviceutil.isAddable(device, req.user)) { @@ -193,14 +190,14 @@ function addUserDevice(req, res) { ) ) ]) - }) + } + return false }) .catch(function(err) { - log.error('Failed to load device "%s": ', req.params.serial, err.stack) - res.status(500).json({ - success: false - , description: 'Internal Server Error' - }) + apiutil.internalError(res, `Failed to take control of ${serial} device: `, err.stack) + }) + .finally(function() { + lockutil.unlockDevice(lock) }) } diff --git a/lib/util/lockutil.js b/lib/util/lockutil.js index 1e2c77e7..959f1caf 100644 --- a/lib/util/lockutil.js +++ b/lib/util/lockutil.js @@ -1,5 +1,5 @@ /** -* Copyright © 2019 code initially contributed by Orange SA, authors: Denis Barbaron - Licensed under the Apache license 2.0 +* Copyright © 2019,2023 code initially contributed by Orange SA, authors: Denis Barbaron - Licensed under the Apache license 2.0 **/ const apiutil = require('./apiutil') @@ -60,7 +60,9 @@ lockutil.unlockGroupAndDevice = function(lock) { } lockutil.lockGenericDevice = function(req, res, lock, lockDevice) { - return lockDevice(req.user.groups.subscribed, req.swagger.params.serial.value) + return lockDevice(req.user.groups.subscribed, + req.hasOwnProperty('body') ? req.body.serial : req.swagger.params.serial.value) + .then(function(stats) { return apiutil.computeStats(res, stats, 'device', lock) })