blob: 761a82dafdce3a9956d41372d3322d231697e48c [file] [log] [blame]
'use strict';
// See https://github.com/jshint/jshint/issues/1747 for context
/* global -Promise */
var Promise = require('es6-promise').Promise;
var adb = require('adbkit');
var portfinder = require('portfinder');
var REMOTE_DEBUGGER_SOCKET = 'localfilesystem:/data/local/debugger-socket';
module.exports = forwardPorts;
function forwardPorts(options) {
var devices;
if (Array.isArray(options)) {
devices = options;
} else {
options = options || {};
devices = options.devices;
}
var adbClient = adb.createClient();
return new Promise(function(resolve, reject) {
if (devices === undefined || !Array.isArray(devices)) {
return reject(new Error('an array of devices is required to forward ports'));
}
return resolve();
}).then(function() {
return findExistingPortForwards(adbClient, devices);
}).then(function(devicesWithPorts) {
return forwardDevices(adbClient, devicesWithPorts);
});
}
function findExistingPortForwards(adbClient, devices) {
return adbClient.listForwards().then(function(ports) {
// Index the list of forwarded ports by device ID.
var portMap = {};
ports.forEach(function(port) {
// Filter for remote debugging sockets, just in case something else has
// been forwarded.
if (port.remote !== REMOTE_DEBUGGER_SOCKET) {
return;
}
// Add this port to a list associated with the device ID
if (!portMap[port.serial]) {
portMap[port.serial] = [];
}
portMap[port.serial].push(port);
});
// Annotate the list of devices with associated ports.
return devices.map(function(device) {
device.ports = portMap[device.id] || [];
return device;
});
});
}
function forwardDevices(adbClient, devices) {
return Promise.all(devices.map(function(device) {
if (device.ports.length > 0) {
// Skip forwarding for this device. But, extract port number from the
// tcp:{port} format returned by adbClient.listForwards()
device.ports.forEach(function(port) {
delete port.serial;
if (port.local.indexOf('tcp:') === -1) {
port.port = null;
} else {
port.port = port.local.replace('tcp:', '');
}
});
return device;
}
return getPort().then(function(port) {
var localAddress = 'tcp:' + port;
var remoteAddress = REMOTE_DEBUGGER_SOCKET;
return adbClient
.forward(device.id, localAddress, remoteAddress)
.then(function() {
device.ports = [
{
port: port,
local: localAddress,
remote: remoteAddress
}
];
return device;
});
});
}));
}
function getPort() {
return new Promise(function(resolve, reject) {
portfinder.getPort({
// Ensure we're looking at localhost, rather than 0.0.0.0
// see: https://github.com/indexzero/node-portfinder/issues/13
host: '127.0.0.1'
}, function(err, port) {
return err ? reject(err) : resolve(port);
});
});
}