UNPKG

appium-remote-debugger

Version:
191 lines (170 loc) 5.46 kB
import log from '../logger'; import events from './events'; import { pageArrayFromDict, getDebuggerAppKey, simpleStringify, appInfoFromDict } from '../utils'; import _ from 'lodash'; /* * Generic callbacks used throughout the lifecycle of the Remote Debugger. * These will be added to the prototype. */ /** * @this {import('../remote-debugger').RemoteDebugger} * @param {Error?} err * @param {string} appIdKey * @param {Record<string, any>} pageDict * @returns {Promise<void>} */ async function onPageChange (err, appIdKey, pageDict) { if (_.isEmpty(pageDict)) { return; } const pageArray = pageArrayFromDict(pageDict); await this.useAppDictLock((done) => { try { // save the page dict for this app if (this.appDict[appIdKey]) { if (this.appDict[appIdKey].pageArray) { if (this.appDict[appIdKey].pageArray.resolve) { // pageDict is a pending promise, so resolve this.appDict[appIdKey].pageArray.resolve(); } else { // we have a pre-existing pageDict if (_.isEqual(this.appDict[appIdKey].pageArray, pageArray)) { log.debug(`Received page change notice for app '${appIdKey}' ` + `but the listing has not changed. Ignoring.`); return done(); } } } // keep track of the page dictionary this.appDict[appIdKey].pageArray = pageArray; } } finally { done(); } }); if (this._navigatingToPage) { // in the middle of navigating, so reporting a page change will cause problems return; } log.debug(`Page changed: ${simpleStringify(pageDict, true)}`); this.emit(events.EVENT_PAGE_CHANGE, { appIdKey: appIdKey.replace('PID:', ''), pageArray, }); } /** * @this {import('../remote-debugger').RemoteDebugger} * @param {Error?} err * @param {Record<string, any>} dict * @returns {Promise<void>} */ async function onAppConnect (err, dict) { const appIdKey = dict.WIRApplicationIdentifierKey; log.debug(`Notified that new application '${appIdKey}' has connected`); await this.useAppDictLock((/** @type {() => Void} */done) => { try { this.updateAppsWithDict(dict); } finally { done(); } }); } /** * @this {import('../remote-debugger').RemoteDebugger} * @param {Error?} err * @param {Record<string, any>} dict * @returns {void} */ function onAppDisconnect (err, dict) { const appIdKey = dict.WIRApplicationIdentifierKey; log.debug(`Application '${appIdKey}' disconnected. Removing from app dictionary.`); log.debug(`Current app is '${this.appIdKey}'`); // get rid of the entry in our app dictionary, // since it is no longer available delete this.appDict[appIdKey]; // if the disconnected app is the one we are connected to, try to find another if (this.appIdKey === appIdKey) { log.debug(`No longer have app id. Attempting to find new one.`); this.appIdKey = getDebuggerAppKey(this.bundleId, this.appDict); } if (!this.appDict) { // this means we no longer have any apps. what the what? log.debug('Main app disconnected. Disconnecting altogether.'); this.connected = false; this.emit(events.EVENT_DISCONNECT, true); } } /** * @this {import('../remote-debugger').RemoteDebugger} * @param {Error?} err * @param {Record<string, any>} dict * @returns {Promise<void>} */ async function onAppUpdate (err, dict) { await this.useAppDictLock((done) => { try { this.updateAppsWithDict(dict); } finally { done(); } }); } /** * @this {import('../remote-debugger').RemoteDebugger} * @param {Error?} err * @param {Record<string, any>} drivers * @returns {void} */ function onConnectedDriverList (err, drivers) { this.connectedDrivers = drivers.WIRDriverDictionaryKey; log.debug(`Received connected driver list: ${JSON.stringify(this.connectedDrivers)}`); } /** * @this {import('../remote-debugger').RemoteDebugger} * @param {Error?} err * @param {Record<string, any>} state * @returns {void} */ function onCurrentState (err, state) { this.currentState = state.WIRAutomationAvailabilityKey; // This state changes when 'Remote Automation' in 'Settings app' > 'Safari' > 'Advanced' > 'Remote Automation' changes // WIRAutomationAvailabilityAvailable or WIRAutomationAvailabilityNotAvailable log.debug(`Received connected automation availability state: ${JSON.stringify(this.currentState)}`); } /** * @this {import('../remote-debugger').RemoteDebugger} * @param {Error?} err * @param {Record<string, any>} apps * @returns {Promise<void>} */ async function onConnectedApplicationList (err, apps) { log.debug(`Received connected applications list: ${_.keys(apps).join(', ')}`); // translate the received information into an easier-to-manage // hash with app id as key, and app info as value let newDict = {}; for (const dict of _.values(apps)) { const [id, entry] = appInfoFromDict(dict); if (this.skippedApps.includes(entry.name)) { continue; } newDict[id] = entry; } // update the object's list of apps await this.useAppDictLock((done) => { try { _.defaults(this.appDict, newDict); } finally { done(); } }); } const messageHandlers = { onPageChange, onAppConnect, onAppDisconnect, onAppUpdate, onConnectedDriverList, onCurrentState, onConnectedApplicationList, }; export default messageHandlers;