消息传递重构&支持侧边面板

This commit is contained in:
IndieKKY
2024-10-05 19:55:43 +08:00
parent c1c21c2fee
commit b283695b02
18 changed files with 454 additions and 214 deletions

View File

@@ -1,12 +1,15 @@
import { MESSAGE_TARGET_EXTENSION, MESSAGE_TARGET_INJECT } from '@/const'
import { MESSAGE_TARGET_APP, MESSAGE_TARGET_EXTENSION, MESSAGE_TARGET_INJECT, MESSAGE_TO_EXTENSION_ROUTE_MSG } from '@/const'
import { PostMessagePayload, PostMessageResponse, startListening } from 'postmessage-promise'
import PortMessageHandler from './PortMessageHandler'
class InjectMessage {
port?: chrome.runtime.Port
portMessageHandler?: PortMessageHandler
//类实例
methods?: {
[key: string]: (params: any, context: MethodContext) => Promise<any>
}
postMessageToApp?: (method: string, payload: PostMessagePayload) => Promise<PostMessageResponse>
// postMessageToApp?: (method: string, payload: PostMessagePayload) => Promise<PostMessageResponse>
debug = (...args: any[]) => {
console.debug('[Inject Messaging]', ...args)
@@ -15,27 +18,30 @@ class InjectMessage {
/**
* @param sendResponse No matter what is returned, this method will definitely be called.
*/
messageHandler = (event: MessageData, sender: chrome.runtime.MessageSender | null, sendResponse: (response?: MessageResult) => void) => {
const source = sender != null ? ((sender.tab != null) ? `tab ${sender.tab.url ?? ''}` : 'extension') : 'app'
this.debug(`${source} => `, JSON.stringify(event))
messageHandler = async (event: MessageData): Promise<MessageResult> => {
this.debug(`${event.from} => `, JSON.stringify(event))
// check event target
if (event.target !== MESSAGE_TARGET_INJECT) return
if (event.target !== MESSAGE_TARGET_INJECT) return Promise.resolve({
success: false,
code: 501,
message: 'Target Error: ' + event.target,
})
const method = this.methods?.[event.method]
if (method != null) {
method(event.params, {
return method(event.params, {
from: event.from,
event,
sender,
// sender,
}).then(data => {
// debug(`${source} <= `, event.method, JSON.stringify(data))
return data
}).then(data => sendResponse({
success: true,
code: 200,
data,
})).catch(err => {
return {
success: true,
code: 200,
data,
}
}).catch(err => {
console.error(err)
let message
if (err instanceof Error) {
@@ -45,55 +51,60 @@ class InjectMessage {
} else {
message = 'error: ' + JSON.stringify(err)
}
sendResponse({
return {
success: false,
code: 500,
message,
})
}
})
return true
} else {
console.error('Unknown method:', event.method)
sendResponse({
return {
success: false,
code: 501,
message: 'Unknown method: ' + event.method,
})
}
}
}
init(methods: {
[key: string]: (params: any, context: MethodContext) => Promise<any>
}) {
this.port = chrome.runtime.connect(import.meta.env.VITE_EXTENSION_ID, {
name: MESSAGE_TARGET_INJECT,
})
this.portMessageHandler = new PortMessageHandler<MessageData, MessageResult>(this.messageHandler, this.port)
this.portMessageHandler!.startListen()
this.portMessageHandler!.init('inject')
this.methods = methods
// listen message from app
startListening({}).then(e => {
const { postMessage, listenMessage, destroy } = e
this.postMessageToApp = postMessage
listenMessage((method, params, sendResponse) => {
this.messageHandler({
from: 'app',
target: MESSAGE_TARGET_INJECT,
method,
params,
}, null, sendResponse)
})
}).catch(console.error)
// startListening({}).then(e => {
// const { postMessage, listenMessage, destroy } = e
// this.postMessageToApp = postMessage
// listenMessage((method, params, sendResponse) => {
// this.messageHandler({
// from: 'app',
// target: MESSAGE_TARGET_INJECT,
// method,
// params,
// }, null, sendResponse)
// })
// }).catch(console.error)
/**
* listen message from extension
* Attention: return true if you need to sendResponse asynchronously
*/
chrome.runtime.onMessage.addListener(this.messageHandler)
// chrome.runtime.onMessage.addListener(this.messageHandler)
}
sendExtension = async <T = any>(method: string, params?: any): Promise<T> => {
return await chrome.runtime.sendMessage<MessageData, MessageResult>({
const messageData: MessageData = {
from: 'inject',
target: MESSAGE_TARGET_EXTENSION,
method,
params: params ?? {},
}).then((messageResult) => {
}
return await this.portMessageHandler!.sendMessage(messageData).then((messageResult) => {
if (messageResult.success) {
return messageResult.data as T
} else {
@@ -103,20 +114,14 @@ class InjectMessage {
}
sendApp = async <T>(method: string, params: any): Promise<T> => {
if (this.postMessageToApp != null) {
const messageResult = await this.postMessageToApp(method, params) as MessageResult | undefined
if (messageResult != null) {
if (messageResult.success) {
return messageResult.data as T
} else {
throw new Error(messageResult.message)
}
} else {
throw new Error('no response')
}
} else {
throw new Error('error: postMessageToApp is not initialized')
if (method === 'setVideoInfo') {
console.log('sendApp>>>', method, params)
}
return this.sendExtension(MESSAGE_TO_EXTENSION_ROUTE_MSG, {
target: MESSAGE_TARGET_APP,
method,
params,
})
}
}