Skip to content
This repository has been archived by the owner on Apr 7, 2024. It is now read-only.
/ rpc-shooter Public archive

A tool library for handling window && iframe && worker communication based on the JSON RPC specification

License

Notifications You must be signed in to change notification settings

kinglisky/rpc-shooter

Repository files navigation

notice

This repository is no longer maintained, there are better ways in reality.

Cái này kho hàng không hề giữ gìn, có càng tốt hiện thực phương thức.

see:https://github /kinglisky/comlink-adapters

rpc-shooter

A tool library for handling window && iframe && worker communication based on the JSON RPC specification

Một cái căn cứ vàoJSON-RPCQuy phạm dùng cho xử lý window && iframe && worker thông tin công cụ kho

Vì cái gì muốn viết cái này công cụ?

Sử dụngiframeCùngWeb WorkerThường xuyên yêu cầu viết như sau số hiệu:

iframe trung phục vụ thuyên chuyển

// parent.js
constchildWindow=document.querySelector('iframe').contentWindow;
window.addEventListener('message',function(event){
constdata=event.data;
if(data.event==='do_something'){
//... handle iframe data
childWindow.postMessage({
event:'re:do_something',
data:'some data',
});
}
});

// iframe.js
window.top.postMessage(
{
event:'do_something',
data:'ifame data',
},
'*'
);
window.addEventListener('message',function(event){
constdata=event.data;
if(data.event==='re:do_something'){
//... handle parent data
}
});

worker phục vụ thuyên chuyển

// parent.js
constworker=newWorker('worker.js');
worker.addEventListener('message',function(event){
constdata=event.data;
if(data.event==='do_something'){
//... handle worker data
worker.postMessage({
event:'re:do_something',
data:'some data',
});
}
});

// worker.js
self.postMessage({
event:'do_something',
data:'worker data',
});
self.addEventListener('message',function(event){
constdata=event.data;
if(data.event==='re:do_something'){
//... handle parent data
}
});

Kể trên phương thức có thể xử lý chuyện đơn giản thông tín, nhưng nhằm vào phức tạp cảnh tượng hạ vượt giao diện ( tiến trình ) thông tín yêu cầu một cái đơn giản hữu hiệu xử lý phương thức, nếu có thể phong giả dạng làm dị bước hàm số thuyên chuyển phương thức, tắc sẽ ưu nhã rất nhiều, như sau:

// parent.js
constparentRPC=newRPC({...});
parentRPC.registerMethod('parent.do_something',(data)=>{
returnPromise.resolve({...});
});
parentRPC.invoke('child.do_something',{data:'xxx'})
.then(res=>{
console.error(res);
})
.catch(error=>{
console.error(error);
});

// child.js
constchildRPC=newRPC({...});
childRPC.registerMethod('child.do_something',(data)=>{
returnPromise.resolve({...});
});
childRPC.invoke('parent.do_something',{data:'xxx'})
.then(res=>{
console.error(res);
})
.catch(error=>{
console.error(error);
});

Sử dụngJSON-RPC 2.0Quy phạm có thể thực rõ ràng đơn giản miêu tả hai cái phục vụ gian thuyên chuyển,rpc-shooterTrung sử dụngJSON-RPCLàm số liệu lẫn nhau cách thức.

Trang bị

yarn add rpc-shooter
#or
npm i rpc-shooter -S

Sử dụng

Sử dụngRPCMessageEventMô khối có thể bao dung dưới đây mô khối tin tức thông tín:

Nếu có càng chuyện phức tạp kiện lẫn nhau cảnh tượng, thực hiện chính mìnheventMô khối là được.

iframe

// main.ts
import{RPCMessageEvent,RPC}from'rpc-shooter';

