var util = require('util') var assert = require('assert') var http = require('http') var Promise = require('bluebird') var syrup = require('syrup') var request = Promise.promisifyAll(require('request')) var httpProxy = require('http-proxy') var logger = require('../../../util/logger') var devutil = require('../../../util/devutil') var lifecycle = require('../../../util/lifecycle') var streamutil = require('../../../util/streamutil') module.exports = syrup.serial() .dependency(require('../support/adb')) .dependency(require('../resources/remote')) .define(function(options, adb, remote) { var log = logger.createLogger('device:plugins:http') var service = { port: 2870 , privateUrl: null , publicUrl: null } function openService() { log.info('Launching HTTP API') return devutil.ensureUnusedPort(adb, options.serial, service.port) .then(function() { return adb.shell(options.serial, [ remote.bin , '--lib', remote.lib , '--listen-http', service.port ]) .then(function(out) { lifecycle.share('Remote shell', out) streamutil.talk(log, 'Remote shell says: "%s"', out) }) .then(function() { return devutil.waitForPort(adb, options.serial, service.port) }) .then(function(conn) { var ours = options.ports.pop() , everyones = options.ports.pop() , url = util.format('http://127.0.0.1:%d', ours) // Don't need the connection conn.end() log.info('Opening device HTTP API forwarder on "%s"', url) service.privateUrl = url service.publicUrl = util.format( 'http://%s:%s' , options.publicIp , everyones ) return adb.forward( options.serial , util.format('tcp:%d', ours) , util.format('tcp:%d', service.port) ) .then(function() { log.info( 'Opening HTTP API proxy on "http://%s:%s"' , options.publicIp , everyones ) var resolver = Promise.defer() function resolve() { lifecycle.share('Proxy server', proxyServer) resolver.resolve() } function reject(err) { resolver.reject(err) } var proxy = httpProxy.createProxyServer({ target: url , ws: false , xfwd: false }) var proxyServer = http.createServer(proxy.web) .listen(everyones) proxyServer.on('listening', resolve) proxyServer.on('error', reject) return resolver.promise.finally(function() { proxyServer.removeListener('listening', resolve) proxyServer.removeListener('error', reject) }) }) }) }) } return openService() .then(function() { return { getDisplay: function(id) { return request.getAsync({ url: util.format( '%s/api/v1/displays/%d' , service.privateUrl , id ) , json: true }) .then(function(args) { var display = args[1] assert.ok('id' in display, 'Invalid response from HTTP API') display.url = util.format( '%s/api/v1/displays/%d/screenshot.jpg' , service.publicUrl , id ) return display }) } } }) })