diff --git a/src/chrome/background.ts b/src/chrome/background.ts index d28c9d8..2225c68 100644 --- a/src/chrome/background.ts +++ b/src/chrome/background.ts @@ -2,6 +2,7 @@ import {v4} from 'uuid' import {handleTask, initTaskService, tasksMap} from './taskService' import {MESSAGE_TARGET_INJECT, MESSAGE_TO_EXTENSION_ADD_TASK, MESSAGE_TO_EXTENSION_CLOSE_SIDE_PANEL, MESSAGE_TO_EXTENSION_GET_TASK, MESSAGE_TO_EXTENSION_SHOW_FLAG, MESSAGE_TO_INJECT_TOGGLE_DISPLAY, STORAGE_ENV} from '@/consts/const' import ExtensionMessage from '@/messaging/ExtensionMessage' +import { TAG_TARGET_INJECT } from '@/messaging/const' const setBadgeOk = async (tabId: number, ok: boolean) => { await chrome.action.setBadgeText({ @@ -114,7 +115,7 @@ chrome.action.onClicked.addListener(async (tab) => { }) } else { closeSidePanel() - extensionMessage.broadcastMessageExact([tab.id!], MESSAGE_TARGET_INJECT, MESSAGE_TO_INJECT_TOGGLE_DISPLAY).catch(console.error) + extensionMessage.broadcastMessageExact([tab.id!], [TAG_TARGET_INJECT], MESSAGE_TO_INJECT_TOGGLE_DISPLAY).catch(console.error) } }) }) diff --git a/src/messaging/ExtensionMessage.ts b/src/messaging/ExtensionMessage.ts index 37ff43d..3814dc5 100644 --- a/src/messaging/ExtensionMessage.ts +++ b/src/messaging/ExtensionMessage.ts @@ -1,7 +1,6 @@ import { MESSAGE_TARGET_INJECT } from '@/consts/const' import Layer1Protocol from './Layer1Protocol' -import { L2ReqMsg, L2ResMsg, MESSAGE_TO_EXTENSION_ROUTE_MSG } from './const' - +import { L2ReqMsg, L2ResMsg, MESSAGE_TO_EXTENSION_HANDSHAKE, MESSAGE_TO_EXTENSION_ROUTE_MSG } from './const' export type PortContext = { id: string @@ -10,91 +9,83 @@ export type PortContext = { portMessageHandler: Layer1Protocol ready: boolean - tabId?: number - type?: 'inject' | 'app' + tabId?: number // 所属tab + tags?: string[] // 标签,用来筛选消息发送目标 +} + +export type L2MethodHandler = (params: any, context: MethodContext, portContext: PortContext) => Promise +export type L2MethodHandlers = { + [key: string]: L2MethodHandler } class ExtensionMessage { portIdToPort: Map = new Map() - methods?: { - [key: string]: (params: any, context: MethodContext) => Promise - } + methods?: L2MethodHandlers debug = (...args: any[]) => { console.debug('[Extension Messaging]', ...args) } - - init = (methods: { - [key: string]: (params: any, context: MethodContext) => Promise - }) => { - const innerMethods = { - [MESSAGE_TO_EXTENSION_ROUTE_MSG]: (params: any, context: MethodContext) => { - return this.broadcastMessageExact([context.tabId!], params.target, params.method, params.params) - } - } - this.methods = {...innerMethods, ...methods} + init = (methods: L2MethodHandlers) => { + const innerMethods: L2MethodHandlers = { + [MESSAGE_TO_EXTENSION_HANDSHAKE]: async (params: any, context: MethodContext, portContext: PortContext) => { + const tags = params.tags + let tabId = params.tabId - const handler = async (req: L2ReqMsg, portContext: PortContext): Promise => { - const { tabId } = portContext - const method = this.methods?.[req.method] - if (method != null) { - return method(req.params, { - from: req.from, - event: req, - tabId, - // sender: portContext.port.sender, - }).then(data => ({ - code: 200, - data, - })).catch(err => { - console.error(err) - return { - code: 500, - message: err.message, - } - }) - } else { - return { - code: 501, - message: 'Unknown method: ' + req.method, + //get current tabId + if (tabId == null) { + const tabs = await chrome.tabs.query({ + active: true, + currentWindow: true, + }) + tabId = tabs[0]?.id } - } + + portContext.tabId = tabId + portContext.tags = tags + portContext.ready = true + }, + [MESSAGE_TO_EXTENSION_ROUTE_MSG]: async (params: any, context: MethodContext) => { + return this.broadcastMessageExact([context.tabId!], params.tags, params.method, params.params) + }, } + this.methods = { ...innerMethods, ...methods } + chrome.runtime.onConnect.addListener((port: chrome.runtime.Port) => { this.debug('onConnect', port) const id = crypto.randomUUID() const name = port.name + // 创建消息处理器 const portMessageHandler = new Layer1Protocol(async (req: L2ReqMsg) => { - // 初始化消息 - if (req.method === '_init') { - const type = req.params.type - let tabId = req.params.tabId - - //get current tabId - if (tabId == null) { - const tabs = await chrome.tabs.query({ - active: true, - currentWindow: true, - }) - tabId = tabs[0]?.id - } - - portContext.tabId = tabId - portContext.type = type - portContext.ready = true - - return { + const { tabId } = portContext + const method = this.methods?.[req.method] + if (method != null) { + return method(req.params, { + from: req.from, + event: req, + tabId, + // sender: portContext.port.sender, + }, portContext).then(data => ({ code: 200, - } as L2ResMsg + data, + })).catch(err => { + console.error(err) + return { + code: 500, + msg: err.message, + } + }) + } else { + return { + code: 501, + msg: 'Unknown method: ' + req.method, + } } - - // 处理消息 - return handler(req, portContext) }, port) - const portContext: PortContext = {id, name, port, portMessageHandler, ready: false} + // 创建portContext + const portContext: PortContext = { id, name, port, portMessageHandler, ready: false } this.portIdToPort.set(id, portContext) // 监听断开连接 @@ -105,15 +96,22 @@ class ExtensionMessage { }) } + //tags 如果为null,则不检查tags,如果为空数组,则不会发送消息 //返回:最后一个响应(因此如果只发送给一个tab,则返回的是该tab的响应) - broadcastMessageExact = async (tabIds: number[], target: string, method: string, params?: any) => { - const targetType = target === MESSAGE_TARGET_INJECT ? 'inject' : 'app' + broadcastMessageExact = async (tabIds: number[], tags: string[] | null, method: string, params?: any) => { + // 如果tags为空数组,则不会发送消息 + if (tags != null && tags.length === 0) { + return + } + let res: L2ResMsg | undefined for (const portContext of this.portIdToPort.values()) { + //check tabId if (tabIds.includes(portContext.tabId!)) { - if (targetType === portContext.type) { + //check tags + if (tags == null || tags.some(tag => portContext.tags?.includes(tag))) { try { - const req: L2ReqMsg = {target, method, params, from: 'extension'} + const req: L2ReqMsg = { method, params, from: 'extension' } res = await portContext.portMessageHandler.sendMessage(req) } catch (e) { console.error('send message to port error', portContext.id, e) @@ -124,13 +122,13 @@ class ExtensionMessage { return res?.data } - broadcastMessage = async (ignoreTabIds: number[] | undefined | null, target: string, method: string, params?: any) => { + broadcastMessage = async (ignoreTabIds: number[] | undefined | null, tags: string[], method: string, params?: any) => { const tabs = await chrome.tabs.query({ discarded: false, }) const tabIds: number[] = tabs.map(tab => tab.id).filter(tabId => tabId != null) as number[] const filteredTabIds: number[] = tabIds.filter(tabId => !ignoreTabIds?.includes(tabId)) - await this.broadcastMessageExact(filteredTabIds, target, method, params) + await this.broadcastMessageExact(filteredTabIds, tags, method, params) } } diff --git a/src/messaging/InjectMessage.ts b/src/messaging/InjectMessage.ts index 3dc97a8..04d7958 100644 --- a/src/messaging/InjectMessage.ts +++ b/src/messaging/InjectMessage.ts @@ -1,6 +1,6 @@ import { MESSAGE_TARGET_APP, MESSAGE_TARGET_EXTENSION, MESSAGE_TARGET_INJECT } from '@/consts/const' import Layer1Protocol from './Layer1Protocol' -import { L2ReqMsg, L2ResMsg, MESSAGE_TO_EXTENSION_ROUTE_MSG } from './const' +import { L2ReqMsg, L2ResMsg, MESSAGE_TO_EXTENSION_HANDSHAKE, MESSAGE_TO_EXTENSION_ROUTE_MSG, TAG_TARGET_APP, TAG_TARGET_INJECT } from './const' class InjectMessage { port?: chrome.runtime.Port @@ -18,11 +18,11 @@ class InjectMessage { this.debug(`${req.from} => `, JSON.stringify(req)) // check event target - if (req.target !== MESSAGE_TARGET_INJECT) return Promise.resolve({ - success: false, - code: 501, - message: 'Target Error: ' + req.target, - }) + // if (req.target !== MESSAGE_TARGET_INJECT) return Promise.resolve({ + // success: false, + // code: 501, + // message: 'Target Error: ' + req.target, + // }) const method = this.methods?.[req.method] if (method != null) { @@ -38,23 +38,23 @@ class InjectMessage { } }).catch(err => { console.error(err) - let message + let msg if (err instanceof Error) { - message = err.message + msg = err.message } else if (typeof err === 'string') { - message = err + msg = err } else { - message = 'error: ' + JSON.stringify(err) + msg = 'error: ' + JSON.stringify(err) } return { code: 500, - message, + msg, } }) } else { return { code: 501, - message: 'Unknown method: ' + req.method, + msg: 'Unknown method: ' + req.method, } } } @@ -69,26 +69,24 @@ class InjectMessage { this.portMessageHandler = new Layer1Protocol(this.messageHandler, this.port) this.portMessageHandler.sendMessage({ from: 'inject', - target: MESSAGE_TARGET_EXTENSION, - method: '_init', + method: MESSAGE_TO_EXTENSION_HANDSHAKE, params: { type: 'inject', + tags: [TAG_TARGET_INJECT], }, }) } sendExtension = async (method: string, params?: any): Promise => { - const req: L2ReqMsg = { + return await this.portMessageHandler!.sendMessage({ from: 'inject', - target: MESSAGE_TARGET_EXTENSION, method, params: params ?? {}, - } - return await this.portMessageHandler!.sendMessage(req).then((res) => { + }).then((res) => { if (res.code === 200) { return res.data as T } else { - throw new Error(res.message) + throw new Error(res.msg) } }) } @@ -98,7 +96,7 @@ class InjectMessage { console.log('sendApp>>>', method, params) } return this.sendExtension(MESSAGE_TO_EXTENSION_ROUTE_MSG, { - target: MESSAGE_TARGET_APP, + tags: [TAG_TARGET_APP], method, params, }) diff --git a/src/messaging/const.ts b/src/messaging/const.ts index c5d50b4..523a0de 100644 --- a/src/messaging/const.ts +++ b/src/messaging/const.ts @@ -1,7 +1,7 @@ // 请求信息 export type L2ReqMsg = { from: 'extension' | 'inject' | 'app' - target: string + // target: string method: string params?: any // [key: string]: any @@ -10,8 +10,12 @@ export type L2ReqMsg = { // 响应信息 export type L2ResMsg = { code: number - message?: string + msg?: string data?: L2Res } +export const MESSAGE_TO_EXTENSION_HANDSHAKE = 'handshake' export const MESSAGE_TO_EXTENSION_ROUTE_MSG = 'routeMsg' + +export const TAG_TARGET_INJECT = 'target:inject' +export const TAG_TARGET_APP = 'target:app' diff --git a/src/messaging/useMessage.ts b/src/messaging/useMessage.ts index bd4dc1c..c8f3706 100644 --- a/src/messaging/useMessage.ts +++ b/src/messaging/useMessage.ts @@ -2,7 +2,7 @@ import { MESSAGE_TARGET_EXTENSION, MESSAGE_TARGET_INJECT } from '@/consts/const' import { injectWaiter } from './useMessageService' import { useCallback } from 'react' import Layer1Protocol from './Layer1Protocol' -import { L2ReqMsg, L2ResMsg, MESSAGE_TO_EXTENSION_ROUTE_MSG } from './const' +import { L2ReqMsg, L2ResMsg, MESSAGE_TO_EXTENSION_ROUTE_MSG, TAG_TARGET_INJECT } from './const' const useMessage = () => { const sendExtension = useCallback(async (method: string, params?: any) => { @@ -11,20 +11,19 @@ const useMessage = () => { // send message const res = await pmh.sendMessage({ from: 'app', - target: MESSAGE_TARGET_EXTENSION, method, params: params ?? {}, }) if (res.code === 200) { return res.data as T } else { - throw new Error(res.message) + throw new Error(res.msg) } }, []) const sendInject = useCallback(async (method: string, params?: any): Promise => { return await sendExtension(MESSAGE_TO_EXTENSION_ROUTE_MSG, { - target: MESSAGE_TARGET_INJECT, + tags: [TAG_TARGET_INJECT], method, params: params ?? {}, }) diff --git a/src/messaging/useMessageService.ts b/src/messaging/useMessageService.ts index 5053a8e..c632913 100644 --- a/src/messaging/useMessageService.ts +++ b/src/messaging/useMessageService.ts @@ -4,7 +4,7 @@ import { } from '@/consts/const' import { Waiter } from '@kky002/kky-util' import Layer1Protocol from './Layer1Protocol' -import { L2ReqMsg, L2ResMsg } from './const' +import { L2ReqMsg, L2ResMsg, MESSAGE_TO_EXTENSION_HANDSHAKE, TAG_TARGET_APP } from './const' const debug = (...args: any[]) => { console.debug('[App Messaging]', ...args) @@ -25,11 +25,11 @@ const useMessageService = (methods?: { const messageHandler = useCallback(async (req: L2ReqMsg): Promise => { debug(`${req.from} => `, JSON.stringify(req)) - // check event target - if (req.target !== MESSAGE_TARGET_APP) return { - code: 501, - message: 'Target Error: ' + req.target, - } + // // check event target + // if (req.target !== MESSAGE_TARGET_APP) return { + // code: 501, + // msg: 'Target Error: ' + req.target, + // } const method = methods?.[req.method] if (method != null) { @@ -44,23 +44,23 @@ const useMessageService = (methods?: { } }).catch(err => { console.error(err) - let message + let msg if (err instanceof Error) { - message = err.message + msg = err.message } else if (typeof err === 'string') { - message = err + msg = err } else { - message = 'error: ' + JSON.stringify(err) + msg = 'error: ' + JSON.stringify(err) } return { code: 500, - message, + msg, } }) } else { return { code: 501, - message: 'Unknown method: ' + req.method, + msg: 'Unknown method: ' + req.method, } } }, [methods]) @@ -79,12 +79,13 @@ const useMessageService = (methods?: { let tabId = tabIdStr ? parseInt(tabIdStr) : undefined // 初始化 pmh.sendMessage({ - method: '_init', + from: 'app', + method: MESSAGE_TO_EXTENSION_HANDSHAKE, params: { - type: 'app', tabId, + tags: [TAG_TARGET_APP], }, - } as L2ReqMsg) + }) portMessageHandlerInit = true return pmh