diff --git a/scripts/excmds_macros.py b/scripts/excmds_macros.py index ad4e52a7..ecc1376c 100755 --- a/scripts/excmds_macros.py +++ b/scripts/excmds_macros.py @@ -68,7 +68,7 @@ def get_block(lines): """next(lines) contains an open brace: return all the lines up to close brace. Moves the lines iterator, so useful for consuming a block. - + """ brace_balance = 0 block = "" @@ -139,7 +139,7 @@ def background(lines, context): return Messaging.message( "excmd_background", "{sig.name}", - [{message_params}], + {message_params} ) }}\n""".format(**locals())) diff --git a/src/background.ts b/src/background.ts index 1ca597f6..4a15a635 100644 --- a/src/background.ts +++ b/src/background.ts @@ -2,7 +2,7 @@ /* tslint:disable:import-spacing */ -import "@src/lib/browser_proxy_background" +import * as proxy_background from "@src/lib/browser_proxy_background" import * as controller from "@src/lib/controller" import * as perf from "@src/perf" @@ -55,8 +55,6 @@ controller.setExCmds({ "text": EditorCmds, "hint": HintingCmds }) -messaging.addListener("excmd_background", messaging.attributeCaller(excmds_background)) -messaging.addListener("controller_background", messaging.attributeCaller(controller)) // {{{ tri.contentLocation // When loading the background, use the active tab to know what the current content url is @@ -165,10 +163,19 @@ browser.tabs.onCreated.addListener( // An object to collect all of our statistics in one place. const statsLogger: perf.StatsLogger = new perf.StatsLogger() -messaging.addListener( - "performance_background", - messaging.attributeCaller(statsLogger), -) +export const messages = { + excmd_background: excmds_background, + controller_background: controller, + performance_background: statsLogger, + download_background: { + downloadUrl: download_background.downloadUrl, + downloadUrlAs: download_background.downloadUrlAs, + }, + browser_proxy_background: {shim: proxy_background.shim} +} +export type Messages = typeof messages + +messaging.setupListener(messages) // Listen for statistics from the background script and store // them. Set this one up to log directly to the statsLogger instead of // going through messaging. diff --git a/src/background/download_background.ts b/src/background/download_background.ts index 9ffd4ea3..e5c3d211 100644 --- a/src/background/download_background.ts +++ b/src/background/download_background.ts @@ -146,14 +146,3 @@ export async function downloadUrlAs(url: string, saveAs: string) { browser.downloads.onChanged.addListener(onDownloadComplete) }) } - -import * as Messaging from "@src/lib/messaging" - -// Get messages from content -Messaging.addListener( - "download_background", - Messaging.attributeCaller({ - downloadUrl, - downloadUrlAs, - }), -) diff --git a/src/excmds.ts b/src/excmds.ts index 898c6f39..7d4be06d 100644 --- a/src/excmds.ts +++ b/src/excmds.ts @@ -839,9 +839,9 @@ export async function restart() { //#content export async function saveas(...filename: string[]) { if (filename.length > 0) { - return Messaging.message("download_background", "downloadUrlAs", [window.location.href, filename.join(" ")]) + return Messaging.message("download_background", "downloadUrlAs", window.location.href, filename.join(" ")) } else { - return Messaging.message("download_background", "downloadUrl", [window.location.href, true]) + return Messaging.message("download_background", "downloadUrl", window.location.href, true) } } @@ -3962,7 +3962,7 @@ export async function hint(option?: string, selectors?: string, ...rest: string[ selectHints = hinting.pipe_elements( elems, elem => { - Messaging.message("download_background", "downloadUrl", [new URL(elem[attr], window.location.href).href, saveAs]) + Messaging.message("download_background", "downloadUrl", new URL(elem[attr], window.location.href).href, saveAs) return elem }, rapid, @@ -4074,7 +4074,7 @@ export function rot13(n: number) { */ //#content export function run_exstr(...commands: string[]) { - return Messaging.message("controller_background", "acceptExCmd", commands) + return Messaging.message("controller_background", "acceptExCmd", commands.join("")) } // }}} diff --git a/src/lib/browser_proxy.ts b/src/lib/browser_proxy.ts index c3398ad0..aad6f54c 100644 --- a/src/lib/browser_proxy.ts +++ b/src/lib/browser_proxy.ts @@ -7,11 +7,11 @@ const browserProxy = new Proxy(Object.create(null), { { get(_, func) { return (...args) => - message("browser_proxy_background", "shim", [ + message("browser_proxy_background", "shim", api, func, args, - ]) + ) }, }, ) diff --git a/src/lib/browser_proxy_background.ts b/src/lib/browser_proxy_background.ts index 56598447..e6c4aaee 100644 --- a/src/lib/browser_proxy_background.ts +++ b/src/lib/browser_proxy_background.ts @@ -1,11 +1,5 @@ /** Shim to access BG browser APIs from content. */ -function shim(api, func, args) { +export function shim(api, func, args) { return browser[api][func](...args) } - -import { addListener, attributeCaller, MessageType } from "@src/lib/messaging" -addListener( - "browser_proxy_background" as MessageType, - attributeCaller({ shim }), -) diff --git a/src/lib/messaging.ts b/src/lib/messaging.ts index e6ae906d..05bf5f4c 100644 --- a/src/lib/messaging.ts +++ b/src/lib/messaging.ts @@ -1,4 +1,5 @@ import { browserBg, activeTabId, ownTabId, getContext } from "@src/lib/webext" +import * as Messages from "@src/message_protocols" import Logger from "@src/lib/logging" const logger = new Logger("messaging") @@ -65,9 +66,48 @@ export function attributeCaller(obj) { return handler } +interface TypedMessage { + type: Type + command: Command + args: Parameters +} + +function backgroundHandler< + Root, + Type extends keyof Root, + Command extends keyof Root[Type] + >(root: Root, + message: TypedMessage, + sender: browser.runtime.MessageSender, + ): ReturnType { + return root[message.type][message.command](...message.args) +} + +export function setupListener(root: Root) { + browser.runtime.onMessage.addListener((message: any, sender: browser.runtime.MessageSender) => { + if (message.type in root) { + if (!(message.command in root[message.type])) + throw new Error(`missing handler in protocol ${message.type} ${message.command}`) + if (!Array.isArray(message.args)) + throw new Error(`wrong arguments in protocol ${message.type} ${message.command}`) + return backgroundHandler(root, message, sender) + } + }); +} + /** Send a message to non-content scripts */ -export async function message(type: NonTabMessageType, command, args?) { - return browser.runtime.sendMessage({ type, command, args } as Message) +export async function message< + Type extends keyof Messages.Background, + Command extends keyof Messages.Background[Type], + F extends ((...args: any) => any) & Messages.Background[Type][Command] + >(type: Type, command: Command, ...args: Parameters) { + const message: TypedMessage = { + type, + command, + args + } + + return browser.runtime.sendMessage>(message) } /** Message the active tab of the currentWindow */ diff --git a/src/message_protocols.ts b/src/message_protocols.ts new file mode 100644 index 00000000..b9c9674c --- /dev/null +++ b/src/message_protocols.ts @@ -0,0 +1,3 @@ +// This file re-exports types for message protocols for background, content and commandline contexts + +export { Messages as Background } from "@src/background" diff --git a/src/newtab.ts b/src/newtab.ts index 71416ed9..1ff1fd02 100644 --- a/src/newtab.ts +++ b/src/newtab.ts @@ -47,6 +47,6 @@ window.addEventListener("load", _ => { // Periodically nag people about updates. window.addEventListener("load", _ => { if (config.get("update", "nag") === true) { - Messaging.message("controller_background", "acceptExCmd", ["updatecheck auto_polite"]) + Messaging.message("controller_background", "acceptExCmd", "updatecheck auto_polite") } }) diff --git a/src/perf.ts b/src/perf.ts index cc606741..7c70855e 100644 --- a/src/perf.ts +++ b/src/perf.ts @@ -416,7 +416,5 @@ class MetricName { } function sendStats(list: PerformanceEntryList) { - messaging.message("performance_background", "receiveStatsJson", [ - JSON.stringify(list), - ]) + messaging.message("performance_background", "receiveStatsJson", JSON.stringify(list)) }