appium-remote-debugger
Version:
Appium proxy for Remote Debugger protocol
219 lines • 10.5 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.onPageChange = onPageChange;
exports.onAppConnect = onAppConnect;
exports.onAppDisconnect = onAppDisconnect;
exports.onAppUpdate = onAppUpdate;
exports.onConnectedDriverList = onConnectedDriverList;
exports.onCurrentState = onCurrentState;
exports.onConnectedApplicationList = onConnectedApplicationList;
exports.getDebuggerAppKey = getDebuggerAppKey;
const events_1 = require("./events");
const utils_1 = require("../utils");
const lodash_1 = __importDefault(require("lodash"));
const property_accessors_1 = require("./property-accessors");
/*
* Generic callbacks used throughout the lifecycle of the Remote Debugger.
* These will be added to the prototype.
*/
/**
* Handles page change notifications from the remote debugger.
* Updates the page array for the specified application and emits a page change
* event if the pages have actually changed and navigation is not in progress.
*
* @param err - Error object if an error occurred, null or undefined otherwise.
* @param appIdKey - The application identifier key for which pages have changed.
* @param pageDict - Dictionary containing the new page information.
*/
async function onPageChange(err, appIdKey, pageDict) {
if (lodash_1.default.isEmpty(pageDict)) {
return;
}
const currentPages = (0, utils_1.pageArrayFromDict)(pageDict);
// save the page dict for this app
if ((0, property_accessors_1.getAppDict)(this)[appIdKey]) {
const previousPages = (0, property_accessors_1.getAppDict)(this)[appIdKey].pageArray;
// we have a pre-existing pageDict
if (previousPages && lodash_1.default.isEqual(previousPages, currentPages)) {
this.log.debug(`Received page change notice for app '${appIdKey}' ` +
`but the listing has not changed. Ignoring.`);
return;
}
// keep track of the page dictionary
(0, property_accessors_1.getAppDict)(this)[appIdKey].pageArray = currentPages;
this.log.debug(`Pages changed for ${appIdKey}: ${JSON.stringify(previousPages)} -> ${JSON.stringify(currentPages)}`);
}
if ((0, property_accessors_1.getNavigatingToPage)(this)) {
// in the middle of navigating, so reporting a page change will cause problems
return;
}
this.emit(events_1.events.EVENT_PAGE_CHANGE, {
appIdKey: appIdKey.replace('PID:', ''),
pageArray: currentPages,
});
}
/**
* Handles notifications when a new application connects to the remote debugger.
* Updates the application dictionary with the new application information.
*
* @param err - Error object if an error occurred, null or undefined otherwise.
* @param dict - Dictionary containing the new application information including
* the WIRApplicationIdentifierKey.
*/
async function onAppConnect(err, dict) {
const appIdKey = dict.WIRApplicationIdentifierKey;
this.log.debug(`Notified that new application '${appIdKey}' has connected`);
updateAppsWithDict.bind(this)(dict);
}
/**
* Handles notifications when an application disconnects from the remote debugger.
* Removes the application from the dictionary and attempts to find a replacement
* if the disconnected app was the currently selected one. Emits a disconnect event
* if no applications remain.
*
* @param err - Error object if an error occurred, null or undefined otherwise.
* @param dict - Dictionary containing the disconnected application information
* including the WIRApplicationIdentifierKey.
*/
function onAppDisconnect(err, dict) {
const appIdKey = dict.WIRApplicationIdentifierKey;
this.log.debug(`Application '${appIdKey}' disconnected. Removing from app dictionary.`);
this.log.debug(`Current app is '${(0, property_accessors_1.getAppIdKey)(this)}'`);
// get rid of the entry in our app dictionary,
// since it is no longer available
delete (0, property_accessors_1.getAppDict)(this)[appIdKey];
// if the disconnected app is the one we are connected to, try to find another
if ((0, property_accessors_1.getAppIdKey)(this) === appIdKey) {
this.log.debug(`No longer have app id. Attempting to find new one.`);
(0, property_accessors_1.setAppIdKey)(this, getDebuggerAppKey.bind(this)((0, property_accessors_1.getBundleId)(this)));
}
if (lodash_1.default.isEmpty((0, property_accessors_1.getAppDict)(this))) {
// this means we no longer have any apps. what the what?
this.log.debug('Main app disconnected. Disconnecting altogether.');
this.emit(events_1.events.EVENT_DISCONNECT, true);
}
}
/**
* Handles notifications when an application's information is updated.
* Updates the application dictionary with the new information while preserving
* any existing page array data.
*
* @param err - Error object if an error occurred, null or undefined otherwise.
* @param dict - Dictionary containing the updated application information.
*/
async function onAppUpdate(err, dict) {
this.log.debug(`Notified that an application has been updated`);
updateAppsWithDict.bind(this)(dict);
}
/**
* Handles notifications containing the list of connected drivers.
* Updates the internal connected drivers list with the received information.
*
* @param err - Error object if an error occurred, null or undefined otherwise.
* @param drivers - Dictionary containing the connected driver list with
* WIRDriverDictionaryKey.
*/
function onConnectedDriverList(err, drivers) {
(0, property_accessors_1.setConnectedDrivers)(this, drivers.WIRDriverDictionaryKey);
this.log.debug(`Received connected driver list: ${JSON.stringify(this.connectedDrivers)}`);
}
/**
* Handles notifications about the current automation availability state.
* This state changes when 'Remote Automation' setting in Safari's advanced settings
* is toggled. The state can be either WIRAutomationAvailabilityAvailable or
* WIRAutomationAvailabilityNotAvailable.
*
* @param err - Error object if an error occurred, null or undefined otherwise.
* @param state - Dictionary containing the automation availability state with
* WIRAutomationAvailabilityKey.
*/
function onCurrentState(err, state) {
(0, property_accessors_1.setCurrentState)(this, state.WIRAutomationAvailabilityKey);
// This state changes when 'Remote Automation' in 'Settings app' > 'Safari' > 'Advanced' > 'Remote Automation' changes
// WIRAutomationAvailabilityAvailable or WIRAutomationAvailabilityNotAvailable
this.log.debug(`Received connected automation availability state: ${JSON.stringify(this.currentState)}`);
}
/**
* Handles notifications containing the list of connected applications.
* Translates the received information into the application dictionary format,
* filtering out any applications that are in the skipped apps list.
*
* @param err - Error object if an error occurred, null or undefined otherwise.
* @param apps - Dictionary containing the connected applications list.
*/
async function onConnectedApplicationList(err, apps) {
this.log.debug(`Received connected applications list: ${lodash_1.default.keys(apps).join(', ')}`);
// translate the received information into an easier-to-manage
// hash with app id as key, and app info as value
const newDict = {};
for (const dict of lodash_1.default.values(apps)) {
const [id, entry] = (0, utils_1.appInfoFromDict)(dict);
if ((0, property_accessors_1.getSkippedApps)(this).includes(entry.name)) {
continue;
}
newDict[id] = entry;
}
// update the object's list of apps
lodash_1.default.defaults((0, property_accessors_1.getAppDict)(this), newDict);
}
/**
* Given a bundle ID, finds the correct remote debugger app identifier key
* that is currently connected. Also handles proxy applications that may act
* on behalf of the requested bundle ID.
*
* @param bundleId - The bundle identifier to search for.
* @returns The application identifier key if found, undefined otherwise.
* If a proxy application is found, returns the proxy's app ID instead.
*/
function getDebuggerAppKey(bundleId) {
let appId;
for (const [key, data] of lodash_1.default.toPairs((0, property_accessors_1.getAppDict)(this))) {
if (data.bundleId === bundleId) {
appId = key;
break;
}
}
// now we need to determine if we should pick a proxy for this instead
if (appId) {
this.log.debug(`Found app id key '${appId}' for bundle '${bundleId}'`);
let proxyAppId;
for (const [key, data] of lodash_1.default.toPairs((0, property_accessors_1.getAppDict)(this))) {
if (data.isProxy && data.hostId === appId) {
this.log.debug(`Found separate bundleId '${data.bundleId}' ` +
`acting as proxy for '${bundleId}', with app id '${key}'`);
// set the app id... the last one will be used, so just keep re-assigning
proxyAppId = key;
}
}
if (proxyAppId) {
appId = proxyAppId;
this.log.debug(`Using proxied app id '${appId}'`);
}
}
return appId;
}
/**
* Updates the application dictionary with information from the provided dictionary.
* Preserves existing page array data if the application already exists in the dictionary.
* Attempts to set the app ID key if one is not currently set.
*
* @param dict - Dictionary containing application information to add or update.
*/
function updateAppsWithDict(dict) {
// get the dictionary entry into a nice form, and add it to the
// application dictionary
const [id, entry] = (0, utils_1.appInfoFromDict)(dict);
if ((0, property_accessors_1.getAppDict)(this)[id]?.pageArray) {
// preserve the page dictionary for this entry
entry.pageArray = (0, property_accessors_1.getAppDict)(this)[id].pageArray;
}
(0, property_accessors_1.getAppDict)(this)[id] = entry;
// try to get the app id from our connected apps
if (!(0, property_accessors_1.getAppIdKey)(this)) {
(0, property_accessors_1.setAppIdKey)(this, getDebuggerAppKey.bind(this)((0, property_accessors_1.getBundleId)(this)));
}
}
//# sourceMappingURL=message-handlers.js.map