(asyncfunction(){
constiframe=document.querySelector('iframe')!;
constrpc=newRPC({
event:newRPCMessageEvent({
currentEndpoint:window,
targetEndpoint:iframe.contentWindow!,
config:{targetOrigin:'*'},
}),
// khởi động lại khi đăng ký xử lý hàm số
methods:{
'Main.max':(a:number,b:number)=>Math.max(a,b),
},
});
// động thái đăng ký xử lý hàm số
rpc.registerMethod('Main.min',(a:number,b:number)=>{
returnPromise.resolve(Math.min(a,b));
});

// kiểm tra liên tiếp, phối trí siêu thời thời gian
awaitrpc.connect(2000);

// thuyên chuyển iframe phục vụ trung đăng ký phương pháp
constrandomValue=awaitrpc.invoke('Child.random',null,{isNotify:false,timeout:2000});
console.log(`Main invoke Child.random result:${randomValue}`);
})();
// child.ts
import{RPCMessageEvent,RPC}from'rpc-shooter';
(asyncfunction(){
constrpc=newRPC({
event:newRPCMessageEvent({
currentEndpoint:window,
targetEndpoint:window.top,
}),
});

rpc.registerMethod('Child.random',()=>Math.random());

awaitrpc.connect(2000);

constmax=awaitrpc.invoke('Main.max',[1,2]);
constmin=awaitrpc.invoke('Main.min',[1,2]);
console.log({max,min});
})();

window

// main.ts
import{RPCMessageEvent,RPC}from'rpc-shooter';
(asyncfunction(){
constopenNewWindow=(path:string)=>{
returnwindow.open(path,'_blank');
};
constnewWindow=openNewWindow('new-window.html');
constrpc=newRPC({
event:newRPCMessageEvent({
currentEndpoint:window,
targetEndpoint:newWindow,
config:{targetOrigin:'*'},
}),
});
rpc.registerMethod('Main.max',(a:number,b:number)=>{
returnPromise.resolve(Math.max(a,b));
});
awaitrpc.connect(2000);
awaitrpc.invoke('Child.random',null);
})();
// child.ts
import{RPCMessageEvent,RPC}from'rpc-shooter';
(asyncfunction(){
constrpc=newRPC({
event:newRPCMessageEvent({
currentEndpoint:window,
targetEndpoint:window.opener,
}),
});
rpc.registerMethod('Child.random',()=>Math.random());

awaitrpc.connect(2000);

awaitrpc.invoke('Main.max',[1,2]);
})();

Web Worker

// main.ts
import{RPCMessageEvent,RPC}from'rpc-shooter';

(asyncfunction(){
constworker=newWorker('./slef.worker.ts');
constrpc=newRPC({
event:newRPCMessageEvent({
currentEndpoint:worker,
targetEndpoint:worker,
}),
});
rpc.registerMethod('Main.max',(a:number,b:number)=>{
returnPromise.resolve(Math.max(a,b));
});
awaitrpc.connect(2000);
awaitrpc.invoke('Child.random',null);
})();
// child.ts
import{RPCMessageEvent,RPC}from'rpc-shooter';

(asyncfunction(){
constctx:Worker=selfasany;
constrpc=newRPC({
event:newRPCMessageEvent({
currentEndpoint:ctx,
targetEndpoint:ctx,
}),
});
rpc.registerMethod('Child.random',()=>Math.random());

awaitrpc.connect(2000);

awaitrpc.invoke('Main.max',[1,2]);
})();

Shared Worker

// main.ts
import{RPCMessageEvent,RPC}from'rpc-shooter';

(asyncfunction(){
constworker:SharedWorker=newSharedWorker('./shared.worker.ts');
worker.port.start();
constrpc=newRPC({
event:newRPCMessageEvent({
currentEndpoint:worker.port,
targetEndpoint:worker.port,
}),
});
rpc.registerMethod('Main.max',(a:number,b:number)=>{
returnPromise.resolve(Math.max(a,b));
});
awaitrpc.connect(2000);
awaitrpc.invoke('Child.random',null);
})();
// child.ts
import{RPCMessageEvent,RPC}from'rpc-shooter';

interfaceSharedWorkerGlobalScope{
onconnect:(event:MessageEvent)=>void;
}

constctx:SharedWorkerGlobalScope=selfasany;

ctx.onconnect=async(event:MessageEvent)=>{
constport=event.ports[0];
port.start();
constrpc=newRPC({
event:newRPCMessageEvent({
currentEndpoint:port,
targetEndpoint:port,
}),
});
rpc.registerMethod('Child.random',()=>Math.random());

awaitrpc.connect(2000);

awaitrpc.invoke('Main.max',[1,2]);
};

Phối trí hạng

rpc-shooterTừ trung tâm hai cái mô khối tạo thành:

  • RPCMessageEvent dùng cho hai cái thông tín trên dưới văn ( window | iframe | worker ) sự kiện lẫn nhau
  • RPC đốiRPCMessageEventSự kiện lẫn nhau tiến hành phong trang, cung cấp phương pháp đăng ký cùng thuyên chuyển

