import net from 'net' ; import Queue from 'promise-queue' ; import { checksum } from './utils' ; import type { PlatformConfig } from 'homebridge' ; import { getLogs } from '../logs' ; const COMMAND_QUERY_STATE = Uint8Array . from ( [ 0x81 , 0x8a , 0x8b ] ) ; const PORT = 5577 ; function wait ( emitter , eventName , timeout ) { return new Promise ( ( resolve , reject ) => { let complete = false ; const waitTimeout = setTimeout ( ( ) => { complete = true ; resolve ( null ) ; } , timeout ) ; emitter . once ( eventName , ( args ) => { clearTimeout ( waitTimeout ) ; if ( ! complete ) { complete = true ; resolve ( args ) ; } } ) ; emitter . once ( 'close' , ( ) => { clearTimeout ( waitTimeout ) ; if ( ! complete ) { complete = true ; reject ( null ) ; } } ) ; emitter . on ( 'error' , ( e ) => { clearTimeout ( waitTimeout ) ; if ( ! complete ) { complete = true ; reject ( e ) ; } } ) ; } ) ; } export class Transport { logs = getLogs ( ) ; host : any ; socket : any ; queue : any ; param { string } host param { number } timeout constructor ( host , public readonly config ) { this . host = host ; this . socket = null ; this . queue = new Queue ( 1 , Infinity ) ; } async connect ( fn , _timeout = 200 ) { const options = { host : this . host , port : PORT , timeout : _timeout , } ; let result ; try { this . socket = net . connect ( options ) ; await wait ( this . socket , 'connect' , _timeout = 200 ) ; result = await fn ( ) ; return result ; } catch ( e ) { const { code , address , port } = e ; if ( code ) { } else { this . logs . error ( 'transport.ts error:' , e ) ; } } finally { this . socket . end ( ) ; this . socket . destroy ( ) ; } return null ; } disconnect ( ) { this . socket . end ( ) ; this . socket = null ; } async send ( buffer , useChecksum = true , _timeout = 2000 ) { return this . queue . add ( async ( ) => ( this . connect ( async ( ) => { await this . write ( buffer ) ; return this . read ( _timeout ) ; } ) ) ) ; } async write ( buffer , useChecksum = true , _timeout = 200 ) { let sent ; if ( useChecksum ) { const chk = checksum ( buffer ) ; const payload = Buffer . concat ( [ buffer , Buffer . from ( [ chk ] ) ] ) ; sent = this . socket . write ( payload ) ; } else { sent = this . socket . write ( buffer ) ; } if ( sent !== true ) { await wait ( this . socket , 'drain' , _timeout ) ; } } async read ( _timeout = 200 ) { const data = await wait ( this . socket , 'data' , _timeout ) ; return data ; } async getState ( _timeout = 500 ) { try { const data = await this . send ( COMMAND_QUERY_STATE , true , _timeout ) ; if ( data == null ) { return null ; } return { debugBuffer : data , controllerHardwareVersion : data . readUInt8 ( 1 ) , isOn : data . readUInt8 ( 2 ) === 0x23 , RGB : { red : data . readUInt8 ( 6 ) , green : data . readUInt8 ( 7 ) , blue : data . readUInt8 ( 8 ) , } , whiteValues : { warmWhite : data . readUInt8 ( 9 ) , coldWhite : data . readUInt8 ( 11 ) , } , controllerFirmwareVersion : data . readUInt8 ( 10 ) , } ; } catch ( error ) { this . logs . debug ( 'Transport getState() error:' , error ) ; } } }