import { Transport } from './Transport' ; import { hexdump } from '../Helpers' ; import { Options } from '../Options' ; const ADB_DEVICE = { classCode : 255 , subclassCode : 66 , protocolCode : 1 } as USBDeviceFilter ; const FASTBOOT_DEVICE = { classCode : 255 , subclassCode : 66 , protocolCode : 3 } as USBDeviceFilter ; const DEVICE_FILTERS = [ ADB_DEVICE , FASTBOOT_DEVICE ] ; interface DeviceMatch { conf : USBConfiguration ; intf : USBInterface ; alternate : USBAlternateInterface ; } /**
 * An implementation of  Transport using WebUSB as the tranport layer.
  export class WebUsbTransport implements Transport { private constructor ( readonly device , readonly match , readonly endpointIn , readonly endpointOut , readonly options , readonly log = console . log ) { } /**
     *  Releases the interface and closes the connection to the WebUSB device
     */ async close ( ) { await this . device . releaseInterface ( this . match . intf . interfaceNumber ) ; await this . device . close ( ) ; } param { ArrayBuffer } data async write ( data ) { if ( this . options . dump ) { hexdump ( new DataView ( data ) , '' + this . endpointOut + '==> ' ) ; } await this . device . transferOut ( this . endpointOut , data ) ; } param { number } len returns { Promise < DataView } async read ( len ) { const response = await this . device . transferIn ( this . endpointIn , len ) ; if ( ! response . data ) { throw new Error ( 'Response didn\'t contain any data' ) ; } return response . data ; } returns { boolean } isAdb ( ) { const match = WebUsbTransport . findMatch ( this . device , ADB_DEVICE ) ; return match != null ; } ; returns { boolean } isFastboot ( ) { const match = WebUsbTransport . findMatch ( this . device , FASTBOOT_DEVICE ) ; return match != null ; } ; param options static async open ( options ) { const device = await navigator . usb . requestDevice ( { filters : DEVICE_FILTERS } ) ; await device . open ( ) ; const match = this . findMatch ( device , ADB_DEVICE ) ; if ( ! match ) { throw new Error ( 'Could not find an ADB device' ) ; } await device . selectConfiguration ( match . conf . configurationValue ) ; await device . claimInterface ( match . intf . interfaceNumber ) ; const endpointIn = WebUsbTransport . getEndpointNum ( match . alternate . endpoints , 'in' ) ; const endpointOut = WebUsbTransport . getEndpointNum ( match . alternate . endpoints , 'out' ) ; const transport = new WebUsbTransport ( device , match , endpointIn , endpointOut , options ) ; if ( options . debug ) { console . log ( 'Created new Transport: ' , transport ) ; } return transport ; } private static findMatch ( device , filter ) { for ( const configuration of device . configurations ) { for ( const intf of configuration . interfaces ) { for ( const alternate of intf . alternates ) { if ( filter . classCode === alternate . interfaceClass && filter . subclassCode === alternate . interfaceSubclass && filter . protocolCode === alternate . interfaceProtocol ) { return { conf : configuration , intf , alternate } ; } } } } return null ; } private static getEndpointNum ( endpoints , dir , type = 'bulk' ) { for ( const ep of endpoints ) { if ( ep . direction === dir && ep . type === type ) { return ep . endpointNumber ; } } throw new Error ( `Cannot find ${ dir } endpoint` ) ; } }