11import type { Message , MessageConnect , RuntimeMessageSender , TMessage } from "./types" ;
22import { v4 as uuidv4 } from "uuid" ;
33import { type PostMessage , type WindowMessageBody , WindowMessageConnect } from "./window_message" ;
4- import LoggerCore from "@App/app/logger/core" ;
54import EventEmitter from "eventemitter3" ;
65import { DefinedFlags } from "@App/app/service/service_worker/runtime.consts" ;
76
87// 避免页面载入后改动 EventTarget.prototype 的方法导致消息传递失败
9- const pageDispatchEvent = performance . dispatchEvent . bind ( performance ) ;
10- const pageAddEventListener = performance . addEventListener . bind ( performance ) ;
8+ export const pageDispatchEvent = performance . dispatchEvent . bind ( performance ) ;
9+ export const pageAddEventListener = performance . addEventListener . bind ( performance ) ;
10+ export const pageRemoveEventListener = performance . removeEventListener . bind ( performance ) ;
11+ const detailClone = typeof cloneInto === "function" ? cloneInto : null ;
12+ export const pageDispatchCustomEvent = ( eventType : string , detail : any ) => {
13+ if ( detailClone && detail ) detail = detailClone ( detail , document . defaultView ) ;
14+ const ev = new CustomEventClone ( eventType , {
15+ detail,
16+ cancelable : true ,
17+ } ) ;
18+ return pageDispatchEvent ( ev ) ;
19+ } ;
1120
1221// 避免页面载入后改动全域物件导致消息传递失败
1322const MouseEventClone = MouseEvent ;
@@ -30,28 +39,59 @@ export class CustomEventPostMessage implements PostMessage {
3039 }
3140}
3241
42+ export type PageMessaging = {
43+ et : string ;
44+ bindEmitter ?: ( ) => void ;
45+ waitReady ?: Promise < void > ;
46+ waitReadyResolve ?: ( ) => any ;
47+ onReady ?: ( callback : ( ) => any ) => any ;
48+ } ;
49+
50+ export const createPageMessaging = ( et : string ) => {
51+ const pageMessaging = { et } as PageMessaging ;
52+ pageMessaging . waitReady = new Promise < void > ( ( resolve ) => {
53+ pageMessaging . waitReadyResolve = resolve ;
54+ } ) ;
55+ pageMessaging . onReady = ( callback : ( ) => any ) => {
56+ if ( pageMessaging . et ) {
57+ callback ( ) ;
58+ } else {
59+ pageMessaging . waitReady ! . then ( callback ) ;
60+ }
61+ } ;
62+ return pageMessaging ;
63+ } ;
64+
3365// 使用CustomEvent来进行通讯, 可以在content与inject中传递一些dom对象
3466export class CustomEventMessage implements Message {
3567 EE = new EventEmitter < string , any > ( ) ;
3668 readonly receiveFlag : string ;
3769 readonly sendFlag : string ;
70+ readonly pageMessagingHandler : ( event : Event ) => any ;
3871
3972 // 关联dom目标
4073 relatedTarget : Map < number , EventTarget > = new Map ( ) ;
4174
4275 constructor (
43- messageFlag : string ,
76+ private pageMessaging : PageMessaging ,
4477 protected readonly isContent : boolean
4578 ) {
46- this . receiveFlag = `evt ${ messageFlag } ${ isContent ? DefinedFlags . contentFlag : DefinedFlags . injectFlag } ${ DefinedFlags . domEvent } ` ;
47- this . sendFlag = `evt ${ messageFlag } ${ isContent ? DefinedFlags . injectFlag : DefinedFlags . contentFlag } ${ DefinedFlags . domEvent } ` ;
48- pageAddEventListener ( this . receiveFlag , ( event ) => {
79+ this . receiveFlag = `${ isContent ? DefinedFlags . contentFlag : DefinedFlags . injectFlag } ${ DefinedFlags . domEvent } ` ;
80+ this . sendFlag = `${ isContent ? DefinedFlags . injectFlag : DefinedFlags . contentFlag } ${ DefinedFlags . domEvent } ` ;
81+ this . pageMessagingHandler = ( event : Event ) => {
4982 if ( event instanceof MouseEventClone && event . movementX && event . relatedTarget ) {
50- relatedTargetMap . set ( event . movementX , event . relatedTarget ! ) ;
83+ relatedTargetMap . set ( event . movementX , event . relatedTarget ) ;
5184 } else if ( event instanceof CustomEventClone ) {
5285 this . messageHandle ( event . detail , new CustomEventPostMessage ( this ) ) ;
5386 }
54- } ) ;
87+ } ;
88+ }
89+
90+ bindEmitter ( ) {
91+ if ( ! this . pageMessaging . et ) throw new Error ( "bindEmitter() failed" ) ;
92+ const receiveFlag = `evt_${ this . pageMessaging . et } _${ this . receiveFlag } ` ;
93+ pageRemoveEventListener ( receiveFlag , this . pageMessagingHandler ) ; // 避免重覆
94+ pageAddEventListener ( receiveFlag , this . pageMessagingHandler ) ;
5595 }
5696
5797 messageHandle ( data : WindowMessageBody , target : PostMessage ) {
@@ -95,56 +135,49 @@ export class CustomEventMessage implements Message {
95135
96136 connect ( data : TMessage ) : Promise < MessageConnect > {
97137 return new Promise ( ( resolve ) => {
98- const body : WindowMessageBody < TMessage > = {
99- messageId : uuidv4 ( ) ,
100- type : "connect" ,
101- data,
102- } ;
103- this . nativeSend ( body ) ;
104- // EventEmitter3 采用同步事件设计,callback会被马上执行而不像传统javascript架构以下一个macrotask 执行
105- resolve ( new WindowMessageConnect ( body . messageId , this . EE , new CustomEventPostMessage ( this ) ) ) ;
138+ this . pageMessaging . onReady ! ( ( ) => {
139+ const body : WindowMessageBody < TMessage > = {
140+ messageId : uuidv4 ( ) ,
141+ type : "connect" ,
142+ data,
143+ } ;
144+ this . nativeSend ( body ) ;
145+ // EventEmitter3 采用同步事件设计,callback会被马上执行而不像传统javascript架构以下一个macrotask 执行
146+ resolve ( new WindowMessageConnect ( body . messageId , this . EE , new CustomEventPostMessage ( this ) ) ) ;
147+ } ) ;
106148 } ) ;
107149 }
108150
109151 nativeSend ( detail : any ) {
110- if ( typeof cloneInto !== "undefined" ) {
111- try {
112- LoggerCore . logger ( ) . info ( "nativeSend" ) ;
113- detail = cloneInto ( detail , document . defaultView ) ;
114- } catch ( e ) {
115- console . log ( e ) ;
116- LoggerCore . logger ( ) . info ( "error data" ) ;
117- }
118- }
119-
120- const ev = new CustomEventClone ( this . sendFlag , {
121- detail,
122- } ) ;
123- pageDispatchEvent ( ev ) ;
152+ if ( ! this . pageMessaging . et ) throw new Error ( "inject.js is not ready or destroyed." ) ;
153+ pageDispatchCustomEvent ( `evt_${ this . pageMessaging . et } _${ this . sendFlag } ` , detail ) ;
124154 }
125155
126156 sendMessage < T = any > ( data : TMessage ) : Promise < T > {
127157 return new Promise ( ( resolve : ( ( value : T ) => void ) | null ) => {
128- const messageId = uuidv4 ( ) ;
129- const body : WindowMessageBody < TMessage > = {
130- messageId,
131- type : "sendMessage" ,
132- data,
133- } ;
134- const eventId = `response:${ messageId } ` ;
135- this . EE . addListener ( eventId , ( body : WindowMessageBody < TMessage > ) => {
136- this . EE . removeAllListeners ( eventId ) ;
137- resolve ! ( body . data as T ) ;
138- resolve = null ; // 设为 null 提醒JS引擎可以GC
158+ this . pageMessaging . onReady ! ( ( ) => {
159+ const messageId = uuidv4 ( ) ;
160+ const body : WindowMessageBody < TMessage > = {
161+ messageId,
162+ type : "sendMessage" ,
163+ data,
164+ } ;
165+ const eventId = `response:${ messageId } ` ;
166+ this . EE . addListener ( eventId , ( body : WindowMessageBody < TMessage > ) => {
167+ this . EE . removeAllListeners ( eventId ) ;
168+ resolve ! ( body . data as T ) ;
169+ resolve = null ; // 设为 null 提醒JS引擎可以GC
170+ } ) ;
171+ this . nativeSend ( body ) ;
139172 } ) ;
140- this . nativeSend ( body ) ;
141173 } ) ;
142174 }
143175
144176 // 同步发送消息
145177 // 与content页的消息通讯实际是同步,此方法不需要经过background
146178 // 但是请注意中间不要有promise
147179 syncSendMessage ( data : TMessage ) : TMessage {
180+ if ( ! this . pageMessaging . et ) throw new Error ( "inject.js is not ready or destroyed." ) ;
148181 const messageId = uuidv4 ( ) ;
149182 const body : WindowMessageBody < TMessage > = {
150183 messageId,
@@ -164,11 +197,12 @@ export class CustomEventMessage implements Message {
164197 }
165198
166199 sendRelatedTarget ( target : EventTarget ) : number {
200+ if ( ! this . pageMessaging . et ) throw new Error ( "inject.js is not ready or destroyed." ) ;
167201 // 特殊处理relatedTarget,返回id进行关联
168202 // 先将relatedTarget转换成id发送过去
169203 const id = ( relateId = relateId === maxInteger ? 1 : relateId + 1 ) ;
170204 // 可以使用此种方式交互element
171- const ev = new MouseEventClone ( this . sendFlag , {
205+ const ev = new MouseEventClone ( `evt_ ${ this . pageMessaging . et } _ ${ this . sendFlag } ` , {
172206 movementX : id ,
173207 relatedTarget : target ,
174208 } ) ;
0 commit comments