diff --git a/cc-inspector/src/core/util.ts b/cc-inspector/src/core/util.ts index 487f7be..4a8ea5b 100644 --- a/cc-inspector/src/core/util.ts +++ b/cc-inspector/src/core/util.ts @@ -1,3 +1,4 @@ +import { Page } from "./types"; interface LogOptions { data: any; @@ -7,12 +8,12 @@ interface LogOptions { export function log(options: LogOptions) { const data: any = options.data; - const time = new Date().toLocaleString() - let log = "" + const time = new Date().toLocaleString(); + let log = ""; if (typeof data === "string") { log = data; } else if (typeof data === "object") { - log = JSON.stringify(data) + log = JSON.stringify(data); } let str = ""; @@ -22,8 +23,16 @@ export function log(options: LogOptions) { str = `[${time}]: ${log} `; } if (options.color) { - console.log(`%c${str}`, `color:${options.color};`) + console.log(`%c${str}`, `color:${options.color};`); } else { console.log(str); } } + +export function assembleDevToolsName(id: number) { + return `${Page.Devtools}-${id}`; +} +export function getDevToolsInspectorId(name: string) { + const id = name.split("-")[1]; + return id ? Number(id) : 0; +} diff --git a/cc-inspector/src/scripts/background/portMan.ts b/cc-inspector/src/scripts/background/content.ts similarity index 58% rename from cc-inspector/src/scripts/background/portMan.ts rename to cc-inspector/src/scripts/background/content.ts index 37f27a4..c26a9a1 100644 --- a/cc-inspector/src/scripts/background/portMan.ts +++ b/cc-inspector/src/scripts/background/content.ts @@ -1,7 +1,10 @@ import { debugLog, Page, PluginEvent } from "../../core/types"; +import { FrameDetails } from "../../views/devtools/data"; import { Terminal } from "../terminal"; +import { TabInfo } from "./tabInfo"; -export abstract class PortMan { +export class Content { + public frameID: number = 0; /** * port的名字标识 */ @@ -14,12 +17,14 @@ export abstract class PortMan { public url: string = ""; protected 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; - public timestamp: number = 0; - constructor(tab: chrome.tabs.Tab, port: chrome.runtime.Port) { - this.timestamp = Date.now(); + /** + * 是否正在使用 + */ + public using: boolean = false; + private tabInfo: TabInfo | null = null; + constructor(tab: chrome.tabs.Tab, port: chrome.runtime.Port, tabInfo: TabInfo) { + this.tabInfo = tabInfo; this.port = port; this.tab = tab; this.name = port.name; @@ -38,31 +43,34 @@ export abstract class PortMan { }); port.onDisconnect.addListener((port: chrome.runtime.Port) => { debugLog && console.log(...this.terminal.disconnect("")); - if (this.onDisconnect) { - this.onDisconnect(port); - } + this.onDisconnect(port); }); + this.frameID = port.sender.frameId || 0; + } + getFrameDetais(): FrameDetails { + return { + tabID: this.tabID, + url: this.url, + frameID: this.frameID, + }; + } + private onDisconnect(disPort: chrome.runtime.Port) { + this.tabInfo.removePort(this); } - abstract init(): void; - isContent() { - return this.name === Page.Content; - } - isDevtools() { - return this.name === Page.Devtools; - } - isUseing(id: number) { - if (!this.port) { - return false; + public onMessage(data: PluginEvent) { + // content的数据一般都是要同步到devtools + if (data.isTargetDevtools()) { + if (this.tabInfo.devtool) { + this.tabInfo.devtool.send(data); + } else { + debugger; + } + } else { + debugger; } - if (!this.port.sender) { - return false; - } - if (this.port.sender.frameId === undefined) { - return false; - } - return this.port.sender.frameId === id; } + send(data: PluginEvent) { if (this.port) { this.port.postMessage(data); diff --git a/cc-inspector/src/scripts/background/devtools.ts b/cc-inspector/src/scripts/background/devtools.ts new file mode 100644 index 0000000..2d79807 --- /dev/null +++ b/cc-inspector/src/scripts/background/devtools.ts @@ -0,0 +1,63 @@ +import { debugLog, Msg, Page, PluginEvent, RequestUseFrameData, ResponseSupportData } from "../../core/types"; +import { Terminal } from "../terminal"; +import { TabInfo } from "./tabInfo"; + +export class Devtools { + /** + * port的名字标识 + */ + public name: string = Page.None; + /** + * tab.id作为唯一标识 + */ + public tabID: number | null = null; + public title: string = ""; + public url: string = ""; + protected port: chrome.runtime.Port | null = null; + public tab: chrome.tabs.Tab | null = null; + + public terminal: Terminal = null; + public tabInfo: TabInfo | null = null; + constructor(port: chrome.runtime.Port, tabInfo: TabInfo) { + this.tabInfo = tabInfo; + this.port = port; + this.name = port.name; + this.url = port.sender.url; + this.terminal = new Terminal(`Port-${this.name}`); + port.onMessage.addListener((data: any, port: chrome.runtime.Port) => { + const event = PluginEvent.create(data); + debugLog && console.log(...this.terminal.chunkMessage(event.toChunk())); + if (event.valid && this.onMessage) { + this.onMessage(event); + } else { + debugLog && console.log(...this.terminal.log(JSON.stringify(data))); + } + }); + port.onDisconnect.addListener((port: chrome.runtime.Port) => { + debugLog && console.log(...this.terminal.disconnect("")); + if (this.onDisconnect) { + this.onDisconnect(port); + } + }); + } + public onDisconnect(port: chrome.runtime.Port) { + this.tabInfo.removeDevtools(this); + } + public onMessage(data: PluginEvent) { + if (data.msg === Msg.RequestUseFrame) { + // 因为devtool是定时器驱动,这里改变了content,后续就会将数据派发到对应的content中去 + this.tabInfo.useFrame((data.data as RequestUseFrameData).id); + } else { + // 从devtools过来的消息统一派发到目标content中 + if (data.check(Page.Devtools, Page.Background)) { + data.reset(Page.Background, Page.Content); + this.tabInfo.sendMsgToContent(data); + } + } + } + send(data: PluginEvent) { + if (this.port) { + this.port.postMessage(data); + } + } +} diff --git a/cc-inspector/src/scripts/background/index.ts b/cc-inspector/src/scripts/background/index.ts index 49ccfa7..f0f073f 100644 --- a/cc-inspector/src/scripts/background/index.ts +++ b/cc-inspector/src/scripts/background/index.ts @@ -1,48 +1,40 @@ -import { ChromeConst } from "cc-plugin/src/chrome/const"; import { debugLog, Page, PluginEvent } from "../../core/types"; +import { getDevToolsInspectorId } from "../../core/util"; import { Terminal } from "../terminal"; -import { PortMan } from "./portMan"; -import { portMgr } from "./portMgr"; +import { tabMgr } from "./tabMgr"; const terminal = new Terminal(Page.Background); debugLog && 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; - } - const 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 { + if (port.name === Page.Content) { const tab: chrome.tabs.Tab | undefined = port.sender?.tab; + const tabID = tab.id; + if (tabID === undefined || tabID <= 0) { + return; + } + tabMgr.addTab(tab, port); + } else if (port.name.startsWith(Page.Devtools)) { + const id = getDevToolsInspectorId(port.name); + const tab = tabMgr.findTab(id); if (tab) { - onTabConnect(tab, port); + tab.addDevtools(port); + } else { + debugger; } } }); chrome.runtime.onMessage.addListener((request: PluginEvent, sender: any, sendResponse: any) => { const event = PluginEvent.create(request); const tabID = sender.tab.id; - const portMan: PortMan | undefined = portMgr.findPort(tabID); - if (portMan) { + const tabInfo = tabMgr.findTab(tabID); + if (tabInfo) { if (event.check(Page.Content, Page.Background)) { // 监听来自content.js发来的事件,将消息转发到devtools event.reset(Page.Background, Page.Devtools); console.log(`%c[Message]url:${sender.url}]\n${JSON.stringify(request)}`, "color:green"); - portMgr.sendDevtoolMsg(request, tabID); + if (tabInfo.devtool) { + tabInfo.devtool.send(request); + } } } }); @@ -52,8 +44,11 @@ chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { if (changeInfo.status === "complete") { const { id } = tab; // -1为自己 - if (id && id > -1) { - portMgr.useFrame(0, id); + if (id >= 0) { + const tabInfo = tabMgr.findTab(id); + if (tabInfo) { + tabInfo.useFrame(0); + } } } }); diff --git a/cc-inspector/src/scripts/background/portContent.ts b/cc-inspector/src/scripts/background/portContent.ts deleted file mode 100644 index beca410..0000000 --- a/cc-inspector/src/scripts/background/portContent.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { PluginEvent } from "../../core/types"; -import { FrameDetails } from "../../views/devtools/data"; -import { PortMan } from "./portMan"; -import { portMgr } from "./portMgr"; - -export class PortContent extends PortMan { - protected frameID: number = 0; - constructor(tab: chrome.tabs.Tab, port: chrome.runtime.Port) { - super(tab, port); - this.frameID = port.sender.frameId || 0; - } - getFrameDetais(): FrameDetails { - return { - tabID: this.tabID, - url: this.url, - frameID: this.frameID, - }; - } - init(): void { - // 新的content连上来,需要更新devtools - this.onDisconnect = (disPort: chrome.runtime.Port) => { - // content失去链接需要更新Devtools - portMgr.removePort(this); - if (portMgr.tabUseFrameID[this.tabID] === this.frameID) { - portMgr.useFrame(0, this.tabID); - } - }; - this.onMessage = (data: PluginEvent) => { - // content的数据一般都是要同步到devtools - if (data.isTargetDevtools()) { - portMgr.sendDevtoolMsg(data, this.tabID); - } else { - debugger; - } - }; - } -} diff --git a/cc-inspector/src/scripts/background/portDevtools.ts b/cc-inspector/src/scripts/background/portDevtools.ts deleted file mode 100644 index 44bb537..0000000 --- a/cc-inspector/src/scripts/background/portDevtools.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Msg, Page, PluginEvent, RequestUseFrameData, ResponseSupportData } from "../../core/types"; -import { PortMan } from "./portMan"; -import { portMgr } from "./portMgr"; - -export class PortDevtools extends PortMan { - init(): void { - this.onDisconnect = () => { - portMgr.removePort(this); - }; - this.onMessage = (data: PluginEvent) => { - if (data.msg === Msg.RequestUseFrame) { - // 因为devtool是定时器驱动,这里改变了content,后续就会将数据派发到对应的content中去 - portMgr.useFrame((data.data as RequestUseFrameData).id, this.tabID); - } else { - // 从devtools过来的消息统一派发到目标content中 - if (data.check(Page.Devtools, Page.Background)) { - data.reset(Page.Background, Page.Content); - const port = portMgr.getCurrentUsePort(this.tabID); - if (port) { - port.send(data); - } else { - const e = new PluginEvent(Page.Background, Page.Devtools, Msg.ResponseSupport, { support: false, msg: "disconnect with game, please refresh page", version: "" } as ResponseSupportData); - this.send(e); - } - } - } - }; - } -} diff --git a/cc-inspector/src/scripts/background/portMgr.ts b/cc-inspector/src/scripts/background/portMgr.ts deleted file mode 100644 index 30156e1..0000000 --- a/cc-inspector/src/scripts/background/portMgr.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { debugLog, Msg, Page, PluginEvent, ResponseUpdateFramesData, ResponseUseFrameData } from "../../core/types"; -import { FrameDetails } from "../../views/devtools/data"; -import { Terminal } from "../terminal"; -import { PortContent } from "./portContent"; -import { PortDevtools } from "./portDevtools"; -import { PortMan } from "./portMan"; - -export class PortMgr { - /** - * 所有的链接都在这里 - * 因为iframe的原因,可能对应多个,主iframe的id是0 - */ - public portArray: Array = []; - /** - * 当前正在通讯的frameID,因为游戏可能被好几个iframe嵌套 - * - * 不同的tab,使用的当前frameID可以不一样 - */ - public tabUseFrameID: Record = {}; - private terminal = new Terminal("PortMgr"); - - public findPort(id: number): PortMan | null { - return this.portArray.find((el) => el.tabID === id) || null; - } - /** - * 通知devtools更新 - */ - public updateFrames(tabID: number) { - // 将content类型的port收集起来,同步到devtools - const data: FrameDetails[] = []; - this.portArray.forEach((item) => { - if (item.isContent() && item.tabID === tabID) { - const frame = (item as PortContent).getFrameDetais(); - data.push(frame); - } - }); - const event = new PluginEvent(Page.Background, Page.Devtools, Msg.ResponseUpdateFrames, data as ResponseUpdateFramesData); - this.sendDevtoolMsg(event, tabID); - } - - 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.updateFrames(tab.id); - 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.tabID, - url: port.url, - }); - str.push(`[${i + 1}] time:${new Date(port.timestamp).toLocaleString()}, name:${port.name}, id:${port.tabID}, url:${port.url}`); - } - - if (arr.length) { - // console.table(arr) - debugLog && console.log(...this.terminal.log(str.join("\n"), true)); - } else { - debugLog && 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.updateFrames(item.tabID); - this.logState(); - } - } - - sendDevtoolMsg(data: PluginEvent, tabID: number) { - const portManArray = this.portArray.filter((el) => el.isDevtools() && el.tabID === tabID); - if (portManArray.length) { - portManArray.forEach((portMan) => { - portMan.send(data); - }); - } else { - console.log("not find devtools port"); - } - } - getCurrentUsePort(tabID: number): PortMan | null { - const portMan = this.portArray.find((portMan: PortMan) => { - return portMan.isContent() && portMan.tabID === tabID && portMan.isUseing(this.tabUseFrameID[tabID]); - }); - return portMan || null; - } - useFrame(id: number, tabID: number) { - this.tabUseFrameID[tabID] = id; - const event = new PluginEvent(Page.Background, Page.Devtools, Msg.ResponseUseFrame, { id } as ResponseUseFrameData); - this.sendDevtoolMsg(event, tabID); - } -} -export const portMgr = new PortMgr(); diff --git a/cc-inspector/src/scripts/background/tabInfo.ts b/cc-inspector/src/scripts/background/tabInfo.ts new file mode 100644 index 0000000..5fcbc77 --- /dev/null +++ b/cc-inspector/src/scripts/background/tabInfo.ts @@ -0,0 +1,80 @@ +import { Msg, Page, PluginEvent, ResponseUpdateFramesData, ResponseUseFrameData } from "../../core/types"; +import { FrameDetails } from "../../views/devtools/data"; +import { Content } from "./content"; +import { Devtools } from "./devtools"; + +export class TabInfo { + /** + * 标签的ID + */ + public tabID: number; + constructor(tabID: number) { + this.tabID = tabID; + } + /** + * 因为iframe的原因,可能对应多个,主iframe的id是0 + */ + public contentArray: Array = []; + addContent(tab: chrome.tabs.Tab, port: chrome.runtime.Port) { + // 新的content连上来,需要更新devtools + let portContent: Content = new Content(tab, port, this); + this.contentArray.push(portContent); + this.updateFrames(); + } + public removePort(item: Content) { + let index = this.contentArray.findIndex((el) => el === item); + if (index > -1) { + this.contentArray.splice(index, 1); + this.updateFrames(); + + // 使用第一个frame + if (this.contentArray.length) { + const id = this.contentArray[0].frameID; + this.useFrame(id); + } + } + } + public removeDevtools(item: Devtools) { + this.devtool = null; + } + useFrame(id: number) { + this.contentArray.map((content) => { + content.using = content.frameID === id; + }); + this.sendMsgToDevtool(Msg.ResponseUseFrame, { id } as ResponseUseFrameData); + } + /** + * 通知devtools更新 + */ + private updateFrames() { + const data: FrameDetails[] = []; + this.contentArray.forEach((item) => { + const frame = (item as Content).getFrameDetais(); + data.push(frame); + }); + this.sendMsgToDevtool(Msg.ResponseUpdateFrames, data as ResponseUpdateFramesData); + } + private sendMsgToDevtool(msg: Msg, data: any) { + if (this.devtool) { + const event = new PluginEvent(Page.Background, Page.Devtools, msg, data); + this.devtool.send(event); + } + } + public sendMsgToContent(data: PluginEvent) { + const content = this.contentArray.find((el) => el.using); + if (content) { + content.send(data); + } else { + // 当页面没有完成刷新状态时,conent并没有using,就会触发此处逻辑 + // 在页面完成刷新后,会主动设置为using + } + } + public devtool: Devtools | null = null; + addDevtools(port: chrome.runtime.Port) { + if (this.devtool === null) { + this.devtool = new Devtools(port, this); + } else { + debugger; + } + } +} diff --git a/cc-inspector/src/scripts/background/tabMgr.ts b/cc-inspector/src/scripts/background/tabMgr.ts new file mode 100644 index 0000000..cce42ab --- /dev/null +++ b/cc-inspector/src/scripts/background/tabMgr.ts @@ -0,0 +1,21 @@ +import { TabInfo } from "./tabInfo"; + +export class TabMgr { + /** + * chrome打开的所有标签页面 + */ + public tabArray: TabInfo[] = []; + public findTab(id: number): TabInfo | null { + return this.tabArray.find((el) => el.tabID === id) || null; + } + + addTab(tab: chrome.tabs.Tab, port: chrome.runtime.Port) { + let tabInfo = this.findTab(tab.id); + if (!tabInfo) { + tabInfo = new TabInfo(tab.id); + this.tabArray.push(tabInfo); + } + tabInfo.addContent(tab, port); + } +} +export const tabMgr = new TabMgr(); diff --git a/cc-inspector/src/views/devtools/bridge.ts b/cc-inspector/src/views/devtools/bridge.ts index 7851df0..2972760 100644 --- a/cc-inspector/src/views/devtools/bridge.ts +++ b/cc-inspector/src/views/devtools/bridge.ts @@ -22,7 +22,9 @@ class Bridge implements TestClient { } this._inited = true; if (CCP.Adaptation.Env.isChromeRuntime) { - this.connect = chrome.runtime.connect({ name: Page.Devtools }); + // 调试的标签ID + const id = chrome.devtools.inspectedWindow.tabId; + this.connect = chrome.runtime.connect({ name: `${Page.Devtools}-${id}` }); this.connect.onDisconnect.addListener(() => { debugLog && console.log(...this.terminal.disconnect("")); this.connect = null;