diff --git a/lib/db/api.js b/lib/db/api.js index 72608eba..d7525c73 100644 --- a/lib/db/api.js +++ b/lib/db/api.js @@ -12,3 +12,32 @@ module.exports.saveUserAfterLogin = function(user) { upsert: true })) } + +module.exports.saveDeviceStatus = function(serial, status) { + return db.run(r.table('devices').get(serial).update({ + status: status + , statusChangedAt: r.now() + })) + .then(function(stats) { + if (stats.skipped) { + return db.run(r.table('devices').insert({ + serial: serial + , status: status + , statusChangedAt: r.now() + , createdAt: r.now() + })) + } + return stats + }) +} + +module.exports.saveDeviceIdentity = function(serial, identity) { + return db.run(r.table('devices').get(serial).update({ + platform: identity.platform + , manufacturer: identity.manufacturer + , model: identity.model + , version: identity.version + , abi: identity.abi + , sdk: identity.sdk + })) +} diff --git a/lib/db/tables.js b/lib/db/tables.js index 48b48490..76e469b4 100644 --- a/lib/db/tables.js +++ b/lib/db/tables.js @@ -2,4 +2,7 @@ module.exports = { users: { primaryKey: 'email' } +, devices: { + primaryKey: 'serial' + } } diff --git a/lib/roles/coordinator.js b/lib/roles/coordinator.js index edd1c714..6eeb4cff 100644 --- a/lib/roles/coordinator.js +++ b/lib/roles/coordinator.js @@ -3,6 +3,7 @@ var zmq = require('zmq') var logger = require('../util/logger') var wire = require('../wire') var wireutil = require('../util/wireutil')(wire) +var dbapi = require('../db/api') module.exports = function(options) { var log = logger.createLogger('coordinator') @@ -44,8 +45,13 @@ module.exports = function(options) { var message = wire.DevicePokeMessage.decode(wrapper.message) devDealer.send([message.channel, wireutil.makeProbeMessage()]) break + case wire.MessageType.DEVICE_IDENTITY: + var message = wire.DeviceIdentityMessage.decode(wrapper.message) + dbapi.saveDeviceIdentity(message.serial, message) + break case wire.MessageType.DEVICE_STATUS: var message = wire.DeviceStatusMessage.decode(wrapper.message) + dbapi.saveDeviceStatus(message.serial, message.status) break case wire.MessageType.DEVICE_PROPERTIES: var message = wire.DevicePropertiesMessage.decode(wrapper.message) diff --git a/lib/roles/device.js b/lib/roles/device.js index 7e4c6b1a..9414347f 100644 --- a/lib/roles/device.js +++ b/lib/roles/device.js @@ -64,7 +64,7 @@ module.exports = function(options) { .then(function(properties) { identity = devutil.makeIdentity(options.serial, properties) push.send([channel, - wireutil.makeDevicePropertiesMessage(options.serial, properties)]) + wireutil.makeDeviceIdentityMessage(options.serial, identity)]) }) break case wire.MessageType.SHELL_COMMAND: diff --git a/lib/util/devutil.js b/lib/util/devutil.js index 1f13541d..7ef540ac 100644 --- a/lib/util/devutil.js +++ b/lib/util/devutil.js @@ -1,33 +1,68 @@ -module.exports = { - makeIdentity: function(serial, properties) { - var model = properties['ro.product.model'] - , brand = properties['ro.product.brand'] - , manufacturer = properties['ro.product.manufacturer'] - , version = properties['ro.build.version.release'] - , sdk = +properties['ro.build.version.sdk'] - , abi = properties['ro.product.cpu.abi'] +var util = require('util') - // Remove brand prefix for consistency - if (model.substr(0, brand.length) === brand) { - model = model.substr(brand.length) - } +var wire = require('../wire') - // Remove manufacturer prefix for consistency - if (model.substr(0, manufacturer.length) === manufacturer) { - model = model.substr(manufacturer.length) - } +var devutil = module.exports = Object.create(null) - // Clean up remaining model name - model = model.replace(/[_ ]/g, '') - - return { - platform: 'android' - , serial: serial - , manufacturer: manufacturer - , model: model - , version: version - , sdk: sdk - , abi: abi - } +devutil.platform = function(platform) { + switch (platform) { + case 'android': + return wire.DevicePlatform.ANDROID + default: + throw new Error(util.format('Unmapped platform "%s"', platform)) + } +} + +devutil.manufacturer = function(manufacturer) { + switch (manufacturer.toUpperCase()) { + case 'SONY': + case 'SONY ERICSSON': + return wire.DeviceManufacturer.SONY + case 'FUJITSU': + return wire.DeviceManufacturer.FUJITSU + case 'HTC': + return wire.DeviceManufacturer.HTC + case 'SHARP': + return wire.DeviceManufacturer.SHARP + case 'LGE': + return wire.DeviceManufacturer.LG + case 'SAMSUNG': + return wire.DeviceManufacturer.SAMSUNG + case 'ASUS': + return wire.DeviceManufacturer.ASUS + default: + throw new Error(util.format('Unmapped manufacturer "%s"', manufacturer)) + } +} + +devutil.makeIdentity = function(serial, properties) { + var model = properties['ro.product.model'] + , brand = properties['ro.product.brand'] + , manufacturer = properties['ro.product.manufacturer'] + , version = properties['ro.build.version.release'] + , sdk = properties['ro.build.version.sdk'] + , abi = properties['ro.product.cpu.abi'] + + // Remove brand prefix for consistency + if (model.substr(0, brand.length) === brand) { + model = model.substr(brand.length) + } + + // Remove manufacturer prefix for consistency + if (model.substr(0, manufacturer.length) === manufacturer) { + model = model.substr(manufacturer.length) + } + + // Clean up remaining model name + // model = model.replace(/[_ ]/g, '') + + return { + serial: serial + , platform: devutil.platform('android') + , manufacturer: devutil.manufacturer(manufacturer) + , model: model + , version: version + , abi: abi + , sdk: sdk } } diff --git a/lib/util/wireutil.js b/lib/util/wireutil.js index dd6d9cc5..270e8b0d 100644 --- a/lib/util/wireutil.js +++ b/lib/util/wireutil.js @@ -76,6 +76,19 @@ module.exports = function(wire) { var message = new wire.DevicePokeMessage(serial, channel) return wireutil.envelope(wire.MessageType.DEVICE_POKE, message) } + , makeDeviceIdentityMessage: function(serial, identity) { + var message = new wire.DeviceIdentityMessage( + serial + , identity.platform + , identity.manufacturer + , identity.model + , identity.version + , identity.abi + , identity.sdk + ) + + return wireutil.envelope(wire.MessageType.DEVICE_IDENTITY, message) + } , makeDevicePropertiesMessage: function(serial, properties) { var message = new wire.DevicePropertiesMessage( serial diff --git a/lib/wire/wire.proto b/lib/wire/wire.proto index 3edee7e2..baf2ec2d 100644 --- a/lib/wire/wire.proto +++ b/lib/wire/wire.proto @@ -1,18 +1,19 @@ // Message wrapper enum MessageType { - DEVICE_POKE = 1; - DEVICE_STATUS = 2; - DEVICE_TYPE = 3; + DEVICE_POKE = 1; + DEVICE_STATUS = 2; + DEVICE_TYPE = 3; DEVICE_PROPERTIES = 4; - GROUP = 5; - JOIN_GROUP = 6; - LEAVE_GROUP = 7; - PROBE = 8; - SHELL_COMMAND = 9; - DEVICE_DATA = 10; - DEVICE_DONE = 11; - DEVICE_FAIL = 12; + GROUP = 5; + JOIN_GROUP = 6; + LEAVE_GROUP = 7; + PROBE = 8; + SHELL_COMMAND = 9; + DEVICE_DATA = 10; + DEVICE_DONE = 11; + DEVICE_FAIL = 12; + DEVICE_IDENTITY = 13; } message Envelope { @@ -52,6 +53,44 @@ message DeviceTypeMessage { required DeviceType type = 2; } +enum DevicePlatform { + ANDROID = 100; + IOS = 200; + FIREFOX = 300; +} + +enum DeviceManufacturer { + ACER = 1100; + APPLE = 1200; + ASUS = 1300; + CASIO = 1400; + FUJITSU = 1500; + HTC = 1600; + HUAWEI = 1700; + KYOCERA = 1800; + LG = 1900; + MOTOROLA = 2000; + NEC = 2100; + PANASONIC = 2200; + PANTECH = 2300; + RIM = 2400; + SAMSUNG = 2500; + SHARP = 2600; + SONY = 2700; + TOSHIBA = 2800; + ZTE = 2900; +} + +message DeviceIdentityMessage { + required string serial = 1; + required DevicePlatform platform = 2; + required DeviceManufacturer manufacturer = 3; + required string model = 4; + required string version = 5; + required string abi = 6; + required string sdk = 7; +} + message DeviceProperty { required string name = 1; required string value = 2;