etcher/lib/sdk/scanner.js
Jonas Hermsmeier b0538099cf
fix(lib): Fix debug namespaces
This fixes some debug namespaces not being prefixed with `etcher:`
and their respective subsystems.

Change-Type: patch
2018-02-16 19:01:26 +01:00

233 lines
5.0 KiB
JavaScript

/*
* Copyright 2017 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict'
const _ = require('lodash')
const EventEmitter = require('events')
const debug = require('debug')('etcher:sdk:scanner')
const SDK = require('./')
debug.enabled = true
/* eslint-disable lodash/prefer-lodash-method */
/**
* Adapter Scanner
* @class Scanner
* @memberOf SDK
*/
class Scanner extends EventEmitter {
/**
* @summary Adapter Scanner constructor
* @param {Object<String,Object>} [options] - device adapter options
* @param {Object} [options.adapters] - map of external device adapters
* @example
* new Scanner({
* blockdevice: { ... },
* usbboot: { ... }
* })
*/
constructor (options = {}) {
// Inherit from EventEmitter
super()
this.options = options
this.isScanning = false
this.adapters = new Map()
// Bind event handlers to own context to facilitate
// removing listeners by reference
this.onDevices = this.onDevices.bind(this)
this.onError = this.onError.bind(this)
this.init()
}
/**
* @summary Initialize adapters
* @private
* @example
* // Only to be used internally
* this.init()
*/
init () {
debug('scanner:init', this)
_.each(_.keys(this.options), (adapterId) => {
const adapter = SDK.adapters[adapterId] ||
_.get(this.options, [ 'adapters', adapterId ])
if (_.isNil(adapter)) {
console.warn(`Unknown adapter "${adapterId}"`)
return
}
this.subscribe(adapter)
})
}
/**
* @summary Event handler for adapter's "device" events
* @private
* @example
* adapter.on('devices', this.onDevices)
*/
onDevices () {
const devices = []
this.adapters.forEach((adapter) => {
devices.push(...adapter.devices)
})
this.emit('devices', devices)
}
/**
* @summary Event handler for adapter's "error" events
* @param {Error} error - error
* @private
* @example
* adapter.on('error', this.onError)
*/
onError (error) {
this.emit('error', error)
}
/**
* @summary Start scanning for devices
* @public
* @returns {Scanner}
* @example
* scanner.start()
*/
start () {
debug('start', !this.isScanning)
if (this.isScanning) {
return this
}
this.adapters.forEach((adapter) => {
const options = this.options[adapter.id]
/**
* @summary Run a scan with an adapter
* @function
* @private
* @example
* runScan()
*/
const runScan = () => {
adapter.scan(options, () => {
if (this.isScanning) {
setTimeout(runScan, Scanner.MIN_SCAN_DELAY)
}
})
}
adapter
.on('devices', this.onDevices)
.on('error', this.onError)
runScan()
})
this.emit('start')
this.isScanning = true
return this
}
/**
* @summary Stop scanning for devices
* @public
* @returns {Scanner}
* @example
* scanner.stop()
*/
stop () {
debug('stop', this.isScanning)
if (!this.isScanning) {
return this
}
this.adapters.forEach((adapter) => {
adapter.removeListener('devices', this.onDevices)
adapter.removeListener('error', this.onError)
})
this.isScanning = false
this.emit('stop')
return this
}
/**
* @summary Subscribe to an adapter
* @public
* @param {Adapter} adapter - device adapter
* @returns {Scanner}
* @example
* scanner.subscribe(adapter)
*/
subscribe (adapter) {
debug('subscribe', adapter)
if (this.adapters.get(adapter.id)) {
throw new Error(`Scanner: Already subscribed to ${adapter.id}`)
}
this.adapters.set(adapter.id, adapter)
this.emit('subscribe', adapter)
return this
}
/**
* @summary Unsubscribe from an adapter
* @public
* @param {Adapter} adapter - device adapter
* @returns {Scanner}
* @example
* scanner.unsubscribe(adapter)
* // OR
* scanner.unsubscribe('adapterName')
*/
unsubscribe (adapter) {
debug('unsubscribe', adapter)
const instance = _.isString(adapter) ? this.adapters.get(adapter) : this.adapters.get(adapter.id)
if (_.isNil(instance)) {
// Not subscribed
return this
}
instance.removeListener('devices', this.onDevices)
instance.removeListener('error', this.onError)
this.adapters.delete(instance.id)
this.emit('unsubscribe', adapter)
return this
}
}
/**
* @summary Minimum delay between scans in ms
* @const
* @type {Number}
*/
Scanner.MIN_SCAN_DELAY = 500
module.exports = Scanner