Skip to content
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 sidebar bricks #1642

Merged
merged 3 commits into from
Oct 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 7 additions & 12 deletions src/action.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ import "@/telemetry/rollbar";
import App from "@/actionPanel/ActionPanelApp";
import ReactDOM from "react-dom";
import React from "react";
import { browser } from "webextension-polyfill-ts";

import { REGISTER_ACTION_FRAME } from "@/background/browserAction";
import { browserAction } from "@/background/messenger/api";
import { UUID } from "@/core";
import "@/actionPanel/protocol";

// Keep in order so precedence is preserved
Expand All @@ -34,15 +34,10 @@ import "@/vendors/overrides.scss";
import "@/action.scss";

const url = new URL(location.href);
const nonce = url.searchParams.get("nonce");

void browser.runtime
.sendMessage({
type: REGISTER_ACTION_FRAME,
payload: { nonce },
})
.then(() => {
console.debug("Registered action frame with background page");
});
const nonce = url.searchParams.get("nonce") as UUID;

void browserAction.registerActionFrame(nonce).then(() => {
console.debug("Registered action frame with background page");
});

ReactDOM.render(<App />, document.querySelector("#container"));
12 changes: 2 additions & 10 deletions src/actionPanel/ActionPanelApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,9 @@ import { PersistGate } from "redux-persist/integration/react";
import { reportEvent } from "@/telemetry/events";
import useExtensionMeta from "@/hooks/useExtensionMeta";
import { selectEventData } from "@/telemetry/deployments";
import { browser } from "webextension-polyfill-ts";
import { HIDE_ACTION_FRAME } from "@/background/browserAction";
import { browserAction } from "@/background/messenger/api";
import { UUID } from "@/core";

const closeSidebar = async () => {
await browser.runtime.sendMessage({
type: HIDE_ACTION_FRAME,
payload: {},
});
};

