@ng1005/chrome-extension-common
Version:
chrome扩展通用库--消息与storage
244 lines (236 loc) • 7.34 kB
text/typescript
import {EventBusDemo} from "../message/EventBusDemo";
import IStorageInterface from "../interface/IStorageInterface";
import $bus,{RuntimeEventBus} from "../message/RuntimeEventBus";
import { KeyValue } from "../types/KeyValue";
import ResponseUtils from "../utils/ResponseUtils";
import { isArray, isBackgroundScript, isFunctionAsync, isObject, isPopupScript, isString } from "../utils/Utils";
class StorageDataService extends EventBusDemo implements IStorageInterface{
script:string='content';
data:KeyValue={}
keys:KeyValue={
get:'_message_storage_data_service_get',
set:'_message_storage_data_service_set',
watch:'_message_storage_data_service_watch',
listener:'_message_storage_data_service_listener',
}
watchKeys:Array<string>=[]//具体要监听的字段
$runtimeBus:RuntimeEventBus=$bus;
constructor(script?:string){
super()
let defaultScript='content'
if(isBackgroundScript()){
defaultScript='background'
}else if(isPopupScript()){
defaultScript='popup'
}
this.script=script||defaultScript;//当前脚本
// this.$runtimeBus=new RuntimeEventBus()
if(this.script==='background'){
this.listener()
}
this.listenerWatch()
}
/**
* 重写方法
* @param name
* @param callback
* @returns
*/
$on(name: string, callback: Function):this {
if(!name)return this;
if(this.script==='background'){
if(isString(name)){
this.watchKeys.push(name)
}
return this;
}
this.$runtimeBus.$emitBackground(this.keys.watch,name)
super.$on(name,callback);
return this;
}
/**
* 重写提交事件
* @param type 消息类型
* @param args 参数
* @returns
*/
$emit(type:string, ...args:any):Promise<any>{
const [oldVal,newVal]=args;
if(!type){
Promise.reject('错误字段')
}
if(this.script==='background'){
const data={key:type,oldVal,newVal}
this.$runtimeBus.$emitAllTabs(this.keys.listener,data)
}
return Promise.resolve('')
}
listenerWatch(){
let _this=this;
if(this.script==='background'){//后台监听其他页面提交过来的需要监听的key
//仅支持每次监听一个key
this.$runtimeBus.$on(this.keys.watch,(data:any,sender:chrome.runtime.MessageSender,sendResponse:any)=>{
if(isString(data)){
_this.watchKeys.push(data)
}
return true;
})
}else{//非background页面
this.$runtimeBus.$on(this.keys.listener,(data:any,sender:chrome.runtime.MessageSender,sendResponse:any)=>{
// console.log('addListener----',request,sender,sendResponse)
//data:{key:监听字段,old:any,new:any}
return new Promise((resolve,reject)=>{
_this.handler(data,sender,sendResponse).then((res)=>{
resolve(res)
}).catch((err:any)=>{
reject(err||'监听失败')
})
})
})
}
}
/**
* 消息处理
* @param {*} request:any
* @param {*} sender:chrome.runtime.MessageSender
* @param {*} sendResponse:any
*/
async handler(data:any,sender:chrome.runtime.MessageSender,sendResponse:any){
let _this=this;
//data:{key:监听字段,old:any,new:any}
// console.log('listener------',data)
const {key,oldVal,newVal}=data;
if(!key){
return;
}
let handler = _this._events.get(key)//所有该类型的函数集合
if(!handler)return;//无任何监听则退出
if (Array.isArray(handler)) {
// 是数组,说明有多个监听者,需要依次触发里边的函数
for (let i = 0; i < handler.length; ++i) {
let res:any=''
if(isFunctionAsync(handler)){
handler[i].call(_this, oldVal,newVal,sender,sendResponse).then(sendResponse)
}else{
res=handler[i].call(_this, oldVal,newVal,sender,sendResponse)
if(res){
sendResponse(res)//发送返回值来实现$emit中Promise返回内容
}
}
}
} else {
// 单个函数的情况直接触发即可
// let res=await handler.call(_this, ...args,sender,sendResponse)
let res:any=''
if(isFunctionAsync(handler)){
handler.call(_this, oldVal,newVal,sender,sendResponse).then(sendResponse)
}else{
res=handler.call(_this,oldVal,newVal,sender,sendResponse)
if(res){
sendResponse(res)//发送返回值来实现$emit中Promise返回内容
}
}
}
}
listener(){
let _this=this;
this.$runtimeBus.$on(this.keys.get,(data:any,sender:chrome.runtime.MessageSender,sendResponse:any)=>{
return new Promise((resolve,reject)=>{
_this.get(data).then((res)=>{
resolve(res)
}).catch((err:any)=>{
reject(err||'获取失败')
})
})
})
this.$runtimeBus.$on(this.keys.set,(data:any,sender:chrome.runtime.MessageSender,sendResponse:any)=>{
return new Promise((resolve,reject)=>{
if(!isObject(data)){
reject('设置失败,data不是对象');
return
}
_this.set(data).then((res)=>{
resolve(res)
}).catch((err:any)=>{
reject(err||'设置失败')
})
})
})
}
/**
* 根据key获取数据
* @param {*} name
*/
get(name:string|Array<string>){
if(this.script!=='background'){
return this.$runtimeBus.$emitBackground(this.keys.get,name)
}
return new Promise((resolve,reject)=>{
let result:KeyValue={}
if(isString(name)){
result[<string>name]=this.data[<string>name]
resolve(result)
}else if(Array.isArray(name)){
name.forEach((key)=>{
result[key]=this.data[key]
})
resolve(result);
}else{
reject('error name')
}
})
}
/**
* 设置数据
* @param {*} name
* @param {*} value
*/
set(name:string|Object,value?:any){
if(this.script!=='background'){
let data:KeyValue={}
if(isObject(name)){
data=<KeyValue>name;
}else{
data[<string>name]=value;
}
return this.$runtimeBus.$emitBackground(this.keys.set,data)
}
return new Promise((resolve,reject)=>{
let data:KeyValue={}
if(isString(name)){
data[<string>name]=value
this.checkWatch(data)
this.data[<string>name]=value;
}else if(isObject(name)){
data=<KeyValue>name
this.checkWatch(data)
this.data=Object.assign(this.data,name)
}else{
reject('name error')
}
resolve(true)
})
}
/**
* 检查本次更新是否有需要监听的字短
* @param data
*/
async checkWatch(data:KeyValue){
let keys=Object.keys(data)
let _this=this;
this.get(keys).then((res:KeyValue) => {
for(let i=0;i<keys.length;i++){
const key=keys[i]
if(_this.watchKeys.includes(key)){//在监听里面
//判断是否有变化
if(JSON.stringify(data[key])!=JSON.stringify(res[key])){//变更
_this.$runtimeBus.$emitAllTabs(_this.keys.listener,{key,oldVal:data[key],newVal:res[key]})
}
}
}
}).catch((e:any)=>{
Promise.reject(e.message||'未知异常')
})
}
}
export default StorageDataService