RPC

constRPCInitOptions={
timeout:200,
event:newRPCMessageEvent({
currentEndpoint:window,
targetEndpoint:iframe.contentWindow!,
config:{targetOrigin:'*'},
}),
// khởi động lại khi đăng ký xử lý hàm số
methods:{
'Main.max':(a:number,b:number)=>Math.max(a,b),
'Main.abs':(a:number)=>Math.abs(a),
},
};
constrpc=newRPC(RPCInitOptions);
// động thái đăng ký xử lý hàm số
rpc.registerMethod('Main.min',(a:number,b:number)=>{
returnPromise.resolve(Math.min(a,b));
});
// di trừ đăng ký hàm số
rpc.removeMethod('Main.abs');
// kiểm tra liên tiếp, phối trí siêu thời thời gian
awaitrpc.connect(2000);
// thuyên chuyển iframe phục vụ trung đăng ký phương pháp
constvalue=awaitrpc.invoke('Child.random',null,{isNotify:false,timeout:2000});

RPC Options

interfaceRPCEvent{
emit(event:string,...args:any[]):void;
on(event:string,fn:RPCHandler):void;
off(event:string,fn?:RPCHandler):void;
onerror:null|((error:RPCError)=>void);
destroy?:()=>void;
}

interfaceRPCHandler{
(...args:any[]):any;
}

interfaceRPCInitOptions{
event:RPCEvent;
methods?:Record<string,RPCHandler>;
timeout?:number;
}
Tham số Loại hình Thuyết minh
event Tất điềnRPCEvent Dùng cho phục vụ gian thông tín sự kiện mô khối, nhưng tham khảoRPCMessageEventThực hiện, thỏa mãnRPCEventTiếp lời có thể
methods Nhưng tuyểnRecord<string, RPCHandler> Dùng cho đăng ký trước mặt phục vụ nhưng thuyên chuyển phương pháp
timeout Nhưng tuyểnnumber Phương pháp thuyên chuyển toàn cục siêu thời thời gian, vì 0 tắc không thiết trí siêu thời thời gian

RPC Methods

connect

connect(timeout?: number):Promise<void>;

timeout siêu khi thiết trí, sẽ bao trùm toàn cục thiết trí

registerMethod

registerMethod(method:string,handler:RPCHandler);

Đăng ký thuyên chuyển phương pháp

removeMethod

removeMethod(method:string);

Di trừ thuyên chuyển phương pháp

invoke

invoke(
method:string,
...args:any[]|[...any[],RPCInvokeOptions]
):Promise<any>;
rpc1.registerMethod('add',(a:number,b:number,c:number)=>{
returnnewPromise((resolve)=>{
setTimeout(()=>resolve(a+b+c),400);
});
});
// có thể thông qua invokeOptions phối trí thuyên chuyển siêu khi
constres1=awaitrpc2.invoke('add',1,2,3);
constres2=awaitrpc2.invoke('add',4,5,6,{isNotify:true});
constres3=awaitrpc2.invoke('add',7,8,9,{timeout:1000});
constres4=awaitrpc2.invoke('add',10,11,12,{timeout:4}).catch((error)=>error);

Thuyên chuyển viễn trình phục vụ

  • methodstringPhương pháp danh
  • argsanyTham số
  • invokeOptions.timeoutnumbertimeout siêu khi thiết trí, sẽ bao trùm toàn cục thiết trí
  • invokeOptions.isNotifybooleanHay không là cái một cái thông tri tin tức

Có thể hàm số thuyên chuyển tham số cuối cùng phối trí invokeOptions lựa chọn, nếu invoke phối trí isNotify, tắc làm một cái thông tri tin tức, phương pháp thuyên chuyển sau sẽ lập tức phản hồi, không để ý tới mục tiêu phục vụ hay không tương ứng, mục tiêu cũng sẽ không hưởng ứng hồi phục này tin tức. Bên trong sử dụng JSON-PRC id tiến hành đánh dấu.

