-
-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for iOS 12.2 #118
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,21 +23,21 @@ function onPageChange (appIdKey, pageDict) { | |
|
||
// save the page dict for this app | ||
if (this.appDict[appIdKey]) { | ||
if (this.appDict[appIdKey].pageDict) { | ||
if (this.appDict[appIdKey].pageDict.resolve) { | ||
// pageDict is a promise, so resolve | ||
this.appDict[appIdKey].pageDict.resolve(pageArray); | ||
if (this.appDict[appIdKey].pageArray) { | ||
if (this.appDict[appIdKey].pageArray.resolve) { | ||
// pageDict is a pending promise, so resolve | ||
this.appDict[appIdKey].pageArray.resolve(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. await? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} else { | ||
// we have a pre-existing pageDict | ||
if (_.isEqual(cleanPageArray(this.appDict[appIdKey].pageDict), cleanPageArray(pageArray))) { | ||
if (_.isEqual(cleanPageArray(this.appDict[appIdKey].pageArray), cleanPageArray(pageArray))) { | ||
log.debug(`Received page change notice for app '${appIdKey}' ` + | ||
`but the listing has not changed. Ignoring.`); | ||
return; | ||
} | ||
} | ||
} | ||
// keep track of the page dictionary | ||
this.appDict[appIdKey].pageDict = pageArray; | ||
this.appDict[appIdKey].pageArray = pageArray; | ||
} | ||
|
||
// only act if this is the correct app | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,14 +14,14 @@ const IGNORED_EVENTS = [ | |
]; | ||
|
||
export default class RpcMessageHandler { | ||
constructor (specialHandlers, targetBased = false) { | ||
constructor (specialHandlers, isTargetBased = false) { | ||
this.setHandlers(); | ||
this.errorHandlers = {}; | ||
this.specialHandlers = _.clone(specialHandlers); | ||
this.dataHandlers = {}; | ||
this.willNavigateWithoutReload = false; | ||
|
||
this.targetBased = targetBased; | ||
this.isTargetBased = isTargetBased; | ||
} | ||
|
||
setDataMessageHandler (key, errorHandler, handler) { | ||
|
@@ -107,6 +107,70 @@ export default class RpcMessageHandler { | |
} | ||
} | ||
|
||
async dispatchDataMessage (msgId, method, params, result, error) { | ||
if (method === 'Profiler.resetProfiles') { | ||
log.debug('Device is telling us to reset profiles. Should probably ' + | ||
'do some kind of callback here'); | ||
} else if (method === 'Page.frameNavigated') { | ||
if (!this.willNavigateWithoutReload && !this.pageLoading) { | ||
log.debug('Frame navigated, unloading page'); | ||
if (_.isFunction(this.specialHandlers['Page.frameNavigated'])) { | ||
await this.specialHandlers['Page.frameNavigated']('remote-debugger'); | ||
this.specialHandlers['Page.frameNavigated'] = null; | ||
} | ||
} else { | ||
log.debug('Frame navigated but we were warned about it, not ' + | ||
'considering page state unloaded'); | ||
this.willNavigateWithoutReload = false; | ||
} | ||
} else if (IGNORED_EVENTS.includes(method)) { | ||
// pass | ||
} else if (method === 'Page.loadEventFired' && _.isFunction(this.specialHandlers.pageLoad)) { | ||
await this.specialHandlers.pageLoad(); | ||
} else if (method === 'Page.frameDetached' && _.isFunction(this.specialHandlers.frameDetached)) { | ||
await this.specialHandlers.frameDetached(); | ||
} else if (method === 'Timeline.eventRecorded' && _.isFunction(this.timelineEventHandler)) { | ||
this.timelineEventHandler(params || params.record); | ||
} else if (method === 'Console.messageAdded' && _.isFunction(this.consoleLogEventHandler)) { | ||
this.consoleLogEventHandler(params.message); | ||
} else if (method && method.startsWith('Network.') && _.isFunction(this.networkLogEventHandler)) { | ||
this.networkLogEventHandler(method, params); | ||
} else if (_.isFunction(this.dataHandlers[msgId])) { | ||
log.debug('Found data handler for response'); | ||
|
||
// we will either get back a result object that has a result.value | ||
// in which case that is what we want, | ||
// or else we return the whole thing | ||
if (result.result && result.result.value) { | ||
result = result.result.value; | ||
} | ||
this.dataHandlers[msgId](result); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. await? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are always regular functions. |
||
this.dataHandlers[msgId] = null; | ||
} else if (this.dataHandlers[msgId] === null) { | ||
log.error(`Debugger returned data for message ${msgId} ` + | ||
`but we already ran that callback! WTF??`); | ||
} else { | ||
if (msgId || result || error) { | ||
log.error(`Debugger returned data for message '${msgId}' ` + | ||
`but we were not waiting for that message! ` + | ||
`result: '${JSON.stringify(result)}'; ` + | ||
`error: '${error}'`); | ||
} | ||
} | ||
} | ||
|
||
logFullMessage (plist) { | ||
// Buffers cannot be serialized in a readable way | ||
const bufferToJSON = Buffer.prototype.toJSON; | ||
delete Buffer.prototype.toJSON; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. interesting hack %) |
||
try { | ||
log(JSON.stringify(plist, (k, v) => Buffer.isBuffer(v) ? v.toString('utf8') : v, 2)); | ||
} finally { | ||
// restore the function, so as to not break further serialization | ||
Buffer.prototype.toJSON = bufferToJSON; | ||
} | ||
} | ||
|
||
async handleDataMessage (plist) { | ||
const dataKey = this.parseDataKey(plist); | ||
let msgId = (dataKey.id || '').toString(); | ||
|
@@ -135,7 +199,7 @@ export default class RpcMessageHandler { | |
|
||
let method = dataKey.method; | ||
let params; | ||
if (this.targetBased) { | ||
if (this.isTargetBased) { | ||
if (method === 'Target.targetCreated') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rather move this code into a separate method. The current one is already quite long |
||
// this is in response to a `_rpc_forwardSocketSetup:` call | ||
// targetInfo: { targetId: 'page-1', type: 'page' } | ||
|
@@ -149,17 +213,29 @@ export default class RpcMessageHandler { | |
await this.specialHandlers.targetDestroyed(app, targetInfo); | ||
return; | ||
} else if (dataKey.method !== 'Target.dispatchMessageFromTarget') { | ||
// this sort of message, at this point, is just an acknowledgement | ||
// that the original message was received | ||
if (!_.isEmpty(msgId)) { | ||
log.debug(`Received receipt for message '${msgId}'`); | ||
} | ||
return; | ||
} | ||
|
||
const message = JSON.parse(dataKey.params.message); | ||
result = message.result || message; | ||
msgId = message.id; | ||
method = message.method; | ||
params = result.params; | ||
// at this point, we have a Target-based message wrapping a protocol message | ||
let message; | ||
try { | ||
message = JSON.parse(dataKey.params.message); | ||
msgId = message.id; | ||
method = message.method; | ||
result = message.result || message; | ||
params = result.params; | ||
} catch (err) { | ||
// if this happens then some aspect of the protocol is missing to us | ||
// so print the entire message to get visibiity into what is going on | ||
log.error(`Unexpected message format from Web Inspector:`); | ||
this.logFullMessage(plist); | ||
throw err; | ||
} | ||
} else { | ||
params = dataKey.params; | ||
} | ||
|
@@ -168,55 +244,7 @@ export default class RpcMessageHandler { | |
log.debug(`Received response for message '${msgId}'`); | ||
} | ||
|
||
if (method === 'Profiler.resetProfiles') { | ||
log.debug('Device is telling us to reset profiles. Should probably ' + | ||
'do some kind of callback here'); | ||
} else if (method === 'Page.frameNavigated') { | ||
if (!this.willNavigateWithoutReload && !this.pageLoading) { | ||
log.debug('Frame navigated, unloading page'); | ||
if (_.isFunction(this.specialHandlers['Page.frameNavigated'])) { | ||
this.specialHandlers['Page.frameNavigated']('remote-debugger'); | ||
this.specialHandlers['Page.frameNavigated'] = null; | ||
} | ||
} else { | ||
log.debug('Frame navigated but we were warned about it, not ' + | ||
'considering page state unloaded'); | ||
this.willNavigateWithoutReload = false; | ||
} | ||
} else if (IGNORED_EVENTS.includes(method)) { | ||
// pass | ||
} else if (method === 'Page.loadEventFired' && _.isFunction(this.specialHandlers.pageLoad)) { | ||
await this.specialHandlers.pageLoad(); | ||
} else if (method === 'Page.frameDetached' && _.isFunction(this.specialHandlers.frameDetached)) { | ||
await this.specialHandlers.frameDetached(); | ||
} else if (method === 'Timeline.eventRecorded' && _.isFunction(this.timelineEventHandler)) { | ||
this.timelineEventHandler(params || params.record); | ||
} else if (method === 'Console.messageAdded' && _.isFunction(this.consoleLogEventHandler)) { | ||
this.consoleLogEventHandler(params.message); | ||
} else if (method && method.startsWith('Network.') && _.isFunction(this.networkLogEventHandler)) { | ||
this.networkLogEventHandler(method, params); | ||
} else if (_.isFunction(this.dataHandlers[msgId])) { | ||
log.debug('Found data handler for response'); | ||
|
||
// we will either get back a result object that has a result.value | ||
// in which case that is what we want, | ||
// or else we return the whole thing | ||
if (result.result && result.result.value) { | ||
result = result.result.value; | ||
} | ||
this.dataHandlers[msgId](result); | ||
this.dataHandlers[msgId] = null; | ||
} else if (this.dataHandlers[msgId] === null) { | ||
log.error(`Debugger returned data for message ${msgId} ` + | ||
`but we already ran that callback! WTF??`); | ||
} else { | ||
if (msgId || result || error) { | ||
log.error(`Debugger returned data for message '${msgId}' ` + | ||
`but we were not waiting for that message! ` + | ||
`result: '${JSON.stringify(result)}'; ` + | ||
`error: '${error}'`); | ||
} | ||
} | ||
await this.dispatchDataMessage(msgId, method, params, result, error); | ||
} | ||
|
||
setHandlers () { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,7 +34,7 @@ export default class RemoteDebuggerRpcClient { | |
this.connected = false; | ||
this.connId = UUID.create().toString(); | ||
this.senderId = UUID.create().toString(); | ||
this.curMsgId = 0; | ||
this.msgId = 0; | ||
this.received = Buffer.alloc(0); | ||
this.readPos = 0; | ||
|
||
|
@@ -45,9 +45,10 @@ export default class RemoteDebuggerRpcClient { | |
if (_.isString(platformVersion)) { | ||
platformVersion = parseFloat(platformVersion); | ||
} | ||
const targetBased = platformVersion >= MIN_PLATFORM_FOR_TARGET_BASED; | ||
this.remoteMessages = new RemoteMessages(targetBased); | ||
this.messageHandler = new RpcMessageHandler(this.specialMessageHandlers, targetBased); | ||
const isTargetBased = platformVersion >= MIN_PLATFORM_FOR_TARGET_BASED; | ||
this.remoteMessages = new RemoteMessages(isTargetBased); | ||
this.messageHandler = new RpcMessageHandler(this.specialMessageHandlers, isTargetBased); | ||
log.debug(`Using '${isTargetBased ? 'Target-based' : 'full Web Inspector protocol'}' communication`); | ||
} | ||
|
||
async connect () { | ||
|
@@ -196,7 +197,7 @@ export default class RemoteDebuggerRpcClient { | |
// replies to our request | ||
|
||
// keep track of the messages coming and going using a simple sequential id | ||
const msgId = this.curMsgId++; | ||
const msgId = this.msgId++; | ||
|
||
// retrieve the correct command to send | ||
opts = _.defaults({connId: this.connId, senderId: this.senderId}, opts); | ||
|
@@ -245,6 +246,8 @@ export default class RemoteDebuggerRpcClient { | |
log.debug(`Original command: ${command}`); | ||
resolve(value); | ||
}); | ||
|
||
// make sure the message being sent has all the information that is needed | ||
if (cmd.__argument.WIRSocketDataKey.params) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hell it's full of magic |
||
cmd.__argument.WIRSocketDataKey.params.id = msgId; | ||
if (!cmd.__argument.WIRSocketDataKey.params.targetId) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isFunction ?