1*c4ef02aeSEvan Bacon/** 2*c4ef02aeSEvan Bacon * Copyright (c) 2021 Expo, Inc. 3*c4ef02aeSEvan Bacon * Copyright (c) 2018 Drifty Co. 4*c4ef02aeSEvan Bacon * 5*c4ef02aeSEvan Bacon * This source code is licensed under the MIT license found in the 6*c4ef02aeSEvan Bacon * LICENSE file in the root directory of this source tree. 7*c4ef02aeSEvan Bacon */ 8*c4ef02aeSEvan Bacon 9*c4ef02aeSEvan Baconimport plist from '@expo/plist'; 10*c4ef02aeSEvan Baconimport Debug from 'debug'; 11*c4ef02aeSEvan Baconimport { Socket } from 'net'; 12*c4ef02aeSEvan Bacon 13*c4ef02aeSEvan Baconimport type { ProtocolWriter } from './AbstractProtocol'; 14*c4ef02aeSEvan Baconimport { PlistProtocolReader, ProtocolClient, ProtocolReaderFactory } from './AbstractProtocol'; 15*c4ef02aeSEvan Bacon 16*c4ef02aeSEvan Baconconst debug = Debug('expo:apple-device:protocol:usbmux'); 17*c4ef02aeSEvan Bacon 18*c4ef02aeSEvan Baconexport const USBMUXD_HEADER_SIZE = 16; 19*c4ef02aeSEvan Bacon 20*c4ef02aeSEvan Baconexport interface UsbmuxMessage { 21*c4ef02aeSEvan Bacon messageType: string; 22*c4ef02aeSEvan Bacon extraFields?: { [key: string]: any }; 23*c4ef02aeSEvan Bacon} 24*c4ef02aeSEvan Bacon 25*c4ef02aeSEvan Baconexport class UsbmuxProtocolClient extends ProtocolClient<UsbmuxMessage> { 26*c4ef02aeSEvan Bacon constructor(socket: Socket) { 27*c4ef02aeSEvan Bacon super(socket, new ProtocolReaderFactory(UsbmuxProtocolReader), new UsbmuxProtocolWriter()); 28*c4ef02aeSEvan Bacon } 29*c4ef02aeSEvan Bacon} 30*c4ef02aeSEvan Bacon 31*c4ef02aeSEvan Baconexport class UsbmuxProtocolReader extends PlistProtocolReader { 32*c4ef02aeSEvan Bacon constructor(callback: (data: any) => any) { 33*c4ef02aeSEvan Bacon super(USBMUXD_HEADER_SIZE, callback); 34*c4ef02aeSEvan Bacon } 35*c4ef02aeSEvan Bacon 36*c4ef02aeSEvan Bacon parseHeader(data: Buffer) { 37*c4ef02aeSEvan Bacon return data.readUInt32LE(0) - USBMUXD_HEADER_SIZE; 38*c4ef02aeSEvan Bacon } 39*c4ef02aeSEvan Bacon 40*c4ef02aeSEvan Bacon parseBody(data: Buffer) { 41*c4ef02aeSEvan Bacon const resp = super.parseBody(data); 42*c4ef02aeSEvan Bacon debug(`Response: ${JSON.stringify(resp)}`); 43*c4ef02aeSEvan Bacon return resp; 44*c4ef02aeSEvan Bacon } 45*c4ef02aeSEvan Bacon} 46*c4ef02aeSEvan Bacon 47*c4ef02aeSEvan Baconexport class UsbmuxProtocolWriter implements ProtocolWriter { 48*c4ef02aeSEvan Bacon private useTag = 0; 49*c4ef02aeSEvan Bacon 50*c4ef02aeSEvan Bacon write(socket: Socket, msg: UsbmuxMessage) { 51*c4ef02aeSEvan Bacon // TODO Usbmux message type 52*c4ef02aeSEvan Bacon debug(`socket write: ${JSON.stringify(msg)}`); 53*c4ef02aeSEvan Bacon const { messageType, extraFields } = msg; 54*c4ef02aeSEvan Bacon const plistMessage = plist.build({ 55*c4ef02aeSEvan Bacon BundleID: 'dev.expo.native-run', // TODO 56*c4ef02aeSEvan Bacon ClientVersionString: 'usbmux.js', // TODO 57*c4ef02aeSEvan Bacon MessageType: messageType, 58*c4ef02aeSEvan Bacon ProgName: 'native-run', // TODO 59*c4ef02aeSEvan Bacon kLibUSBMuxVersion: 3, 60*c4ef02aeSEvan Bacon ...extraFields, 61*c4ef02aeSEvan Bacon }); 62*c4ef02aeSEvan Bacon 63*c4ef02aeSEvan Bacon const dataSize = plistMessage ? plistMessage.length : 0; 64*c4ef02aeSEvan Bacon const protocolVersion = 1; 65*c4ef02aeSEvan Bacon const messageCode = 8; 66*c4ef02aeSEvan Bacon 67*c4ef02aeSEvan Bacon const header = Buffer.alloc(USBMUXD_HEADER_SIZE); 68*c4ef02aeSEvan Bacon header.writeUInt32LE(USBMUXD_HEADER_SIZE + dataSize, 0); 69*c4ef02aeSEvan Bacon header.writeUInt32LE(protocolVersion, 4); 70*c4ef02aeSEvan Bacon header.writeUInt32LE(messageCode, 8); 71*c4ef02aeSEvan Bacon header.writeUInt32LE(this.useTag++, 12); // TODO 72*c4ef02aeSEvan Bacon socket.write(header); 73*c4ef02aeSEvan Bacon socket.write(plistMessage); 74*c4ef02aeSEvan Bacon } 75*c4ef02aeSEvan Bacon} 76