diff --git a/lib/shared/sdk/index.js b/lib/shared/sdk/index.js index 4690d3bf..f515a639 100644 --- a/lib/shared/sdk/index.js +++ b/lib/shared/sdk/index.js @@ -18,25 +18,36 @@ const Bluebird = require('bluebird') const _ = require('lodash') +const sdk = module.exports /** - * @summary The list of loaded adaptors + * @summary The list of loaded adapters * @type {Object[]} * @constant */ -const ADAPTORS = [ +const ADAPTERS = [ require('./standard'), require('./usbboot') ] /** - * @summary Scan for drives using all registered adaptors + * @summary Initialised adapters + * @type {Object} + * @constant + */ +sdk.adapters = _.reduce(ADAPTERS, (adapters, Adapter) => { + adapters[Adapter.name] = new Adapter() + return adapters +}, {}) + +/** + * @summary Scan for drives using all registered adapters * @function * @public * * @description * The options object contains options for all the registered - * adaptors. For the `standard` adaptor, for example, place + * adapters. For the `standard` adapter, for example, place * options in `options.standard`. * * @param {Object} options - options @@ -52,8 +63,16 @@ const ADAPTORS = [ * console.log(drives) * }) */ -exports.scan = (options) => { - return Bluebird.all(_.map(ADAPTORS, (adaptor) => { - return adaptor.scan(_.get(options, [ adaptor.name ], {})) +sdk.scan = (options) => { + return Bluebird.all(_.map(sdk.adapters, (adapter) => { + return new Bluebird((resolve, reject) => { + adapter.scan(_.get(options, [ adapter.id ], {}), (error, devices) => { + if (error) { + reject(error) + } else { + resolve(devices) + } + }) + }) })).then(_.flatten) } diff --git a/lib/shared/sdk/standard/index.js b/lib/shared/sdk/standard/index.js index ef6c9185..3358b67f 100644 --- a/lib/shared/sdk/standard/index.js +++ b/lib/shared/sdk/standard/index.js @@ -18,49 +18,78 @@ const _ = require('lodash') const Bluebird = require('bluebird') +const EventEmitter = require('events') const drivelist = Bluebird.promisifyAll(require('drivelist')) /** - * @summary The name of this adaptor + * @summary StandardAdapter + * @class + */ +class StandardAdapter extends EventEmitter { + /** + * @summary StandardAdapter constructor + * @class + * @example + * const adapter = new StandardAdapter() + */ + constructor () { + super() + + /** @type {String} Adapter name */ + this.id = this.constructor.id + } + + /** + * @summary Scan for block devices + * @public + * + * @param {Object} [options] - options + * @param {Object} [options.includeSystemDrives=false] - include system drives + * @param {Function} callback - callback + * @returns {StandardAdapter} + * + * @example + * adapter.scan({ + * includeSystemDrives: true + * }, (error, devices) => { + * // ... + * }) + */ + scan (options = {}, callback) { + // eslint-disable-next-line lodash/prefer-lodash-method + drivelist.listAsync().map((drive) => { + drive.adapter = this.id + + // TODO: Find a better way to detect that a certain + // block device is a compute module initialized + // through usbboot. + if (_.includes([ '0001', 'RPi-MSD- 0001', 'File-Stor Gadget', 'Linux File-Stor Gadget USB Device' ], drive.description)) { + drive.description = 'Compute Module' + drive.icon = 'raspberrypi' + drive.system = false + } + + return drive + }).catch((error) => { + callback(error) + }).filter((drive) => { + return options.includeSystemDrives || !drive.system + }).then((drives) => { + this.emit('devices', drives) + callback(null, drives) + }) + + return this + } +} + +/** + * @summary The name of this adapter * @public * @type {String} * @constant */ -exports.name = 'standard' +StandardAdapter.id = 'standard' -/** - * @summary Scan for block devices - * @function - * @public - * - * @param {Object} [options] - options - * @param {Object} [options.includeSystemDrives=false] - include system drives - * @fulfil {Object[]} - block devices - * @returns {Promise} - * - * @example - * standard.scan({ - * includeSystemDrives: true - * }).each((device) => { - * console.log(device) - * }) - */ -exports.scan = (options = {}) => { - // eslint-disable-next-line lodash/prefer-lodash-method - return drivelist.listAsync().map((drive) => { - drive.adaptor = exports.name - - // TODO: Find a better way to detect that a certain - // block device is a compute module initialized - // through usbboot. - if (_.includes([ '0001', 'RPi-MSD- 0001', 'File-Stor Gadget', 'Linux File-Stor Gadget USB Device' ], drive.description)) { - drive.description = 'Compute Module' - drive.icon = 'raspberrypi' - drive.system = false - } - - return drive - }).filter((drive) => { - return options.includeSystemDrives || !drive.system - }) -} +// Exports +module.exports = StandardAdapter diff --git a/lib/shared/sdk/usbboot/index.js b/lib/shared/sdk/usbboot/index.js index 8221f104..3751eb5e 100644 --- a/lib/shared/sdk/usbboot/index.js +++ b/lib/shared/sdk/usbboot/index.js @@ -22,18 +22,27 @@ 'use strict' const _ = require('lodash') +const EventEmitter = require('events') const Bluebird = require('bluebird') const debug = require('debug')('sdk:usbboot') const usb = require('./usb') const protocol = require('./protocol') +debug.enabled = true + /** - * @summary The name of this adaptor - * @public - * @type {String} + * @summary The radix used by USB ID numbers + * @type {Number} * @constant */ -exports.name = 'usbboot' +const USB_ID_RADIX = 16 + +/** + * @summary The expected length of a USB ID number + * @type {Number} + * @constant + */ +const USB_ID_LENGTH = 4 /** * @summary Vendor ID of "Broadcom Corporation" @@ -56,29 +65,6 @@ const USB_PRODUCT_ID_BCM2708_BOOT = 0x2763 */ const USB_PRODUCT_ID_BCM2710_BOOT = 0x2764 -/** - * @summary List of usbboot capable devices - * @type {Object[]} - * @constant - */ -const USBBOOT_CAPABLE_USB_DEVICES = [ - - // BCM2835 - - { - vendorID: USB_VENDOR_ID_BROADCOM_CORPORATION, - productID: USB_PRODUCT_ID_BCM2708_BOOT - }, - - // BCM2837 - - { - vendorID: USB_VENDOR_ID_BROADCOM_CORPORATION, - productID: USB_PRODUCT_ID_BCM2710_BOOT - } - -] - /** * @summary The timeout for USB device operations * @type {Number} @@ -107,6 +93,45 @@ const USB_DESCRIPTOR_NULL_INDEX = 0 */ const USBBOOT_BOOTCODE_FILE_NAME = 'bootcode.bin' +/** + * @summary List of usbboot capable devices + * @type {Object[]} + * @constant + */ +const USBBOOT_CAPABLE_USB_DEVICES = [ + + // BCM2835 + + { + vendorID: USB_VENDOR_ID_BROADCOM_CORPORATION, + productID: USB_PRODUCT_ID_BCM2708_BOOT + }, + + // BCM2837 + + { + vendorID: USB_VENDOR_ID_BROADCOM_CORPORATION, + productID: USB_PRODUCT_ID_BCM2710_BOOT + } + +] + +/** + * @summary Convert a USB id (e.g. product/vendor) to a string + * @function + * @private + * + * @param {Number} id - USB id + * @returns {String} string id + * + * @example + * console.log(usbIdToString(2652)) + * > '0x0a5c' + */ +const usbIdToString = (id) => { + return `0x${_.padStart(id.toString(USB_ID_RADIX), USB_ID_LENGTH, '0')}` +} + /** * @summary Check if a USB device object is usbboot-capable * @function @@ -128,315 +153,307 @@ const isUsbBootCapableUSBDevice = (device) => { } /** - * @summary The radix used by USB ID numbers - * @type {Number} - * @constant + * @summary USBBootAdapter + * @class */ -const USB_ID_RADIX = 16 +class USBBootAdapter extends EventEmitter { + /** + * @summary USBBootAdapter constructor + * @class + * @example + * const adapter = new USBBootAdapter() + */ + constructor () { + super() -/** - * @summary The expected length of a USB ID number - * @type {Number} - * @constant - */ -const USB_ID_LENGTH = 4 + /** @type {String} Adapter name */ + this.id = this.constructor.id -/** - * @summary The cache of blobs - * @type {Object} - * @constant - */ -const BLOBS_CACHE = {} - -/** - * @summary Query a blob from the internal cache - * @function - * @private - * - * @param {String} name - blob name - * @param {Function} fallback - fallback function - * @fulfil {Buffer} - blob - * @returns {Promise} - * - * @example - * const Bluebird = require('bluebird') - * const fs = Bluebird.promisifyAll(require('fs')) - * - * const blob = queryBlobFromCache('start.elf', (name) => { - * return fs.readFileAsync(path.join('./blobs', name)) - * }) - */ -const queryBlobFromCache = (name, fallback) => { - if (BLOBS_CACHE[name]) { - return Bluebird.resolve(BLOBS_CACHE[name]) + /** @type {Object} Blob cache */ + this.blobCache = {} } - return fallback(name).tap((buffer) => { - BLOBS_CACHE[name] = buffer - }) -} - -/** - * @summary Convert a USB id (e.g. product/vendor) to a string - * @function - * @private - * - * @param {Number} id - USB id - * @returns {String} string id - * - * @example - * console.log(usbIdToString(2652)) - * > '0x0a5c' - */ -const usbIdToString = (id) => { - return `0x${_.padStart(id.toString(USB_ID_RADIX), USB_ID_LENGTH, '0')}` -} - -/** - * @summary Write bootcode to USB device (usbboot first stage) - * @function - * @private - * - * @description - * After this stage is run, the USB will be re-mounted as 0x0a5c:0x2764. - * - * @param {Object} device - node-usb device - * @param {Object} endpoint - node-usb endpoint - * @param {Buffer} bootCodeBuffer - bootcode buffer - * @returns {Promise} - * - * @example - * const usb = require('usb') - * const device = usb.findByIds(0x0a5c, 0x2763) - * const bootcode = fs.readFileSync('./bootcode.bin') - * - * writeBootCode(device, device.interfaces(0).endpoint(1), bootcode).then(() => { - * console.log('Done!') - * }) - */ -const writeBootCode = (device, endpoint, bootCodeBuffer) => { - debug('Writing bootcode') - debug(`Bootcode buffer length: ${bootCodeBuffer.length}`) - const bootMessageBuffer = protocol.createBootMessageBuffer(bootCodeBuffer.length) - - debug('Writing boot message buffer to out endpoint') - return protocol.write(device, endpoint, bootMessageBuffer).then(() => { - debug('Writing boot code buffer to out endpoint') - return protocol.write(device, endpoint, bootCodeBuffer) - }).then(() => { - debug('Reading return code from device') - return protocol.read(device, protocol.RETURN_CODE_LENGTH) - }).then((data) => { - const returnCode = data.readInt32LE() - debug(`Received return code: ${returnCode}`) - - if (returnCode !== protocol.RETURN_CODE_SUCCESS) { - throw new Error(`Couldn't write the bootcode, got return code ${returnCode} from device`) + /** + * @summary Query a blob from the internal cache + * @private + * + * @param {String} name - blob name + * @param {Function} fallback - fallback function + * @fulfil {Buffer} - blob + * @returns {Promise} + * + * @example + * const Bluebird = require('bluebird') + * const fs = Bluebird.promisifyAll(require('fs')) + * + * const blob = adapter.queryBlobFromCache('start.elf', (name) => { + * return fs.readFileAsync(path.join('./blobs', name)) + * }) + */ + queryBlobFromCache (name, fallback) { + if (this.blobCache[name]) { + return Bluebird.resolve(this.blobCache[name]) } - }) -} -/** - * @summary Mount a USB device as a block device (usbboot second stage) - * @function - * @private - * - * @description - * The possible files you can pass here are: - * - * - autoboot.txt - * - config.txt - * - recovery.elf - * - start.elf - * - fixup.dat - * - * @param {Object} device - node-usb device - * @param {Object} endpoint - node-usb endpoint - * @param {Function} readFile - read file function - * @returns {Promise} - * - * @example - * const fs = Bluebird.promisifyAll(require('fs')) - * const usb = require('usb') - * const device = usb.findByIds(0x0a5c, 0x2763) - * - * startFileServer(device, device.interfaces(0).endpoint(1), (name) => { - * return fs.readFileAsync(name) - * }).then(() => { - * console.log('Done!') - * }) - */ -const startFileServer = (device, endpoint, readFile) => { - debug('Listening for file messages') - return protocol - .read(device, protocol.FILE_MESSAGE_SIZE) - .then(protocol.parseFileMessageBuffer) - - // We get these error messages when reading a command - // from the device when the communication has ended - .catch({ - message: 'LIBUSB_TRANSFER_STALL' - }, { - message: 'LIBUSB_TRANSFER_ERROR' - }, (error) => { - debug(`Got ${error.message} when reading a command, assuming everything is done`) - return { - command: protocol.FILE_MESSAGE_COMMANDS.DONE - } + return fallback(name).tap((buffer) => { + this.blobCache[name] = buffer }) + } - .then((fileMessage) => { - debug(`Received message: ${fileMessage.command} -> ${fileMessage.fileName}`) + /** + * @summary Scan for usbboot capable USB devices + * @public + * + * @description + * You should at the very least pass a file named `bootcode.bin`. + * + * @param {Object} options - options + * @param {Object} options.files - files buffers + * @param {Function} callback - callback + * @returns {USBBootAdapter} + * + * @example + * adapter.scan({ + * files: { + * 'bootcode.bin': fs.readFileSync('./msd/bootcode.bin'), + * 'start.elf': fs.readFileSync('./msd/start.elf') + * } + * }, (error, devices) => { + * // ... + * }) + */ + scan (options = {}, callback) { + /* eslint-disable lodash/prefer-lodash-method */ + usb.listDevices().filter(isUsbBootCapableUSBDevice).map((device) => { + /* eslint-enable lodash/prefer-lodash-method */ - if (fileMessage.command === protocol.FILE_MESSAGE_COMMANDS.DONE) { - debug('Done') - return Bluebird.resolve() + // This is the only way we can unique identify devices + device.device = `${device.busNumber}:${device.deviceAddress}` + + device.displayName = 'Initializing device' + device.description = 'Compute Module' + device.raw = device.device + device.size = null + device.mountpoints = [] + device.protected = false + device.system = false + device.disabled = true + device.icon = 'loading' + device.vendor = usbIdToString(device.deviceDescriptor.idVendor) + device.product = usbIdToString(device.deviceDescriptor.idProduct) + device.adaptor = exports.name + + // We need to open the device in order to access _configDescriptor + debug(`Opening device: ${device.device} (${device.vendor}:${device.product})`) + device.open() + + // Ensures we don't wait forever if an issue occurs + device.timeout = USB_OPERATION_TIMEOUT_MS + + // Handle 2837 where it can start with two interfaces, the first + // is mass storage the second is the vendor interface for programming + const addresses = {} + /* eslint-disable no-underscore-dangle */ + if (device._configDescriptor.bNumInterfaces === USB_ENDPOINT_INTERFACES_SOC_BCM2835) { + /* eslint-enable no-underscore-dangle */ + addresses.interface = 0 + addresses.endpoint = 1 + } else { + addresses.interface = 1 + addresses.endpoint = 3 } + const deviceInterface = device.interface(addresses.interface) + debug(`Claiming interface: ${addresses.interface}`) + + try { + deviceInterface.claim() + } catch (error) { + if (error.message === 'LIBUSB_ERROR_NO_DEVICE') { + debug('Couldn\'t claim the interface. Assuming the device is gone') + return null + } + + throw error + } + + const endpoint = deviceInterface.endpoint(addresses.endpoint) + return Bluebird.try(() => { - if (fileMessage.command === protocol.FILE_MESSAGE_COMMANDS.GET_FILE_SIZE) { - debug(`Getting the size of ${fileMessage.fileName}`) + const serialNumberIndex = device.deviceDescriptor.iSerialNumber + debug(`Serial number index: ${serialNumberIndex}`) - return queryBlobFromCache(fileMessage.fileName, readFile).then((fileBuffer) => { - const fileSize = fileBuffer.length - debug(`Sending size: ${fileSize}`) - return protocol.sendBufferSize(device, fileSize) - }).catch({ - code: 'ENOENT' - }, () => { - debug(`Couldn't find ${fileMessage.fileName}`) - debug('Sending error signal') - return protocol.sendErrorSignal(device) - }) + if (serialNumberIndex === USB_DESCRIPTOR_NULL_INDEX) { + return USBBootAdapter.writeBootCode(device, endpoint, _.get(options.files, [ + USBBOOT_BOOTCODE_FILE_NAME + ])) } - if (fileMessage.command === protocol.FILE_MESSAGE_COMMANDS.READ_FILE) { - debug(`Reading ${fileMessage.fileName}`) - - return queryBlobFromCache(fileMessage.fileName, readFile).then((fileBuffer) => { - return protocol.write(device, endpoint, fileBuffer) - }).catch({ - code: 'ENOENT' - }, () => { - debug(`Couldn't find ${fileMessage.fileName}`) - debug('Sending error signal') - return protocol.sendErrorSignal(device) - }) - } - - return Bluebird.reject(new Error(`Unrecognized command: ${fileMessage.command}`)) - }).then(() => { - debug('Starting again') - return startFileServer(device, endpoint, readFile) + debug('Starting file server') + return this.startFileServer(device, endpoint, options.files) + }).return(device).finally(() => { + device.close() }) + + // See http://bluebirdjs.com/docs/api/promise.map.html + }, { + concurrency: 5 + }).catch((error) => { + callback(error) + }).then((devices) => { + this.emit('devices', devices) + callback(null, devices) }) + + return this + } + + /** + * @summary Write bootcode to USB device (usbboot first stage) + * @private + * + * @description + * After this stage is run, the USB will be re-mounted as 0x0a5c:0x2764. + * + * @param {Object} device - node-usb device + * @param {Object} endpoint - node-usb endpoint + * @param {Buffer} bootCodeBuffer - bootcode buffer + * @returns {Promise} + * + * @example + * const usb = require('usb') + * const device = usb.findByIds(0x0a5c, 0x2763) + * const bootcode = fs.readFileSync('./bootcode.bin') + * + * adapter.writeBootCode(device, device.interfaces(0).endpoint(1), bootcode).then(() => { + * console.log('Done!') + * }) + */ + static writeBootCode (device, endpoint, bootCodeBuffer) { + debug('Writing bootcode') + debug(`Bootcode buffer length: ${bootCodeBuffer.length}`) + const bootMessageBuffer = protocol.createBootMessageBuffer(bootCodeBuffer.length) + + debug('Writing boot message buffer to out endpoint') + return protocol.write(device, endpoint, bootMessageBuffer).then(() => { + debug('Writing boot code buffer to out endpoint') + return protocol.write(device, endpoint, bootCodeBuffer) + }).then(() => { + debug('Reading return code from device') + return protocol.read(device, protocol.RETURN_CODE_LENGTH) + }).then((data) => { + const returnCode = data.readInt32LE() + debug(`Received return code: ${returnCode}`) + + if (returnCode !== protocol.RETURN_CODE_SUCCESS) { + throw new Error(`Couldn't write the bootcode, got return code ${returnCode} from device`) + } + }) + } + + /** + * @summary Mount a USB device as a block device (usbboot second stage) + * @private + * + * @description + * The possible files you can pass here are: + * + * - autoboot.txt + * - config.txt + * - recovery.elf + * - start.elf + * - fixup.dat + * + * @param {Object} device - node-usb device + * @param {Object} endpoint - node-usb endpoint + * @param {Function} readFile - read file function + * @returns {Promise} + * + * @example + * const fs = Bluebird.promisifyAll(require('fs')) + * const usb = require('usb') + * const device = usb.findByIds(0x0a5c, 0x2763) + * + * adapter.startFileServer(device, device.interfaces(0).endpoint(1), (name) => { + * return fs.readFileAsync(name) + * }).then(() => { + * console.log('Done!') + * }) + */ + startFileServer (device, endpoint, readFile) { + debug('Listening for file messages') + return protocol + .read(device, protocol.FILE_MESSAGE_SIZE) + .then(protocol.parseFileMessageBuffer) + + // We get these error messages when reading a command + // from the device when the communication has ended + .catch({ + message: 'LIBUSB_TRANSFER_STALL' + }, { + message: 'LIBUSB_TRANSFER_ERROR' + }, (error) => { + debug(`Got ${error.message} when reading a command, assuming everything is done`) + return { + command: protocol.FILE_MESSAGE_COMMANDS.DONE + } + }) + + .then((fileMessage) => { + debug(`Received message: ${fileMessage.command} -> ${fileMessage.fileName}`) + + if (fileMessage.command === protocol.FILE_MESSAGE_COMMANDS.DONE) { + debug('Done') + return Bluebird.resolve() + } + + return Bluebird.try(() => { + if (fileMessage.command === protocol.FILE_MESSAGE_COMMANDS.GET_FILE_SIZE) { + debug(`Getting the size of ${fileMessage.fileName}`) + + return this.queryBlobFromCache(fileMessage.fileName, readFile).then((fileBuffer) => { + const fileSize = fileBuffer.length + debug(`Sending size: ${fileSize}`) + return protocol.sendBufferSize(device, fileSize) + }).catch({ + code: 'ENOENT' + }, () => { + debug(`Couldn't find ${fileMessage.fileName}`) + debug('Sending error signal') + return protocol.sendErrorSignal(device) + }) + } + + if (fileMessage.command === protocol.FILE_MESSAGE_COMMANDS.READ_FILE) { + debug(`Reading ${fileMessage.fileName}`) + + return this.queryBlobFromCache(fileMessage.fileName, readFile).then((fileBuffer) => { + return protocol.write(device, endpoint, fileBuffer) + }).catch({ + code: 'ENOENT' + }, () => { + debug(`Couldn't find ${fileMessage.fileName}`) + debug('Sending error signal') + return protocol.sendErrorSignal(device) + }) + } + + return Bluebird.reject(new Error(`Unrecognized command: ${fileMessage.command}`)) + }).then(() => { + debug('Starting again') + return this.startFileServer(device, endpoint, readFile) + }) + }) + } } /** - * @summary Scan for usbboot capable USB devices - * @function + * @summary The name of this adapter * @public - * - * @description - * You should at the very least pass a file named `bootcode.bin`. - * - * @param {Object} options - options - * @param {Function} options.readFile - file reading function - * @fulfil {Object[]} - USB devices - * @returns {Promise} - * - * @example - * const fs = Bluebird.promisifyAll(require('fs')) - * - * usbboot.scan({ - * readFile: (name) => { - * return fs.readFileAsync(name) - * } - * }).each((device) => { - * console.log(device) - * }) + * @type {String} + * @constant */ -exports.scan = (options) => { - /* eslint-disable lodash/prefer-lodash-method */ - return usb.listDevices().filter(isUsbBootCapableUSBDevice).map((device) => { - /* eslint-enable lodash/prefer-lodash-method */ +USBBootAdapter.id = 'usbboot' - // This is the only way we can unique identify devices - device.device = `${device.busNumber}:${device.deviceAddress}` - - device.displayName = 'Initializing device' - device.description = 'Compute Module' - device.raw = device.device - device.size = null - device.mountpoints = [] - device.protected = false - device.system = false - device.disabled = true - device.icon = 'loading' - device.vendor = usbIdToString(device.deviceDescriptor.idVendor) - device.product = usbIdToString(device.deviceDescriptor.idProduct) - device.adaptor = exports.name - - // We need to open the device in order to access _configDescriptor - debug(`Opening device: ${device.device} (${device.vendor}:${device.product})`) - device.open() - - // Ensures we don't wait forever if an issue occurs - device.timeout = USB_OPERATION_TIMEOUT_MS - - // Handle 2837 where it can start with two interfaces, the first - // is mass storage the second is the vendor interface for programming - const addresses = {} - /* eslint-disable no-underscore-dangle */ - if (device._configDescriptor.bNumInterfaces === USB_ENDPOINT_INTERFACES_SOC_BCM2835) { - /* eslint-enable no-underscore-dangle */ - addresses.interface = 0 - addresses.endpoint = 1 - } else { - addresses.interface = 1 - addresses.endpoint = 3 - } - - const deviceInterface = device.interface(addresses.interface) - debug(`Claiming interface: ${addresses.interface}`) - - try { - deviceInterface.claim() - } catch (error) { - if (error.message === 'LIBUSB_ERROR_NO_DEVICE') { - debug('Couldn\'t claim the interface. Assuming the device is gone') - return null - } - - throw error - } - - const endpoint = deviceInterface.endpoint(addresses.endpoint) - - return Bluebird.try(() => { - const serialNumberIndex = device.deviceDescriptor.iSerialNumber - debug(`Serial number index: ${serialNumberIndex}`) - - if (serialNumberIndex === USB_DESCRIPTOR_NULL_INDEX) { - return queryBlobFromCache(USBBOOT_BOOTCODE_FILE_NAME, options.readFile).then((bootcode) => { - return writeBootCode(device, endpoint, bootcode) - }) - } - - debug('Starting file server') - return startFileServer(device, endpoint, options.readFile) - }).return(device).catch({ - message: 'LIBUSB_TRANSFER_CANCELLED' - }, { - message: 'LIBUSB_ERROR_NO_DEVICE' - }, _.constant(null)).tap((result) => { - if (result) { - result.close() - } - }) - - // See http://bluebirdjs.com/docs/api/promise.map.html - }, { - concurrency: 5 - }).then(_.compact) -} +// Exports +module.exports = USBBootAdapter diff --git a/tests/gui/modules/drive-scanner.spec.js b/tests/gui/modules/drive-scanner.spec.js index f406d04f..c2e45834 100644 --- a/tests/gui/modules/drive-scanner.spec.js +++ b/tests/gui/modules/drive-scanner.spec.js @@ -160,7 +160,7 @@ describe('Browser: driveScanner', function () { path: '/mnt/foo' } ], - adaptor: 'standard', + adapter: 'standard', system: false }, { @@ -173,7 +173,7 @@ describe('Browser: driveScanner', function () { path: '/mnt/bar' } ], - adaptor: 'standard', + adapter: 'standard', system: false } ]) @@ -254,7 +254,7 @@ describe('Browser: driveScanner', function () { description: 'Foo', size: '14G', mountpoints: [], - adaptor: 'standard', + adapter: 'standard', system: false }, { @@ -267,7 +267,7 @@ describe('Browser: driveScanner', function () { path: 'F:' } ], - adaptor: 'standard', + adapter: 'standard', system: false } ])