2021-11-17 22:19:00 +08:00

222 lines
6.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {Msg, Page, PluginEvent} from "@/core/types";
// @ts-ignore
import * as UA from "universal-analytics"
import {v4} from "uuid"
import {devtools_page} from "./manifest.json"
// 统计服务
const userID = localStorage.getItem("userID") || v4()
UA("UA-134924925-3", userID);
console.log("on background")
class PortMan {
public currentUseContentFrameID = 0;
public content: Array<chrome.runtime.Port> = []; // 因为iframe的原因可能对应多个主iframe的id===0
public devtools: chrome.runtime.Port | null = null;
public id: number | null = null;// tab.id作为唯一标识
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) {
console.log(`%c[Connect] ${port.name}`, "color:green");
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 {
return this.content.find(el => el.sender?.frameId !== undefined && el.sender.frameId === this.currentUseContentFrameID) || null;
}
dealConnect(port: chrome.runtime.Port) {
switch (port.name) {
case Page.Content: {
this.content.push(port);
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.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.getCurrentUseContent()?.postMessage(data)
}
},
() => {
this.devtools = null;
this.checkValid();
})
break
}
}
}
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<PortMan> = [];
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.Support);
portMan.sendContentMsg(data);
}
}
}
})
}
isDevtools(port: chrome.runtime.Port) {
const devtoolsUrl = `chrome-extension://${port.sender?.id}/${devtools_page}`
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.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);
}
}
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 = [];
let parent = chrome.contextMenus.create({id: "parent", title: "CC-Inspector"});
chrome.contextMenus.create({
id: "test",
title: "测试右键菜单",
parentId: parent,
// 上下文环境,可选:["all", "page", "frame", "selection", "link", "editable", "image", "video", "audio"]默认page
contexts: ["page"],
});
chrome.contextMenus.create({
id: "notify",
parentId: parent,
title: "通知"
})
chrome.contextMenus.onClicked.addListener(function (info, tab) {
if (info.menuItemId === "test") {
alert("您点击了右键菜单!");
} else if (info.menuItemId === "notify") {
chrome.notifications.create("null", {
type: "basic",
iconUrl: "icons/48.png",
title: "通知",
message: "测试通知",
})
}
})
}
chrome.contextMenus.removeAll(function () {
createPluginMenus();
});