重构background

This commit is contained in:
xu_yanfeng
2024-12-24 17:31:26 +08:00
parent 81edca1a3c
commit d62cc0a26c
8 changed files with 363 additions and 241 deletions

View File

@@ -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);
}
}
}
});

View File

@@ -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;
}
};
}
}

View File

@@ -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);
}
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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<PortMan> = [];
/**
* 当前正在通讯的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();