From d62cc0a26c4a832fb90a1bb314ff8ad456ba0063 Mon Sep 17 00:00:00 2001 From: xu_yanfeng Date: Tue, 24 Dec 2024 17:31:26 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84background?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cc-inspector/src/core/types.ts | 24 ++ cc-inspector/src/scripts/background.ts | 235 ------------------ cc-inspector/src/scripts/background/index.ts | 68 +++++ .../src/scripts/background/portContent.ts | 31 +++ .../src/scripts/background/portDevtools.ts | 36 +++ .../src/scripts/background/portMan.ts | 56 +++++ .../src/scripts/background/portMgr.ts | 125 ++++++++++ cc-inspector/src/scripts/terminal.ts | 29 ++- 8 files changed, 363 insertions(+), 241 deletions(-) delete mode 100644 cc-inspector/src/scripts/background.ts create mode 100644 cc-inspector/src/scripts/background/index.ts create mode 100644 cc-inspector/src/scripts/background/portContent.ts create mode 100644 cc-inspector/src/scripts/background/portDevtools.ts create mode 100644 cc-inspector/src/scripts/background/portMan.ts create mode 100644 cc-inspector/src/scripts/background/portMgr.ts diff --git a/cc-inspector/src/core/types.ts b/cc-inspector/src/core/types.ts index ae06af6..8945550 100644 --- a/cc-inspector/src/core/types.ts +++ b/cc-inspector/src/core/types.ts @@ -1,4 +1,5 @@ export enum Page { + None = "None", Inject = "Inject", Devtools = "Devtools", Background = "Background", @@ -64,7 +65,30 @@ export class PluginEvent { * 事件要发送的目标 */ target: Page | null = null; + isTargetDevtools() { + return this.target === Page.Devtools; + } + isTargetBackground() { + return this.target === Page.Background; + } + isTargetContent() { + return this.target === Page.Content; + } + /** + * 将addListener监听的数据转换为类 + */ + static create(data: any): PluginEvent { + let obj = data; + if (typeof data === "string") { + obj = JSON.stringify(data) + } else if (typeof data === "object") { + } else { + debugger; + } + const cls = data as PluginEvent; + return new PluginEvent(cls.source, cls.target, cls.msg, cls.data); + } static check(event: PluginEvent, source: Page, target: Page) { return event && source && target && event.source === source && event.target === target; } diff --git a/cc-inspector/src/scripts/background.ts b/cc-inspector/src/scripts/background.ts deleted file mode 100644 index 8f3d707..0000000 --- a/cc-inspector/src/scripts/background.ts +++ /dev/null @@ -1,235 +0,0 @@ -import { ChromeConst } from "cc-plugin/src/chrome/const"; -import { Msg, Page, PluginEvent } from "../core/types"; -import { FrameDetails } from "../views/devtools/data"; -import { Terminal } from "./terminal"; -const terminal: Terminal = new Terminal("background"); -class PortMan { - public currentUseContentFrameID = 0; - /** - * 因为iframe的原因,可能对应多个,主iframe的id===0 - */ - public content: Array = []; - /** - * devtools的链接,方便background转发到devtools - */ - public devtools: chrome.runtime.Port | null = null; - /** - * tab.id作为唯一标识 - */ - public id: number | null = null; - public title: string = ""; - public url: string = ""; - private mgr: PortManagement | null = null; - - constructor(mgr: PortManagement, { id, url, title }: any) { - this.mgr = mgr; - this.id = id; - this.url = url; - this.title = title; - } - - private onPortConnect(port: chrome.runtime.Port, onMsg: Function, onDisconnect: Function) { - terminal.connect(port.name); - port.onMessage.addListener((data: any, sender: any) => { - console.log( - `%c[Connect-Message] ${sender.name}\n${JSON.stringify(data)}`, - "color:blue;" - ); - // 如果多个页面都监听 onMessage 事件,对于某一次事件只有第一次调用 sendResponse() 能成功发出回应,所有其他回应将被忽略。 - // sender.postMessage(data); - onMsg && onMsg(data); - }); - port.onDisconnect.addListener((port: chrome.runtime.Port) => { - console.log(`%c[Connect-Dis] ${port.name}`, "color:red"); - onDisconnect && onDisconnect(port); - }); - } - - getCurrentUseContent(): chrome.runtime.Port | null { - const port: chrome.runtime.Port = this.content.find((el) => { - const b1 = el.sender?.frameId !== undefined; - const b2 = el.sender.frameId === this.currentUseContentFrameID - return b1 && b2 - }) - return port || null; - } - - _updateFrames() { - const data: FrameDetails[] = this.content.map((item) => { - return { - url: item.sender?.url || "", - frameID: item.sender?.frameId || 0, - }; - }); - const event = new PluginEvent(Page.Background, Page.Devtools, Msg.UpdateFrames, data); - this.sendDevtoolMsg(event); - } - - dealConnect(port: chrome.runtime.Port) { - switch (port.name) { - case Page.Content: { - this.content.push(port); - this._updateFrames(); - this.onPortConnect(port, - (data: PluginEvent) => { - if (data.target === Page.Devtools) { - this.sendDevtoolMsg(data); - } - }, - (disPort: chrome.runtime.Port) => { - const index = this.content.findIndex( - (el) => - disPort.sender?.frameId !== undefined && - el.sender?.frameId !== undefined && - el.sender?.frameId === disPort.sender?.frameId - ); - this.content.splice(index, 1); - this._updateFrames(); - this.checkValid(); - }); - break; - } - case Page.Devtools: { - this.devtools = port; - this._updateFrames(); // 当devtools链接后,主动派发frames数据 - this.onPortConnect( - port, - (data: PluginEvent) => { - if (data.msg === Msg.UseFrame) { - this.currentUseContentFrameID = data.data; - // 更新这个frame的tree - this.updateCurrentFrameTree(); - } else { - // 从devtools过来的消息统一派发到Content中 - if (PluginEvent.check(data, Page.Devtools, Page.Background)) { - if (data.msg === Msg.TreeInfo) { - if (this.currentUseContentFrameID !== data.data) { - console.log(`frameID[${data.data}]不一致`); - } - } - PluginEvent.reset(data, Page.Background, Page.Content); - this.getCurrentUseContent()?.postMessage(data); - } - } - }, - () => { - this.devtools = null; - this.checkValid(); - } - ); - break; - } - } - } - - private updateCurrentFrameTree() { - const sendData = new PluginEvent( - Page.Background, - Page.Content, - Msg.Support - ); - this.getCurrentUseContent()?.postMessage(sendData); - } - - checkValid() { - if (!this.devtools && !this.content.length) { - this.mgr?.remove(this); - } - } - - sendContentMsg(data: PluginEvent) { - this.getCurrentUseContent()?.postMessage(data); - } - - sendDevtoolMsg(data: PluginEvent) { - this.devtools?.postMessage(data); - } -} - -class PortManagement { - port: Array = []; - - constructor() { - terminal.ok(); - this.initConnect(); - chrome.runtime.onMessage.addListener((request: PluginEvent, sender: any, sendResponse: any) => { - const tabID = sender.tab.id; - const portMan: PortMan | undefined = this.find(tabID); - if (portMan) { - if (PluginEvent.check(request, Page.Content, Page.Background)) { - // 监听来自content.js发来的事件,将消息转发到devtools - PluginEvent.reset(request, Page.Background, Page.Devtools); - console.log( - `%c[Message]url:${sender.url}]\n${JSON.stringify(request)}`, - "color:green" - ); - portMan.sendDevtoolMsg(request); - } - } - } - ); - chrome.tabs.onActivated.addListener(({ tabId, windowId }) => { }); - chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { - // 页面发生刷新,通知重新生成数据 - if (changeInfo.status === "complete") { - const { id } = tab; - // -1为自己 - if (id && id > -1) { - let portMan = this.find(id); - if (portMan) { - let data = new PluginEvent(Page.Background, Page.Content, Msg.Support); - portMan.sendContentMsg(data); - } - } - } - }); - } - - isDevtools(port: chrome.runtime.Port) { - const devtoolsUrl = `chrome-extension://${port.sender?.id}/${ChromeConst.html.devtools}`; - if (port.sender?.url === devtoolsUrl) { - } - } - - initConnect() { - chrome.runtime.onConnect.addListener((port: chrome.runtime.Port) => { - if (port.name === Page.Devtools) { - // devtool链接过来没有port.sender.tab - chrome.tabs.query({ active: true }, (tabs: chrome.tabs.Tab[]) => { - tabs.forEach((tab) => { - this._onConnect(tab, port); - }) - }); - } else { - const tab: chrome.tabs.Tab | undefined = port.sender?.tab; - if (tab) { - this._onConnect(tab, port); - } - } - }); - } - - private _onConnect(tab: chrome.tabs.Tab, port: chrome.runtime.Port) { - const { id, title, url } = tab; - if (id !== undefined && id > -1) { - let portMan: PortMan | undefined = this.find(id); - if (!portMan) { - portMan = new PortMan(this, { id, title, url }); - this.port.push(portMan); - } - portMan.dealConnect(port); - } - } - - find(id: number): PortMan | undefined { - return this.port.find((el) => el.id === id); - } - - remove(item: PortMan) { - let index = this.port.findIndex((el) => el === item); - if (index > -1) { - this.port.splice(index, 1); - } - } -} -new PortManagement(); \ No newline at end of file diff --git a/cc-inspector/src/scripts/background/index.ts b/cc-inspector/src/scripts/background/index.ts new file mode 100644 index 0000000..f920093 --- /dev/null +++ b/cc-inspector/src/scripts/background/index.ts @@ -0,0 +1,68 @@ +import { ChromeConst } from "cc-plugin/src/chrome/const"; +import { Msg, Page, PluginEvent } from "../../core/types"; +import { FrameDetails } from "../../views/devtools/data"; +import { PortMan } from "./portMan"; +import { PortMgr, portMgr } from "./portMgr"; +import { Terminal } from "../terminal"; +const terminal = new Terminal(Page.Background); +console.log(...terminal.init()); +function isDevtools(port: chrome.runtime.Port) { + const devtoolsUrl = `chrome-extension://${port.sender?.id}/${ChromeConst.html.devtools}`; + if (port.sender?.url === devtoolsUrl) { + } +} +function onTabConnect(tab: chrome.tabs.Tab, port: chrome.runtime.Port) { + if (tab.id === undefined || tab.id <= 0) { + debugger; + return; + } + let portMan = portMgr.findPort(tab.id) + if (portMan) { + // 一个port发起多次发起链接,以最后一次的为数据通讯基准 + // portMgr.removePort(portMan); + } + portMan = portMgr.addPort(tab, port); + portMan.init(); +} +chrome.runtime.onConnect.addListener((port: chrome.runtime.Port) => { + if (port.name === Page.Devtools) { + // devtool链接过来没有port.sender.tab + chrome.tabs.query({ active: true }, (tabs: chrome.tabs.Tab[]) => { + tabs.forEach((tab) => { + onTabConnect(tab, port); + }) + }); + } else { + const tab: chrome.tabs.Tab | undefined = port.sender?.tab; + if (tab) { + onTabConnect(tab, port); + } + } +}); +chrome.runtime.onMessage.addListener((request: PluginEvent, sender: any, sendResponse: any) => { + const tabID = sender.tab.id; + const portMan: PortMan | undefined = portMgr.findPort(tabID); + if (portMan) { + if (PluginEvent.check(request, Page.Content, Page.Background)) { + // 监听来自content.js发来的事件,将消息转发到devtools + PluginEvent.reset(request, Page.Background, Page.Devtools); + console.log(`%c[Message]url:${sender.url}]\n${JSON.stringify(request)}`, "color:green"); + portMgr.sendDevtoolMsg(request); + } + } +}); +chrome.tabs.onActivated.addListener(({ tabId, windowId }) => { }); +chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { + // 页面发生刷新,通知重新生成数据 + if (changeInfo.status === "complete") { + const { id } = tab; + // -1为自己 + if (id && id > -1) { + let portMan = portMgr.findPort(id); + if (portMan) { + let data = new PluginEvent(Page.Background, Page.Content, Msg.Support); + portMgr.sendContentMsg(data); + } + } + } +}); diff --git a/cc-inspector/src/scripts/background/portContent.ts b/cc-inspector/src/scripts/background/portContent.ts new file mode 100644 index 0000000..4cc7fa1 --- /dev/null +++ b/cc-inspector/src/scripts/background/portContent.ts @@ -0,0 +1,31 @@ +import { Msg, Page, PluginEvent } from "../../core/types"; +import { PortMan } from "./portMan"; +import { portMgr } from "./portMgr"; +import { FrameDetails } from "views/devtools/data"; + +export class PortContent extends PortMan { + init(): void { + // content连上来要同时devtools更新 + portMgr._updateFrames(); + this.onDisconnect = (disPort: chrome.runtime.Port) => { + /** + * const index = this.content.findIndex((el) => + disPort.sender?.frameId !== undefined && + el.sender?.frameId !== undefined && + el.sender?.frameId === disPort.sender?.frameId + ); + */ + // content失去链接需要更新Devtools + portMgr.removePort(this); + portMgr._updateFrames(); + }; + this.onMessage = (data: PluginEvent) => { + // content的数据一般都是要同步到devtools + if (data.isTargetDevtools()) { + portMgr.sendDevtoolMsg(data); + } else { + debugger; + } + }; + } +} \ No newline at end of file diff --git a/cc-inspector/src/scripts/background/portDevtools.ts b/cc-inspector/src/scripts/background/portDevtools.ts new file mode 100644 index 0000000..0299f3b --- /dev/null +++ b/cc-inspector/src/scripts/background/portDevtools.ts @@ -0,0 +1,36 @@ +import { Msg, Page, PluginEvent } from "../../core/types"; +import { PortMan } from "./portMan"; +import { portMgr } from "./portMgr"; + +export class PortDevtools extends PortMan { + init(): void { + // 当devtools链接后,主动同步frames数据 + portMgr._updateFrames(); + this.onDisconnect = () => { + portMgr.removePort(this); + } + this.onMessage = (data: PluginEvent) => { + if (data.msg === Msg.UseFrame) { + portMgr.useFrame(data.data); + } else { + // 从devtools过来的消息统一派发到Content中 + if (PluginEvent.check(data, Page.Devtools, Page.Background)) { + if (data.msg === Msg.TreeInfo) { + if (portMgr.isCurrentFrme(data.data)) { + console.log(`frameID[${data.data}]不一致`); + } + } + PluginEvent.reset(data, Page.Background, Page.Content); + const port = portMgr.getCurrentUseContent(); + if (!port) { + console.warn(`not find andy port`); + return; + } + port.postMessage(data); + } + } + + } + } + +} \ No newline at end of file diff --git a/cc-inspector/src/scripts/background/portMan.ts b/cc-inspector/src/scripts/background/portMan.ts new file mode 100644 index 0000000..8e070b2 --- /dev/null +++ b/cc-inspector/src/scripts/background/portMan.ts @@ -0,0 +1,56 @@ +import { ChromeConst } from "cc-plugin/src/chrome/const"; +import { Msg, Page, PluginEvent } from "../../core/types"; +import { FrameDetails } from "../../views/devtools/data"; +import { Terminal } from "../terminal"; +import { portMgr } from "./portMgr"; + +export abstract class PortMan { + /** + * port的名字标识 + */ + public name: string = Page.None; + /** + * tab.id作为唯一标识 + */ + public id: number | null = null; + public title: string = ""; + public url: string = ""; + public port: chrome.runtime.Port | null = null; + public tab: chrome.tabs.Tab | null = null; + public onDisconnect: (port: chrome.runtime.Port) => void | null = null; + public onMessage: (data: PluginEvent) => void | null = null; + public terminal: Terminal = null; + constructor(tab: chrome.tabs.Tab, port: chrome.runtime.Port) { + this.port = port; + this.tab = tab; + this.name = port.name; + this.id = tab.id; + this.url = tab.url; + this.title = tab.title; + this.terminal = new Terminal(`Port-${this.name}/ID-${this.id}`); + port.onMessage.addListener((data: any, sender: any) => { + const str = `${sender.name}\n${JSON.stringify(data)}` + console.log(... this.terminal.green(str)); + // 如果多个页面都监听 onMessage 事件,对于某一次事件只有第一次调用 sendResponse() 能成功发出回应,所有其他回应将被忽略。 + // sender.postMessage(data); + const cls = PluginEvent.create(data); + if (this.onMessage) { + this.onMessage(cls); + } + }); + port.onDisconnect.addListener((port: chrome.runtime.Port) => { + console.log(...this.terminal.disconnect("")); + if (this.onDisconnect) { + this.onDisconnect(port); + } + }); + } + abstract init(): void; + + isConnectPort() { + return this.name === Page.Content; + } + isDevtoolsPort() { + return this.name === Page.Devtools; + } +} \ No newline at end of file diff --git a/cc-inspector/src/scripts/background/portMgr.ts b/cc-inspector/src/scripts/background/portMgr.ts new file mode 100644 index 0000000..1cd67ed --- /dev/null +++ b/cc-inspector/src/scripts/background/portMgr.ts @@ -0,0 +1,125 @@ +import { Msg, Page, PluginEvent } from "../../core/types"; +import { PortMan } from "./portMan"; +import { PortDevtools } from "./portDevtools"; +import { PortContent } from "./portContent"; +import { FrameDetails } from "views/devtools/data"; +import { Terminal } from "../terminal"; + +export class PortMgr { + /** + * 所有的链接都在这里 + * 因为iframe的原因,可能对应多个,主iframe的id是0 + */ + public portArray: Array = []; + /** + * 当前正在通讯的frameID,因为游戏可能被好几个iframe嵌套 + */ + private currentUseContentFrameID = 0; + private terminal = new Terminal('PortMgr'); + public findDevtoolsPort() { + return this.portArray.find((el) => el.name === Page.Devtools); + } + public findPort(id: number): PortMan | null { + return this.portArray.find((el) => el.id === id) || null; + } + public _updateFrames() { + // 将content类型的port收集起来,同步到devtools + const data: FrameDetails[] = []; + this.portArray.forEach(item => { + if (item.isConnectPort()) { + data.push({ + url: item.port.sender?.url || "", + frameID: item.port.sender?.frameId || 0, + }) + } + }) + const event = new PluginEvent(Page.Background, Page.Devtools, Msg.UpdateFrames, data); + this.sendDevtoolMsg(event); + } + + addPort(tab: chrome.tabs.Tab, port: chrome.runtime.Port): PortMan | null { + let portMan: PortMan = null; + switch (port.name) { + case Page.Devtools: { + portMan = new PortDevtools(tab, port); + break; + } + case Page.Content: { + portMan = new PortContent(tab, port); + break; + } + default: { + debugger + break; + } + } + if (portMan) { + this.portArray.push(portMan); + this.logState(); + return portMan; + } + return null; + } + public logState() { + let arr: Array<{ name: string, id: number, url: string }> = []; + let str: string[] = []; + for (let i = 0; i < this.portArray.length; i++) { + const port = this.portArray[i]; + arr.push({ + name: port.name, + id: port.id, + url: port.url + }); + str.push(`[${i + 1}] name:${port.name}, id:${port.id}, url:${port.url}`); + } + + if (arr.length) { + // console.table(arr) + console.log(... this.terminal.log(str.join('\n'), true)); + } else { + console.log(... this.terminal.log("no port connected")); + } + } + public removePort(item: PortMan) { + let index = this.portArray.findIndex((el) => el === item); + if (index > -1) { + this.portArray.splice(index, 1); + this.logState(); + } + } + + sendContentMsg(data: PluginEvent) { + this.getCurrentUseContent()?.postMessage(data); + } + sendDevtoolMsg(data: PluginEvent) { + const portMan = this.portArray.find(el => el.isDevtoolsPort()); + if (portMan) { + portMan.port.postMessage(data); + } else { + console.log('not find devtools port'); + } + } + getCurrentUseContent(): chrome.runtime.Port | null { + const portMan = this.portArray.find((portMan: PortMan) => { + const el = portMan.port; + const b1 = el.sender?.frameId !== undefined; + const b2 = el.sender.frameId === this.currentUseContentFrameID + return b1 && b2 + }) + if (portMan) { + return portMan.port; + } else { + return null; + } + } + useFrame(id: number) { + this.currentUseContentFrameID = id; + // 更新这个frame的tree + const sendData = new PluginEvent(Page.Background, Page.Content, Msg.Support); + this.getCurrentUseContent()?.postMessage(sendData); + } + isCurrentFrme(id: number) { + return this.currentUseContentFrameID === id + } +} +export const portMgr = new PortMgr(); \ No newline at end of file diff --git a/cc-inspector/src/scripts/terminal.ts b/cc-inspector/src/scripts/terminal.ts index 93fad96..42e8399 100644 --- a/cc-inspector/src/scripts/terminal.ts +++ b/cc-inspector/src/scripts/terminal.ts @@ -7,13 +7,30 @@ export class Terminal { this.background = background; this.tag = tag; } - ok() { - this.log(`ok`); + init(): string[] { + return this.log(`init`); } - log(message: string) { - console.log(`%c${this.tag}%c${message}`, `color:${this.color};background:${this.background};padding:0 4px`, "color:black;margin-left:5px") + public log(message: string, newline: boolean = false): string[] { + return [`%c${this.tag}%c${newline ? '\n' : ''}${message}`, `color:${this.color};background:${this.background};padding:0 4px`, "color:black;margin-left:5px"]; } - connect(msg: string) { - this.log(`[connect] ${msg}`); + + + public blue(message: string): string[] { + this.color = 'blue'; + return this.log(message); + } + public green(message: string): string[] { + this.color = 'green'; + return this.log(message); + } + public red(message: string): string[] { + this.color = 'red'; + return this.log(message); + } + connect(msg: string): string[] { + return this.log(`[connect] ${msg}`); + } + disconnect(msg: string): string[] { + return this.log(`[disconnect] ${msg}`); } }