You've already forked bilibili-subtitle
fix
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { MESSAGE_TARGET_EXTENSION, MESSAGE_TARGET_INJECT, MESSAGE_TO_EXTENSION_ROUTE_MSG } from '@/consts/const'
|
import { MESSAGE_TARGET_EXTENSION, MESSAGE_TARGET_INJECT, MESSAGE_TO_EXTENSION_ROUTE_MSG } from '@/consts/const'
|
||||||
import PortMessageHandler from './PortMessageHandler'
|
import Layer1Protocol from './Layer1Protocol'
|
||||||
|
|
||||||
export type PortContext = {
|
export type PortContext = {
|
||||||
id: string
|
id: string
|
||||||
@@ -7,7 +7,7 @@ export type PortContext = {
|
|||||||
tabId: number
|
tabId: number
|
||||||
type: 'inject' | 'app'
|
type: 'inject' | 'app'
|
||||||
port: chrome.runtime.Port
|
port: chrome.runtime.Port
|
||||||
portMessageHandler: PortMessageHandler
|
portMessageHandler: Layer1Protocol
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExtensionMessage {
|
class ExtensionMessage {
|
||||||
@@ -86,7 +86,7 @@ class ExtensionMessage {
|
|||||||
if (tabId != null) {
|
if (tabId != null) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const portContext: PortContext = {id, name, tabId, port, type}
|
const portContext: PortContext = {id, name, tabId, port, type}
|
||||||
const portMessageHandler = new PortMessageHandler<MessageData, MessageResult>(async (value: MessageData) => {
|
const portMessageHandler = new Layer1Protocol<MessageData, MessageResult>(async (value: MessageData) => {
|
||||||
return handler(value, portContext)
|
return handler(value, portContext)
|
||||||
}, port)
|
}, port)
|
||||||
portContext.portMessageHandler = portMessageHandler
|
portContext.portMessageHandler = portMessageHandler
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
import { MESSAGE_TARGET_APP, MESSAGE_TARGET_EXTENSION, MESSAGE_TARGET_INJECT, MESSAGE_TO_EXTENSION_ROUTE_MSG } from '@/consts/const'
|
import { MESSAGE_TARGET_APP, MESSAGE_TARGET_EXTENSION, MESSAGE_TARGET_INJECT, MESSAGE_TO_EXTENSION_ROUTE_MSG } from '@/consts/const'
|
||||||
import PortMessageHandler from './PortMessageHandler'
|
import Layer1Protocol from './Layer1Protocol'
|
||||||
|
|
||||||
class InjectMessage {
|
class InjectMessage {
|
||||||
port?: chrome.runtime.Port
|
port?: chrome.runtime.Port
|
||||||
portMessageHandler?: PortMessageHandler
|
portMessageHandler?: Layer1Protocol
|
||||||
//类实例
|
//类实例
|
||||||
methods?: {
|
methods?: {
|
||||||
[key: string]: (params: any, context: MethodContext) => Promise<any>
|
[key: string]: (params: any, context: MethodContext) => Promise<any>
|
||||||
@@ -71,7 +71,7 @@ class InjectMessage {
|
|||||||
this.port = chrome.runtime.connect(import.meta.env.VITE_EXTENSION_ID, {
|
this.port = chrome.runtime.connect(import.meta.env.VITE_EXTENSION_ID, {
|
||||||
name: MESSAGE_TARGET_INJECT,
|
name: MESSAGE_TARGET_INJECT,
|
||||||
})
|
})
|
||||||
this.portMessageHandler = new PortMessageHandler<MessageData, MessageResult>(this.messageHandler, this.port)
|
this.portMessageHandler = new Layer1Protocol<MessageData, MessageResult>(this.messageHandler, this.port)
|
||||||
this.portMessageHandler!.startListen()
|
this.portMessageHandler!.startListen()
|
||||||
this.portMessageHandler!.init('inject')
|
this.portMessageHandler!.init('inject')
|
||||||
this.methods = methods
|
this.methods = methods
|
||||||
|
107
src/messaging/Layer1Protocol.ts
Normal file
107
src/messaging/Layer1Protocol.ts
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
// 请求信息
|
||||||
|
type ReqMsg<L1Req = any, L1Res = any> = {
|
||||||
|
id: string
|
||||||
|
// 类型
|
||||||
|
type: 'req' | 'res'
|
||||||
|
// 请求
|
||||||
|
req?: L1Req
|
||||||
|
// 响应
|
||||||
|
res?: RespMsg<L1Res>
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应信息
|
||||||
|
type RespMsg<T = any> = {
|
||||||
|
code: number
|
||||||
|
data?: T
|
||||||
|
msg?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个 Layer1Protocol 类,用于持久监听 port 并通过消息 ID 处理响应,支持超时
|
||||||
|
class Layer1Protocol<L1Req = any, L1Res = any> {
|
||||||
|
private port: chrome.runtime.Port
|
||||||
|
private timeout: number
|
||||||
|
private messageMap: Map<string, { resolve: (value: L1Res) => void, timer: number }>
|
||||||
|
private handler: (value: L1Req) => Promise<L1Res>
|
||||||
|
private type?: 'inject' | 'app'
|
||||||
|
private tabId?: number
|
||||||
|
|
||||||
|
constructor(handler: (value: L1Req) => Promise<L1Res>, port: chrome.runtime.Port, timeout = 30000) { // 默认超时 30 秒
|
||||||
|
this.port = port;
|
||||||
|
this.timeout = timeout;
|
||||||
|
this.messageMap = new Map();
|
||||||
|
this.handler = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
init(type: 'inject' | 'app', tabId?: number) {
|
||||||
|
this.type = type
|
||||||
|
this.tabId = tabId
|
||||||
|
this.port.postMessage({
|
||||||
|
type,
|
||||||
|
tabId,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
startListen() {
|
||||||
|
// 持久监听 port.onMessage
|
||||||
|
this.port.onMessage.addListener((msg: ReqMsg<L1Req, L1Res>) => {
|
||||||
|
const { id, type, req, res } = msg;
|
||||||
|
if (type === 'req') {
|
||||||
|
this.handler(req!).then(res => {
|
||||||
|
const response: RespMsg<L1Res> = {
|
||||||
|
code: 200,
|
||||||
|
msg: 'success',
|
||||||
|
data: res
|
||||||
|
}
|
||||||
|
this.port.postMessage({ id, type: 'res', res: response });
|
||||||
|
}).catch(error => {
|
||||||
|
const response: RespMsg<L1Res> = {
|
||||||
|
code: 500,
|
||||||
|
msg: error.message,
|
||||||
|
}
|
||||||
|
this.port.postMessage({ id, type: 'res', res: response });
|
||||||
|
});
|
||||||
|
} else if (type === 'res') {
|
||||||
|
if (this.messageMap.has(id)) {
|
||||||
|
const { resolve, timer } = this.messageMap.get(id)!;
|
||||||
|
// 清除超时定时器
|
||||||
|
clearTimeout(timer);
|
||||||
|
// 移除消息 ID
|
||||||
|
this.messageMap.delete(id);
|
||||||
|
// 通过 ID 找到对应的 Promise 并 resolve
|
||||||
|
resolve(res!.data!);
|
||||||
|
}else {
|
||||||
|
console.error('unknown response message id: ', id)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('unknown message type: ', type)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 Promise 发送消息并等待响应,支持超时
|
||||||
|
sendMessage(req: L1Req): Promise<L1Res> {
|
||||||
|
const id = this._generateUniqueId();
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// 设置一个超时定时器
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
// 超时后执行 reject 并从 Map 中删除
|
||||||
|
this.messageMap.delete(id);
|
||||||
|
reject(new Error(`Request timed out after ${this.timeout / 1000} seconds`));
|
||||||
|
}, this.timeout);
|
||||||
|
|
||||||
|
// 将 resolve 和 timer 函数与消息 ID 绑定,存入 Map
|
||||||
|
this.messageMap.set(id, { resolve, timer });
|
||||||
|
|
||||||
|
// 发送消息,并附带 ID
|
||||||
|
this.port.postMessage({ id, type: 'req', req });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成唯一 ID(简单示例,可以使用更复杂的生成策略)
|
||||||
|
_generateUniqueId() {
|
||||||
|
return crypto.randomUUID()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Layer1Protocol
|
@@ -1,102 +0,0 @@
|
|||||||
export type RespMsg<T = any> = {
|
|
||||||
code: number
|
|
||||||
data?: T
|
|
||||||
msg?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type PortMessageType = 'req' | 'res'
|
|
||||||
|
|
||||||
export type PortMessage<Req = any, Res = any> = {
|
|
||||||
msgId: string
|
|
||||||
msgType: PortMessageType
|
|
||||||
req?: Req
|
|
||||||
res?: RespMsg<Res>
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建一个 PortMessageHandler 类,用于持久监听 port 并通过消息 ID 处理响应,支持超时
|
|
||||||
class PortMessageHandler<Req = any, Res = any> {
|
|
||||||
private port: chrome.runtime.Port
|
|
||||||
private timeout: number
|
|
||||||
private messageMap: Map<string, { resolve: (value: Res) => void, timer: number }>
|
|
||||||
private handler: (value: Req) => Promise<Res>
|
|
||||||
private type?: 'inject' | 'app'
|
|
||||||
private tabId?: number
|
|
||||||
|
|
||||||
constructor(handler: (value: Req) => Promise<Res>, port: chrome.runtime.Port, timeout = 30000) { // 默认超时 30 秒
|
|
||||||
this.port = port;
|
|
||||||
this.timeout = timeout;
|
|
||||||
this.messageMap = new Map();
|
|
||||||
this.handler = handler
|
|
||||||
}
|
|
||||||
|
|
||||||
init(type: 'inject' | 'app', tabId?: number) {
|
|
||||||
this.type = type
|
|
||||||
this.tabId = tabId
|
|
||||||
this.port.postMessage({
|
|
||||||
type,
|
|
||||||
tabId,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
startListen() {
|
|
||||||
// 持久监听 port.onMessage
|
|
||||||
this.port.onMessage.addListener((msg: PortMessage<Req, Res>) => {
|
|
||||||
console.log('msg', this.type, this.tabId, msg)
|
|
||||||
const { msgId, msgType, req, res } = msg;
|
|
||||||
if (msgType === 'req') {
|
|
||||||
this.handler(req!).then(res => {
|
|
||||||
const response: RespMsg<Res> = {
|
|
||||||
code: 200,
|
|
||||||
msg: 'success',
|
|
||||||
data: res
|
|
||||||
}
|
|
||||||
this.port.postMessage({ msgId, msgType: 'res', res: response });
|
|
||||||
}).catch(error => {
|
|
||||||
const response: RespMsg<Res> = {
|
|
||||||
code: 500,
|
|
||||||
msg: error.message,
|
|
||||||
}
|
|
||||||
this.port.postMessage({ msgId, msgType: 'res', res: response });
|
|
||||||
});
|
|
||||||
} else if (msgType === 'res') {
|
|
||||||
if (this.messageMap.has(msgId)) {
|
|
||||||
const { resolve, timer } = this.messageMap.get(msgId)!;
|
|
||||||
// 清除超时定时器
|
|
||||||
clearTimeout(timer);
|
|
||||||
// 处理完毕后,移除该消息 ID
|
|
||||||
this.messageMap.delete(msgId);
|
|
||||||
// 通过 ID 找到对应的 Promise 并 resolve
|
|
||||||
resolve(res!.data!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用 Promise 发送消息并等待响应,支持超时
|
|
||||||
sendMessage(req: Req): Promise<Res> {
|
|
||||||
const msgId = this._generateUniqueId();
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// 设置一个超时定时器
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
// 超时后执行 reject 并从 Map 中删除
|
|
||||||
this.messageMap.delete(msgId);
|
|
||||||
reject(new Error(`Request timed out after ${this.timeout / 1000} seconds`));
|
|
||||||
}, this.timeout);
|
|
||||||
|
|
||||||
// 将 resolve 和 timer 函数与消息 ID 绑定,存入 Map
|
|
||||||
this.messageMap.set(msgId, { resolve, timer });
|
|
||||||
|
|
||||||
// 发送消息,并附带 ID
|
|
||||||
this.port.postMessage({ msgId, msgType: 'req', req });
|
|
||||||
console.log('sendMessage>>>', msgId, 'req', req)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成唯一 ID(简单示例,可以使用更复杂的生成策略)
|
|
||||||
_generateUniqueId() {
|
|
||||||
return crypto.randomUUID()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PortMessageHandler
|
|
@@ -1,12 +1,12 @@
|
|||||||
import { MESSAGE_TARGET_EXTENSION, MESSAGE_TARGET_INJECT, MESSAGE_TO_EXTENSION_ROUTE_MSG } from '@/consts/const'
|
import { MESSAGE_TARGET_EXTENSION, MESSAGE_TARGET_INJECT, MESSAGE_TO_EXTENSION_ROUTE_MSG } from '@/consts/const'
|
||||||
import { injectWaiter } from './useMessageService'
|
import { injectWaiter } from './useMessageService'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import PortMessageHandler from './PortMessageHandler'
|
import Layer1Protocol from './Layer1Protocol'
|
||||||
|
|
||||||
const useMessage = () => {
|
const useMessage = () => {
|
||||||
const sendExtension = useCallback(async <T = any>(method: string, params?: any) => {
|
const sendExtension = useCallback(async <T = any>(method: string, params?: any) => {
|
||||||
// wait
|
// wait
|
||||||
const portMessageHandler = await injectWaiter.wait() as PortMessageHandler<MessageData, MessageResult>
|
const portMessageHandler = await injectWaiter.wait() as Layer1Protocol<MessageData, MessageResult>
|
||||||
// send message
|
// send message
|
||||||
const messageResult = await portMessageHandler.sendMessage({
|
const messageResult = await portMessageHandler.sendMessage({
|
||||||
from: 'app',
|
from: 'app',
|
||||||
|
@@ -3,14 +3,14 @@ import {
|
|||||||
MESSAGE_TARGET_APP,
|
MESSAGE_TARGET_APP,
|
||||||
} from '@/consts/const'
|
} from '@/consts/const'
|
||||||
import { Waiter } from '@kky002/kky-util'
|
import { Waiter } from '@kky002/kky-util'
|
||||||
import PortMessageHandler from './PortMessageHandler'
|
import Layer1Protocol from './Layer1Protocol'
|
||||||
|
|
||||||
const debug = (...args: any[]) => {
|
const debug = (...args: any[]) => {
|
||||||
console.debug('[App Messaging]', ...args)
|
console.debug('[App Messaging]', ...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
let portMessageHandlerInit: boolean = false
|
let portMessageHandlerInit: boolean = false
|
||||||
let portMessageHandler: PortMessageHandler<MessageData, MessageResult> | undefined
|
let portMessageHandler: Layer1Protocol<MessageData, MessageResult> | undefined
|
||||||
// let postInjectMessage: (method: string, params: PostMessagePayload) => Promise<PostMessageResponse> | undefined
|
// let postInjectMessage: (method: string, params: PostMessagePayload) => Promise<PostMessageResponse> | undefined
|
||||||
|
|
||||||
export const injectWaiter = new Waiter<any>(() => ({
|
export const injectWaiter = new Waiter<any>(() => ({
|
||||||
@@ -75,7 +75,7 @@ const useMessageService = (methods?: {
|
|||||||
}, [])
|
}, [])
|
||||||
portMessageHandler = useMemo(() => {
|
portMessageHandler = useMemo(() => {
|
||||||
if (messageHandler && port) {
|
if (messageHandler && port) {
|
||||||
const pmh = new PortMessageHandler<MessageData, MessageResult>(messageHandler, port)
|
const pmh = new Layer1Protocol<MessageData, MessageResult>(messageHandler, port)
|
||||||
|
|
||||||
//get tabId from url params
|
//get tabId from url params
|
||||||
let tabId = window.location.search.split('tabId=')[1]
|
let tabId = window.location.search.split('tabId=')[1]
|
||||||
|
Reference in New Issue
Block a user