var r = require('rethinkdb') var util = require('util') var db = require('./') var wireutil = require('../wire/util') var dbapi = Object.create(null) dbapi.DuplicateSecondaryIndexError = function DuplicateSecondaryIndexError() { Error.call(this) this.name = 'DuplicateSecondaryIndexError' Error.captureStackTrace(this, DuplicateSecondaryIndexError) } util.inherits(dbapi.DuplicateSecondaryIndexError, Error) dbapi.close = function(options) { return db.close(options) } dbapi.saveUserAfterLogin = function(user) { return db.run(r.table('users').get(user.email).update({ name: user.name , ip: user.ip , lastLoggedInAt: r.now() })) .then(function(stats) { if (stats.skipped) { return db.run(r.table('users').insert({ email: user.email , name: user.name , ip: user.ip , group: wireutil.makePrivateChannel() , lastLoggedInAt: r.now() , createdAt: r.now() , forwards: [] , settings: {} })) } return stats }) } dbapi.loadUser = function(email) { return db.run(r.table('users').get(email)) } dbapi.updateUserSettings = function(email, changes) { return db.run(r.table('users').get(email).update({ settings: changes })) } dbapi.resetUserSettings = function(email) { return db.run(r.table('users').get(email).update({ settings: r.literal({}) })) } dbapi.insertUserAdbKey = function(email, key) { return db.run(r.table('users').get(email).update({ adbKeys: r.row('adbKeys').default([]).append({ title: key.title , fingerprint: key.fingerprint }) })) } dbapi.deleteUserAdbKey = function(email, fingerprint) { return db.run(r.table('users').get(email).update({ adbKeys: r.row('adbKeys').default([]).filter(function(key) { return key('fingerprint').ne(fingerprint) }) })) } dbapi.lookupUsersByAdbKey = function(fingerprint) { return db.run(r.table('users').getAll(fingerprint, { index: 'adbKeys' })) } dbapi.lookupUserByAdbFingerprint = function(fingerprint) { return db.run(r.table('users').getAll(fingerprint, { index: 'adbKeys' }) .pluck('email', 'name', 'group')) .then(function(cursor) { return cursor.toArray() }) .then(function(groups) { switch (groups.length) { case 1: return groups[0] case 0: return null default: throw new Error('Found multiple users for same ADB fingerprint') } }) } dbapi.addUserForward = function(email, forward) { var devicePort = forward.devicePort return db.run(r.table('users').get(email).update({ forwards: r.row('forwards').default([]).filter(function(forward) { return forward('devicePort').ne(devicePort) }).append(forward) })) } dbapi.removeUserForward = function(email, devicePort) { return db.run(r.table('users').get(email).update({ forwards: r.row('forwards').default([]).filter(function(forward) { return forward('devicePort').ne(devicePort) }) })) } dbapi.loadGroup = function(email) { return db.run(r.table('devices').getAll(email, { index: 'owner' })) } dbapi.saveDeviceLog = function(serial, entry) { return db.run(r.table('logs').insert({ serial: entry.serial , timestamp: r.epochTime(entry.timestamp) , priority: entry.priority , tag: entry.tag , pid: entry.pid , message: entry.message } , { durability: 'soft' })) } dbapi.saveDevice = function(serial, device) { var data = { present: true , provider: device.provider , owner: null , status: device.status , ready: false , statusChangedAt: r.now() , createdAt: r.now() , lastHeartbeatAt: r.now() } return db.run(r.table('devices').get(serial).update(data)) .then(function(stats) { if (stats.skipped) { data.serial = serial return db.run(r.table('devices').insert(data)) } return stats }) } dbapi.saveDeviceStatus = function(serial, status) { return db.run(r.table('devices').get(serial).update({ status: status , statusChangedAt: r.now() })) } dbapi.setDeviceOwner = function(serial, owner) { return db.run(r.table('devices').get(serial).update({ owner: owner })) } dbapi.unsetDeviceOwner = function(serial) { return db.run(r.table('devices').get(serial).update({ owner: null })) } dbapi.setDeviceAbsent = function(serial) { return db.run(r.table('devices').get(serial).update({ present: false , ready: false , lastHeartbeatAt: null })) } dbapi.setDeviceAirplaneMode = function(serial, enabled) { return db.run(r.table('devices').get(serial).update({ airplaneMode: enabled })) } dbapi.setDeviceBattery = function(serial, battery) { return db.run(r.table('devices').get(serial).update({ battery: { status: battery.status , health: battery.health , source: battery.source , level: battery.level , scale: battery.scale , temp: battery.temp , voltage: battery.voltage } } , { durability: 'soft' })) } dbapi.setDeviceBrowser = function(serial, browser) { return db.run(r.table('devices').get(serial).update({ browser: { selected: browser.selected , apps: browser.apps } })) } dbapi.setDeviceConnectivity = function(serial, connectivity) { return db.run(r.table('devices').get(serial).update({ network: { connected: connectivity.connected , type: connectivity.type , subtype: connectivity.subtype , failover: !!connectivity.failover , roaming: !!connectivity.roaming } })) } dbapi.setDevicePhoneState = function(serial, state) { return db.run(r.table('devices').get(serial).update({ network: { state: state.state , manual: state.manual , operator: state.operator } })) } dbapi.setDeviceRotation = function(serial, rotation) { return db.run(r.table('devices').get(serial).update({ display: { rotation: rotation } })) } dbapi.setDeviceChannel = function(serial, channel) { return db.run(r.table('devices').get(serial).update({ channel: channel })) } dbapi.saveDeviceIdentity = function(serial, identity) { return db.run(r.table('devices').get(serial).update({ ready: true , platform: identity.platform , manufacturer: identity.manufacturer , operator: identity.operator , model: identity.model , version: identity.version , abi: identity.abi , sdk: identity.sdk , display: identity.display , phone: identity.phone , product: identity.product })) } dbapi.loadDevices = function() { return db.run(r.table('devices')) } dbapi.loadDevice = function(serial) { return db.run(r.table('devices').get(serial)) } dbapi.updateProviderHeartbeat = function(channel) { return db.run( r.table('devices').getAll(channel, { index: 'providerChannel' }) .update({ lastHeartbeatAt: r.now() }) , { noreply: true , durability: 'soft' } ) } dbapi.getDeadDevices = function(timeout) { return db.run( r.table('devices') .between(null, r.now().sub(timeout / 1000), { index: 'lastHeartbeatAt' }) .pluck('serial') ) } module.exports = dbapi