diff --git a/packages/message/window_message.ts b/packages/message/window_message.ts index efa58cc..3de3306 100644 --- a/packages/message/window_message.ts +++ b/packages/message/window_message.ts @@ -1,10 +1,22 @@ import { v4 as uuidv4 } from "uuid"; -import { Message, MessageConnect } from "./server"; +import { Message, MessageConnect, MessageSend } from "./server"; // 通过 window.postMessage/onmessage 实现通信 import EventEmitter from "eventemitter3"; +interface PostMessage { + postMessage(message: any): void; +} + +class WindowPostMessage implements PostMessage { + constructor(private target: Window) {} + + postMessage(message: any) { + this.target.postMessage(message, "*"); + } +} + // 消息体 export type WindowMessageBody = { messageId: string; // 消息id @@ -19,25 +31,33 @@ export class WindowMessage implements Message { // target: Window 消息目标 constructor( private source: Window, - private target: Window + private target: Window, + private serviceWorker?: boolean ) { // 监听消息 this.source.addEventListener("message", (e) => { console.log(e); if (e.source === this.target || e.source === this.source) { - this.messageHandle(e.data); + this.messageHandle(e.data, new WindowPostMessage(this.target)); } }); + // 是否监听serviceWorker消息 + if (this.serviceWorker) { + navigator.serviceWorker.addEventListener("message", (e) => { + if (e.source) { + this.messageHandle(e.data, e.source as Window); + } + }); + } } - messageHandle(data: WindowMessageBody) { + messageHandle(data: WindowMessageBody, target: PostMessage) { // 处理消息 if (data.type === "sendMessage") { // 接收到消息 this.EE.emit("message", data.data, (resp: any) => { // 发送响应消息 // 无消息id则不发送响应消息 - console.log("data", data, "resp", resp); if (!data.messageId) { return; } @@ -46,13 +66,13 @@ export class WindowMessage implements Message { type: "respMessage", data: resp, }; - this.target.postMessage(body, "*"); + target.postMessage(body); }); } else if (data.type === "respMessage") { // 接收到响应消息 this.EE.emit("response:" + data.messageId, data); } else if (data.type === "connect") { - this.EE.emit("connect", data.data, new WindowMessageConnect(data.messageId, this.EE, this.target)); + this.EE.emit("connect", data.data, new WindowMessageConnect(data.messageId, this.EE, target)); } else if (data.type === "disconnect") { this.EE.emit("disconnect:" + data.messageId); } else if (data.type === "connectMessage") { @@ -102,7 +122,7 @@ export class WindowMessageConnect implements MessageConnect { constructor( private messageId: string, private EE: EventEmitter, - private target: Window + private target: PostMessage ) { this.onDisconnect(() => { // 移除所有监听 @@ -117,7 +137,7 @@ export class WindowMessageConnect implements MessageConnect { type: "connectMessage", data, }; - this.target.postMessage(body, "*"); + this.target.postMessage(body); } onMessage(callback: (data: any) => void) { @@ -137,3 +157,65 @@ export class WindowMessageConnect implements MessageConnect { this.EE.addListener("disconnect:" + this.messageId, callback); } } + +// service_worker和offscreen同时监听消息,会导致消息被两边同时接收,但是返回结果时会产生问题,导致报错 +// 不进行监听的话又无法从service_worker主动发送消息 +// 所以service_worker与offscreen使用ServiceWorker的方式进行通信 +export class ServiceWorkerMessageSend implements MessageSend { + EE: EventEmitter = new EventEmitter(); + + private target: PostMessage | undefined = undefined; + + constructor() {} + + async init() { + const list = await clients.matchAll(); + this.target = list[0]; + console.log(this.target); + addEventListener("message", (e) => { + console.log(e); + this.messageHandle(e.data); + }); + } + + messageHandle(data: WindowMessageBody) { + // 处理消息 + if (data.type === "respMessage") { + // 接收到响应消息 + this.EE.emit("response:" + data.messageId, data); + } else if (data.type === "disconnect") { + this.EE.emit("disconnect:" + data.messageId); + } else if (data.type === "connectMessage") { + this.EE.emit("connectMessage:" + data.messageId, data.data); + } + } + + connect(data: any): Promise { + return new Promise((resolve) => { + const body: WindowMessageBody = { + messageId: uuidv4(), + type: "connect", + data, + }; + this.target!.postMessage(body); + resolve(new WindowMessageConnect(body.messageId, this.EE, this.target!)); + }); + } + + // 发送消息 注意不进行回调的内存泄漏 + sendMessage(data: any): Promise { + return new Promise((resolve) => { + const body: WindowMessageBody = { + messageId: uuidv4(), + type: "sendMessage", + data, + }; + const callback = (body: WindowMessageBody) => { + this.EE.removeListener("response:" + body.messageId, callback); + resolve(body.data); + }; + this.EE.addListener("response:" + body.messageId, callback); + this.target!.postMessage(body); + }); + } +} diff --git a/src/app/service/offscreen/index.ts b/src/app/service/offscreen/index.ts index b7be4ce..80ae36b 100644 --- a/src/app/service/offscreen/index.ts +++ b/src/app/service/offscreen/index.ts @@ -12,7 +12,7 @@ import { GMApi } from "./gm_api"; export class OffscreenManager { private extensionMessage: MessageSend = new ExtensionMessageSend("service_worker"); - private windowMessage = new WindowMessage(window, sandbox); + private windowMessage = new WindowMessage(window, sandbox, true); private windowApi: Server = new Server(this.windowMessage); @@ -35,6 +35,11 @@ export class OffscreenManager { } async initManager() { + navigator.serviceWorker.ready.then((registration) => { + // 通知service worker已经准备好了 + registration.active?.postMessage("okkkk"); + }); + // 监听消息 this.windowApi.on("logger", this.logger.bind(this)); this.windowApi.on("preparationSandbox", this.preparationSandbox.bind(this)); diff --git a/src/app/service/service_worker/index.ts b/src/app/service/service_worker/index.ts index 78738a3..44a6b9d 100644 --- a/src/app/service/service_worker/index.ts +++ b/src/app/service/service_worker/index.ts @@ -5,24 +5,27 @@ import { ExtensionMessage } from "@Packages/message/extension_message"; import { ResourceService } from "./resource"; import { ValueService } from "./value"; import { RuntimeService } from "./runtime"; +import { ServiceWorkerMessageSend } from "@Packages/message/window_message"; +import { sendMessageToOffscreen } from "./gm_api"; export type InstallSource = "user" | "system" | "sync" | "subscribe" | "vscode"; // service worker的管理器 export default class ServiceWorkerManager { - constructor() {} - private api: Server = new Server(new ExtensionMessage("service_worker")); private mq: MessageQueue = new MessageQueue(this.api); + private sender: ServiceWorkerMessageSend = new ServiceWorkerMessageSend(); + async initManager() { const group = this.api.group("serviceWorker"); group.on("preparationOffscreen", async () => { // 准备好环境 + sendMessageToOffscreen("aa", "aa"); + await this.sender.init(); this.mq.emit("preparationOffscreen", {}); - - // sendMessageToOffscreen("preparationOffscreen", {}); + this.sender.sendMessage("test"); }); const resource = new ResourceService(group.group("resource"), this.mq);