-
Notifications
You must be signed in to change notification settings - Fork 22
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
Use Messenger for executeInTarget
#2044
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,7 +41,6 @@ import { | |
|
||
const RUN_BLOCK = `${MESSAGE_PREFIX}RUN_BLOCK`; | ||
const MESSAGE_RUN_BLOCK_OPENER = `${MESSAGE_PREFIX}RUN_BLOCK_OPENER`; | ||
const MESSAGE_RUN_BLOCK_TARGET = `${MESSAGE_PREFIX}RUN_BLOCK_TARGET`; | ||
const MESSAGE_RUN_BLOCK_BROADCAST = `${MESSAGE_PREFIX}RUN_BLOCK_BROADCAST`; | ||
const MESSAGE_RUN_BLOCK_FRAME_NONCE = `${MESSAGE_PREFIX}RUN_BLOCK_FRAME_NONCE`; | ||
|
||
|
@@ -104,25 +103,6 @@ async function waitNonceReady( | |
return true; | ||
} | ||
|
||
async function waitReady( | ||
{ tabId, frameId }: Target, | ||
{ maxWaitMillis = 10_000 }: WaitOptions = {} | ||
): Promise<boolean> { | ||
const startTime = Date.now(); | ||
while (tabReady[tabId]?.[frameId] == null) { | ||
if (Date.now() - startTime > maxWaitMillis) { | ||
throw new BusinessError( | ||
`Tab ${tabId} was not ready after ${maxWaitMillis}ms` | ||
); | ||
Comment on lines
-114
to
-116
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. This specific error no longer exists because the retries are handled automatically by I suppose this is an issue on large pages that have If you think this is an issue, I could add an option¹ for this or increase the default timeout. 1 options are kind of difficult at the moment, 🤭 which is why I split 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. Since I'm bringing the handler back to this context, I will restore this function 🎉 |
||
} | ||
|
||
// eslint-disable-next-line no-await-in-loop -- retry loop | ||
await sleep(50); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
const handlers = new HandlerMap(); | ||
|
||
handlers.set( | ||
|
@@ -220,42 +200,18 @@ handlers.set( | |
} | ||
); | ||
|
||
handlers.set( | ||
MESSAGE_RUN_BLOCK_TARGET, | ||
async (request: RunBlockRequestAction, sender) => { | ||
const target = tabToTarget.get(sender.tab.id); | ||
|
||
if (!target) { | ||
throw new BusinessError("Sender tab has no target"); | ||
} | ||
|
||
console.debug(`Waiting for target tab ${target} to be ready`); | ||
// For now, only support top-level frame as target | ||
await waitReady({ tabId: target, frameId: 0 }); | ||
console.debug( | ||
`Sending ${RUN_BLOCK} to target tab ${target} (sender=${sender.tab.id})` | ||
); | ||
return runBlockInContentScript( | ||
{ tabId: target, frameId: 0 }, | ||
{ | ||
sourceTabId: sender.tab.id, | ||
...request.payload, | ||
} | ||
); | ||
} | ||
); | ||
|
||
export async function openTab( | ||
this: MessengerMeta, | ||
createProperties: Tabs.CreateCreatePropertiesType | ||
): Promise<void> { | ||
): Promise<number> { | ||
// Natively links the new tab to its opener + opens it right next to it | ||
const openerTabId = this.trace[0].tab.id; | ||
const tab = await browser.tabs.create({ ...createProperties, openerTabId }); | ||
|
||
// FIXME: include frame information here | ||
tabToTarget.set(openerTabId, tab.id); | ||
tabToOpener.set(tab.id, openerTabId); | ||
return tab.id; | ||
} | ||
|
||
export async function markTabAsReady(this: MessengerMeta) { | ||
|
@@ -388,33 +344,6 @@ export async function executeForNonce( | |
); | ||
} | ||
|
||
export async function executeInTarget( | ||
blockId: string, | ||
blockArgs: BlockArg, | ||
options: RemoteBlockOptions | ||
): Promise<unknown> { | ||
console.debug(`Running ${blockId} in the target tab`, { | ||
blockId, | ||
blockArgs, | ||
options, | ||
}); | ||
|
||
const { maxRetries = DEFAULT_MAX_RETRIES } = options; | ||
|
||
return retrySend( | ||
async () => | ||
browser.runtime.sendMessage({ | ||
type: MESSAGE_RUN_BLOCK_TARGET, | ||
payload: { | ||
blockId, | ||
blockArgs, | ||
options, | ||
}, | ||
}), | ||
maxRetries | ||
); | ||
} | ||
|
||
export async function executeInAll( | ||
blockId: string, | ||
blockArgs: BlockArg, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,10 @@ import { | |
} from "@/blocks/transformers/url"; | ||
import { makeURL } from "@/utils"; | ||
|
||
export const target = { | ||
id: -1, | ||
}; | ||
Comment on lines
+27
to
+29
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. The target was previous stored in the background page and the messaging solution expected the background page to match "sender" with "target". With the messenger we can message the tab "directly" (i.e. the messenger takes care of forwarding) so we can store it locally (which is where the tab is created anyway). This might not be the best solution but it's clean-ish (when messaging the target, you'll have to import this block, which shows the direct dependency between the two) 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.
This change actually changes the behavior. The old code also tracked if a normal link opened up a new tab. With this new code the "target" relationship will only be tracked through this block?
See the bookkeeping via browser.tabs.onCreated at initExecutor: http://github.com/pixiebrix/pixiebrix-extension/blob/main/src/background/executor.ts#L300-L300 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. Indeed. In that case we can exclusively send messages via the background page because that's the only context that can know that information. I'll have to restore the previous manual forwarding |
||
|
||
export class NavigateURLEffect extends Effect { | ||
constructor() { | ||
super( | ||
|
@@ -62,7 +66,7 @@ export class OpenURLEffect extends Effect { | |
params, | ||
spaceEncoding = URL_INPUT_SPACE_ENCODING_DEFAULT, | ||
}: BlockArg): Promise<void> { | ||
await openTab({ | ||
target.id = await openTab({ | ||
url: makeURL(url, params, spaceEncoding), | ||
}); | ||
} | ||
|
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.
A note about the other targets:
opener
can probably be handled by the messenger by usingrunBlock({tabId: "opener"})
broadcast
likely similar implementation to ReplacenotifyContentScripts
with Messenger #1329frame_nonce
I haven't looked at it yet, but maybe via{tabId: "this", page: "?nonce=ABC"}
. Related: How can a content script target a frame? webext-messenger#41There 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.
Unlike notifications, broadcast actually returns the results as the array. You mean in terms of how it notifies all the tabs?
I think using the more general page matching capability here to support our nonce based frame approach makes sense here
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.
I'm starting to think that all of these methods will continue existing in the background page because that's the only context that can do this.