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