const ActionPanelTabs: React.FunctionComponent<{ panels: PanelEntry[] }> = ({
panels,
}) => {
Expand Down Expand Up @@ -141,7 +133,7 @@ const ActionPanelApp: React.FunctionComponent = () => {
<div className="d-flex flex-row mb-2 p-2 justify-content-between align-content-center">
<Button
className="action-panel-button"
onClick={closeSidebar}
onClick={browserAction.hideActionFrame}
size="sm"
variant="link"
>
Expand Down
14 changes: 5 additions & 9 deletions src/actionPanel/native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ import {
RendererError,
RendererPayload,
} from "@/actionPanel/protocol";
import { FORWARD_FRAME_NOTIFICATION } from "@/background/browserAction";
import { IS_BROWSER } from "@/helpers";
import { reportEvent } from "@/telemetry/events";
import { expectContext } from "@/utils/expectContext";
import { ExtensionRef } from "@/core";
import { browserAction } from "@/background/messenger/api";

const SIDEBAR_WIDTH_PX = 400;
const PANEL_CONTAINER_ID = "pixiebrix-extension";
Expand Down Expand Up @@ -164,14 +164,10 @@ function renderPanels() {
const seqNum = renderSequenceNumber;
renderSequenceNumber++;

void browser.runtime.sendMessage({
type: FORWARD_FRAME_NOTIFICATION,
meta: { $seq: seqNum },
payload: {
type: RENDER_PANELS_MESSAGE,
payload: { panels },
},
});
browserAction.forwardFrameNotification(seqNum, {
type: RENDER_PANELS_MESSAGE,
payload: { panels },
} as any); // Temporary, until https://github.com/pixiebrix/webext-messenger/issues/31
} else {
console.debug(
"Skipping renderPanels because the action panel is not visible"
Expand Down
92 changes: 39 additions & 53 deletions src/background/browserAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,18 @@ import { ensureContentScript, showErrorInOptions } from "@/background/util";
import { browser } from "webextension-polyfill-ts";
import { safeParseUrl, sleep } from "@/utils";
import { JsonObject, JsonValue } from "type-fest";
import { HandlerMap } from "@/messaging/protocol";
import { getErrorMessage } from "@/errors";
import { emitDevtools } from "@/background/devtools/internal";
import {
hideActionPanel,
showActionPanel,
toggleActionPanel,
} from "@/contentScript/messenger/api";
import { MessengerMeta } from "webext-messenger";
import { UUID } from "@/core";

const MESSAGE_PREFIX = "@@pixiebrix/background/browserAction/";
export const REGISTER_ACTION_FRAME = `${MESSAGE_PREFIX}/REGISTER_ACTION_FRAME`;
export const FORWARD_FRAME_NOTIFICATION = `${MESSAGE_PREFIX}/FORWARD_ACTION_FRAME_NOTIFICATION`;
export const SHOW_ACTION_FRAME = `${MESSAGE_PREFIX}/SHOW_ACTION_FRAME`;
export const HIDE_ACTION_FRAME = `${MESSAGE_PREFIX}/HIDE_ACTION_FRAME`;

// The sidebar is always injected to into the top level frame
const TOP_LEVEL_FRAME_ID = 0;
Expand Down Expand Up @@ -94,21 +92,6 @@ async function handleBrowserAction(tab: browser.tabs.Tab): Promise<void> {
}
}

type RegisterActionFrameMessage = {
type: typeof REGISTER_ACTION_FRAME;
payload: { nonce: string };
};

type ForwardActionFrameNotification = {
type: typeof FORWARD_FRAME_NOTIFICATION;
meta: { $seq: number };
payload: {
type: string;
meta?: JsonObject;
payload: JsonValue;
};
};

const FORWARD_RETRY_INTERVAL_MILLIS = 50;

const FORWARD_RETRY_MAX_WAIT_MILLIS = 3000;
Expand Down Expand Up @@ -220,40 +203,43 @@ async function forwardWhenReady(
);
}

const handlers = new HandlerMap();

handlers.set(
REGISTER_ACTION_FRAME,
async (request: RegisterActionFrameMessage, sender) => {
const tabId = sender.tab.id;
const expected = tabNonces.get(tabId);
if (expected != null && expected !== request.payload.nonce) {
console.warn("Action frame nonce mismatch", {
expected,
actual: request.payload.nonce,
});
}

console.debug("Setting action frame metadata", {
tabId,
frameId: sender.frameId,
export async function registerActionFrame(
this: MessengerMeta,
nonce: UUID
): Promise<void> {
const sender = this.trace[0];
const tabId = sender.tab.id;
const expected = tabNonces.get(tabId);
if (expected != null && expected !== nonce) {
console.warn("Action frame nonce mismatch", {
expected,
actual: nonce,
});
tabFrames.set(tabId, sender.frameId);
tabSeqNumber.delete(tabId);
}
);

handlers.set(
FORWARD_FRAME_NOTIFICATION,
async (request: ForwardActionFrameNotification, sender) => {
const tabId = sender.tab.id;
return forwardWhenReady(tabId, request.meta.$seq, request.payload).catch(
reportError
);

console.debug("Setting action frame metadata", {
tabId,
frameId: sender.frameId,
});
tabFrames.set(tabId, sender.frameId);
tabSeqNumber.delete(tabId);
}

export async function forwardFrameNotification(
this: MessengerMeta,
sequence: number,
payload: {
type: string;
meta?: JsonObject;
payload: JsonValue;
}
);
) {
const tabId = this.trace[0].tab.id;
return forwardWhenReady(tabId, sequence, payload).catch(reportError);
}

handlers.set(SHOW_ACTION_FRAME, async (_, sender) => {
export async function showActionFrame(this: MessengerMeta): Promise<void> {
const sender = this.trace[0];
const tabId = sender.tab.id;
tabFrames.delete(tabId);
const nonce = await showActionPanel({
Expand All @@ -263,19 +249,19 @@ handlers.set(SHOW_ACTION_FRAME, async (_, sender) => {
console.debug("Setting action frame nonce", { sender, nonce });
tabNonces.set(tabId, nonce);
tabSeqNumber.delete(tabId);
});
}

handlers.set(HIDE_ACTION_FRAME, async (_, sender) => {
export async function hideActionFrame(this: MessengerMeta): Promise<void> {
const sender = this.trace[0];
const tabId = sender.tab.id;
tabFrames.delete(tabId);
await hideActionPanel({ tabId, frameId: TOP_LEVEL_FRAME_ID });
console.debug("Clearing action frame nonce", { sender });
tabNonces.delete(tabId);
tabSeqNumber.delete(tabId);
});
}

if (isBackgroundPage()) {
browser.browserAction.onClicked.addListener(handleBrowserAction);
console.debug("Installed browserAction click listener");
browser.runtime.onMessage.addListener(handlers.asListener());
}
9 changes: 9 additions & 0 deletions src/background/messenger/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ export const uninstallContextMenu = getMethod("UNINSTALL_CONTEXT_MENU");
export const ensureContextMenu = getMethod("ENSURE_CONTEXT_MENU");
export const openTab = getMethod("OPEN_TAB");

export const browserAction = {
registerActionFrame: getMethod("REGISTER_ACTION_FRAME"),
forwardFrameNotification: getMethod("FORWARD_FRAME_NOTIFICATION", {
isNotification: true,
}),
showActionFrame: getMethod("SHOW_ACTION_FRAME"),
hideActionFrame: getMethod("HIDE_ACTION_FRAME"),
};
Comment on lines +59 to +65
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test report

Working

  • REGISTER_ACTION_FRAME
  • SHOW_ACTION_FRAME
  • HIDE_ACTION_FRAME

Untested

  • FORWARD_FRAME_NOTIFICATION

Can you tell me what I should set up to test this? I have not ported it messenger yet because a couple of key components might be missing

Copy link
Contributor

@twschiller twschiller Oct 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FORWARD_FRAME_NOTIFICATION is used to pass information from the content script on the main page to the sidebar panel. It's used in many of the methods in actionPanel/native.tsx via calls to renderPanels

The way to test would be:

If the messages aren't working you won't see the header for the panel and won't see any panel content on pages where the panel should appear


export const registry = {
getKind: getMethod("REGISTRY_GET_KIND"),
syncRemote: getMethod("REGISTRY_SYNC"),
Expand Down
9 changes: 9 additions & 0 deletions src/background/messenger/registration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
openTab,
} from "@/background/executor";
import * as registry from "@/registry/localRegistry";
import * as browserAction from "@/background/browserAction";

expectContext("background");

Expand Down Expand Up @@ -60,6 +61,10 @@ declare global {
REGISTRY_GET_KIND: typeof registry.getKind;
REGISTRY_SYNC: typeof registry.syncRemote;
REGISTRY_FIND: typeof registry.find;
REGISTER_ACTION_FRAME: typeof browserAction.registerActionFrame;
FORWARD_FRAME_NOTIFICATION: typeof browserAction.forwardFrameNotification;
SHOW_ACTION_FRAME: typeof browserAction.showActionFrame;
HIDE_ACTION_FRAME: typeof browserAction.hideActionFrame;
}
}

Expand All @@ -84,4 +89,8 @@ registerMethods({
REGISTRY_GET_KIND: registry.getKind,
REGISTRY_SYNC: registry.syncRemote,
REGISTRY_FIND: registry.find,
REGISTER_ACTION_FRAME: browserAction.registerActionFrame,
FORWARD_FRAME_NOTIFICATION: browserAction.forwardFrameNotification,
SHOW_ACTION_FRAME: browserAction.showActionFrame,
HIDE_ACTION_FRAME: browserAction.hideActionFrame,
});
17 changes: 3 additions & 14 deletions src/blocks/effects/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@

import { Effect } from "@/types";
import { Schema } from "@/core";
import { browser } from "webextension-polyfill-ts";
import {
HIDE_ACTION_FRAME,
SHOW_ACTION_FRAME,
} from "@/background/browserAction";
import { browserAction } from "@/background/messenger/api";

const NO_PARAMS: Schema = {
$schema: "https://json-schema.org/draft/2019-09/schema#",
Expand All @@ -41,11 +37,7 @@ export class ShowSidebar extends Effect {
inputSchema: Schema = NO_PARAMS;

async effect(): Promise<void> {
console.debug("show sidebar");
await browser.runtime.sendMessage({
type: SHOW_ACTION_FRAME,
payload: {},
});
await browserAction.showActionFrame();
}
}

Expand All @@ -61,9 +53,6 @@ export class HideSidebar extends Effect {
inputSchema: Schema = NO_PARAMS;

async effect(): Promise<void> {
await browser.runtime.sendMessage({
type: HIDE_ACTION_FRAME,
payload: {},
});
await browserAction.hideActionFrame();
}
}