Skip to content
This repository was archived by the owner on Feb 2, 2021. It is now read-only.

Commit 0812ce9

Browse files
Merge pull request #1022 from telerik/vladimirov/fix-sidekick-justlaunch
Fix leaking handlers for iOS device logs
2 parents eac6e6b + c6853d3 commit 0812ce9

File tree

7 files changed

+52
-17
lines changed

7 files changed

+52
-17
lines changed

appbuilder/device-emitter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { EventEmitter } from "events";
2-
import { DeviceDiscoveryEventNames } from "../constants";
2+
import { DeviceDiscoveryEventNames, DEVICE_LOG_EVENT_NAME } from "../constants";
33

44
export class DeviceEmitter extends EventEmitter {
55
constructor(private $deviceLogProvider: EventEmitter,
@@ -34,7 +34,7 @@ export class DeviceEmitter extends EventEmitter {
3434
});
3535

3636
this.$deviceLogProvider.on("data", (identifier: string, data: any) => {
37-
this.emit('deviceLogData', identifier, data.toString());
37+
this.emit(DEVICE_LOG_EVENT_NAME, identifier, data.toString());
3838
});
3939
}
4040

constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export class DeviceDiscoveryEventNames {
3939
static DEVICE_LOST = "deviceLost";
4040
}
4141

