mirror of
https://github.com/openstf/stf
synced 2025-10-04 10:19:30 +02:00
Modify APIs from Aysnc -> Sync using timeout
This commit is contained in:
parent
d67d06a19f
commit
a6266931ad
10 changed files with 354 additions and 239 deletions
|
@ -874,6 +874,9 @@ program
|
||||||
.option('-c, --connect-push <endpoint>'
|
.option('-c, --connect-push <endpoint>'
|
||||||
, 'push endpoint'
|
, 'push endpoint'
|
||||||
, cliutil.list)
|
, cliutil.list)
|
||||||
|
.option('-u, --connect-sub <endpoint>'
|
||||||
|
, 'sub endpoint'
|
||||||
|
, cliutil.list)
|
||||||
.action(function(options) {
|
.action(function(options) {
|
||||||
if (!options.secret) {
|
if (!options.secret) {
|
||||||
this.missingArgument('--secret')
|
this.missingArgument('--secret')
|
||||||
|
@ -881,6 +884,9 @@ program
|
||||||
if (!options.connectPush) {
|
if (!options.connectPush) {
|
||||||
this.missingArgument('--connect-push')
|
this.missingArgument('--connect-push')
|
||||||
}
|
}
|
||||||
|
if (!options.connectSub) {
|
||||||
|
this.missingArgument('--connect-sub')
|
||||||
|
}
|
||||||
|
|
||||||
require('./units/api')({
|
require('./units/api')({
|
||||||
port: options.port
|
port: options.port
|
||||||
|
@ -888,6 +894,7 @@ program
|
||||||
, secret: options.secret
|
, secret: options.secret
|
||||||
, endpoints: {
|
, endpoints: {
|
||||||
push: options.connectPush
|
push: options.connectPush
|
||||||
|
, sub: options.connectSub
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1338,6 +1345,7 @@ program
|
||||||
, '--port', options.apiPort
|
, '--port', options.apiPort
|
||||||
, '--secret', options.authSecret
|
, '--secret', options.authSecret
|
||||||
, '--connect-push', options.bindAppPull
|
, '--connect-push', options.bindAppPull
|
||||||
|
, '--connect-sub', options.bindAppPub
|
||||||
])
|
])
|
||||||
// websocket
|
// websocket
|
||||||
, procutil.fork(__filename, [
|
, procutil.fork(__filename, [
|
||||||
|
|
|
@ -152,7 +152,7 @@ dbapi.saveDeviceInitialState = function(serial, device) {
|
||||||
, ready: false
|
, ready: false
|
||||||
, reverseForwards: []
|
, reverseForwards: []
|
||||||
, remoteConnect: false
|
, remoteConnect: false
|
||||||
, remoteDebugUrl: null
|
, remoteConnectUrl: null
|
||||||
}
|
}
|
||||||
return db.run(r.table('devices').get(serial).update(data))
|
return db.run(r.table('devices').get(serial).update(data))
|
||||||
.then(function(stats) {
|
.then(function(stats) {
|
||||||
|
@ -167,14 +167,14 @@ dbapi.saveDeviceInitialState = function(serial, device) {
|
||||||
|
|
||||||
dbapi.setDeviceConnectUrl = function(serial, url) {
|
dbapi.setDeviceConnectUrl = function(serial, url) {
|
||||||
return db.run(r.table('devices').get(serial).update({
|
return db.run(r.table('devices').get(serial).update({
|
||||||
remoteDebugUrl: url
|
remoteConnectUrl: url
|
||||||
, remoteConnect: true
|
, remoteConnect: true
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
dbapi.unsetDeviceConnectUrl = function(serial, url) {
|
dbapi.unsetDeviceConnectUrl = function(serial, url) {
|
||||||
return db.run(r.table('devices').get(serial).update({
|
return db.run(r.table('devices').get(serial).update({
|
||||||
remoteDebugUrl: null
|
remoteConnectUrl: null
|
||||||
, remoteConnect: false
|
, remoteConnect: false
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,24 +49,22 @@ function getDeviceBySerial(req, res) {
|
||||||
|
|
||||||
dbapi.loadDevice(serial)
|
dbapi.loadDevice(serial)
|
||||||
.then(function(device) {
|
.then(function(device) {
|
||||||
if (device) {
|
if (!device) {
|
||||||
datautil.normalize(device, req.user)
|
return res.status(404).json({
|
||||||
|
|
||||||
if(fields) {
|
|
||||||
device = _.pick(device, fields.split(','))
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true
|
|
||||||
, device: device
|
|
||||||
})
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
res.status(404).json({
|
|
||||||
success: false
|
success: false
|
||||||
, description: 'Device not found'
|
, description: 'Device not found'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
datautil.normalize(device, req.user)
|
||||||
|
if(fields) {
|
||||||
|
device = _.pick(device, fields.split(','))
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true
|
||||||
|
, device: device
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
log.error('Failed to load device "%s": ', req.params.serial, err.stack)
|
log.error('Failed to load device "%s": ', req.params.serial, err.stack)
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
var util = require('util')
|
var util = require('util')
|
||||||
|
|
||||||
var Promise = require('bluebird')
|
|
||||||
var _ = require('lodash')
|
var _ = require('lodash')
|
||||||
|
var Promise = require('bluebird')
|
||||||
|
var uuid = require('node-uuid')
|
||||||
|
|
||||||
var dbapi = require('../../../db/api')
|
var dbapi = require('../../../db/api')
|
||||||
var logger = require('../../../util/logger')
|
var logger = require('../../../util/logger')
|
||||||
var datautil = require('../../../util/datautil')
|
var datautil = require('../../../util/datautil')
|
||||||
|
var deviceutil = require('../../../util/deviceutil')
|
||||||
var wire = require('../../../wire')
|
var wire = require('../../../wire')
|
||||||
var wireutil = require('../../../wire/util')
|
var wireutil = require('../../../wire/util')
|
||||||
|
var wirerouter = require('../../../wire/router')
|
||||||
|
|
||||||
var log = logger.createLogger('api:controllers:user')
|
var log = logger.createLogger('api:controllers:user')
|
||||||
|
|
||||||
|
@ -66,32 +69,29 @@ function getUserDeviceBySerial(req, res) {
|
||||||
|
|
||||||
dbapi.loadDevice(serial)
|
dbapi.loadDevice(serial)
|
||||||
.then(function(device) {
|
.then(function(device) {
|
||||||
if (device) {
|
if (!device) {
|
||||||
datautil.normalize(device, req.user)
|
return res.status(404).json({
|
||||||
|
|
||||||
if (device.owner && device.owner.email === req.user.email) {
|
|
||||||
if(fields) {
|
|
||||||
device = _.pick(device, fields.split(','))
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true
|
|
||||||
, device: device
|
|
||||||
})
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
res.status(401).json({
|
|
||||||
success: false
|
|
||||||
, description: 'Device is not owned by you'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
res.status(404).json({
|
|
||||||
success: false
|
success: false
|
||||||
, description: 'Device not found'
|
, description: 'Device not found'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
datautil.normalize(device, req.user)
|
||||||
|
if (!deviceutil.isOwnedByUser(device, req.user)) {
|
||||||
|
return res.status(403).json({
|
||||||
|
success: false
|
||||||
|
, description: 'Device is not owned by you'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fields) {
|
||||||
|
device = _.pick(device, fields.split(','))
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true
|
||||||
|
, device: device
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
log.error('Failed to load device "%s": ', req.params.serial, err.stack)
|
log.error('Failed to load device "%s": ', req.params.serial, err.stack)
|
||||||
|
@ -107,55 +107,71 @@ function addUserDevice(req, res) {
|
||||||
|
|
||||||
dbapi.loadDevice(serial)
|
dbapi.loadDevice(serial)
|
||||||
.then(function(device) {
|
.then(function(device) {
|
||||||
if (device) {
|
if (!device) {
|
||||||
datautil.normalize(device, req.user)
|
return res.status(404).json({
|
||||||
if(device.present && device.ready && !device.using && !device.owner) {
|
|
||||||
|
|
||||||
var requirements = {
|
|
||||||
'serial': {
|
|
||||||
'value': serial,
|
|
||||||
'match': 'exact'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
req.options.push.send([
|
|
||||||
device.channel
|
|
||||||
, wireutil.envelope(
|
|
||||||
new wire.GroupMessage(
|
|
||||||
new wire.OwnerMessage(
|
|
||||||
req.user.email
|
|
||||||
, req.user.name
|
|
||||||
, req.user.group
|
|
||||||
)
|
|
||||||
, timeout
|
|
||||||
, wireutil.toDeviceRequirements(requirements)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
])
|
|
||||||
|
|
||||||
res.status(202).json({
|
|
||||||
success: true
|
|
||||||
, description: 'Device Add request is accepted. Check if device is successfully added using pollingUrl'
|
|
||||||
, pollingUrl: util.format('%s://%s%s/user/devices/%s'
|
|
||||||
, req.protocol
|
|
||||||
, req.get('host')
|
|
||||||
, req.swagger.operation.api.basePath
|
|
||||||
, serial
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
} else {
|
|
||||||
res.status(401).json({
|
|
||||||
success: false
|
|
||||||
, description: 'Device is being used or not available'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res.status(404).json({
|
|
||||||
success: false
|
success: false
|
||||||
, description: 'Bad device serial'
|
, description: 'Device not found'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
datautil.normalize(device, req.user)
|
||||||
|
if (!deviceutil.isAddable(device, req.user)) {
|
||||||
|
return res.status(403).json({
|
||||||
|
success: false
|
||||||
|
, description: 'Device is being used or not available'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timer will be called if no JoinGroupMessage is received till 5 seconds
|
||||||
|
var responseTimer = setTimeout(function() {
|
||||||
|
req.options.channelRouter.removeListener(wireutil.global, messageListener)
|
||||||
|
return res.status(504).json({
|
||||||
|
success: false
|
||||||
|
, description: 'Device is not responding'
|
||||||
|
})
|
||||||
|
}, 5000)
|
||||||
|
|
||||||
|
var messageListener = wirerouter()
|
||||||
|
.on(wire.JoinGroupMessage, function(channel, message) {
|
||||||
|
if (message.serial === serial && message.owner.email === req.user.email) {
|
||||||
|
clearTimeout(responseTimer)
|
||||||
|
req.options.channelRouter.removeListener(wireutil.global, messageListener)
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
success: true
|
||||||
|
, description: 'Device successfully added'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.handler()
|
||||||
|
|
||||||
|
req.options.channelRouter.on(wireutil.global, messageListener)
|
||||||
|
|
||||||
|
req.options.push.send([
|
||||||
|
device.channel
|
||||||
|
, wireutil.envelope(
|
||||||
|
new wire.GroupMessage(
|
||||||
|
new wire.OwnerMessage(
|
||||||
|
req.user.email
|
||||||
|
, req.user.name
|
||||||
|
, req.user.group
|
||||||
|
)
|
||||||
|
, timeout
|
||||||
|
, wireutil.toDeviceRequirements({
|
||||||
|
'serial': {
|
||||||
|
'value': serial
|
||||||
|
, 'match': 'exact'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
])
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
log.error('Failed to load device "%s": ', req.params.serial, err.stack)
|
||||||
|
res.status(500).json({
|
||||||
|
success: false
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,49 +180,66 @@ function deleteUserDeviceBySerial(req, res) {
|
||||||
|
|
||||||
dbapi.loadDevice(serial)
|
dbapi.loadDevice(serial)
|
||||||
.then(function(device) {
|
.then(function(device) {
|
||||||
if (device) {
|
if (!device) {
|
||||||
datautil.normalize(device, req.user)
|
return res.status(404).json({
|
||||||
if(device.using && device.owner.email == req.user.email) {
|
|
||||||
|
|
||||||
var requirements = {
|
|
||||||
'serial': {
|
|
||||||
'value': serial,
|
|
||||||
'match': 'exact'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
req.options.push.send([
|
|
||||||
device.channel
|
|
||||||
, wireutil.envelope(
|
|
||||||
new wire.UngroupMessage(
|
|
||||||
wireutil.toDeviceRequirements(requirements)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
])
|
|
||||||
|
|
||||||
res.status(202).json({
|
|
||||||
success: true
|
|
||||||
, description: 'Device Release request is accepted. Check if device is successfully removed using pollingUrl'
|
|
||||||
, pollingUrl: util.format('%s://%s%s/user/devices/%s'
|
|
||||||
, req.protocol
|
|
||||||
, req.get('host')
|
|
||||||
, req.swagger.operation.api.basePath
|
|
||||||
, serial
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
} else {
|
|
||||||
res.status(401).json({
|
|
||||||
success: false
|
|
||||||
, description: 'You cannot kick this device'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res.status(404).json({
|
|
||||||
success: false
|
success: false
|
||||||
, description: 'Bad device serial'
|
, description: 'Device not found'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
datautil.normalize(device, req.user)
|
||||||
|
if (!deviceutil.isOwnedByUser(device, req.user)) {
|
||||||
|
return res.status(403).json({
|
||||||
|
success: false
|
||||||
|
, description: 'You cannot release this device. Not owned by you'
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timer will be called if no JoinGroupMessage is received till 5 seconds
|
||||||
|
var responseTimer = setTimeout(function() {
|
||||||
|
req.options.channelRouter.removeListener(wireutil.global, messageListener)
|
||||||
|
return res.status(504).json({
|
||||||
|
success: false
|
||||||
|
, description: 'Device is not responding'
|
||||||
|
})
|
||||||
|
}, 5000)
|
||||||
|
|
||||||
|
var messageListener = wirerouter()
|
||||||
|
.on(wire.LeaveGroupMessage, function(channel, message) {
|
||||||
|
if (message.serial === serial && message.owner.email === req.user.email) {
|
||||||
|
clearTimeout(responseTimer)
|
||||||
|
req.options.channelRouter.removeListener(wireutil.global, messageListener)
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
success: true
|
||||||
|
, description: 'Device successfully removed'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.handler()
|
||||||
|
|
||||||
|
req.options.channelRouter.on(wireutil.global, messageListener)
|
||||||
|
|
||||||
|
req.options.push.send([
|
||||||
|
device.channel
|
||||||
|
, wireutil.envelope(
|
||||||
|
new wire.UngroupMessage(
|
||||||
|
wireutil.toDeviceRequirements({
|
||||||
|
'serial': {
|
||||||
|
'value': serial
|
||||||
|
, 'match': 'exact'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
])
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
log.error('Failed to load device "%s": ', req.params.serial, err.stack)
|
||||||
|
res.status(500).json({
|
||||||
|
success: false
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,41 +248,58 @@ function remoteConnectUserDeviceBySerial(req, res) {
|
||||||
|
|
||||||
dbapi.loadDevice(serial)
|
dbapi.loadDevice(serial)
|
||||||
.then(function(device) {
|
.then(function(device) {
|
||||||
if (device) {
|
if (!device) {
|
||||||
datautil.normalize(device, req.user)
|
return res.status(404).json({
|
||||||
|
|
||||||
if (device.present && device.ready && device.using && device.owner.email === req.user.email) {
|
|
||||||
req.options.push.send([
|
|
||||||
device.channel
|
|
||||||
, wireutil.envelope(
|
|
||||||
new wire.ConnectStartMessage()
|
|
||||||
)
|
|
||||||
])
|
|
||||||
|
|
||||||
res.status(202).json({
|
|
||||||
success: true
|
|
||||||
, description: 'Device Connect request is accepted. Check if device is successfully connected using pollingUrl'
|
|
||||||
, pollingUrl: util.format('%s://%s%s/user/devices/%s'
|
|
||||||
, req.protocol
|
|
||||||
, req.get('host')
|
|
||||||
, req.swagger.operation.api.basePath
|
|
||||||
, serial
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
res.status(401).json({
|
|
||||||
success: false
|
|
||||||
, description: 'Device is not owned by you or is not available'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
res.status(404).json({
|
|
||||||
success: false
|
success: false
|
||||||
, description: 'Device not found'
|
, description: 'Device not found'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
datautil.normalize(device, req.user)
|
||||||
|
if (!deviceutil.isOwnedByUser(device, req.user)) {
|
||||||
|
return res.status(403).json({
|
||||||
|
success: false
|
||||||
|
, description: 'Device is not owned by you or is not available'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var responseChannel = 'txn_' + uuid.v4()
|
||||||
|
req.options.sub.subscribe(responseChannel)
|
||||||
|
|
||||||
|
// Timer will be called if no JoinGroupMessage is received till 5 seconds
|
||||||
|
var timer = setTimeout(function() {
|
||||||
|
req.options.channelRouter.removeListener(responseChannel, messageListener)
|
||||||
|
req.options.sub.unsubscribe(responseChannel)
|
||||||
|
return res.status(504).json({
|
||||||
|
success: false
|
||||||
|
, description: 'Device is not responding'
|
||||||
|
})
|
||||||
|
}, 5000)
|
||||||
|
|
||||||
|
var messageListener = wirerouter()
|
||||||
|
.on(wire.ConnectStartedMessage, function(channel, message) {
|
||||||
|
if (message.serial === serial) {
|
||||||
|
clearTimeout(timer)
|
||||||
|
req.options.sub.unsubscribe(responseChannel)
|
||||||
|
req.options.channelRouter.removeListener(responseChannel, messageListener)
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
success: true
|
||||||
|
, remoteConnectUrl: message.url
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.handler()
|
||||||
|
|
||||||
|
req.options.channelRouter.on(responseChannel, messageListener)
|
||||||
|
|
||||||
|
req.options.push.send([
|
||||||
|
device.channel
|
||||||
|
, wireutil.transaction(
|
||||||
|
responseChannel
|
||||||
|
, new wire.ConnectStartMessage()
|
||||||
|
)
|
||||||
|
])
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
log.error('Failed to load device "%s": ', req.params.serial, err.stack)
|
log.error('Failed to load device "%s": ', req.params.serial, err.stack)
|
||||||
|
@ -264,41 +314,59 @@ function remoteDisconnectUserDeviceBySerial(req, res) {
|
||||||
|
|
||||||
dbapi.loadDevice(serial)
|
dbapi.loadDevice(serial)
|
||||||
.then(function(device) {
|
.then(function(device) {
|
||||||
if (device) {
|
|
||||||
datautil.normalize(device, req.user)
|
|
||||||
|
|
||||||
if (device.present && device.ready && device.using && device.owner.email == req.user.email) {
|
if (!device) {
|
||||||
req.options.push.send([
|
return res.status(404).json({
|
||||||
device.channel
|
|
||||||
, wireutil.envelope(
|
|
||||||
new wire.ConnectStopMessage()
|
|
||||||
)
|
|
||||||
])
|
|
||||||
|
|
||||||
res.status(202).json({
|
|
||||||
success: true
|
|
||||||
, description: 'Device Disonnect request is accepted. Check if device is successfully disconnected using pollingUrl'
|
|
||||||
, pollingUrl: util.format('%s://%s%s/user/devices/%s'
|
|
||||||
, req.protocol
|
|
||||||
, req.get('host')
|
|
||||||
, req.swagger.operation.api.basePath
|
|
||||||
, serial
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
res.status(401).json({
|
|
||||||
success: false
|
|
||||||
, description: 'Device is not owned by you or is not available'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
res.status(404).json({
|
|
||||||
success: false
|
success: false
|
||||||
, description: 'Device not found'
|
, description: 'Device not found'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
datautil.normalize(device, req.user)
|
||||||
|
if (!deviceutil.isOwnedByUser(device, req.user)) {
|
||||||
|
return res.status(403).json({
|
||||||
|
success: false
|
||||||
|
, description: 'Device is not owned by you or is not available'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var responseChannel = 'txn_' + uuid.v4()
|
||||||
|
req.options.sub.subscribe(responseChannel)
|
||||||
|
|
||||||
|
// Timer will be called if no JoinGroupMessage is received till 5 seconds
|
||||||
|
var timer = setTimeout(function() {
|
||||||
|
req.options.channelRouter.removeListener(responseChannel, messageListener)
|
||||||
|
req.options.sub.unsubscribe(responseChannel)
|
||||||
|
return res.status(504).json({
|
||||||
|
success: false
|
||||||
|
, description: 'Device is not responding'
|
||||||
|
})
|
||||||
|
}, 5000)
|
||||||
|
|
||||||
|
var messageListener = wirerouter()
|
||||||
|
.on(wire.ConnectStoppedMessage, function(channel, message) {
|
||||||
|
if (message.serial === serial) {
|
||||||
|
clearTimeout(timer)
|
||||||
|
req.options.sub.unsubscribe(responseChannel)
|
||||||
|
req.options.channelRouter.removeListener(responseChannel, messageListener)
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
success: true
|
||||||
|
, description: 'Device remote disconnected successfully'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.handler()
|
||||||
|
|
||||||
|
req.options.channelRouter.on(responseChannel, messageListener)
|
||||||
|
|
||||||
|
req.options.push.send([
|
||||||
|
device.channel
|
||||||
|
, wireutil.transaction(
|
||||||
|
responseChannel
|
||||||
|
, new wire.ConnectStopMessage()
|
||||||
|
)
|
||||||
|
])
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
log.error('Failed to load device "%s": ', req.params.serial, err.stack)
|
log.error('Failed to load device "%s": ', req.params.serial, err.stack)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
var http = require('http')
|
var http = require('http')
|
||||||
var path = require('path')
|
var path = require('path')
|
||||||
|
var events = require('events')
|
||||||
|
|
||||||
var express = require('express')
|
var express = require('express')
|
||||||
var SwaggerExpress = require('swagger-express-mw')
|
var SwaggerExpress = require('swagger-express-mw')
|
||||||
|
@ -11,11 +12,13 @@ var logger = require('../../util/logger')
|
||||||
var zmqutil = require('../../util/zmqutil')
|
var zmqutil = require('../../util/zmqutil')
|
||||||
var srv = require('../../util/srv')
|
var srv = require('../../util/srv')
|
||||||
var lifecycle = require('../../util/lifecycle')
|
var lifecycle = require('../../util/lifecycle')
|
||||||
|
var wireutil = require('../../wire/util')
|
||||||
|
|
||||||
module.exports = function(options) {
|
module.exports = function(options) {
|
||||||
var log = logger.createLogger('api')
|
var log = logger.createLogger('api')
|
||||||
, app = express()
|
, app = express()
|
||||||
, server = http.createServer(app)
|
, server = http.createServer(app)
|
||||||
|
, channelRouter = new events.EventEmitter()
|
||||||
|
|
||||||
var push = zmqutil.socket('push')
|
var push = zmqutil.socket('push')
|
||||||
Promise.map(options.endpoints.push, function(endpoint) {
|
Promise.map(options.endpoints.push, function(endpoint) {
|
||||||
|
@ -27,18 +30,47 @@ module.exports = function(options) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {w
|
||||||
log.fatal('Unable to connect to push endpoint', err)
|
log.fatal('Unable to connect to push endpoint', err)
|
||||||
lifecycle.fatal()
|
lifecycle.fatal()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Input
|
||||||
|
var sub = zmqutil.socket('sub')
|
||||||
|
Promise.map(options.endpoints.sub, function(endpoint) {
|
||||||
|
return srv.resolve(endpoint).then(function(records) {
|
||||||
|
return srv.attempt(records, function(record) {
|
||||||
|
log.info('Receiving input from "%s"', record.url)
|
||||||
|
sub.connect(record.url)
|
||||||
|
return Promise.resolve(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
log.fatal('Unable to connect to sub endpoint', err)
|
||||||
|
lifecycle.fatal()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Establish always-on channels
|
||||||
|
;[wireutil.global].forEach(function(channel) {
|
||||||
|
log.info('Subscribing to permanent channel "%s"', channel)
|
||||||
|
sub.subscribe(channel)
|
||||||
|
})
|
||||||
|
|
||||||
|
sub.on('message', function(channel, data) {
|
||||||
|
channelRouter.emit(channel.toString(), channel, data)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Swagger Express Config
|
||||||
var config = {
|
var config = {
|
||||||
appRoot: __dirname
|
appRoot: __dirname
|
||||||
, swaggerFile: path.resolve(__dirname, 'swagger', 'api_v1.yaml')
|
, swaggerFile: path.resolve(__dirname, 'swagger', 'api_v1.yaml')
|
||||||
};
|
};
|
||||||
|
|
||||||
SwaggerExpress.create(config, function(err, swaggerExpress) {
|
SwaggerExpress.create(config, function(err, swaggerExpress) {
|
||||||
if (err) { throw err; }
|
if (err) {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
swaggerExpress.register(app);
|
swaggerExpress.register(app);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -47,6 +79,8 @@ module.exports = function(options) {
|
||||||
app.use(function(req, res, next) {
|
app.use(function(req, res, next) {
|
||||||
var reqOptions = _.merge(options, {
|
var reqOptions = _.merge(options, {
|
||||||
'push': push
|
'push': push
|
||||||
|
, 'sub': sub
|
||||||
|
, 'channelRouter': channelRouter
|
||||||
})
|
})
|
||||||
|
|
||||||
req.options = reqOptions
|
req.options = reqOptions
|
||||||
|
@ -59,6 +93,17 @@ module.exports = function(options) {
|
||||||
, keys: [options.secret]
|
, keys: [options.secret]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
lifecycle.observe(function() {
|
||||||
|
[push, sub].forEach(function(sock) {
|
||||||
|
try {
|
||||||
|
sock.close()
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
// No-op
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
server.listen(options.port)
|
server.listen(options.port)
|
||||||
log.info('Listening on port %d', options.port)
|
log.info('Listening on port %d', options.port)
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ paths:
|
||||||
/user/devices:
|
/user/devices:
|
||||||
x-swagger-router-controller: user
|
x-swagger-router-controller: user
|
||||||
get:
|
get:
|
||||||
summary: List devices owned by current user
|
summary: User Devices
|
||||||
description: The User Devices endpoint returns device list owner by current authorized user
|
description: The User Devices endpoint returns device list owner by current authorized user
|
||||||
operationId: getUserDevices
|
operationId: getUserDevices
|
||||||
tags:
|
tags:
|
||||||
|
@ -70,22 +70,20 @@ paths:
|
||||||
- accessTokenAuth: []
|
- accessTokenAuth: []
|
||||||
post:
|
post:
|
||||||
summary: Add a device to a user
|
summary: Add a device to a user
|
||||||
description: The User Devices endpoint will request stf server for a new device. It will return request accepted if device is usable
|
description: The User Devices endpoint will request stf server for a new device.
|
||||||
operationId: addUserDevice
|
operationId: addUserDevice
|
||||||
tags:
|
tags:
|
||||||
- user
|
- user
|
||||||
parameters:
|
parameters:
|
||||||
- name: devices
|
- name: device
|
||||||
in: body
|
in: body
|
||||||
description: Device to add
|
description: Device to add
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/AddUserDevicePayload"
|
$ref: "#/definitions/AddUserDevicePayload"
|
||||||
responses:
|
responses:
|
||||||
"202":
|
"200":
|
||||||
description: Add User Device Request Status and polling Url
|
description: Add User Device Status
|
||||||
schema:
|
|
||||||
$ref: "#/definitions/AddUserDeviceResponse"
|
|
||||||
default:
|
default:
|
||||||
description: Unexpected Error
|
description: Unexpected Error
|
||||||
schema:
|
schema:
|
||||||
|
@ -95,8 +93,8 @@ paths:
|
||||||
/user/devices/{serial}:
|
/user/devices/{serial}:
|
||||||
x-swagger-router-controller: user
|
x-swagger-router-controller: user
|
||||||
get:
|
get:
|
||||||
summary: Device Information
|
summary: User Device
|
||||||
description: The device enpoint return information about device owned by user
|
description: The devices enpoint return information about device owned by user
|
||||||
operationId: getUserDeviceBySerial
|
operationId: getUserDeviceBySerial
|
||||||
tags:
|
tags:
|
||||||
- user
|
- user
|
||||||
|
@ -113,9 +111,9 @@ paths:
|
||||||
type: string
|
type: string
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: Delete User Device Request Status and polling Url
|
description: Device Information owned by user
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/DeleteUserDeviceBySerialResponse"
|
$ref: "#/definitions/DeviceResponse"
|
||||||
default:
|
default:
|
||||||
description: Unexpected Error
|
description: Unexpected Error
|
||||||
schema:
|
schema:
|
||||||
|
@ -123,7 +121,7 @@ paths:
|
||||||
security:
|
security:
|
||||||
- accessTokenAuth: []
|
- accessTokenAuth: []
|
||||||
delete:
|
delete:
|
||||||
summary: Release device from user
|
summary: Delete User Device
|
||||||
description: The User Devices endpoint will request for device release from stf server. It will return request accepted if device is being used by current user
|
description: The User Devices endpoint will request for device release from stf server. It will return request accepted if device is being used by current user
|
||||||
operationId: deleteUserDeviceBySerial
|
operationId: deleteUserDeviceBySerial
|
||||||
tags:
|
tags:
|
||||||
|
@ -135,8 +133,8 @@ paths:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
responses:
|
responses:
|
||||||
"202":
|
"200":
|
||||||
description: Device Release Request Status
|
description: Delete User Device Status
|
||||||
default:
|
default:
|
||||||
description: Unexpected Error
|
description: Unexpected Error
|
||||||
schema:
|
schema:
|
||||||
|
@ -160,7 +158,7 @@ paths:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
responses:
|
responses:
|
||||||
"202":
|
"200":
|
||||||
description: Remote Connect User Device Request Status
|
description: Remote Connect User Device Request Status
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/RemoteConnectUserDeviceResponse"
|
$ref: "#/definitions/RemoteConnectUserDeviceResponse"
|
||||||
|
@ -183,10 +181,8 @@ paths:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
responses:
|
responses:
|
||||||
"202":
|
"200":
|
||||||
description: Remote Disonnect User Device Request Status
|
description: Remote Disonnect User Device Request Status
|
||||||
schema:
|
|
||||||
$ref: "#/definitions/RemoteDisconnectUserDeviceResponse"
|
|
||||||
default:
|
default:
|
||||||
description: Unexpected Error
|
description: Unexpected Error
|
||||||
schema:
|
schema:
|
||||||
|
@ -194,7 +190,7 @@ paths:
|
||||||
security:
|
security:
|
||||||
- accessTokenAuth: []
|
- accessTokenAuth: []
|
||||||
/user/accessTokens:
|
/user/accessTokens:
|
||||||
x-swagger-router-controller: token
|
x-swagger-router-controller: user
|
||||||
get:
|
get:
|
||||||
summary: Access Tokens
|
summary: Access Tokens
|
||||||
description: The Access Tokens endpoints returns titles of all the valid access tokens
|
description: The Access Tokens endpoints returns titles of all the valid access tokens
|
||||||
|
@ -298,35 +294,14 @@ definitions:
|
||||||
properties:
|
properties:
|
||||||
device:
|
device:
|
||||||
type: object
|
type: object
|
||||||
AddUserDeviceResponse:
|
|
||||||
required:
|
|
||||||
- pollingUrl
|
|
||||||
properties:
|
|
||||||
pollingUrl:
|
|
||||||
type: string
|
|
||||||
DeleteUserDeviceBySerialResponse:
|
|
||||||
required:
|
|
||||||
- pollingUrl
|
|
||||||
properties:
|
|
||||||
pollingUrl:
|
|
||||||
type: string
|
|
||||||
RemoteDisconnectUserDeviceResponse:
|
|
||||||
required:
|
|
||||||
- pollingUrl
|
|
||||||
properties:
|
|
||||||
pollingUrl:
|
|
||||||
type: string
|
|
||||||
RemoteConnectUserDeviceResponse:
|
RemoteConnectUserDeviceResponse:
|
||||||
required:
|
required:
|
||||||
- pollingUrl
|
- remoteConnectUrl
|
||||||
|
- serial
|
||||||
properties:
|
properties:
|
||||||
pollingUrl:
|
remoteConnectUrl:
|
||||||
type: string
|
type: string
|
||||||
ErrorResponse:
|
serial:
|
||||||
required:
|
|
||||||
- message
|
|
||||||
properties:
|
|
||||||
message:
|
|
||||||
type: string
|
type: string
|
||||||
AddUserDevicePayload:
|
AddUserDevicePayload:
|
||||||
description: payload object for adding device to user
|
description: payload object for adding device to user
|
||||||
|
@ -339,7 +314,12 @@ definitions:
|
||||||
timeout:
|
timeout:
|
||||||
description: Device timeout in ms. If device is kept idle for this period, it will be automatically disconnected. Default is provider group timeout
|
description: Device timeout in ms. If device is kept idle for this period, it will be automatically disconnected. Default is provider group timeout
|
||||||
type: integer
|
type: integer
|
||||||
|
ErrorResponse:
|
||||||
|
required:
|
||||||
|
- message
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
accessTokenAuth:
|
accessTokenAuth:
|
||||||
type: apiKey
|
type: apiKey
|
||||||
|
|
|
@ -142,15 +142,16 @@ module.exports = syrup.serial()
|
||||||
channel
|
channel
|
||||||
, reply.okay(url)
|
, reply.okay(url)
|
||||||
])
|
])
|
||||||
|
|
||||||
// Update DB
|
// Update DB
|
||||||
push.send([
|
push.send([
|
||||||
wireutil.global
|
channel
|
||||||
, wireutil.envelope(new wire.ConnectStartedMessage(
|
, wireutil.envelope(new wire.ConnectStartedMessage(
|
||||||
options.serial
|
options.serial
|
||||||
, url
|
, url
|
||||||
))
|
))
|
||||||
])
|
])
|
||||||
log.info('Remote Connect Started for device "%s" at "%s"', options.serial, url)
|
log.important('Remote Connect Started for device "%s" at "%s"', options.serial, url)
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
log.error('Unable to start remote connect service', err.stack)
|
log.error('Unable to start remote connect service', err.stack)
|
||||||
|
@ -170,12 +171,12 @@ module.exports = syrup.serial()
|
||||||
])
|
])
|
||||||
// Update DB
|
// Update DB
|
||||||
push.send([
|
push.send([
|
||||||
wireutil.global
|
channel
|
||||||
, wireutil.envelope(new wire.ConnectStoppedMessage(
|
, wireutil.envelope(new wire.ConnectStoppedMessage(
|
||||||
options.serial
|
options.serial
|
||||||
))
|
))
|
||||||
])
|
])
|
||||||
log.info('Remote Connect Stopped for device "%s"', options.serial)
|
log.important('Remote Connect Stopped for device "%s"', options.serial)
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
log.error('Failed to stop connect service', err.stack)
|
log.error('Failed to stop connect service', err.stack)
|
||||||
|
|
|
@ -167,9 +167,11 @@ module.exports = function(options) {
|
||||||
})
|
})
|
||||||
.on(wire.ConnectStartedMessage, function(channel, message, data) {
|
.on(wire.ConnectStartedMessage, function(channel, message, data) {
|
||||||
dbapi.setDeviceConnectUrl(message.serial, message.url)
|
dbapi.setDeviceConnectUrl(message.serial, message.url)
|
||||||
|
appDealer.send([channel, data])
|
||||||
})
|
})
|
||||||
.on(wire.ConnectStoppedMessage, function(channel, message, data) {
|
.on(wire.ConnectStoppedMessage, function(channel, message, data) {
|
||||||
dbapi.unsetDeviceConnectUrl(message.serial)
|
dbapi.unsetDeviceConnectUrl(message.serial)
|
||||||
|
appDealer.send([channel, data])
|
||||||
})
|
})
|
||||||
.on(wire.JoinGroupMessage, function(channel, message, data) {
|
.on(wire.JoinGroupMessage, function(channel, message, data) {
|
||||||
dbapi.setDeviceOwner(message.serial, message.owner)
|
dbapi.setDeviceOwner(message.serial, message.owner)
|
||||||
|
|
|
@ -59,7 +59,7 @@ datautil.applyOwnerOnlyInfo = function(device, user) {
|
||||||
if (device.owner && device.owner.email === user.email) {
|
if (device.owner && device.owner.email === user.email) {
|
||||||
} else {
|
} else {
|
||||||
device.remoteConnect = false
|
device.remoteConnect = false
|
||||||
device.remoteDebugUrl = null
|
device.remoteConnectUrl = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
lib/util/deviceutil.js
Normal file
13
lib/util/deviceutil.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
var logger = require('./logger')
|
||||||
|
|
||||||
|
var log = logger.createLogger('util:deviceutil')
|
||||||
|
|
||||||
|
var deviceutil = module.exports = Object.create(null)
|
||||||
|
|
||||||
|
deviceutil.isOwnedByUser = function(device, user) {
|
||||||
|
return device.present && device.ready && device.owner && device.owner.email === user.email && device.using
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceutil.isAddable = function(device, user) {
|
||||||
|
return device.present && device.ready && !device.using && !device.owner
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue