@ng1005/chrome-extension-common
Version:
chrome扩展通用库--消息与storage
278 lines (274 loc) • 9.2 kB
text/typescript
import MessageEventBus from "./MessageEventBus";
import {isBackgroundScript, isContentScript, isFunctionAsync, isPopupScript, isPromise} from '../utils/Utils'
import ResponseUtils, { SendMessage,ResponseMessage } from "../utils/ResponseUtils";
import IMessageInterface from "../interface/IMessageInterface";
import { KeyValue } from "../types/KeyValue";
interface SendMessageBridge{
script:string;//发送方
bridgeType:string;//桥接消息类型---统一
type:string;//消息类型---动态
message:any;//消息数据
}
export class RuntimeEventBus extends MessageEventBus implements IMessageInterface{
script:string='content'
types:KeyValue={
content2AllTabs:'_message_bridge_content2AllTabs_',
}
constructor (script?:string) {
super();
let defaultScript='content'
if(isBackgroundScript()){
defaultScript='background'
}else if(isPopupScript()){
defaultScript='popup'
}
this.script=script||defaultScript;//当前脚本
this.listener()
this.listenerBridge()
}
listener(): void {
let _this=this
chrome.runtime.onMessage.addListener(function(request,sender,sendResponse){
if(sender.id!=chrome.runtime.id){//不属于当前插件
return;
}
let script=request.script
if(_this.script!==script){//不是当前脚本的请求
return;
}
_this.handler(request,sender,sendResponse)
return true;
});
}
/**
* content2AllTabs需要中转
*/
listenerBridge(){
if(this.script==='background'){
let _this=this
// console.log('listener bridge-----')
chrome.runtime.onMessage.addListener(function(request:SendMessageBridge,sender,sendResponse){
if(sender.id!=chrome.runtime.id&&!_this.crossExtension){//不属于当前插件
return;
}
let script=request.script
if(_this.script!==script){//不是当前脚本的请求
return;
}
// console.log('bridge-----',_this.script,request)
switch (request.bridgeType) {
case _this.types.content2AllTabs:
_this.$emitAllTabs(request.type,...request.message)
break;
default:
break;
}
return true;
});
}
}
/**
* 消息处理
* @param {*} request:any
* @param {*} sender:chrome.runtime.MessageSender
* @param {*} sendResponse:any
*/
async handler(request:SendMessage,sender:chrome.runtime.MessageSender,sendResponse:any){
let type=request.type||''//$emit提交时的事件
let args=request.message
let _this=this;
let handler = _this._events.get(type)//所有该类型的函数集合
if(!handler)return;//无任何监听则退出
if (Array.isArray(handler)) {
// 是数组,说明有多个监听者,需要依次触发里边的函数
for (let i = 0; i < handler.length; ++i) {
let res:any=''
if(isFunctionAsync(handler[i])){
handler[i].call(_this, ...args,sender,sendResponse).then((data:any)=>{
sendResponse(ResponseUtils.success(data))
}).catch((e:any)=>{
sendResponse(ResponseUtils.error(e))//默认发送
})
}else{
res=handler[i].call(_this, ...args,sender,sendResponse)
if(isPromise(res)){
res.then((r:any)=>{
sendResponse(ResponseUtils.success(r))
}).catch((e:any)=>{
sendResponse(ResponseUtils.error(e))//默认发送
})
}else if(res){
sendResponse(ResponseUtils.success(res))//发送返回值来实现$emit中Promise返回内容
}else{
sendResponse(ResponseUtils.error('未知错误'))//发送返回值来实现$emit中Promise返回内容
}
}
}
} else {
// 单个函数的情况直接触发即可
// let res=await handler.call(_this, ...args,sender,sendResponse)
let res:any=''
if(isFunctionAsync(handler)){
handler.call(_this, ...args,sender,sendResponse).then((data:any)=>{
sendResponse(ResponseUtils.success(data))
}).catch((e:any)=>{
sendResponse(ResponseUtils.error(e))//默认发送
})
}else{
res=handler.call(_this, ...args,sender,sendResponse)
if(isPromise(res)){
res.then((r:any)=>{
sendResponse(ResponseUtils.success(r))
}).catch((e:any)=>{
sendResponse(ResponseUtils.error(e))//默认发送
})
}else if(res){
sendResponse(ResponseUtils.success(res))//发送返回值来实现$emit中Promise返回内容
}else{
sendResponse(ResponseUtils.error('未知错误'))//发送返回值来实现$emit中Promise返回内容
}
}
}
}
$emitContent(type: string, ...args: any): Promise<any> {
let _this=this
let _script='content';
if(_this.script===_script){//
return new Promise((resolve,reject)=>{
chrome.runtime.sendMessage({
script:'content',//发送给background的
type: type,//事件名
message: args
},(response:ResponseMessage)=>{
if(ResponseUtils.isSuccess(response)){
resolve(response.data)
}else{
reject(response.message)
}
});
})
}
return new Promise((resolve,reject)=>{//调整成Promise
_this.getCurrentTabs((tabs:any)=>{
const tabId=tabs.length ? tabs[0].id: null
if(!tabId){
reject('找到激活的tab')
}
const message:SendMessage={
script:_script,
type: type,//事件名
message: args
}
// console.log('ssss',message)
chrome.tabs.sendMessage(tabId, message, function(response){
// console.log('response=====',response);
if(ResponseUtils.isSuccess(response)){
resolve(response.data)
}else{
reject(response.message)
}
});
})
})
}
$emitBackground(type: string, ...args: any): Promise<any> {
let _this=this
let _script='background';
return new Promise((resolve,reject)=>{
const message:SendMessage={
script:_script,
type: type,//事件名
message: args
}
chrome.runtime.sendMessage(message,(response:ResponseMessage)=>{
if(ResponseUtils.isSuccess(response)){
resolve(response.data)
}else{
reject(response.message)
}
});
})
}
$emitPopup(type: string, ...args: any): Promise<any> {
let _this=this
let _script='popup';
return new Promise((resolve,reject)=>{
const message:SendMessage={
script:_script,
type: type,//事件名
message: args
}
chrome.runtime.sendMessage(message,(response:ResponseMessage)=>{
if(ResponseUtils.isSuccess(response)){
resolve(response.data)
}else{
reject(response.message)
}
});
})
}
$emitWindow(type: string, ...args: any): Promise<any> {
switch (this.script) {//只支持contentScript
case 'content':
return new Promise((resolve,reject)=>{
window.postMessage({
script:'window',
type:type,
message:args
})
})
default:
throw new Error("当前页面不支持发送消息给window.");
}
}
$emitAllTabs(type: string, ...args: any): Promise<any> {
let _this=this
let _script='content';
if(_this.script===_script){//contentScript本身
return new Promise((resolve,reject)=>{
chrome.runtime.sendMessage({
bridgeType:_this.types.content2AllTabs,
script:'background',
type: type,//事件名
message: args
},(response:ResponseMessage)=>{
// console.log('response=====',response);
if(ResponseUtils.isSuccess(response)){
resolve(response.data)
}else{
reject(response.message)
}
});
})
}
return new Promise((resolve,reject)=>{//调整成Promise
_this.getTabs((tabs:any)=>{
// console.log('tabs----',tabs,args)
if(tabs&&Array.isArray(tabs)&&tabs.length>0){
for(let i=0;i<tabs.length;i++){
const tabId=tabs[i].id|| null
const message:SendMessage={
script:_script,
type: type,//事件名
message: args
}
chrome.tabs.sendMessage(tabId, message, function(response){
// console.log('response=====',response);
if(i===tabs.length){//最后一个发送完成
if(ResponseUtils.isSuccess(response)){
resolve(response.data)
}else{
reject(response.message)
}
}
});
}
}else{
reject('找到激活的tab')
}
},{})//{windowType:'normal'}
})
}
}
const $bus=new RuntimeEventBus()
export default $bus