This commit is contained in:
IndieKKY
2024-10-06 12:04:43 +08:00
parent d7b274d338
commit faa15b9510

View File

@@ -16,69 +16,79 @@ type RespMsg<T = any> = {
msg?: string msg?: string
} }
// 处理函数
type Handler<L1Req = any, L1Res = any> = (req: L1Req) => Promise<L1Res>
// 创建一个 Layer1Protocol 类,用于持久监听 port 并通过消息 ID 处理响应,支持超时 // 创建一个 Layer1Protocol 类,用于持久监听 port 并通过消息 ID 处理响应,支持超时
class Layer1Protocol<L1Req = any, L1Res = any> { class Layer1Protocol<L1Req = any, L1Res = any> {
private port: chrome.runtime.Port private port: chrome.runtime.Port
private timeout: number private timeout: number
private requests: Map<string, { resolve: (value: L1Res) => void, timer: number }> private requests: Map<string, { resolve: (value: L1Res) => void, reject: (reason?: any) => void, timer: number }>
private handler: (value: L1Req) => Promise<L1Res> private handler: Handler<L1Req, L1Res>
constructor(handler: (value: L1Req) => Promise<L1Res>, port: chrome.runtime.Port, timeout = 30000) { // 默认超时 30 秒 constructor(handler: Handler<L1Req, L1Res>, port: chrome.runtime.Port, timeout = 30000) { // 默认超时 30 秒
this.port = port; this.port = port;
this.timeout = timeout; this.timeout = timeout;
this.requests = new Map(); this.requests = new Map();
this.handler = handler this.handler = handler
this._startListen() // 开始监听
this.port.onMessage.addListener(this._messageListener);
} }
// 生成唯一 ID简单示例可以使用更复杂的生成策略 // 生成唯一 ID简单示例可以使用更复杂的生成策略
_generateUniqueId() { private _generateUniqueId() {
return crypto.randomUUID() return crypto.randomUUID()
} }
_startListen() { private _messageListener = (msg: ReqMsg<L1Req, L1Res>) => {
// 持久监听 port.onMessage
this.port.onMessage.addListener((msg: ReqMsg<L1Req, L1Res>) => {
const { id, type, req, res } = msg; const { id, type, req, res } = msg;
if (type === 'req') { if (type === 'req') {
this.handler(req!).then(res => { this.handler(req!).then(res => {
const response: RespMsg<L1Res> = { const response: RespMsg<L1Res> = {
code: 200, code: 200,
msg: 'success',
data: res data: res
} }
this.port.postMessage({ id, type: 'res', res: response }); this.port.postMessage({ id, type: 'res', res: response });
}).catch(error => { }).catch(error => {//业务错误
const response: RespMsg<L1Res> = { const response: RespMsg<L1Res> = {
code: 500, code: 500,
msg: error.message, msg: error instanceof Error ? error.message : String(error),
} }
this.port.postMessage({ id, type: 'res', res: response }); this.port.postMessage({ id, type: 'res', res: response });
}); });
} else if (type === 'res') { } else if (type === 'res') {
if (this.requests.has(id)) { if (this.requests.has(id)) {
const { resolve, timer } = this.requests.get(id)!; const { resolve, reject, timer } = this.requests.get(id)!;
// 清除超时定时器 // 清除超时定时器
clearTimeout(timer); clearTimeout(timer);
// 移除消息 ID // 移除消息 ID
this.requests.delete(id); this.requests.delete(id);
// 通过 ID 找到对应的 Promise 并 resolve // 通过 ID 找到对应的 Promise 并 resolve
if (res!.code === 200) {
resolve(res!.data!); resolve(res!.data!);
}else { } else {//业务错误
console.error('unknown response message id: ', id) reject(new Error(`${res!.code}: ${res!.msg || 'Unknown error'}`));
} }
} else { } else {
console.error('unknown response message id: ', id)
}
} else {//语法格式错误
console.error('unknown message type: ', type) console.error('unknown message type: ', type)
} }
}); }
dispose() {
this.port.onMessage.removeListener(this._messageListener);
this.requests.forEach(({ timer }) => clearTimeout(timer));
this.requests.clear();
} }
// 使用 Promise 发送消息并等待响应,支持超时 // 使用 Promise 发送消息并等待响应,支持超时
sendMessage(req: L1Req): Promise<L1Res> { sendMessage(req: L1Req): Promise<L1Res> {
const id = this._generateUniqueId(); const id = this._generateUniqueId();
return new Promise((resolve, reject) => { return new Promise<L1Res>((resolve, reject) => {
// 设置一个超时定时器 // 设置一个超时定时器
const timer = setTimeout(() => { const timer = setTimeout(() => {
// 超时后执行 reject 并从 Map 中删除 // 超时后执行 reject 并从 Map 中删除
@@ -87,7 +97,7 @@ class Layer1Protocol<L1Req = any, L1Res = any> {
}, this.timeout); }, this.timeout);
// 将 resolve 和 timer 函数与消息 ID 绑定,存入 Map // 将 resolve 和 timer 函数与消息 ID 绑定,存入 Map
this.requests.set(id, { resolve, timer }); this.requests.set(id, { resolve, reject, timer });
// 发送消息,并附带 ID // 发送消息,并附带 ID
this.port.postMessage({ id, type: 'req', req }); this.port.postMessage({ id, type: 'req', req });