Không có bao hàm “id” thành viên thỉnh cầu đối tượng vì thông tri, làm thông tri thỉnh cầu đối tượng cho thấy bản cài đặt đối tương ứng hưởng ứng đối tượng cũng không cảm thấy hứng thú, bản thân cũng không có hưởng ứng đối tượng yêu cầu phản hồi cấp bản cài đặt. Phục vụ đoan cần thiết không hồi phục một cái thông tri, bao hàm những cái đó phê lượng thỉnh cầu trung. Bởi vì thông tri không có phản hồi hưởng ứng đối tượng, cho nên thông tri không xác định hay không bị định nghĩa. Đồng dạng, bản cài đặt sẽ không ý thức được bất luận cái gì sai lầm ( tỷ như tham số thiếu tỉnh, bên trong sai lầm ).

RPCMessageEvent

RPCMessageEvent thực hiện một bộ cùngsocket.ioCùng loại sự kiện tiếp lời, dùng cho xử lý window iframe worker cảnh tượng hạ tin tức thông tín:

interfaceRPCHandler{
(...args:any[]):any;
}

interfaceRPCEvent{
emit(event:string,...args:any[]):void;
on(event:string,fn:RPCHandler):void;
off(event:string,fn?:RPCHandler):void;
onerror:null|((error:RPCError)=>void);
destroy?:()=>void;
}

Sử dụng:

// main.ts
import{RPCMessageEvent}from'rpc-shooter';
constmainEvent=newRPCMessageEvent({
currentEndpoint:window,
targetEndpoint:iframe.contentWindow,
config:{
targetOrigin:'*',
},
receiveAdapter(event){
returnevent.data;
},
receiveAdapter(data){
returndata;
},
});

mainEvent.on('Main.test',(data)=>{});
mainEvent.emit('Child.test',(data)=>{});
// mainEvent.off('Main.someMethod');
// mainEvent.destroy();
// child.ts
import{RPCMessageEvent}from'rpc-shooter';
constchildEvent=newRPCMessageEvent({
currentEndpoint:window,
targetEndpoint:window.top,
config:{
targetOrigin:'*',
},
receiveAdapter(event){
returnevent.data;
},
receiveAdapter(data){
returndata;
},
});

childEvent.emit('Main.test',(data)=>{});

RPCMessageEvent Options

RPCMessageEvent khởi động lại lựa chọn định nghĩa như sau:

interfaceRPCMessageDataFormat{
event:string;
args:any[];
}

interfaceRPCPostMessageConfig{
targetOrigin?:string;
transfer?:Transferable[];
}

interfaceRPCMessageEventOptions{
currentEndpoint:RPCMessageReceiveEndpoint;
targetEndpoint:RPCMessageSendEndpoint;
config?:
|((data:any,context:RPCMessageSendEndpoint)=>RPCPostMessageConfig)
|RPCPostMessageConfig;
sendAdapter?:(
data:RPCMessageDataFormat|any,
context:RPCMessageSendEndpoint
)=>{
data:RPCMessageDataFormat;
transfer?:Transferable[];
};
receiveAdapter?:(event:MessageEvent)=>RPCMessageDataFormat;
}
Tham số Loại hình Thuyết minh
currentEndpoint Tất điềnWindow,Worker,MessagePortChờ thỏa mãnRPCMessageReceiveEndpointTiếp lời đối tượng Trước mặt thông tín đối tượng trên dưới văn, có thể làWindow,WorkerHoặc làMessagePortĐối tượng
targetEndpoint Tất điềnWindow,Worker,MessagePortChờ thỏa mãnRPCMessageSendEndpointTiếp lời đối tượng Mục tiêu thông tín đối tượng trên dưới văn, có thể làWindow,WorkerHoặc làMessagePortĐối tượng
config Nhưng tuyểnRPCPostMessageConfigorFunction Dùng cho cấp targetEndpoint.postMessage phương pháp phối trí tham số
sendAdapter Nhưng tuyểnFunction Tin tức phát động trước số liệu xử lý hàm số
receiveAdapter Nhưng tuyểnFunction Tin tức tiếp thu trước số liệu xử lý hàm số

config

interfaceWindowPostMessageOptions{
transfer?:Transferable[];
targetOrigin?:string;
}

interfaceRPCPostMessageConfigextendsWindowPostMessageOptions{
}

typeconfig?:
|((data:any,context:RPCMessageSendEndpoint)=>RPCPostMessageConfig)
|RPCPostMessageConfig;

Dùng cho cấp targetEndpointpostMessagePhương pháp phối trí tham số, có thể trực tiếp phối trí một cái đối tượng, cũng có thể thông qua hàm số động thái phản hồi một cái phối trí.

  • Cấpwindow.postMessagePhối trítargetOrigin->{ targetOrigin: '*' }
  • Cấpworker.postMessagePhối trítransfer->{ transfer: [...] }
  • Cấpfigma.ui.postMessagePhối tríorigin->{ origin: '*' }
