From cff5edf2639ff1ceedba10d6a59f66f87a57a221 Mon Sep 17 00:00:00 2001 From: xyf-mac Date: Thu, 4 Nov 2021 21:01:33 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/package.json | 2 +- source/src/background.ts | 213 ++++++++++++++++------- source/src/content.ts | 76 +++++--- source/src/core/types.ts | 5 +- source/src/core/util.ts | 36 +++- source/src/devtools/connectBackground.ts | 12 +- source/src/devtools/inject.ts | 1 - source/src/devtools/register-panel.ts | 2 +- source/src/devtools/ui/index.vue | 25 ++- 9 files changed, 255 insertions(+), 117 deletions(-) diff --git a/source/package.json b/source/package.json index 8af876d..77d74d1 100644 --- a/source/package.json +++ b/source/package.json @@ -1,6 +1,6 @@ { "name": "app", - "version": "0.1.0", + "version": "0.1.1", "private": true, "scripts": { "serve": "vue-cli-service serve", diff --git a/source/src/background.ts b/source/src/background.ts index cf8c534..a99e7c3 100644 --- a/source/src/background.ts +++ b/source/src/background.ts @@ -1,83 +1,166 @@ -import {Page, PluginEvent, Msg} from "@/core/types"; +import {Msg, Page, PluginEvent} from "@/core/types"; -let Devtools: chrome.runtime.Port | null = null; -let Content: chrome.runtime.Port | null = null; -console.log('on background') +console.log("on background") -chrome.runtime.onConnect.addListener((port: chrome.runtime.Port) => { - switch (port.name) { - case Page.Devtools: { - Devtools = port; - onPortConnect(port, - (data: PluginEvent) => { - // 从devtools过来的消息统一派发到Content中 - if (PluginEvent.check(data, Page.Devtools, Page.Background)) { - PluginEvent.reset(data, Page.Background, Page.Content); - Content && Content.postMessage(data) - } - }, - () => { - Devtools = null; - }) - break; - } - case Page.Content: { - Content = port; - onPortConnect(port, - () => { +class PortMan { + content: chrome.runtime.Port | null = null; + devtools: chrome.runtime.Port | null = null; + public id: number | null = null;// tab.id作为唯一标识 + public title: string = ""; + public url: string = ""; + private mgr: PortManagement | null = null; - }, - () => { - Content = null; + constructor(mgr: PortManagement, {id, url, title}: any) { + this.mgr = mgr; + this.id = id; + this.url = url; + this.title = title; + } - }) - break + private onPortConnect(port: chrome.runtime.Port, onMsg: Function, onDisconnect: Function) { + port.onMessage.addListener((data: any, sender: any) => { + console.log(`%c[Connect-Message] ${sender.name}\n${JSON.stringify(data)}`, "color:green;") + // 如果多个页面都监听 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() + }); + } + + dealConnect(port: chrome.runtime.Port) { + switch (port.name) { + case Page.Content: { + this.content = port; + this.onPortConnect(port, + (data: PluginEvent) => { + if (data.target === Page.Devtools) { + this.sendDevtoolMsg(data); + } + }, + () => { + this.content = null; + this.checkValid(); + }) + break; + } + case Page.Devtools: { + this.devtools = port; + this.onPortConnect(port, + (data: PluginEvent) => { + // 从devtools过来的消息统一派发到Content中 + if (PluginEvent.check(data, Page.Devtools, Page.Background)) { + PluginEvent.reset(data, Page.Background, Page.Content); + this.content?.postMessage(data) + } + }, + () => { + this.devtools = null; + this.checkValid(); + }) + break + } } } -}); -function onPortConnect(port: chrome.runtime.Port, onMsg: Function, onDisconnect: Function) { - console.log(`%c[Connect] ${port.name}`, "color:blue;"); - port.onMessage.addListener((data: any, sender: any) => { - console.log(`%c[Connect-Message] ${sender.name}\n${JSON.stringify(data)}`, "color:green;") - // 如果多个页面都监听 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() - }); + checkValid() { + if (!this.devtools && !this.content) { + this.mgr?.remove(this); + } + } + + sendContentMsg(data: PluginEvent) { + this.content?.postMessage(data); + } + + sendDevtoolMsg(data: PluginEvent) { + this.devtools?.postMessage(data) + } } +class PortManagement { + port: Array = []; -// background.js 更像是一个主进程,负责整个插件的调度,生命周期和chrome保持一致 -// 监听来自content.js发来的事件,将消息转发到devtools -chrome.runtime.onMessage.addListener((request: PluginEvent, sender: any, sendResponse: any) => { - if (PluginEvent.check(request, Page.Content, Page.Background)) { - PluginEvent.reset(request, Page.Background, Page.Devtools) - console.log(`%c[Message]url:${sender.url}]\n${JSON.stringify(request)}`, 'color:green') - sendResponse && sendResponse(request); - Devtools && Devtools.postMessage(request); + constructor() { + 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.Test, + {url: tab.url} + ); + // portMan.sendContentMsg(data); + } + } + } + }) + } + + initConnect() { + chrome.runtime.onConnect.addListener((port: chrome.runtime.Port) => { + if (port.name === Page.Devtools) { + // devtool链接过来没有port.sender.tab + chrome.tabs.getSelected((tab: chrome.tabs.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); } } -); -chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { - console.warn(changeInfo.status) - if (changeInfo.status === "complete") { - // 加载新的url - if (Content) { - let data = new PluginEvent( - Page.Background, - Page.Content, - Msg.UrlChange, - {url: tab.favIconUrl} - ); - Content.postMessage(data); + 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) } } -}) +} + +(window as any).backgroundInstance = new PortManagement(); function createPluginMenus() { const menus = []; diff --git a/source/src/content.ts b/source/src/content.ts index a6f750f..904eaa2 100644 --- a/source/src/content.ts +++ b/source/src/content.ts @@ -5,37 +5,57 @@ import {Msg, Page, PluginEvent} from "@/core/types"; injectScript("js/inject.js"); -// 和background.js保持长连接通讯 -let conn = chrome.runtime.connect({name: Page.Content}) -conn.onMessage.addListener((data: PluginEvent, sender) => { - // 将background.js的消息返回到injection.js - if (PluginEvent.check(data, Page.Background, Page.Content)) { - // console.log(`%c[Connect-Message] ${JSON.stringify(data)}`, "color:green;") - console.log('[Connect-Message]: ', data); - PluginEvent.reset(data, Page.Content, Page.Inject) - window.postMessage(data, "*"); +class Content { + private connect: chrome.runtime.Port | null = null; + + constructor() { + // 接受来自inject.js的消息数据,然后中转到background.js + window.addEventListener("message", (event) => { + let data: PluginEvent = event.data; + if (PluginEvent.check(data, Page.Inject, Page.Content)) { + console.log("[Window-Message]: ", data); + PluginEvent.reset(data, Page.Content, Page.Devtools) + this.connect?.postMessage(data) + } + }, false); } -}) -// 接受来自inject.js的消息数据,然后中转到background.js -window.addEventListener('message', function (event) { - let data: PluginEvent = event.data; - if (PluginEvent.check(data, Page.Inject, Page.Content)) { - // console.log(`%c[Window-Message] ${JSON.stringify(data)}`, "color:green;"); - console.log('[Window-Message]: ', data); - PluginEvent.reset(data, Page.Content, Page.Background) - chrome.runtime.sendMessage(data); + // 和background.js保持长连接通讯,background和content的交互也要通过这个链接进行通讯 + private connectToBackground() { + this.connect = chrome.runtime.connect({name: Page.Content}) + this.connect.onMessage.addListener((data: PluginEvent, sender) => { + if (PluginEvent.check(data, Page.Background, Page.Content)) { + // console.log(`%c[Connect-Message] ${JSON.stringify(data)}`, "color:green;") + console.log("[Connect-Message]: ", data); + PluginEvent.reset(data, Page.Content, Page.Inject) + window.postMessage(data, "*"); + } + }) } -}, false); + private sendMessageToBackground(data: PluginEvent) { + if (this.connect) { + this.connect.postMessage(data); + } + } -let gameCanvas = document.querySelector("#GameCanvas"); -if (!gameCanvas) { - let sendData = new PluginEvent(Page.Content, Page.Background, Msg.Support, { - support: false, - msg: "未发现GameCanvas,不支持调试游戏!" - }) - chrome.runtime.sendMessage(sendData, (ret) => { - console.log(ret) - }); + async run() { + this.connectToBackground(); + this.checkGame(); + } + + private checkGame() { + let gameCanvas = document.querySelector("#GameCanvas"); + if (!gameCanvas) { + let sendData = new PluginEvent(Page.Content, Page.Devtools, Msg.Support, { + support: false, + msg: "未发现GameCanvas,不支持调试游戏!" + }) + this.sendMessageToBackground(sendData) + } + } } + + +const content = new Content(); +content.run(); diff --git a/source/src/core/types.ts b/source/src/core/types.ts index 4fd118b..a462a01 100644 --- a/source/src/core/types.ts +++ b/source/src/core/types.ts @@ -13,7 +13,8 @@ export enum Msg { Support = "game-support",// 游戏支持信息 MemoryInfo = "memory-info",// TabsInfo = "tabs_info", // 当前页面信息 - UrlChange = "url_change", // 网址发生变化 + GetTabID = "GetTabID", // 获取页面ID + Test='Test', SetProperty = "set-property", // 设置node属性 UpdateProperty = 'update-property', // 更新属性 } @@ -45,7 +46,7 @@ export class PluginEvent { this.source = source; this.target = target; this.msg = msg; - this.data = data || null; + this.data = data; } else { console.warn(`无效的target: ${target}`) } diff --git a/source/src/core/util.ts b/source/src/core/util.ts index 96fa946..a4b6954 100644 --- a/source/src/core/util.ts +++ b/source/src/core/util.ts @@ -2,12 +2,42 @@ export function injectScript(url: string) { if (chrome && chrome.extension && chrome.extension.getURL) { let content = chrome.extension.getURL(url) console.log(`[cc-inspector]注入脚本:${content}`); - let script = document.createElement('script') - script.setAttribute('type', 'text/javascript') - script.setAttribute('src', content) + const script = document.createElement("script") + script.setAttribute("type", "text/javascript") + script.setAttribute("src", content) script.onload = function () { document.body.removeChild(script); } document.body.appendChild(script) } } + + +interface LogOptions { + data: any; + flag?: string; + color?: "red" | "blue"; +} + +export function log(options: LogOptions) { + const data: any = options.data; + const time = new Date().toLocaleString() + let log = "" + if (typeof data === "string") { + log = data; + } else if (typeof data === "object") { + log = JSON.stringify(data) + } + + let str = ""; + if (options.flag) { + str = `[${time}][${options.flag}]: ${log} `; + } else { + str = `[${time}]: ${log} `; + } + if (options.color) { + console.log(`%c${str}`, `color:${options.color};`) + } else { + console.log(str); + } +} diff --git a/source/src/devtools/connectBackground.ts b/source/src/devtools/connectBackground.ts index f74e24d..82d4202 100644 --- a/source/src/devtools/connectBackground.ts +++ b/source/src/devtools/connectBackground.ts @@ -4,10 +4,14 @@ class ConnectBackground { connect: chrome.runtime.Port | null = null; constructor() { + this._initConnect(); + } + + private _initConnect() { if (chrome && chrome.runtime) { this.connect = chrome.runtime.connect({name: Page.Devtools}); this.connect.onDisconnect.addListener(() => { - console.log(`%c[Connect-Dis]`, 'color:red;') + console.log(`%c[Connect-Dis]`, "color:red;") this.connect = null; }) } @@ -21,12 +25,14 @@ class ConnectBackground { } } - postMessageToBackground(msg: Msg, data?: any ) { + postMessageToBackground(msg: Msg, data?: any) { if (this.connect) { let sendData = new PluginEvent(Page.Devtools, Page.Background, msg, data) this.connect.postMessage(sendData) } else { - console.warn('没有和background建立链接') + console.warn("重新和background建立链接") + this._initConnect(); + this.postMessageToBackground(msg, data) } } diff --git a/source/src/devtools/inject.ts b/source/src/devtools/inject.ts index 5b07f2f..590c8be 100644 --- a/source/src/devtools/inject.ts +++ b/source/src/devtools/inject.ts @@ -47,7 +47,6 @@ class CCInspector { console.log(`%c[Inject] ${JSON.stringify(pluginEvent)}`, "color:green;"); PluginEvent.finish(pluginEvent) switch (pluginEvent.msg) { - case Msg.UrlChange: case Msg.Support: { let isCocosGame = this._isCocosGame(); this.notifySupportGame(isCocosGame) diff --git a/source/src/devtools/register-panel.ts b/source/src/devtools/register-panel.ts index 3e80f53..04cf9ae 100644 --- a/source/src/devtools/register-panel.ts +++ b/source/src/devtools/register-panel.ts @@ -15,7 +15,7 @@ export function init() { panel.onShown.addListener((window) => { // 面板显示,查询是否是cocos游戏 console.log("panel show"); - connectBackground.postMessageToBackground(Msg.Support, null) + // connectBackground.postMessageToBackground(Msg.Support, null) }); panel.onHidden.addListener(() => { // 面板隐藏 diff --git a/source/src/devtools/ui/index.vue b/source/src/devtools/ui/index.vue index e5e4e79..6268c30 100644 --- a/source/src/devtools/ui/index.vue +++ b/source/src/devtools/ui/index.vue @@ -28,7 +28,7 @@ @node-expand="onNodeExpand" @node-collapse="onNodeCollapse" @node-click="handleNodeClick"> - + {{ node.label }} @@ -52,10 +52,10 @@ import Vue from "vue"; import {Component} from "vue-property-decorator"; import properties from "./propertys.vue"; -import {Msg, Page, PluginEvent} from '@/core/types' +import {Msg, Page, PluginEvent} from "@/core/types" import {connectBackground} from "@/devtools/connectBackground"; import {EngineData, Info, TreeData} from "@/devtools/data"; -import Bus, {BusMsg} from '@/devtools/bus'; +import Bus, {BusMsg} from "@/devtools/bus"; @Component({ components: { @@ -130,7 +130,7 @@ export default class Index extends Vue { renderContent(h: Function, options: any) { let {node, data, store} = options; - return h('span', {class:''}, data.name) + return h("span", {class: ""}, data.name) // return(1111) } @@ -184,14 +184,12 @@ export default class Index extends Vue { if (!data) { return; } - if (PluginEvent.check(data, Page.Background, Page.Devtools)) { + if (data.target === Page.Devtools) { + debugger console.log(`[Devtools] ${JSON.stringify(data)}`); PluginEvent.finish(data); let eventData: any = data.data; switch (data.msg) { - case Msg.UrlChange: { - break; - } case Msg.TreeInfo: { this._onMsgListInfo(eventData as Array); break; @@ -238,10 +236,10 @@ export default class Index extends Vue { circle(this.treeData) let ret = treeArray.find(el => el.uuid === uuid); if (ret) { - if (key === 'name') { + if (key === "name") { ret.name = value; } - if (key === 'active') { + if (key === "active") { ret.active = !!value; } } @@ -287,7 +285,7 @@ export default class Index extends Vue { } _inspectedCode() { - let injectCode = ''; + let injectCode = ""; chrome.devtools.inspectedWindow.eval(injectCode, (result, isException) => { if (isException) { console.error(isException); @@ -302,6 +300,7 @@ export default class Index extends Vue { } onBtnClickUpdatePage() { + debugger this.runToContentScript(Msg.Support); } @@ -310,13 +309,13 @@ export default class Index extends Vue { } onNodeExpand(data: TreeData) { - if (data.hasOwnProperty('uuid') && data.uuid) { + if (data.hasOwnProperty("uuid") && data.uuid) { this.expandedKeys.push(data.uuid) } } onNodeCollapse(data: TreeData) { - if (data.hasOwnProperty('uuid')) { + if (data.hasOwnProperty("uuid")) { let index = this.expandedKeys.findIndex(el => el === data.uuid); if (index !== -1) { this.expandedKeys.splice(index, 1)