@ng1005/chrome-extension-common
Version:
chrome扩展通用库--消息与storage
208 lines (202 loc) • 6.45 kB
text/typescript
import MessageEventBus from "./MessageEventBus";
import {isBackgroundScript, isPopupScript} from '../utils/Utils'
import { SendMessage } from "../utils/ResponseUtils";
import IMessageInterface from '../interface/IMessageInterface'
export class PortEventBus extends MessageEventBus implements IMessageInterface{
script='content';
port:chrome.runtime.Port|undefined
portTab:chrome.runtime.Port|undefined
popupListener:boolean=false;
constructor (script?:string) {
super();
let defaultScript='content'
if(isBackgroundScript()){
defaultScript='background'
}else if(isPopupScript()){
defaultScript='popup'
}
this.script=script||defaultScript;//当前脚本
this.connect()
}
/**
* 链接(监听)
*/
connect(){
let _this=this;
if(['popup','background'].indexOf(_this.script)>-1){//当是background和popup的时候就是初始化和当前tab的连接
_this.getCurrentTabs((tabs:any)=>{
const tabId=tabs.length ? tabs[0].id: null
if(tabId){//
_this.portTab = chrome.tabs.connect(tabId, {name: _this.script});
// console.log('_this.portTab---connect---',tabId,this.portTab)
_this.portTab.onMessage.addListener(function(requests) {
// console.log('port onMessage---',requests)
_this.handler(requests)
});
_this.popupListener=true;
}else{//没有activeId----如果是background.js中$portBus正常获取不到tabId
this.popListener();//监听tabs.onActivated
}
})
}
//初始化和popup和background的连接
// 监听长连接
let port=chrome.runtime.connect({name:this.script});
this.port=port;
// console.log('connect------')
this.port.onMessage.addListener(function(requests) {
// console.log('port onMessage---',requests)
_this.handler(requests)
});
this.listener()
return this
}
/**
* contentScript监听
*/
popListener(){
let _this=this;
chrome.tabs.onActivated.addListener(
()=>{//
if(this.popupListener){
return;//已经监听了
}
_this.getCurrentTabs((tabs:any)=>{
const tabId=tabs.length ? tabs[0].id: null
_this.popupListener=true;
_this.portTab = chrome.tabs.connect(tabId, {name: _this.script});
// console.log('_this.portTab---popListener-----',this.portTab)
_this.portTab.onMessage.addListener(function(requests) {
// console.log('port onMessage---',requests)
_this.handler(requests)
});
});
},
)
return this
}
/**
* 需要监听用来接收消息
*/
listener(){
let _this=this;
chrome.runtime.onConnect.addListener((port)=>{
port.onMessage.addListener((requests)=>{
// console.log('port onMessage---',requests)
_this.handler(requests)
})
})
return this
}
/**
* 检查链接
*/
checkConnect(){
// console.log('this.connect----',this.port)
if(this.port==undefined||this.portTab==undefined||this.port.name==''){//空对象的时候自动连接
this.connect();
}
return this
}
/**
* 消息处理
* @param {*} request
*/
async handler(request:SendMessage){
let type=request.type||''//$emit提交时的事件
let args=request.message
if(this.script!==request.script){
return;
}
let _this=this;
let handler = _this._events.get(type)//所有该类型的函数集合
if(!handler)return;//无任何监听则退出
let res='';
if (Array.isArray(handler)) {
// 是数组,说明有多个监听者,需要依次触发里边的函数
for (let i = 0; i < handler.length; ++i) {
//用call代替apply----有些消息需要确认tabId
// handler.call(_this, ...args,sender,sendResponse).then(res=>{
let res=await handler[i].call(_this, ...args)
//这是无效的发送消息都是通过port port.postMessage({text: '这里并没有sendResponse!'});
}
} else {
// 单个函数的情况直接触发即可
//用call代替apply----有些消息需要确认tabId
// handler.call(_this, ...args,sender,sendResponse).then(res=>{
let res=await handler.call(_this, ...args)
//这是无效的发送消息都是通过port port.postMessage({text: '这里并没有sendResponse!'});
}
return this
}
$emitContent(type: string, ...args: any): Promise<any> {
if(this.script=='content'){
return this.$emit(type,...args);
}
return new Promise((resolve,reject)=>{
this.checkConnect();
// console.log('this.portTab-----',this._script,this.portTab)
if(this.portTab){
let message:SendMessage={
script:'content',
type: type,//事件名
message: args
}
this.portTab.postMessage(message);
}else{
reject('portTab is undefine!')
return;
// console.log('portTab is undefine!')
}
resolve('')
})
}
$emitBackground(type: string, ...args: any): Promise<any> {
if(this.script==='background'){
return this.$emit(type,...args);
}
return new Promise((resolve,reject)=>{
this.checkConnect();
// console.log('this.portTab-----',this._script,this.portTab)
if(this.port){
let message:SendMessage={
script:'background',
type: type,//事件名
message: args
}
this.port.postMessage(message);
}else{
console.log('port is undefine!')
}
resolve('')
})
}
$emitPopup(type: string, ...args: any): Promise<any> {
if(this.script==='popup'){
return this.$emit(type,...args);
}
return new Promise((resolve,reject)=>{
this.checkConnect();
// console.log('this.portTab-----',this._script,this.portTab)
if(this.port){
let message:SendMessage={
script:'popup',
type: type,//事件名
message: args
}
this.port.postMessage(message);
}else{
console.log('port is undefine!')
}
resolve('')
})
}
$emitWindow(type: string, ...args: any): Promise<any> {
throw new Error("Method not support.");
}
$emitAllTabs(type: string, ...args: any): Promise<any> {
throw new Error("Method not support.");
}
}
const $bus=new PortEventBus()
export default $bus