42+
export const DEVICE_LOG_EVENT_NAME = "deviceLogData";
43+
4244
export const TARGET_FRAMEWORK_IDENTIFIERS = {
4345
Cordova: "Cordova",
4446
NativeScript: "NativeScript"

definitions/mobile.d.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ declare module Mobile {
9696
isEmulator: boolean;
9797
openDeviceLogStream(): Promise<void>;
9898
getApplicationInfo(applicationIdentifier: string): Promise<Mobile.IApplicationInfo>;
99+
100+
/**
101+
* Called when device is lost. Its purpose is to clean any resources used by the instance.
102+
* @returns {void}
103+
*/
104+
detach?(): void;
99105
}
100106

101107
interface IiOSDevice extends IDevice {
@@ -767,14 +773,14 @@ declare module Mobile {
767773
}
768774
}
769775

770-
interface IIOSDeviceOperations extends IDisposable {
776+
interface IIOSDeviceOperations extends IDisposable, NodeJS.EventEmitter {
771777
install(ipaPath: string, deviceIdentifiers: string[], errorHandler?: DeviceOperationErrorHandler): Promise<IOSDeviceResponse>;
772778

773779
uninstall(appIdentifier: string, deviceIdentifiers: string[], errorHandler?: DeviceOperationErrorHandler): Promise<IOSDeviceResponse>;
774780

775781
startLookingForDevices(deviceFoundCallback: DeviceInfoCallback, deviceLostCallback: DeviceInfoCallback, options?: Mobile.IDeviceLookingOptions): Promise<void>;
776782

777-
startDeviceLog(deviceIdentifier: string, printLogFunction: (response: IOSDeviceLib.IDeviceLogData) => void): void;
783+
startDeviceLog(deviceIdentifier: string): void;
778784

779785
apps(deviceIdentifiers: string[], errorHandler?: DeviceOperationErrorHandler): Promise<IOSDeviceAppInfo>;
780786

mobile/ios/device/ios-device-operations.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import { IOSDeviceLib as IOSDeviceLibModule } from "ios-device-lib";
22
import { cache } from "../../../decorators";
3+
import { DEVICE_LOG_EVENT_NAME } from "../../../constants";
34
import assert = require("assert");
5+
import { EventEmitter } from "events";
46

5-
export class IOSDeviceOperations implements IIOSDeviceOperations, IDisposable {
7+
export class IOSDeviceOperations extends EventEmitter implements IIOSDeviceOperations, IDisposable {
68
public isInitialized: boolean;
79
public shouldDispose: boolean;
810
private deviceLib: IOSDeviceLib.IOSDeviceLib;
911

1012
constructor(private $logger: ILogger,
1113
private $processService: IProcessService) {
14+
super();
15+
1216
this.isInitialized = false;
1317
this.shouldDispose = true;
1418
this.$processService.attachToProcessExitSignals(this, () => {
@@ -67,15 +71,13 @@ export class IOSDeviceOperations implements IIOSDeviceOperations, IDisposable {
6771
}
6872
}
6973

70-
public startDeviceLog(deviceIdentifier: string, printLogFunction: (response: IOSDeviceLib.IDeviceLogData) => void): void {
74+
public startDeviceLog(deviceIdentifier: string): void {
7175
this.assertIsInitialized();
7276
this.setShouldDispose(false);
7377

7478
this.$logger.trace(`Printing device log for device with identifier: ${deviceIdentifier}.`);
7579

76-
this.deviceLib.on("deviceLogData", (response: IOSDeviceLib.IDeviceLogData) => {
77-
printLogFunction(response);
78-
});
80+
this.attacheDeviceLogDataHandler();
7981

8082
this.deviceLib.startDeviceLog([deviceIdentifier]);
8183
}
@@ -230,6 +232,13 @@ export class IOSDeviceOperations implements IIOSDeviceOperations, IDisposable {
230232
private assertIsInitialized(): void {
231233
assert.ok(this.isInitialized, "iOS device operations not initialized.");
232234
}
235+
236+
@cache()
237+
private attacheDeviceLogDataHandler(): void {
238+
this.deviceLib.on(DEVICE_LOG_EVENT_NAME, (response: IOSDeviceLib.IDeviceLogData) => {
239+
this.emit(DEVICE_LOG_EVENT_NAME, response);
240+
});
241+
}
233242
}
234243

235244
$injector.register("iosDeviceOperations", IOSDeviceOperations);

mobile/ios/device/ios-device.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ import * as applicationManagerPath from "./ios-application-manager";
22
import * as fileSystemPath from "./ios-device-file-system";
33
import * as constants from "../../../constants";
44
import * as net from "net";
5+
import { cache } from "../../../decorators";
56

67
export class IOSDevice implements Mobile.IiOSDevice {
78
public applicationManager: Mobile.IDeviceApplicationManager;
89
public fileSystem: Mobile.IDeviceFileSystem;
910
public deviceInfo: Mobile.IDeviceInfo;
1011

1112
private _socket: net.Socket;
13+
private _deviceLogHandler: Function;
1214

1315
constructor(private deviceActionInfo: IOSDeviceLib.IDeviceActionInfo,
1416
private $injector: IInjector,
@@ -48,13 +50,24 @@ export class IOSDevice implements Mobile.IiOSDevice {
4850
return this.applicationManager.getApplicationInfo(applicationIdentifier);
4951
}
5052

53+
private actionOnDeviceLog(response: IOSDeviceLib.IDeviceLogData): void {
54+
if (response.deviceId === this.deviceInfo.identifier) {
55+
this.$deviceLogProvider.logData(response.message, this.$devicePlatformsConstants.iOS, this.deviceInfo.identifier);
56+
}
57+
}
58+
59+
@cache()
5160
public async openDeviceLogStream(): Promise<void> {
5261
if (this.deviceInfo.status !== constants.UNREACHABLE_STATUS) {
53-
this.$iosDeviceOperations.startDeviceLog(this.deviceInfo.identifier, (response: IOSDeviceLib.IDeviceLogData) => {
54-
if (response.deviceId === this.deviceInfo.identifier) {
55-
this.$deviceLogProvider.logData(response.message, this.$devicePlatformsConstants.iOS, this.deviceInfo.identifier);
56-
}
57-
});
62+
this.$iosDeviceOperations.startDeviceLog(this.deviceInfo.identifier);
63+
this._deviceLogHandler = this.actionOnDeviceLog.bind(this);
64+
this.$iosDeviceOperations.on(constants.DEVICE_LOG_EVENT_NAME, this._deviceLogHandler);
65+
}
66+
}
67+
68+
public detach(): void {
69+
if (this._deviceLogHandler) {
70+
this.$iosDeviceOperations.removeListener(constants.DEVICE_LOG_EVENT_NAME, this._deviceLogHandler);
5871
}
5972
}
6073

mobile/mobile-core/devices-service.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ export class DevicesService extends EventEmitter implements Mobile.IDevicesServi
139139

140140
private onDeviceLost(device: Mobile.IDevice): void {
141141
this.$logger.trace(`Lost device with identifier '${device.deviceInfo.identifier}'`);
142+
143+
if (device.detach) {
144+
device.detach();
145+
}
146+
142147
delete this._devices[device.deviceInfo.identifier];
143148
this.emit(constants.DeviceDiscoveryEventNames.DEVICE_LOST, device);
144149
}

test/unit-tests/appbuilder/device-emitter.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { assert } from "chai";
33
import { EventEmitter } from "events";
44
import { ProjectConstants } from "../../../appbuilder/project-constants";
55
import { DeviceEmitter } from "../../../appbuilder/device-emitter";
6-
import { DeviceDiscoveryEventNames } from "../../../constants";
6+
import { DeviceDiscoveryEventNames, DEVICE_LOG_EVENT_NAME } from "../../../constants";
77
// Injector dependencies must be classes.
88
// EventEmitter is function, so our annotate method will fail.
99
class CustomEventEmitter extends EventEmitter {
@@ -109,11 +109,11 @@ describe("deviceEmitter", () => {
109109
deviceLogProvider = testInjector.resolve("deviceLogProvider");
110110
});
111111

112-
describe("raises deviceLogData with correct identifier and data", () => {
112+
describe(`raises ${DEVICE_LOG_EVENT_NAME} with correct identifier and data`, () => {
113113
const expectedDeviceLogData = "This is some log data from device.";
114114

115115
const attachDeviceLogDataVerificationHandler = (expectedDeviceIdentifier: string, done: mocha.Done) => {
116-
deviceEmitter.on("deviceLogData", (identifier: string, data: any) => {
116+
deviceEmitter.on(DEVICE_LOG_EVENT_NAME, (identifier: string, data: any) => {
117117
assert.deepEqual(identifier, expectedDeviceIdentifier);
118118
assert.deepEqual(data, expectedDeviceLogData);
119119
// Wait for all operations to be completed and call done after that.

0 commit comments

Comments
 (0)