From 9cff42c4724af19e92fb4e049634acbb21daaa48 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Tue, 15 Jan 2019 14:03:52 +0200 Subject: [PATCH 1/3] fix: error is raised when DevTools are closed while sending message In case you open Chrome DevTools and close them while the iOS runtime still sends messages, an error is raised in CLI: ``` Error: WebSocket is not open: readyState 2 (CLOSING) ``` The problem is that we are using Transform stream between the communication and close event of the socket is not raised until the stream flushes its current state. Fix it by skipping the write operation in case the socket is not in OPEN state. --- lib/device-sockets/ios/app-debug-socket-proxy-factory.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts b/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts index 10cebd65ea..0079ac2cf1 100644 --- a/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts +++ b/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts @@ -138,7 +138,12 @@ export class AppDebugSocketProxyFactory extends EventEmitter implements IAppDebu appDebugSocket.pipe(packets); packets.on("data", (buffer: Buffer) => { - webSocket.send(buffer.toString(encoding)); + const message = buffer.toString(encoding); + if (webSocket.readyState === webSocket.OPEN) { + webSocket.send(message); + } else { + this.$logger.trace(`Received message ${message}, but unable to send it to webSocket as its state is: ${webSocket.readyState}`); + } }); webSocket.on("error", err => { From 6bb7f8b5d5d86539e4bcbcb949917e5d6ec37126 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Tue, 15 Jan 2019 14:11:22 +0200 Subject: [PATCH 2/3] chore: update ios-device-lib to 0.5.0 Update ios-device-lib to 0.5.0, so we can use the new fixes and features: https://github.com/telerik/ios-device-lib/releases/tag/v0.5.0 --- npm-shrinkwrap.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index fd6b5c244f..d62842ad09 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -3893,9 +3893,9 @@ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" }, "ios-device-lib": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/ios-device-lib/-/ios-device-lib-0.4.15.tgz", - "integrity": "sha512-OzyKbLxrmpTB87hPelpAsvtmPYeucSP53IaLb2QHaIDW6ZqHjJV4XCHMpwtLGvLOcMNb2WVUHxoirQ+rwC21dQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/ios-device-lib/-/ios-device-lib-0.5.0.tgz", + "integrity": "sha512-EKSXHYvOhjB+R/8EaWX9Iha7AIk1U26rxvxq7Hpg/19zOXqsnjuakyJ3fDKh5BXnU7CzBpkz1V2lwi8JPvD5fw==", "requires": { "bufferpack": "0.0.6", "node-uuid": "1.4.7" diff --git a/package.json b/package.json index b3c6e2f907..af05dac8f2 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "gaze": "1.1.0", "iconv-lite": "0.4.11", "inquirer": "6.2.0", - "ios-device-lib": "0.4.15", + "ios-device-lib": "0.5.0", "ios-mobileprovision-finder": "1.0.10", "ios-sim-portable": "4.0.6", "istextorbinary": "2.2.1", From 19acf2e8494d5c1558f0f2426d4cedd1362828d2 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Tue, 15 Jan 2019 14:20:21 +0200 Subject: [PATCH 3/3] fix: Chrome debug messages from iOS Runtime are not parsed correctly During debug operation, iOS Runtime "talks" to Chrome DevTools. CLI stands as proxy between them and translates the messages. Due to Node.js socket implementation, some messages may come on chunks. The format of each message is: - first 4 bytes contain the lenght of the message (in Big-Endian) - the next bytes are the actual message Currently, the following behavior is observed: - when a full message is received, CLI sends it correctly to Chrome DevTools - when more than one message is received in the data, CLI sends only the first message to Chrome DevTools and disregards the other part - in case a split message is received, when the first part is only part of the first 4 bytes (part of the length), CLI fails with `Index out of Range` or `ERR_BUFFER_OUT_OF_BOUNDS` error (based on the inner state of the variables). To fix this behavior, remove CLI's parsing and reuse the one from `ios-device-lib`. --- .../ios/app-debug-socket-proxy-factory.ts | 4 +-- lib/device-sockets/ios/packet-stream.ts | 33 ------------------- 2 files changed, 2 insertions(+), 35 deletions(-) delete mode 100644 lib/device-sockets/ios/packet-stream.ts diff --git a/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts b/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts index 0079ac2cf1..5f015aca8d 100644 --- a/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts +++ b/lib/device-sockets/ios/app-debug-socket-proxy-factory.ts @@ -1,9 +1,9 @@ import { EventEmitter } from "events"; import { CONNECTION_ERROR_EVENT_NAME } from "../../constants"; -import { PacketStream } from "./packet-stream"; import * as net from "net"; import * as ws from "ws"; import temp = require("temp"); +import { MessageUnpackStream } from "ios-device-lib"; export class AppDebugSocketProxyFactory extends EventEmitter implements IAppDebugSocketProxyFactory { private deviceWebServers: IDictionary = {}; @@ -134,7 +134,7 @@ export class AppDebugSocketProxyFactory extends EventEmitter implements IAppDebu const encoding = "utf16le"; const appDebugSocket: net.Socket = (req)["__deviceSocket"]; - const packets = new PacketStream(); + const packets = new MessageUnpackStream(); appDebugSocket.pipe(packets); packets.on("data", (buffer: Buffer) => { diff --git a/lib/device-sockets/ios/packet-stream.ts b/lib/device-sockets/ios/packet-stream.ts deleted file mode 100644 index 220d525dd5..0000000000 --- a/lib/device-sockets/ios/packet-stream.ts +++ /dev/null @@ -1,33 +0,0 @@ -import * as stream from "stream"; - -export class PacketStream extends stream.Transform { - private buffer: Buffer; - private offset: number; - - constructor(opts?: stream.TransformOptions) { - super(opts); - } - - public _transform(packet: any, encoding: string, done: Function): void { - while (packet.length > 0) { - if (!this.buffer) { - // read length - const length = packet.readInt32BE(0); - this.buffer = Buffer.allocUnsafe(length); - this.offset = 0; - packet = packet.slice(4); - } - - packet.copy(this.buffer, this.offset); - const copied = Math.min(this.buffer.length - this.offset, packet.length); - this.offset += copied; - packet = packet.slice(copied); - - if (this.offset === this.buffer.length) { - this.push(this.buffer); - this.buffer = undefined; - } - } - done(); - } -}