diff --git a/.gitignore b/.gitignore index ced2153..fa4939f 100644 --- a/.gitignore +++ b/.gitignore @@ -275,7 +275,12 @@ xcuserdata/ .DS_Store ### VS Code -.vscode +.vscode/**/* +!.vscode/launch.json ### The following folder is present because of a workaround for MobileDevice.framework and Xcode 9.0 .frameworks/* + +### Node.js files +coverage/ +*.tgz \ No newline at end of file diff --git a/.npmignore b/.npmignore index cc77f48..16407ea 100644 --- a/.npmignore +++ b/.npmignore @@ -11,3 +11,8 @@ DerivedData **/*.ipdb **/*.iobj .frameworks/* + +### Test files +test/ +coverage/ +*.tgz \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..b7a08e3 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Tests", + "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", + // modify timeout, so we can debug tests without failing with timeout error + // real value can be found in mocha.opts file + "args": ["--timeout", "1500000"] + } + ] +} \ No newline at end of file diff --git a/index.js b/index.js index 2711e3a..0b99b10 100644 --- a/index.js +++ b/index.js @@ -1,176 +1,7 @@ "use strict"; -const uuid = require('node-uuid'); -const EventEmitter = require("events"); - -const Constants = require("./constants"); - -const IOSDeviceLibStdioHandler = require("./ios-device-lib-stdio-handler").IOSDeviceLibStdioHandler; - -const MethodNames = { - install: "install", - uninstall: "uninstall", - list: "list", - log: "log", - upload: "upload", - download: "download", - read: "read", - delete: "delete", - postNotification: "postNotification", - awaitNotificationResponse: "awaitNotificationResponse", - start: "start", - stop: "stop", - apps: "apps", - connectToPort: "connectToPort" -}; - -const Events = { - deviceLogData: "deviceLogData" -}; - -class IOSDeviceLib extends EventEmitter { - constructor(onDeviceFound, onDeviceLost, options) { - super(); - this._options = options || {}; - this._iosDeviceLibStdioHandler = new IOSDeviceLibStdioHandler(this._options); - this._iosDeviceLibStdioHandler.startReadingData(); - this._iosDeviceLibStdioHandler.on(Constants.DeviceFoundEventName, onDeviceFound); - this._iosDeviceLibStdioHandler.on(Constants.DeviceLostEventName, onDeviceLost); - } - - install(ipaPath, deviceIdentifiers) { - return deviceIdentifiers.map(di => this._getPromise(MethodNames.install, [ipaPath, [di]])); - } - - uninstall(appId, deviceIdentifiers) { - return deviceIdentifiers.map(di => this._getPromise(MethodNames.uninstall, [appId, [di]])); - } - - list(listArray) { - return listArray.map(listObject => this._getPromise(MethodNames.list, [listObject])); - } - - upload(uploadArray) { - return uploadArray.map(uploadObject => this._getPromise(MethodNames.upload, [uploadObject])); - } - - download(downloadArray) { - return downloadArray.map(downloadObject => this._getPromise(MethodNames.download, [downloadObject])); - } - - read(readArray) { - return readArray.map(readObject => this._getPromise(MethodNames.read, [readObject])); - } - - delete(deleteArray) { - return deleteArray.map(deleteObject => this._getPromise(MethodNames.delete, [deleteObject])); - } - - postNotification(postNotificationArray) { - return postNotificationArray.map(notificationObject => this._getPromise(MethodNames.postNotification, [notificationObject])); - } - - awaitNotificationResponse(awaitNotificationResponseArray) { - return awaitNotificationResponseArray.map(awaitNotificationObject => this._getPromise(MethodNames.awaitNotificationResponse, [awaitNotificationObject])); - } - - apps(deviceIdentifiers) { - return deviceIdentifiers.map(di => this._getPromise(MethodNames.apps, [di])); - } - - start(startArray) { - return startArray.map(startObject => this._getPromise(MethodNames.start, [startObject])); - } - - stop(stopArray) { - return stopArray.map(stopObject => this._getPromise(MethodNames.stop, [stopObject])); - } - - startDeviceLog(deviceIdentifiers) { - this._getPromise(MethodNames.log, deviceIdentifiers, { shouldEmit: true, disregardTimeout: true, doNotFailOnDeviceLost: true }); - } - - connectToPort(connectToPortArray) { - return connectToPortArray.map(connectToPortObject => this._getPromise(MethodNames.connectToPort, [connectToPortObject])); - } - - dispose(signal) { - this.removeAllListeners(); - this._iosDeviceLibStdioHandler.dispose(signal); - } - - _getPromise(methodName, args, options = {}) { - return new Promise((resolve, reject) => { - if (!args || !args.length) { - return reject(new Error("No arguments provided")); - } - - let timer = null; - let eventHandler = null; - let deviceLostHandler = null; - const id = uuid.v4(); - const removeListeners = () => { - if (eventHandler) { - this._iosDeviceLibStdioHandler.removeListener(Constants.DataEventName, eventHandler); - } - - if (deviceLostHandler) { - this._iosDeviceLibStdioHandler.removeListener(Constants.DeviceLostEventName, deviceLostHandler); - } - }; - - // In case device is lost during waiting for operation to complete - // or in case we do not execute operation in the specified timeout - // remove all handlers and reject the promise. - // NOTE: This is not applicable for device logs, where the Promise is not awaited - // Rejecting it results in Unhandled Rejection - const handleMessage = (message) => { - removeListeners(); - message.error ? reject(message.error) : resolve(message); - }; - - deviceLostHandler = (device) => { - let message = `Device ${device.deviceId} lost during operation ${methodName} for message ${id}`; - - if (!options.doNotFailOnDeviceLost) { - message = { error: new Error(message) }; - } - - handleMessage(message); - }; - - eventHandler = (message) => { - if (message && message.id === id) { - if (timer) { - clearTimeout(timer); - } - - delete message.id; - if (options && options.shouldEmit) { - this.emit(Events.deviceLogData, message); - } else { - handleMessage(message); - } - } - }; - - if (this._options.timeout && !options.disregardTimeout) { - // TODO: Check if we should clear the timers when dispose is called. - timer = setTimeout(() => { - handleMessage({ error: new Error(`Timeout waiting for ${methodName} response from ios-device-lib, message id: ${id}.`) }); - }, this._options.timeout); - } - - this._iosDeviceLibStdioHandler.on(Constants.DataEventName, eventHandler); - this._iosDeviceLibStdioHandler.on(Constants.DeviceLostEventName, deviceLostHandler); - - this._iosDeviceLibStdioHandler.writeData(this._getMessage(id, methodName, args)); - }); - } - - _getMessage(id, name, args) { - return JSON.stringify({ methods: [{ id: id, name: name, args: args }] }) + '\n'; - } -} +const IOSDeviceLib = require("./ios-device-lib").IOSDeviceLib; +const MessageUnpackStream = require("./message-unpack-stream").MessageUnpackStream; exports.IOSDeviceLib = IOSDeviceLib; +exports.MessageUnpackStream = MessageUnpackStream; diff --git a/ios-device-lib.js b/ios-device-lib.js new file mode 100644 index 0000000..c80d202 --- /dev/null +++ b/ios-device-lib.js @@ -0,0 +1,174 @@ +const uuid = require('node-uuid'); +const EventEmitter = require("events"); + +const Constants = require("./constants"); + +const IOSDeviceLibStdioHandler = require("./ios-device-lib-stdio-handler").IOSDeviceLibStdioHandler; + +const MethodNames = { + install: "install", + uninstall: "uninstall", + list: "list", + log: "log", + upload: "upload", + download: "download", + read: "read", + delete: "delete", + postNotification: "postNotification", + awaitNotificationResponse: "awaitNotificationResponse", + start: "start", + stop: "stop", + apps: "apps", + connectToPort: "connectToPort" +}; + +const Events = { + deviceLogData: "deviceLogData" +}; + +class IOSDeviceLib extends EventEmitter { + constructor(onDeviceFound, onDeviceLost, options) { + super(); + this._options = options || {}; + this._iosDeviceLibStdioHandler = new IOSDeviceLibStdioHandler(this._options); + this._iosDeviceLibStdioHandler.startReadingData(); + this._iosDeviceLibStdioHandler.on(Constants.DeviceFoundEventName, onDeviceFound); + this._iosDeviceLibStdioHandler.on(Constants.DeviceLostEventName, onDeviceLost); + } + + install(ipaPath, deviceIdentifiers) { + return deviceIdentifiers.map(di => this._getPromise(MethodNames.install, [ipaPath, [di]])); + } + + uninstall(appId, deviceIdentifiers) { + return deviceIdentifiers.map(di => this._getPromise(MethodNames.uninstall, [appId, [di]])); + } + + list(listArray) { + return listArray.map(listObject => this._getPromise(MethodNames.list, [listObject])); + } + + upload(uploadArray) { + return uploadArray.map(uploadObject => this._getPromise(MethodNames.upload, [uploadObject])); + } + + download(downloadArray) { + return downloadArray.map(downloadObject => this._getPromise(MethodNames.download, [downloadObject])); + } + + read(readArray) { + return readArray.map(readObject => this._getPromise(MethodNames.read, [readObject])); + } + + delete(deleteArray) { + return deleteArray.map(deleteObject => this._getPromise(MethodNames.delete, [deleteObject])); + } + + postNotification(postNotificationArray) { + return postNotificationArray.map(notificationObject => this._getPromise(MethodNames.postNotification, [notificationObject])); + } + + awaitNotificationResponse(awaitNotificationResponseArray) { + return awaitNotificationResponseArray.map(awaitNotificationObject => this._getPromise(MethodNames.awaitNotificationResponse, [awaitNotificationObject])); + } + + apps(deviceIdentifiers) { + return deviceIdentifiers.map(di => this._getPromise(MethodNames.apps, [di])); + } + + start(startArray) { + return startArray.map(startObject => this._getPromise(MethodNames.start, [startObject])); + } + + stop(stopArray) { + return stopArray.map(stopObject => this._getPromise(MethodNames.stop, [stopObject])); + } + + startDeviceLog(deviceIdentifiers) { + this._getPromise(MethodNames.log, deviceIdentifiers, { shouldEmit: true, disregardTimeout: true, doNotFailOnDeviceLost: true }); + } + + connectToPort(connectToPortArray) { + return connectToPortArray.map(connectToPortObject => this._getPromise(MethodNames.connectToPort, [connectToPortObject])); + } + + dispose(signal) { + this.removeAllListeners(); + this._iosDeviceLibStdioHandler.dispose(signal); + } + + _getPromise(methodName, args, options = {}) { + return new Promise((resolve, reject) => { + if (!args || !args.length) { + return reject(new Error("No arguments provided")); + } + + let timer = null; + let eventHandler = null; + let deviceLostHandler = null; + const id = uuid.v4(); + const removeListeners = () => { + if (eventHandler) { + this._iosDeviceLibStdioHandler.removeListener(Constants.DataEventName, eventHandler); + } + + if (deviceLostHandler) { + this._iosDeviceLibStdioHandler.removeListener(Constants.DeviceLostEventName, deviceLostHandler); + } + }; + + // In case device is lost during waiting for operation to complete + // or in case we do not execute operation in the specified timeout + // remove all handlers and reject the promise. + // NOTE: This is not applicable for device logs, where the Promise is not awaited + // Rejecting it results in Unhandled Rejection + const handleMessage = (message) => { + removeListeners(); + message.error ? reject(message.error) : resolve(message); + }; + + deviceLostHandler = (device) => { + let message = `Device ${device.deviceId} lost during operation ${methodName} for message ${id}`; + + if (!options.doNotFailOnDeviceLost) { + message = { error: new Error(message) }; + } + + handleMessage(message); + }; + + eventHandler = (message) => { + if (message && message.id === id) { + if (timer) { + clearTimeout(timer); + } + + delete message.id; + if (options && options.shouldEmit) { + this.emit(Events.deviceLogData, message); + } else { + handleMessage(message); + } + } + }; + + if (this._options.timeout && !options.disregardTimeout) { + // TODO: Check if we should clear the timers when dispose is called. + timer = setTimeout(() => { + handleMessage({ error: new Error(`Timeout waiting for ${methodName} response from ios-device-lib, message id: ${id}.`) }); + }, this._options.timeout); + } + + this._iosDeviceLibStdioHandler.on(Constants.DataEventName, eventHandler); + this._iosDeviceLibStdioHandler.on(Constants.DeviceLostEventName, deviceLostHandler); + + this._iosDeviceLibStdioHandler.writeData(this._getMessage(id, methodName, args)); + }); + } + + _getMessage(id, name, args) { + return JSON.stringify({ methods: [{ id: id, name: name, args: args }] }) + '\n'; + } +} + +exports.IOSDeviceLib = IOSDeviceLib; diff --git a/message-unpack-stream.js b/message-unpack-stream.js index a783e14..3d8da01 100644 --- a/message-unpack-stream.js +++ b/message-unpack-stream.js @@ -5,16 +5,18 @@ const bufferpack = require("bufferpack"); const HeaderSize = 4; -exports.MessageUnpackStream = class MessageUnpackStream extends stream.Transform { +class MessageUnpackStream extends stream.Transform { constructor(opts) { super(opts); - this._unfinishedMessage = new Buffer(0); + this._unfinishedMessage = Buffer.from(""); } _transform(data, encoding, done) { if (!this._unfinishedMessage.length && data.length >= HeaderSize) { // Get the message length header. const messageSizeBuffer = data.slice(0, HeaderSize); + // > - big-endian + // i - signed long const messageLength = bufferpack.unpack(">i", messageSizeBuffer)[0]; const dataLengthWithoutHeader = data.length - HeaderSize; @@ -40,14 +42,17 @@ exports.MessageUnpackStream = class MessageUnpackStream extends stream.Transform this.push(messageBuffer); this._endUnpackingMessages(done); } - } else { + } else if (this._unfinishedMessage.length && data.length) { // Append the new data to the unfinished message and try to unpack again. const concatenatedMessage = Buffer.concat([this._unfinishedMessage, data]); // Clear the unfinished message buffer. - this._unfinishedMessage = new Buffer(0); + this._unfinishedMessage = Buffer.from(""); this._transform(concatenatedMessage); this._endUnpackingMessages(done); + } else { + this._unfinishedMessage = Buffer.from(data); + this._endUnpackingMessages(done); } } @@ -61,3 +66,5 @@ exports.MessageUnpackStream = class MessageUnpackStream extends stream.Transform } } } + +exports.MessageUnpackStream = MessageUnpackStream; \ No newline at end of file diff --git a/package.json b/package.json index d1475f0..b4e34d8 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,9 @@ "types": "./typings/ios-device-lib.d.ts", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "prepack": "npm test", + "mocha": "mocha", + "test": "istanbul cover ./node_modules/mocha/bin/_mocha" }, "repository": { "type": "git", @@ -20,5 +22,10 @@ "dependencies": { "bufferpack": "0.0.6", "node-uuid": "1.4.7" + }, + "devDependencies": { + "chai": "4.2.0", + "istanbul": "0.4.5", + "mocha": "5.2.0" } } diff --git a/test/message-unpack-stream.js b/test/message-unpack-stream.js new file mode 100644 index 0000000..1d93301 --- /dev/null +++ b/test/message-unpack-stream.js @@ -0,0 +1,161 @@ +const { assert } = require("chai"); +const sinon = require("sinon"); +const bufferpack = require("bufferpack"); +const MessageUnpackStream = require("../message-unpack-stream").MessageUnpackStream; + +describe("message-unpack-stream", () => { + describe("_transform", () => { + const createMessageToSend = (message) => { + const header = bufferpack.pack(">i", [message.length]); + const binaryMsg = Buffer.from(message); + const dataToSend = Buffer.concat([header, binaryMsg]); + return { + binaryMsg, + dataToSend + }; + }; + + it("parses correctly one message", (mochaDone) => { + const { dataToSend, binaryMsg } = createMessageToSend("testMessage"); + const msgUnpackStreamInstance = new MessageUnpackStream(); + + let pushedMessage = null; + msgUnpackStreamInstance.push = (data, encoding) => { + pushedMessage = data; + }; + + msgUnpackStreamInstance._transform(dataToSend, null, () => { + assert.deepEqual(pushedMessage, binaryMsg); + mochaDone(); + }); + }); + + it("does not parse anything when only partial message is sent", (mochaDone) => { + const { dataToSend, binaryMsg } = createMessageToSend("testMessage"); + const msgUnpackStreamInstance = new MessageUnpackStream(); + + let pushedMessage = null; + msgUnpackStreamInstance.push = (data, encoding) => { + assert.fail("Push should not be called with partial message"); + pushedMessage = data; + }; + + msgUnpackStreamInstance._transform(dataToSend.slice(0, 6), null, () => { + assert.deepEqual(pushedMessage, null); + mochaDone(); + }); + }); + + describe("parses correctly one message passed on two calls, when the first one", () => { + const validateMessage = (endSplitIndex, mochaDone) => { + const { dataToSend, binaryMsg } = createMessageToSend("testMessage"); + const msgUnpackStreamInstance = new MessageUnpackStream(); + + let pushedMessage = null; + msgUnpackStreamInstance.push = (data, encoding) => { + pushedMessage = data; + }; + + let doneCallbackCounter = 0; + const doneCallback = () => { + doneCallbackCounter++; + + if (doneCallbackCounter === 2) { + assert.deepEqual(pushedMessage, binaryMsg); + mochaDone(); + } + }; + const firstMessage = dataToSend.slice(0, endSplitIndex); + msgUnpackStreamInstance._transform(firstMessage, null, doneCallback); + msgUnpackStreamInstance._transform(dataToSend.slice(firstMessage.length), null, doneCallback); + }; + + it("does not contain full header", (mochaDone) => { + validateMessage(1, mochaDone); + }); + + it("contains only header", (mochaDone) => { + validateMessage(4, mochaDone); + }); + + it("contains header and part of the message", (mochaDone) => { + validateMessage(7, mochaDone); + }); + }); + + it("parses correctly two messages passed on one call", (mochaDone) => { + const { dataToSend: firstDataToSend, binaryMsg: firstBinaryMsg } = createMessageToSend("testMessage"); + const { dataToSend: secondDataToSend, binaryMsg: secondBinaryMsg } = createMessageToSend("secondTestMessage"); + + const msgUnpackStreamInstance = new MessageUnpackStream(); + + let pushedMessages = []; + msgUnpackStreamInstance.push = (data, encoding) => { + pushedMessages.push(data) + }; + + const doneCallback = () => { + assert.deepEqual(pushedMessages, [firstBinaryMsg, secondBinaryMsg]); + mochaDone(); + }; + + const dataToSend = Buffer.concat([firstDataToSend, secondDataToSend]); + msgUnpackStreamInstance._transform(dataToSend, null, doneCallback); + }); + + describe("parses correctly two messages passed on two calls, when", () => { + const validateMessage = (endSplitIndex, mochaDone) => { + // NOTE: Do NOT change the messages here as it will result in incorrect tests below + const { dataToSend: firstDataToSend, binaryMsg: firstBinaryMsg } = createMessageToSend("abc"); + const { dataToSend: secondDataToSend, binaryMsg: secondBinaryMsg } = createMessageToSend("def"); + + const msgUnpackStreamInstance = new MessageUnpackStream(); + + let pushedMessages = []; + msgUnpackStreamInstance.push = (data, encoding) => { + pushedMessages.push(data) + }; + + let doneCallbackCounter = 0; + const doneCallback = () => { + doneCallbackCounter++; + + if (doneCallbackCounter === 2) { + assert.deepEqual(pushedMessages, [firstBinaryMsg, secondBinaryMsg]); + mochaDone(); + } + }; + + const dataToSend = Buffer.concat([firstDataToSend, secondDataToSend]); + const firstMessage = dataToSend.slice(0, endSplitIndex); + msgUnpackStreamInstance._transform(firstMessage, null, doneCallback); + msgUnpackStreamInstance._transform(dataToSend.slice(firstMessage.length), null, doneCallback); + }; + + it("first call contains part of the header of the first message", (mochaDone) => { + validateMessage(1, mochaDone); + }); + + it("first call contains only the header of the first message", (mochaDone) => { + validateMessage(4, mochaDone); + }); + + it("first call contains the header and part of the first message", (mochaDone) => { + validateMessage(6, mochaDone); + }); + + it("first call contains the first message and part of the header of the second message", (mochaDone) => { + validateMessage(9, mochaDone); + }); + + it("first call contains the first message and the header of the second message", (mochaDone) => { + validateMessage(11, mochaDone); + }); + + it("first call contains the first message, the header of the second message and part of the second message", (mochaDone) => { + validateMessage(13, mochaDone); + }); + }); + + }); +}); diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 0000000..03e158f --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1,4 @@ +--recursive +--reporter spec +--timeout 50 +test/ diff --git a/typings/interfaces.d.ts b/typings/interfaces.d.ts index 4af73ff..244ae75 100644 --- a/typings/interfaces.d.ts +++ b/typings/interfaces.d.ts @@ -1,148 +1,155 @@ -declare module IOSDeviceLib { - interface IDeviceActionInfo { - deviceId: string; - event: string; - deviceColor?: string; - deviceName?: string; - productType?: string; - productVersion?: string; - status?: string; +import { Transform, TransformOptions } from "stream"; + +declare global { + namespace IOSDeviceLib { + interface IDeviceActionInfo { + deviceId: string; + event: string; + deviceColor?: string; + deviceName?: string; + productType?: string; + productVersion?: string; + status?: string; + } + + interface IDeviceId { + deviceId: string; + } + + interface IAppId { + appId: string; + } + + interface IAppDevice extends IDeviceId, IAppId { + } + + interface IDestination { + destination: string; + } + + interface ISource { + source: string; + } + + interface IReadOperationData extends IAppDevice { + path: string; + } + + interface IFileData extends ISource, IDestination { + } + + interface IFileOperationData extends IAppDevice, IFileData { + } + + + interface IUploadFilesData extends IAppDevice { + files: IFileData[]; + } + + interface IDeleteFileData extends IAppDevice, IDestination { + } + + interface IDdiApplicationData extends IAppDevice { + ddi: string; + } + + interface IPostNotificationData extends IDeviceId { + commandType: string; + notificationName: string; + } + + interface IAwaitNotificatioNResponseData extends IDeviceId { + responseCommandType: string; + responsePropertyName: string; + socket: number; + timeout: number; + } + + interface IDeviceResponse extends IDeviceId { + response: string; + } + + interface IDeviceMultipleResponse extends IDeviceId { + response: string[]; + } + + interface IApplicationInfo { + CFBundleIdentifier: string; + IceniumLiveSyncEnabled: boolean; + configuration: string; + } + + interface IDeviceAppInfo extends IDeviceId { + response: IApplicationInfo[]; + } + + interface IMessage { + message: string; + } + + interface IDeviceLogData extends IDeviceId, IMessage { + } + + interface IDeviceApplication { + CFBundleExecutable: string; + Path: string; + } + + interface IDeviceLookupInfo extends IDeviceId { + response: { [key: string]: IDeviceApplication }; + } + + interface IDeviceError extends Error { + deviceId: string; + } + + interface IConnectToPortData extends IDeviceId { + port: number; + } + + interface ISocketData extends IDeviceId { + socket: number; + } + + interface ISendMessageToSocketData extends ISocketData, IMessage { + } + + interface IReceiveMessagesFromSocketData extends ISocketData { + callback: SocketMessageHandler; + context: any; + } + + interface ISocketMessage extends ISocketData, IMessage { + } + + interface IConnectToPortResponse extends IDeviceId { + host: string; + port: number; + } + + interface IOSDeviceLib extends NodeJS.EventEmitter { + new(onDeviceFound: (found: IDeviceActionInfo) => void, onDeviceLost: (found: IDeviceActionInfo) => void): IOSDeviceLib; + install(ipaPath: string, deviceIdentifiers: string[]): Promise[]; + uninstall(ipaPath: string, deviceIdentifiers: string[]): Promise[]; + list(listArray: IReadOperationData[]): Promise[]; + upload(uploadArray: IUploadFilesData[]): Promise[]; + download(downloadArray: IFileOperationData[]): Promise[]; + read(readArray: IReadOperationData[]): Promise[]; + delete(deleteArray: IDeleteFileData[]): Promise[]; + postNotification(postNotificationArray: IPostNotificationData[]): Promise[]; + awaitNotificationResponse(awaitNotificationResponseArray: IAwaitNotificatioNResponseData[]): Promise[]; + apps(deviceIdentifiers: string[]): Promise[]; + start(startArray: IDdiApplicationData[]): Promise[]; + stop(stopArray: IDdiApplicationData[]): Promise[]; + startDeviceLog(deviceIdentifiers: string[]): void; + connectToPort(connectToPortArray: IConnectToPortData[]): Promise[]; + dispose(signal?: string): void; + on(event: "deviceLogData", listener: (response: IDeviceLogData) => void): this; + } + + type SocketMessageHandler = (message: ISocketMessage) => void; + interface MessageUnpackStream extends Transform { + new(opts?: TransformOptions): MessageUnpackStream; + } } - - interface IDeviceId { - deviceId: string; - } - - interface IAppId { - appId: string; - } - - interface IAppDevice extends IDeviceId, IAppId { - } - - interface IDestination { - destination: string; - } - - interface ISource { - source: string; - } - - interface IReadOperationData extends IAppDevice { - path: string; - } - - interface IFileData extends ISource, IDestination { - } - - interface IFileOperationData extends IAppDevice, IFileData { - } - - - interface IUploadFilesData extends IAppDevice { - files: IFileData[]; - } - - interface IDeleteFileData extends IAppDevice, IDestination { - } - - interface IDdiApplicationData extends IAppDevice { - ddi: string; - } - - interface IPostNotificationData extends IDeviceId { - commandType: string; - notificationName: string; - } - - interface IAwaitNotificatioNResponseData extends IDeviceId { - responseCommandType: string; - responsePropertyName: string; - socket: number; - timeout: number; - } - - interface IDeviceResponse extends IDeviceId { - response: string; - } - - interface IDeviceMultipleResponse extends IDeviceId { - response: string[]; - } - - interface IApplicationInfo { - CFBundleIdentifier: string; - IceniumLiveSyncEnabled: boolean; - configuration: string; - } - - interface IDeviceAppInfo extends IDeviceId { - response: IApplicationInfo[]; - } - - interface IMessage { - message: string; - } - - interface IDeviceLogData extends IDeviceId, IMessage { - } - - interface IDeviceApplication { - CFBundleExecutable: string; - Path: string; - } - - interface IDeviceLookupInfo extends IDeviceId { - response: { [key: string]: IDeviceApplication }; - } - - interface IDeviceError extends Error { - deviceId: string; - } - - interface IConnectToPortData extends IDeviceId { - port: number; - } - - interface ISocketData extends IDeviceId { - socket: number; - } - - interface ISendMessageToSocketData extends ISocketData, IMessage { - } - - interface IReceiveMessagesFromSocketData extends ISocketData { - callback: SocketMessageHandler; - context: any; - } - - interface ISocketMessage extends ISocketData, IMessage { - } - - interface IConnectToPortResponse extends IDeviceId { - host: string; - port: number; - } - - interface IOSDeviceLib extends NodeJS.EventEmitter { - new (onDeviceFound: (found: IDeviceActionInfo) => void, onDeviceLost: (found: IDeviceActionInfo) => void): IOSDeviceLib; - install(ipaPath: string, deviceIdentifiers: string[]): Promise[]; - uninstall(ipaPath: string, deviceIdentifiers: string[]): Promise[]; - list(listArray: IReadOperationData[]): Promise[]; - upload(uploadArray: IUploadFilesData[]): Promise[]; - download(downloadArray: IFileOperationData[]): Promise[]; - read(readArray: IReadOperationData[]): Promise[]; - delete(deleteArray: IDeleteFileData[]): Promise[]; - postNotification(postNotificationArray: IPostNotificationData[]): Promise[]; - awaitNotificationResponse(awaitNotificationResponseArray: IAwaitNotificatioNResponseData[]): Promise[]; - apps(deviceIdentifiers: string[]): Promise[]; - start(startArray: IDdiApplicationData[]): Promise[]; - stop(stopArray: IDdiApplicationData[]): Promise[]; - startDeviceLog(deviceIdentifiers: string[]): void; - connectToPort(connectToPortArray: IConnectToPortData[]): Promise[]; - dispose(signal?: string): void; - on(event: "deviceLogData", listener: (response: IDeviceLogData) => void): this; - } - - type SocketMessageHandler = (message: ISocketMessage) => void; } \ No newline at end of file diff --git a/typings/ios-device-lib.d.ts b/typings/ios-device-lib.d.ts index 0c614f9..962d5c6 100644 --- a/typings/ios-device-lib.d.ts +++ b/typings/ios-device-lib.d.ts @@ -2,4 +2,5 @@ declare module "ios-device-lib" { export const IOSDeviceLib: IOSDeviceLib.IOSDeviceLib; + export const MessageUnpackStream: IOSDeviceLib.MessageUnpackStream; }