1- import type { Message , MessageConnect , MessageSend , RuntimeMessageSender , TMessage } from "./types" ;
1+ import type {
2+ Message ,
3+ MessageConnect ,
4+ MessageSend ,
5+ OnConnectCallback ,
6+ OnMessageCallback ,
7+ RuntimeMessageSender ,
8+ TMessage ,
9+ } from "./types" ;
210import { uuidv4 } from "@App/pkg/utils/uuid" ;
311import EventEmitter from "eventemitter3" ;
412
@@ -205,32 +213,46 @@ export class WindowMessageConnect implements MessageConnect {
205213// service_worker和offscreen同时监听消息,会导致消息被两边同时接收,但是返回结果时会产生问题,导致报错
206214// 不进行监听的话又无法从service_worker主动发送消息
207215// 所以service_worker与offscreen使用ServiceWorker的方式进行通信
208- export class ServiceWorkerMessageSend implements MessageSend {
216+ // 现在同时支持接收来自offscreen的请求(实现完整Message接口),使双向通道都走postMessage(结构化克隆,支持Blob)
217+ export class ServiceWorkerMessageSend implements Message {
209218 EE = new EventEmitter < string , any > ( ) ;
210219
211220 private target : PostMessage | undefined = undefined ;
212221
213- constructor ( ) { }
214-
215- listened : boolean = false ;
222+ constructor ( ) {
223+ // 在构造函数中设置监听,确保能接收来自offscreen的请求
224+ self . addEventListener ( "message" , ( e : MessageEvent ) => {
225+ this . messageHandle ( e . data , e . source as PostMessage ) ;
226+ } ) ;
227+ }
216228
217229 async init ( ) {
218230 if ( ! this . target && self . clients ) {
219- if ( ! this . listened ) {
220- this . listened = true ;
221- self . addEventListener ( "message" , ( e ) => {
222- this . messageHandle ( e . data ) ;
223- } ) ;
224- }
225231 const list = await self . clients . matchAll ( { includeUncontrolled : true , type : "window" } ) ;
226232 // 找到offscreen.html窗口
227233 this . target = list . find ( ( client ) => client . url == chrome . runtime . getURL ( "src/offscreen.html" ) ) as PostMessage ;
228234 }
229235 }
230236
231- messageHandle ( data : WindowMessageBody ) {
237+ messageHandle ( data : WindowMessageBody , source ?: PostMessage ) {
232238 // 处理消息
233- if ( data . type === "respMessage" ) {
239+ if ( data . type === "sendMessage" && source ) {
240+ // 接收到来自offscreen的请求消息
241+ this . EE . emit ( "message" , data . data , ( resp : any ) => {
242+ if ( ! data . messageId ) {
243+ return ;
244+ }
245+ const body : WindowMessageBody = {
246+ messageId : data . messageId ,
247+ type : "respMessage" ,
248+ data : resp ,
249+ } ;
250+ source . postMessage ( body ) ;
251+ } ) ;
252+ } else if ( data . type === "connect" && source ) {
253+ // 接收到来自offscreen的连接请求
254+ this . EE . emit ( "connect" , data . data , new WindowMessageConnect ( data . messageId , this . EE , source ) ) ;
255+ } else if ( data . type === "respMessage" ) {
234256 // 接收到响应消息
235257 this . EE . emit ( `response:${ data . messageId } ` , data ) ;
236258 } else if ( data . type === "disconnect" ) {
@@ -240,6 +262,14 @@ export class ServiceWorkerMessageSend implements MessageSend {
240262 }
241263 }
242264
265+ onMessage ( callback : OnMessageCallback ) : void {
266+ this . EE . addListener ( "message" , callback ) ;
267+ }
268+
269+ onConnect ( callback : OnConnectCallback ) : void {
270+ this . EE . addListener ( "connect" , callback ) ;
271+ }
272+
243273 async connect ( data : TMessage ) : Promise < MessageConnect > {
244274 await this . init ( ) ;
245275 const body : WindowMessageBody < TMessage > = {
@@ -271,3 +301,61 @@ export class ServiceWorkerMessageSend implements MessageSend {
271301 } ) ;
272302 }
273303}
304+
305+ // Offscreen端通过navigator.serviceWorker.controller.postMessage向SW发送消息
306+ // 与ServiceWorkerMessageSend配对使用,实现Offscreen→SW的postMessage通道
307+ export class ServiceWorkerClientMessage implements MessageSend {
308+ EE = new EventEmitter < string , any > ( ) ;
309+
310+ constructor ( ) {
311+ navigator . serviceWorker . addEventListener ( "message" , ( e ) => {
312+ this . messageHandle ( e . data ) ;
313+ } ) ;
314+ }
315+
316+ messageHandle ( data : WindowMessageBody ) {
317+ // 只处理响应类消息,请求类消息由WindowMessage处理
318+ if ( data . type === "respMessage" ) {
319+ this . EE . emit ( `response:${ data . messageId } ` , data ) ;
320+ } else if ( data . type === "disconnect" ) {
321+ this . EE . emit ( `disconnect:${ data . messageId } ` ) ;
322+ } else if ( data . type === "connectMessage" ) {
323+ this . EE . emit ( `connectMessage:${ data . messageId } ` , data . data ) ;
324+ }
325+ }
326+
327+ private postToServiceWorker ( message : any ) {
328+ navigator . serviceWorker . controller ! . postMessage ( message ) ;
329+ }
330+
331+ async connect ( data : TMessage ) : Promise < MessageConnect > {
332+ const body : WindowMessageBody < TMessage > = {
333+ messageId : uuidv4 ( ) ,
334+ type : "connect" ,
335+ data,
336+ } ;
337+ const target : PostMessage = {
338+ postMessage : ( msg ) => this . postToServiceWorker ( msg ) ,
339+ } ;
340+ this . postToServiceWorker ( body ) ;
341+ return new WindowMessageConnect ( body . messageId , this . EE , target ) ;
342+ }
343+
344+ sendMessage < T = any > ( data : TMessage ) : Promise < T > {
345+ return new Promise ( ( resolve : ( ( value : T ) => void ) | null ) => {
346+ const messageId = uuidv4 ( ) ;
347+ const body : WindowMessageBody < TMessage > = {
348+ messageId,
349+ type : "sendMessage" ,
350+ data,
351+ } ;
352+ const eventId = `response:${ messageId } ` ;
353+ this . EE . addListener ( eventId , ( body : WindowMessageBody < TMessage > ) => {
354+ this . EE . removeAllListeners ( eventId ) ;
355+ resolve ! ( body . data as T ) ;
356+ resolve = null ;
357+ } ) ;
358+ this . postToServiceWorker ( body ) ;
359+ } ) ;
360+ }
361+ }
0 commit comments