newRPCMessageEvent({
currentEndpoint:worker,
targetEndpoint:worker,
config:{
targetOrigin:'*',
},
});
// window.postMessage(data, targetOrigin, [transfer]);

sendAdapter

typesendAdapter=(
data:RPCMessageDataFormat|any,
context:RPCMessageSendEndpoint
)=>{
data:RPCMessageDataFormat;
transfer?:Transferable[];
};

Gửi đi số liệu trước thích xứng hàm số, ở một ít đặc thù hoàn cảnh hạ có thể đối gửi đi số liệu làm một ít xử lý:

  • Có thể vì gửi đi số liệu phụ giatransferƯu hoá số liệu truyền
  • Một ít ứng dụng cắm kiện cảnh tượng đối lẫn nhau số liệu cách thức có nhất định yêu cầu tắc có thể sử dụng này thích xứng khí tiến hành đóng gói
newRPCMessageEvent({
currentEndpoint:worker,
targetEndpoint:worker,
sendAdapter(data){
consttransfer=[];
// đem ImageBitmap tăng thêm đến transfer ưu hoá số liệu truyền
JSON.stringify(data,(_,value)=>{
if(value?.constructor.name==='ImageBitmap'){
transfer.push(value);
}
returnvalue;
});
return{data,transfer};
},
});

receiveAdapter

typereceiveAdapter=(event:MessageEvent)=>RPCMessageDataFormat;

Số liệu tiếp thu trước xử lý hàm số,Tình hình chung không cần phối trí,Ở một ít đặc thù cảnh tượng hạ:

  • Kiểm tra số liệuoriginNơi phát ra lọc rớt không an toàn tin tức thỉnh cầu
  • Lọc rớt bản địa khai phá cảnh tượng tiếp theo chút dev server tung ra tin tức sự kiện
  • Một ít ứng dụng cắm kiện cảnh tượng đối lẫn nhau số liệu cách thức có nhất định yêu cầu tắc có thể sử dụng này thích xứng khí tiến hành đóng gói
newRPCMessageEvent({
currentEndpoint:window,
targetEndpoint:window.parent,
receiveAdapter(event){
if(event.origin==='xxx'){
returnevent.data;
}
returnnull;
},
});

Như figma cắm kiện trung iframe cùng chủ ứng dụng thông tín yêu cầu sử dụngpluginMessageTự đoạn bao vây.

// figma plugin ifame
newRPCMessageEvent({
currentEndpoint:window,
targetEndpoint:window.parent,
receiveAdapter(event){
returnevent.data.pluginMessage;
},
sendAdapter(data){
return{pluginMessage:data};
},
});

RPCMessageEvent Methods

interfaceRPCHandler{
(...args:any[]):any;
}

interfaceRPCEvent{
emit(event:string,...args:any[]):void;
on(event:string,fn:RPCHandler):void;
off(event:string,fn?:RPCHandler):void;
onerror:null|((error:RPCError)=>void);
destroy?:()=>void;
}

Tham khảosocket.ioAPI không làm lắm lời

Phương pháp Thuyết minh
on Thiết trí bản địa phục vụ sự kiện nghe lén
emit Kích phát viễn trình phục vụ sự kiện
off Di trừ bản địa phục vụ sự kiện nghe lén
onerror Phát sinh sai lầm khi kích phát onerror hồi điều
destroy Phóng thích RPCMessageEvent tài nguyên cùng bên trong sự kiện nghe lén

RPCMessageEvent Event

onerror

typeonerror=null|((error:RPCError)=>void);

Sự kiện mô khối bên trong phát sinh sai lầm khi hồi công hàm thuyên chuyển công tác số.

constevent=newRPCMessageEvent({...});
event.onerror=(error)=>{
console.log(error);
};

Khai phá

#Ỷ lại
yarn
#Khai phá
yarn dev
#Xây dựng
yarn build

TODO

  • Tăng thêm thí nghiệm dùng lệ
  • onmessage yêu cầu kiểm tra tin tức nơi phát ra
  • proxy hóa
  • Hiệp trình duy trì

About

A tool library for handling window && iframe && worker communication based on the JSON RPC specification

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published