diff --git a/lib/roles/app.js b/lib/roles/app.js index 3ec0f499..bc1b5273 100644 --- a/lib/roles/app.js +++ b/lib/roles/app.js @@ -295,42 +295,60 @@ module.exports = function(options) { }) .on(wire.DevicePresentMessage, function(channel, message) { socket.emit('device.add', { - serial: message.serial - , present: true + important: true + , data: { + serial: message.serial + , present: true + } }) }) .on(wire.DeviceAbsentMessage, function(channel, message) { socket.emit('device.remove', { - serial: message.serial - , present: false - , ready: false - , lastHeartbeatAt: null - , using: false + important: true + , data: { + serial: message.serial + , present: false + , ready: false + , lastHeartbeatAt: null + , using: false + } }) }) .on(wire.JoinGroupMessage, function(channel, message) { - socket.emit('device.change', datautil.applyOwner({ - serial: message.serial - , owner: message.owner - } - , user - )) + socket.emit('device.change', { + important: true + , data: datautil.applyOwner({ + serial: message.serial + , owner: message.owner + } + , user + ) + }) }) .on(wire.LeaveGroupMessage, function(channel, message) { - socket.emit('device.change', datautil.applyOwner({ - serial: message.serial - , owner: null - } - , user - )) + socket.emit('device.change', { + important: true + , data: datautil.applyOwner({ + serial: message.serial + , owner: null + } + , user + ) + }) }) .on(wire.DeviceStatusMessage, function(channel, message) { - socket.emit('device.change', message) + socket.emit('device.change', { + important: true + , data: message + }) }) .on(wire.DeviceIdentityMessage, function(channel, message) { datautil.applyData(message) message.ready = true - socket.emit('device.change', message) + socket.emit('device.change', { + important: true + , data: message + }) }) .on(wire.TransactionProgressMessage, function(channel, message) { socket.emit('tx.progress', channel.toString(), message) @@ -343,47 +361,65 @@ module.exports = function(options) { }) .on(wire.AirplaneModeEvent, function(channel, message) { socket.emit('device.change', { - serial: message.serial - , airplaneMode: message.enabled + important: true + , data: { + serial: message.serial + , airplaneMode: message.enabled + } }) }) .on(wire.BatteryEvent, function(channel, message) { var serial = message.serial delete message.serial socket.emit('device.change', { - serial: serial - , battery: message + important: false + , data: { + serial: serial + , battery: message + } }) }) .on(wire.DeviceBrowserMessage, function(channel, message) { var serial = message.serial delete message.serial - socket.emit('device.change', datautil.applyBrowsers({ - serial: serial - , browser: message - })) + socket.emit('device.change', { + important: true + , data: datautil.applyBrowsers({ + serial: serial + , browser: message + }) + }) }) .on(wire.ConnectivityEvent, function(channel, message) { var serial = message.serial delete message.serial socket.emit('device.change', { - serial: serial - , network: message + important: false + , data: { + serial: serial + , network: message + } }) }) .on(wire.PhoneStateEvent, function(channel, message) { var serial = message.serial delete message.serial socket.emit('device.change', { - serial: serial - , network: message + important: false + , data: { + serial: serial + , network: message + } }) }) .on(wire.RotationEvent, function(channel, message) { socket.emit('device.change', { - serial: message.serial - , display: { - orientation: message.rotation + important: false + , data: { + serial: message.serial + , display: { + orientation: message.rotation + } } }) }) diff --git a/res/app/components/stf/device/device-service.js b/res/app/components/stf/device/device-service.js index 14051f3b..a5685f90 100644 --- a/res/app/components/stf/device/device-service.js +++ b/res/app/components/stf/device/device-service.js @@ -8,14 +8,45 @@ module.exports = function DeviceServiceFactory($http, socket) { var devices = [] , devicesBySerial = Object.create(null) , scopedSocket = socket.scoped($scope) + , digestTimer + , lastDigest - function notify() { + $scope.$on('$destroy', function() { + clearTimeout(digestTimer) + }) + + function digest() { $scope.$broadcast('devices.update', true) // Not great. Consider something else if (!$scope.$$phase) { $scope.$digest() } + + lastDigest = Date.now() + digestTimer = null + } + + function notify(event) { + if (event.important) { + // Handle important updates immediately. + digest() + } + else { + if (!digestTimer) { + var delta = Date.now() - lastDigest + if (delta > 1000) { + // It's been a while since the last update, so let's just update + // right now even though it's low priority. + digest() + } + else { + // It hasn't been long since the last update. Let's wait for a + // while so that the UI doesn't get stressed out. + digestTimer = setTimeout(digest, delta) + } + } + } } function sync(data) { @@ -70,7 +101,6 @@ module.exports = function DeviceServiceFactory($http, socket) { function insert(data) { devicesBySerial[data.serial] = devices.push(data) - 1 sync(data) - notify() } function modify(data, newData) { @@ -79,7 +109,6 @@ module.exports = function DeviceServiceFactory($http, socket) { return _.isArray(b) ? b : undefined }) sync(data) - notify() } function remove(data) { @@ -87,67 +116,64 @@ module.exports = function DeviceServiceFactory($http, socket) { if (index >= 0) { devices.splice(index, 1) delete devicesBySerial[data.serial] - notify() } } function fetch(data) { deviceService.load(data.serial) - .then(changeListener) + .then(function(device) { + return changeListener({ + important: true + , data: device + }) + }) .catch(function() {}) } - function addListener(data) { - var device = get(data) + function addListener(event) { + var device = get(event.data) if (device) { - modify(device, data) - } - else if (options.filter(data)) { - insert(data) - } - } - - function removeListener(data) { - var device = get(data) - if (device) { - modify(device, data) - if (!options.filter(device)) { - remove(device) - } + modify(device, event.data) + notify(event) } else { - if (options.filter(data)) { - insert(data) - // We've only got partial data - fetch(data) + if (options.filter(event.data)) { + insert(event.data) + notify(event) } } } - function changeListener(data) { - var device = get(data) + function changeListener(event) { + var device = get(event.data) if (device) { - modify(device, data) + modify(device, event.data) if (!options.filter(device)) { remove(device) } + notify(event) } else { - if (options.filter(data)) { - insert(data) + if (options.filter(event.data)) { + insert(event.data) // We've only got partial data - fetch(data) + fetch(event.data) + notify(event) } } } scopedSocket.on('device.add', addListener) - scopedSocket.on('device.remove', removeListener) + scopedSocket.on('device.remove', changeListener) scopedSocket.on('device.change', changeListener) this.add = function(device) { remove(device) insert(device) + notify({ + important: true + , data: device + }) } this.devices = devices @@ -155,7 +181,7 @@ module.exports = function DeviceServiceFactory($http, socket) { deviceService.trackAll = function ($scope) { var tracker = new Tracker($scope, { - filter: function(device) { + filter: function() { return true } })