appium-remote-debugger 15.2.13 → 15.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/build/lib/protocol/index.d.ts +13 -8
- package/build/lib/protocol/index.d.ts.map +1 -1
- package/build/lib/protocol/index.js +17 -12
- package/build/lib/protocol/index.js.map +1 -1
- package/build/lib/rpc/index.d.ts +2 -3
- package/build/lib/rpc/index.d.ts.map +1 -1
- package/build/lib/rpc/index.js +2 -2
- package/build/lib/rpc/index.js.map +1 -1
- package/build/lib/rpc/remote-messages.d.ts +62 -41
- package/build/lib/rpc/remote-messages.d.ts.map +1 -1
- package/build/lib/rpc/remote-messages.js +56 -41
- package/build/lib/rpc/remote-messages.js.map +1 -1
- package/build/lib/rpc/rpc-client-real-device.d.ts +26 -8
- package/build/lib/rpc/rpc-client-real-device.d.ts.map +1 -1
- package/build/lib/rpc/rpc-client-real-device.js +21 -16
- package/build/lib/rpc/rpc-client-real-device.js.map +1 -1
- package/build/lib/rpc/rpc-client-simulator.d.ts +36 -28
- package/build/lib/rpc/rpc-client-simulator.d.ts.map +1 -1
- package/build/lib/rpc/rpc-client-simulator.js +39 -36
- package/build/lib/rpc/rpc-client-simulator.js.map +1 -1
- package/build/lib/rpc/rpc-client.d.ts +278 -189
- package/build/lib/rpc/rpc-client.d.ts.map +1 -1
- package/build/lib/rpc/rpc-client.js +222 -178
- package/build/lib/rpc/rpc-client.js.map +1 -1
- package/build/lib/rpc/rpc-message-handler.d.ts +32 -39
- package/build/lib/rpc/rpc-message-handler.d.ts.map +1 -1
- package/build/lib/rpc/rpc-message-handler.js +39 -53
- package/build/lib/rpc/rpc-message-handler.js.map +1 -1
- package/build/lib/types.d.ts +28 -0
- package/build/lib/types.d.ts.map +1 -1
- package/build/test/functional/safari-e2e-specs.js +5 -1
- package/build/test/functional/safari-e2e-specs.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/lib/protocol/{index.js → index.ts} +29 -17
- package/lib/rpc/index.ts +2 -0
- package/lib/rpc/{remote-messages.js → remote-messages.ts} +73 -59
- package/lib/rpc/rpc-client-real-device.ts +68 -0
- package/lib/rpc/{rpc-client-simulator.js → rpc-client-simulator.ts} +54 -57
- package/lib/rpc/{rpc-client.js → rpc-client.ts} +368 -284
- package/lib/rpc/{rpc-message-handler.js → rpc-message-handler.ts} +73 -64
- package/lib/types.ts +31 -0
- package/package.json +1 -1
- package/lib/rpc/index.js +0 -4
- package/lib/rpc/rpc-client-real-device.js +0 -64
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import type { StringRecord } from '@appium/types';
|
|
2
|
+
import type { RemoteCommandOpts, ProtocolCommandOpts } from '../types';
|
|
3
|
+
|
|
1
4
|
const OBJECT_GROUP = 'console';
|
|
2
5
|
|
|
3
6
|
// See https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/inspector/protocol
|
|
4
|
-
const COMMANDS =
|
|
7
|
+
const COMMANDS = {
|
|
5
8
|
// https://github.com/WebKit/WebKit/blob/main/Source/JavaScriptCore/inspector/protocol/Animation.json
|
|
6
9
|
//#region ANIMATION DOMAIN
|
|
7
10
|
'Animation.enable': [], // Enables Canvas domain events
|
|
@@ -196,28 +199,39 @@ const COMMANDS = /** @type {const} */ ({
|
|
|
196
199
|
'Worker.initialized': ['workerId'],
|
|
197
200
|
'Worker.sendMessageToWorker': ['workerId', 'message']
|
|
198
201
|
//#endregion
|
|
199
|
-
}
|
|
202
|
+
} as const;
|
|
200
203
|
|
|
201
204
|
/**
|
|
205
|
+
* Generates a protocol command object based on the command name and options.
|
|
206
|
+
* Extracts only the parameters that are defined for the specific command in the
|
|
207
|
+
* WebKit Inspector protocol specification.
|
|
202
208
|
*
|
|
203
|
-
* @param
|
|
204
|
-
* @param
|
|
205
|
-
* @param
|
|
206
|
-
* @param
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
+
* @param id - The command identifier.
|
|
210
|
+
* @param method - The protocol method name (e.g., 'Page.navigate', 'Runtime.evaluate').
|
|
211
|
+
* @param opts - Options containing parameters for the command.
|
|
212
|
+
* @param direct - If false (default), the resulting command params will be patched
|
|
213
|
+
* with default values (objectGroup, includeCommandLineAPI, etc.).
|
|
214
|
+
* If true, only the specified parameters are included.
|
|
215
|
+
* @returns A ProtocolCommandOpts object with id, method, and params.
|
|
216
|
+
* @throws Error if the command method is unknown.
|
|
209
217
|
*/
|
|
210
|
-
export function getProtocolCommand
|
|
211
|
-
|
|
218
|
+
export function getProtocolCommand(
|
|
219
|
+
id: string,
|
|
220
|
+
method: string,
|
|
221
|
+
opts: RemoteCommandOpts,
|
|
222
|
+
direct: boolean = false
|
|
223
|
+
): ProtocolCommandOpts {
|
|
224
|
+
const paramNames = COMMANDS[method as keyof typeof COMMANDS];
|
|
212
225
|
if (!paramNames) {
|
|
213
226
|
throw new Error(`Unknown command: '${method}'`);
|
|
214
227
|
}
|
|
215
228
|
|
|
216
|
-
const params = paramNames
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
229
|
+
const params: StringRecord = (paramNames as readonly string[])
|
|
230
|
+
.reduce(function (acc: StringRecord, name: string) {
|
|
231
|
+
acc[name] = opts[name];
|
|
232
|
+
return acc;
|
|
233
|
+
}, {} as StringRecord);
|
|
234
|
+
const result: ProtocolCommandOpts = {
|
|
221
235
|
id,
|
|
222
236
|
method,
|
|
223
237
|
params,
|
|
@@ -235,5 +249,3 @@ export function getProtocolCommand (id, method, opts, direct = false) {
|
|
|
235
249
|
}
|
|
236
250
|
return result;
|
|
237
251
|
}
|
|
238
|
-
|
|
239
|
-
export default getProtocolCommand;
|
package/lib/rpc/index.ts
ADDED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import { getProtocolCommand } from '../protocol';
|
|
3
|
-
|
|
3
|
+
import type { RawRemoteCommand, RemoteCommandOpts, ProtocolCommandOpts, AppIdKey, PageIdKey, RemoteCommandId } from '../types';
|
|
4
4
|
|
|
5
5
|
const OBJECT_GROUP = 'console';
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ const DIRECT_COMMAND = 'getDirectCommand';
|
|
|
10
10
|
|
|
11
11
|
// mapping of commands to the function for getting the command
|
|
12
12
|
// defaults to `getMinimalCommand`, so no need to have those listed here
|
|
13
|
-
const COMMANDS =
|
|
13
|
+
const COMMANDS = {
|
|
14
14
|
'Page.getCookies': FULL_COMMAND,
|
|
15
15
|
'Page.navigate': FULL_COMMAND,
|
|
16
16
|
|
|
@@ -24,17 +24,23 @@ const COMMANDS = /** @type {const} */ ({
|
|
|
24
24
|
|
|
25
25
|
'Timeline.start': FULL_COMMAND,
|
|
26
26
|
'Timeline.stop': FULL_COMMAND,
|
|
27
|
-
}
|
|
27
|
+
} as const;
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
// #region Connection functions
|
|
29
|
+
type CommandBuilderFunction = typeof MINIMAL_COMMAND | typeof FULL_COMMAND | typeof DIRECT_COMMAND;
|
|
31
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Generates remote commands for communicating with the Web Inspector.
|
|
33
|
+
* Provides methods for creating various types of commands including connection
|
|
34
|
+
* setup, application management, and protocol commands.
|
|
35
|
+
*/
|
|
36
|
+
export class RemoteMessages {
|
|
32
37
|
/**
|
|
38
|
+
* Creates a command to set the connection key for the Web Inspector session.
|
|
33
39
|
*
|
|
34
|
-
* @param
|
|
35
|
-
* @returns
|
|
40
|
+
* @param connId - The connection identifier.
|
|
41
|
+
* @returns A RawRemoteCommand for setting the connection key.
|
|
36
42
|
*/
|
|
37
|
-
setConnectionKey
|
|
43
|
+
setConnectionKey(connId: string): RawRemoteCommand {
|
|
38
44
|
return {
|
|
39
45
|
__argument: {
|
|
40
46
|
WIRConnectionIdentifierKey: connId
|
|
@@ -44,12 +50,13 @@ export class RemoteMessages {
|
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
/**
|
|
53
|
+
* Creates a command to connect to a specific application.
|
|
47
54
|
*
|
|
48
|
-
* @param
|
|
49
|
-
* @param
|
|
50
|
-
* @returns
|
|
55
|
+
* @param connId - The connection identifier.
|
|
56
|
+
* @param appIdKey - The application identifier key.
|
|
57
|
+
* @returns A RawRemoteCommand for connecting to the application.
|
|
51
58
|
*/
|
|
52
|
-
connectToApp
|
|
59
|
+
connectToApp(connId: string, appIdKey: AppIdKey): RawRemoteCommand {
|
|
53
60
|
return {
|
|
54
61
|
__argument: {
|
|
55
62
|
WIRConnectionIdentifierKey: connId,
|
|
@@ -60,14 +67,15 @@ export class RemoteMessages {
|
|
|
60
67
|
}
|
|
61
68
|
|
|
62
69
|
/**
|
|
70
|
+
* Creates a command to set the sender key for message routing.
|
|
63
71
|
*
|
|
64
|
-
* @param
|
|
65
|
-
* @param
|
|
66
|
-
* @param
|
|
67
|
-
* @param
|
|
68
|
-
* @returns
|
|
72
|
+
* @param connId - The connection identifier.
|
|
73
|
+
* @param senderId - The sender identifier.
|
|
74
|
+
* @param appIdKey - The application identifier key.
|
|
75
|
+
* @param pageIdKey - Optional page identifier key.
|
|
76
|
+
* @returns A RawRemoteCommand for setting the sender key.
|
|
69
77
|
*/
|
|
70
|
-
setSenderKey
|
|
78
|
+
setSenderKey(connId: string, senderId: string, appIdKey: AppIdKey, pageIdKey?: PageIdKey): RawRemoteCommand {
|
|
71
79
|
return {
|
|
72
80
|
__argument: {
|
|
73
81
|
WIRApplicationIdentifierKey: appIdKey,
|
|
@@ -81,14 +89,15 @@ export class RemoteMessages {
|
|
|
81
89
|
}
|
|
82
90
|
|
|
83
91
|
/**
|
|
92
|
+
* Creates a command to indicate web view status.
|
|
84
93
|
*
|
|
85
|
-
* @param
|
|
86
|
-
* @param
|
|
87
|
-
* @param
|
|
88
|
-
* @param
|
|
89
|
-
* @returns
|
|
94
|
+
* @param connId - The connection identifier.
|
|
95
|
+
* @param appIdKey - The application identifier key.
|
|
96
|
+
* @param pageIdKey - Optional page identifier key.
|
|
97
|
+
* @param enabled - Whether the web view indication is enabled. Defaults to true if not provided.
|
|
98
|
+
* @returns A RawRemoteCommand for indicating web view status.
|
|
90
99
|
*/
|
|
91
|
-
indicateWebView
|
|
100
|
+
indicateWebView(connId: string, appIdKey: AppIdKey, pageIdKey?: PageIdKey, enabled?: boolean): RawRemoteCommand {
|
|
92
101
|
return {
|
|
93
102
|
__argument: {
|
|
94
103
|
WIRApplicationIdentifierKey: appIdKey,
|
|
@@ -101,11 +110,12 @@ export class RemoteMessages {
|
|
|
101
110
|
}
|
|
102
111
|
|
|
103
112
|
/**
|
|
113
|
+
* Creates a command to launch an application.
|
|
104
114
|
*
|
|
105
|
-
* @param
|
|
106
|
-
* @returns
|
|
115
|
+
* @param bundleId - The bundle identifier of the application to launch.
|
|
116
|
+
* @returns A RawRemoteCommand for launching the application.
|
|
107
117
|
*/
|
|
108
|
-
launchApplication
|
|
118
|
+
launchApplication(bundleId: string): RawRemoteCommand {
|
|
109
119
|
return {
|
|
110
120
|
__argument: {
|
|
111
121
|
WIRApplicationBundleIdentifierKey: bundleId
|
|
@@ -115,11 +125,13 @@ export class RemoteMessages {
|
|
|
115
125
|
}
|
|
116
126
|
|
|
117
127
|
/**
|
|
128
|
+
* Creates a full command with all default parameters included.
|
|
129
|
+
* This includes objectGroup, includeCommandLineAPI, and other runtime options.
|
|
118
130
|
*
|
|
119
|
-
* @param
|
|
120
|
-
* @returns
|
|
131
|
+
* @param opts - Options combining RemoteCommandOpts and ProtocolCommandOpts.
|
|
132
|
+
* @returns A RawRemoteCommand with full parameter set.
|
|
121
133
|
*/
|
|
122
|
-
getFullCommand
|
|
134
|
+
getFullCommand(opts: RemoteCommandOpts & ProtocolCommandOpts): RawRemoteCommand {
|
|
123
135
|
const {
|
|
124
136
|
method,
|
|
125
137
|
params,
|
|
@@ -143,7 +155,7 @@ export class RemoteMessages {
|
|
|
143
155
|
const realParams = {
|
|
144
156
|
targetId,
|
|
145
157
|
message: JSON.stringify({
|
|
146
|
-
id,
|
|
158
|
+
id: parseInt(id, 10),
|
|
147
159
|
method,
|
|
148
160
|
params: Object.assign({
|
|
149
161
|
objectGroup: OBJECT_GROUP,
|
|
@@ -169,23 +181,24 @@ export class RemoteMessages {
|
|
|
169
181
|
},
|
|
170
182
|
__selector: '_rpc_forwardSocketData:',
|
|
171
183
|
};
|
|
172
|
-
|
|
173
|
-
return _.omitBy(plist, _.isNil);
|
|
184
|
+
return _.omitBy(plist, _.isNil) as RawRemoteCommand;
|
|
174
185
|
}
|
|
175
186
|
|
|
176
187
|
/**
|
|
188
|
+
* Creates a minimal command with only the essential parameters.
|
|
189
|
+
* This is the default command type for most operations.
|
|
177
190
|
*
|
|
178
|
-
* @param
|
|
179
|
-
* @returns
|
|
191
|
+
* @param opts - Options combining RemoteCommandOpts and ProtocolCommandOpts.
|
|
192
|
+
* @returns A RawRemoteCommand with minimal parameter set.
|
|
180
193
|
*/
|
|
181
|
-
getMinimalCommand
|
|
194
|
+
getMinimalCommand(opts: RemoteCommandOpts & ProtocolCommandOpts): RawRemoteCommand {
|
|
182
195
|
const {method, params, connId, senderId, appIdKey, pageIdKey, targetId, id} = opts;
|
|
183
196
|
|
|
184
197
|
const realMethod = 'Target.sendMessageToTarget';
|
|
185
198
|
const realParams = {
|
|
186
199
|
targetId,
|
|
187
200
|
message: JSON.stringify({
|
|
188
|
-
id,
|
|
201
|
+
id: parseInt(id, 10),
|
|
189
202
|
method,
|
|
190
203
|
params,
|
|
191
204
|
}),
|
|
@@ -204,22 +217,23 @@ export class RemoteMessages {
|
|
|
204
217
|
},
|
|
205
218
|
__selector: '_rpc_forwardSocketData:'
|
|
206
219
|
};
|
|
207
|
-
|
|
208
|
-
return _.omitBy(plist, _.isNil);
|
|
220
|
+
return _.omitBy(plist, _.isNil) as RawRemoteCommand;
|
|
209
221
|
}
|
|
210
222
|
|
|
211
223
|
/**
|
|
224
|
+
* Creates a direct command that bypasses the Target.sendMessageToTarget wrapper.
|
|
225
|
+
* Used for certain Target domain commands.
|
|
212
226
|
*
|
|
213
|
-
* @param
|
|
214
|
-
* @returns
|
|
227
|
+
* @param opts - Options combining RemoteCommandOpts and ProtocolCommandOpts.
|
|
228
|
+
* @returns A RawRemoteCommand for direct protocol communication.
|
|
215
229
|
*/
|
|
216
|
-
getDirectCommand
|
|
230
|
+
getDirectCommand(opts: RemoteCommandOpts & ProtocolCommandOpts): RawRemoteCommand {
|
|
217
231
|
const {method, params, connId, senderId, appIdKey, pageIdKey, id} = opts;
|
|
218
232
|
|
|
219
233
|
const plist = {
|
|
220
234
|
__argument: {
|
|
221
235
|
WIRSocketDataKey: {
|
|
222
|
-
id,
|
|
236
|
+
id: parseInt(id, 10),
|
|
223
237
|
method,
|
|
224
238
|
params,
|
|
225
239
|
},
|
|
@@ -230,17 +244,19 @@ export class RemoteMessages {
|
|
|
230
244
|
},
|
|
231
245
|
__selector: '_rpc_forwardSocketData:'
|
|
232
246
|
};
|
|
233
|
-
|
|
234
|
-
return _.omitBy(plist, _.isNil);
|
|
247
|
+
return _.omitBy(plist, _.isNil) as RawRemoteCommand;
|
|
235
248
|
}
|
|
236
249
|
|
|
237
250
|
/**
|
|
251
|
+
* Gets a remote command based on the command name and options.
|
|
252
|
+
* Handles both Safari Web Inspector commands and WebKit protocol commands.
|
|
238
253
|
*
|
|
239
|
-
* @param
|
|
240
|
-
* @param
|
|
241
|
-
* @returns
|
|
254
|
+
* @param command - The command name (e.g., 'setConnectionKey', 'Page.navigate').
|
|
255
|
+
* @param opts - Options for the command.
|
|
256
|
+
* @returns A RawRemoteCommand appropriate for the given command.
|
|
257
|
+
* @throws Error if required parameters are missing for specific commands.
|
|
242
258
|
*/
|
|
243
|
-
getRemoteCommand
|
|
259
|
+
getRemoteCommand(command: string, opts: RemoteCommandOpts & RemoteCommandId): RawRemoteCommand {
|
|
244
260
|
const {
|
|
245
261
|
id,
|
|
246
262
|
connId,
|
|
@@ -280,9 +296,9 @@ export class RemoteMessages {
|
|
|
280
296
|
}
|
|
281
297
|
|
|
282
298
|
// deal with WebKit commands
|
|
283
|
-
const builderFunction = COMMANDS[command] || MINIMAL_COMMAND;
|
|
299
|
+
const builderFunction = (COMMANDS[command as keyof typeof COMMANDS] || MINIMAL_COMMAND) as CommandBuilderFunction;
|
|
284
300
|
const commonOpts = getProtocolCommand(
|
|
285
|
-
|
|
301
|
+
id,
|
|
286
302
|
command,
|
|
287
303
|
opts,
|
|
288
304
|
isDirectCommand(command),
|
|
@@ -296,17 +312,15 @@ export class RemoteMessages {
|
|
|
296
312
|
targetId,
|
|
297
313
|
});
|
|
298
314
|
}
|
|
299
|
-
|
|
300
|
-
// #endregion
|
|
301
315
|
}
|
|
302
316
|
|
|
303
317
|
/**
|
|
318
|
+
* Checks if a command should use the direct command format.
|
|
319
|
+
* Direct commands bypass the Target.sendMessageToTarget wrapper.
|
|
304
320
|
*
|
|
305
|
-
* @param
|
|
306
|
-
* @returns
|
|
321
|
+
* @param command - The command name to check.
|
|
322
|
+
* @returns True if the command should use direct format, false otherwise.
|
|
307
323
|
*/
|
|
308
|
-
export function isDirectCommand
|
|
309
|
-
return COMMANDS[command] === DIRECT_COMMAND;
|
|
324
|
+
export function isDirectCommand(command: string): boolean {
|
|
325
|
+
return COMMANDS[command as keyof typeof COMMANDS] === DIRECT_COMMAND;
|
|
310
326
|
}
|
|
311
|
-
|
|
312
|
-
export default RemoteMessages;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { log } from '../logger';
|
|
2
|
+
import { RpcClient } from './rpc-client';
|
|
3
|
+
import { services } from 'appium-ios-device';
|
|
4
|
+
import type { RemoteCommand } from '../types';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* RPC client implementation for real iOS devices.
|
|
8
|
+
* Extends RpcClient to provide device-specific connection handling.
|
|
9
|
+
*/
|
|
10
|
+
export class RpcClientRealDevice extends RpcClient {
|
|
11
|
+
protected service?: any;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Connects to the Web Inspector service on a real iOS device.
|
|
15
|
+
* Starts the Web Inspector service and sets up message listening.
|
|
16
|
+
*/
|
|
17
|
+
override async connect(): Promise<void> {
|
|
18
|
+
this.service = await services.startWebInspectorService(this.udid, {
|
|
19
|
+
osVersion: this.platformVersion,
|
|
20
|
+
isSimulator: false,
|
|
21
|
+
verbose: this.logAllCommunication,
|
|
22
|
+
verboseHexDump: this.logAllCommunicationHexDump,
|
|
23
|
+
socketChunkSize: this.socketChunkSize,
|
|
24
|
+
maxFrameLength: this.webInspectorMaxFrameLength,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
this.service.listenMessage(this.receive.bind(this));
|
|
28
|
+
this.isConnected = true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Disconnects from the Web Inspector service on the real device.
|
|
33
|
+
* Closes the service connection and cleans up resources.
|
|
34
|
+
*/
|
|
35
|
+
override async disconnect(): Promise<void> {
|
|
36
|
+
if (!this.isConnected) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
log.debug('Disconnecting from remote debugger');
|
|
41
|
+
await super.disconnect();
|
|
42
|
+
this.service?.close();
|
|
43
|
+
this.isConnected = false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Sends a command message to the Web Inspector service.
|
|
48
|
+
*
|
|
49
|
+
* @param cmd - The command to send to the device.
|
|
50
|
+
*/
|
|
51
|
+
override async sendMessage(cmd: RemoteCommand): Promise<void> {
|
|
52
|
+
if (!this.service) {
|
|
53
|
+
throw new Error('RPC service is not initialized. Is the client connected?');
|
|
54
|
+
}
|
|
55
|
+
this.service.sendMessage(cmd);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Receives data from the Web Inspector service and handles it.
|
|
60
|
+
*
|
|
61
|
+
* @param data - The data received from the service.
|
|
62
|
+
*/
|
|
63
|
+
override async receive(data: any): Promise<void> {
|
|
64
|
+
if (this.isConnected) {
|
|
65
|
+
await this.messageHandler.handleMessage(data);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -4,27 +4,26 @@ import B from 'bluebird';
|
|
|
4
4
|
import net from 'net';
|
|
5
5
|
import { RpcClient } from './rpc-client';
|
|
6
6
|
import { services } from 'appium-ios-device';
|
|
7
|
+
import type { RpcClientOptions, RpcClientSimulatorOptions, RemoteCommand } from '../types';
|
|
7
8
|
|
|
9
|
+
/**
|
|
10
|
+
* RPC client implementation for iOS simulators.
|
|
11
|
+
* Extends RpcClient to provide simulator-specific connection handling
|
|
12
|
+
* via TCP sockets or Unix domain sockets.
|
|
13
|
+
*/
|
|
8
14
|
export class RpcClientSimulator extends RpcClient {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
/** @type {any} */
|
|
16
|
-
messageProxy;
|
|
17
|
-
|
|
18
|
-
/** @type {import('node:net').Socket|null} */
|
|
19
|
-
socket;
|
|
20
|
-
|
|
21
|
-
/** @type {string|undefined} */
|
|
22
|
-
socketPath;
|
|
15
|
+
protected readonly host?: string;
|
|
16
|
+
protected port?: number;
|
|
17
|
+
protected readonly messageProxy?: any;
|
|
18
|
+
protected socket: net.Socket | null;
|
|
19
|
+
protected readonly socketPath?: string;
|
|
20
|
+
protected service?: any;
|
|
23
21
|
|
|
24
22
|
/**
|
|
25
|
-
* @param
|
|
23
|
+
* @param opts - Options for configuring the RPC client, including
|
|
24
|
+
* simulator-specific options like socketPath, host, and port.
|
|
26
25
|
*/
|
|
27
|
-
constructor
|
|
26
|
+
constructor(opts: RpcClientOptions & RpcClientSimulatorOptions = {}) {
|
|
28
27
|
super(opts);
|
|
29
28
|
|
|
30
29
|
const {
|
|
@@ -44,9 +43,10 @@ export class RpcClientSimulator extends RpcClient {
|
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
/**
|
|
47
|
-
*
|
|
46
|
+
* Connects to the Web Inspector service on an iOS simulator.
|
|
47
|
+
* Supports both Unix domain sockets and TCP connections, with optional proxy support.
|
|
48
48
|
*/
|
|
49
|
-
async connect
|
|
49
|
+
override async connect(): Promise<void> {
|
|
50
50
|
// create socket and handle its messages
|
|
51
51
|
if (this.socketPath) {
|
|
52
52
|
if (this.messageProxy) {
|
|
@@ -57,10 +57,11 @@ export class RpcClientSimulator extends RpcClient {
|
|
|
57
57
|
// Forward the actual socketPath to the proxy
|
|
58
58
|
this.socket.once('connect', () => {
|
|
59
59
|
log.debug(`Forwarding the actual web inspector socket to the proxy: '${this.socketPath}'`);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
if (this.socket) {
|
|
61
|
+
this.socket.write(JSON.stringify({
|
|
62
|
+
socketPath: this.socketPath
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
64
65
|
});
|
|
65
66
|
|
|
66
67
|
} else {
|
|
@@ -77,7 +78,11 @@ export class RpcClientSimulator extends RpcClient {
|
|
|
77
78
|
// tcp socket
|
|
78
79
|
log.debug(`Connecting to remote debugger ${this.messageProxy ? 'via proxy ' : ''}through TCP: ${this.host}:${this.port}`);
|
|
79
80
|
this.socket = new net.Socket();
|
|
80
|
-
|
|
81
|
+
if (this.port && this.host) {
|
|
82
|
+
this.socket.connect(this.port, this.host);
|
|
83
|
+
} else {
|
|
84
|
+
throw new Error('Both port and host must be defined for TCP connection');
|
|
85
|
+
}
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
this.socket.setNoDelay(true);
|
|
@@ -103,16 +108,17 @@ export class RpcClientSimulator extends RpcClient {
|
|
|
103
108
|
this.service.listenMessage(this.receive.bind(this));
|
|
104
109
|
|
|
105
110
|
// connect the socket
|
|
106
|
-
return await new B((resolve, reject) => {
|
|
111
|
+
return await new B<void>((resolve, reject) => {
|
|
107
112
|
// only resolve this function when we are actually connected
|
|
108
|
-
|
|
113
|
+
if (!this.socket) {
|
|
114
|
+
return reject(new Error('RPC socket is not connected. Please contact developers'));
|
|
115
|
+
}
|
|
109
116
|
this.socket.on('connect', () => {
|
|
110
117
|
log.debug(`Debugger socket connected`);
|
|
111
118
|
this.isConnected = true;
|
|
112
119
|
|
|
113
120
|
resolve();
|
|
114
121
|
});
|
|
115
|
-
// @ts-ignore socket must be defined here
|
|
116
122
|
this.socket.on('error', (err) => {
|
|
117
123
|
if (this.isConnected) {
|
|
118
124
|
log.error(`Socket error: ${err.message}`);
|
|
@@ -126,37 +132,41 @@ export class RpcClientSimulator extends RpcClient {
|
|
|
126
132
|
}
|
|
127
133
|
|
|
128
134
|
/**
|
|
129
|
-
*
|
|
135
|
+
* Disconnects from the Web Inspector service on the simulator.
|
|
136
|
+
* Closes the socket and service connection, and cleans up resources.
|
|
130
137
|
*/
|
|
131
|
-
async disconnect
|
|
138
|
+
override async disconnect(): Promise<void> {
|
|
132
139
|
if (!this.isConnected) {
|
|
133
140
|
return;
|
|
134
141
|
}
|
|
135
142
|
|
|
136
143
|
log.debug('Disconnecting from remote debugger');
|
|
137
144
|
await super.disconnect();
|
|
138
|
-
this.service
|
|
145
|
+
this.service?.close();
|
|
139
146
|
this.isConnected = false;
|
|
140
147
|
}
|
|
141
148
|
|
|
142
149
|
/**
|
|
143
|
-
*
|
|
150
|
+
* Sends a command message to the Web Inspector service via the socket.
|
|
151
|
+
* Handles socket errors and ensures the socket is available before sending.
|
|
152
|
+
*
|
|
153
|
+
* @param cmd - The command to send to the simulator.
|
|
144
154
|
*/
|
|
145
|
-
async sendMessage
|
|
146
|
-
let onSocketError;
|
|
155
|
+
override async sendMessage(cmd: RemoteCommand): Promise<void> {
|
|
156
|
+
let onSocketError: ((err: Error) => void) | undefined;
|
|
147
157
|
|
|
148
|
-
return await new B((resolve, reject) => {
|
|
158
|
+
return await new B<void>((resolve, reject) => {
|
|
149
159
|
// handle socket problems
|
|
150
|
-
onSocketError = (err) => {
|
|
160
|
+
onSocketError = (err: Error) => {
|
|
151
161
|
log.error(`Socket error: ${err.message}`);
|
|
152
162
|
|
|
153
163
|
// the connection was refused, so reject the connect promise
|
|
154
164
|
reject(err);
|
|
155
165
|
};
|
|
156
166
|
|
|
157
|
-
if (!this.socket) {
|
|
167
|
+
if (!this.socket || !this.service) {
|
|
158
168
|
return reject(
|
|
159
|
-
new Error('The RPC
|
|
169
|
+
new Error('The RPC client is not connected. Have you called `connect()` before sending a message?')
|
|
160
170
|
);
|
|
161
171
|
}
|
|
162
172
|
this.socket.on('error', onSocketError);
|
|
@@ -165,22 +175,20 @@ export class RpcClientSimulator extends RpcClient {
|
|
|
165
175
|
})
|
|
166
176
|
.finally(() => {
|
|
167
177
|
// remove this listener, so we don't exhaust the system
|
|
168
|
-
|
|
169
|
-
// @ts-ignore socket must be defined
|
|
178
|
+
if (this.socket && onSocketError) {
|
|
170
179
|
this.socket.removeListener('error', onSocketError);
|
|
171
|
-
}
|
|
180
|
+
}
|
|
172
181
|
});
|
|
173
182
|
}
|
|
174
183
|
|
|
175
184
|
/**
|
|
176
|
-
*
|
|
185
|
+
* Receives data from the Web Inspector service and handles it.
|
|
186
|
+
* Converts Buffer data to strings for certain message keys.
|
|
187
|
+
*
|
|
188
|
+
* @param data - The data received from the service.
|
|
177
189
|
*/
|
|
178
|
-
async receive
|
|
179
|
-
if (!this.isConnected) {
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (!data) {
|
|
190
|
+
override async receive(data: any): Promise<void> {
|
|
191
|
+
if (!this.isConnected || !data) {
|
|
184
192
|
return;
|
|
185
193
|
}
|
|
186
194
|
|
|
@@ -189,17 +197,6 @@ export class RpcClientSimulator extends RpcClient {
|
|
|
189
197
|
data[key] = data[key].toString('utf8');
|
|
190
198
|
}
|
|
191
199
|
}
|
|
192
|
-
// @ts-ignore messageHandler must be defined
|
|
193
200
|
await this.messageHandler.handleMessage(data);
|
|
194
201
|
}
|
|
195
202
|
}
|
|
196
|
-
|
|
197
|
-
export default RpcClientSimulator;
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* @typedef {Object} RpcClientSimulatorOptions
|
|
201
|
-
* @property {string} [socketPath]
|
|
202
|
-
* @property {string} [host='::1']
|
|
203
|
-
* @property {number} [port]
|
|
204
|
-
* @property {any} [messageProxy]
|
|
205
|
-
*/
|