This commit is contained in:
2019-09-18 01:43:58 +02:00
parent 34ec2d0244
commit 741c253202
10 changed files with 131 additions and 48 deletions
+1 -1
View File
File diff suppressed because one or more lines are too long
+5 -5
View File
@@ -1,6 +1,5 @@
import { Socket } from "./RPCSocketServer"; import { Socket } from "./RPCSocketServer";
declare type rpcType = 'hook' | 'unhook' | 'call'; declare type rpcType = 'hook' | 'unhook' | 'call';
declare type visibility = 'public' | 'private';
export declare type Outcome = "Success" | "Error"; export declare type Outcome = "Success" | "Error";
export declare type Visibility = "127.0.0.1" | "0.0.0.0"; export declare type Visibility = "127.0.0.1" | "0.0.0.0";
export declare class Response { export declare class Response {
@@ -25,11 +24,11 @@ export declare type AsyncFunction = (...args: any[]) => Promise<any>;
export interface RPCExporter { export interface RPCExporter {
name: string; name: string;
exportRPCs(): socketioRPC[]; exportRPCs(): socketioRPC[];
exportPublicRPCs(): socketioRPC[];
} }
declare type baseRPC = { declare type baseRPC = {
type: rpcType; type: rpcType;
name: string; name: string;
visibility: visibility;
}; };
declare type hookRPC = baseRPC & { declare type hookRPC = baseRPC & {
type: 'hook'; type: 'hook';
@@ -69,7 +68,7 @@ export declare type ExtendedRpcInfo = RpcInfo & {
export declare const rpcToRpcinfo: (rpc: socketioRPC, owner: string) => RpcInfo; export declare const rpcToRpcinfo: (rpc: socketioRPC, owner: string) => RpcInfo;
export declare const rpcHooker: (socket: Socket, owner: string, RPCs: socketioRPC[], makeUnique?: boolean) => ExtendedRpcInfo[]; export declare const rpcHooker: (socket: Socket, owner: string, RPCs: socketioRPC[], makeUnique?: boolean) => ExtendedRpcInfo[];
declare type OnFunction = (type: 'error' | 'close', f: (e?: any) => void) => Socket; declare type OnFunction = (type: 'error' | 'close', f: (e?: any) => void) => Socket;
export declare type Socket = { export interface Socket {
port: number; port: number;
hook: (rpcname: string, ...args: any[]) => Socket; hook: (rpcname: string, ...args: any[]) => Socket;
unhook: (rpcname: string) => Socket; unhook: (rpcname: string) => Socket;
@@ -78,7 +77,7 @@ export declare type Socket = {
on: OnFunction; on: OnFunction;
destroy: () => void; destroy: () => void;
close: () => void; close: () => void;
}; }
export declare type RPCSocketConf = { export declare type RPCSocketConf = {
connectionHandler: (socket: Socket) => void; connectionHandler: (socket: Socket) => void;
errorHandler: (socket: Socket) => (error: any) => void; errorHandler: (socket: Socket) => (error: any) => void;
@@ -93,6 +92,7 @@ export declare class RPCSocketServer {
private wsServer; private wsServer;
constructor(port: number, rpcExporters?: RPCExporter[], visibility?: Visibility, conf?: RPCSocketConf); constructor(port: number, rpcExporters?: RPCExporter[], visibility?: Visibility, conf?: RPCSocketConf);
private startWebsocket; private startWebsocket;
protected initApis(socket: any): void; protected initApis(socket: Socket): void;
protected initPublicApis(socket: Socket): void;
} }
export {}; export {};
+18 -6
View File
@@ -38,7 +38,6 @@ exports.rpcToRpcinfo = (rpc, owner) => {
owner: owner, owner: owner,
argNames: extractArgs(rpc.func), argNames: extractArgs(rpc.func),
type: rpc.type, type: rpc.type,
visibility: rpc.visibility,
name: rpc.name, name: rpc.name,
func: rpc.func, func: rpc.func,
}; };
@@ -47,7 +46,6 @@ exports.rpcToRpcinfo = (rpc, owner) => {
owner: owner, owner: owner,
argNames: extractArgs(rpc.func), argNames: extractArgs(rpc.func),
type: rpc.type, type: rpc.type,
visibility: rpc.visibility,
name: rpc.name, name: rpc.name,
func: rpc.func, func: rpc.func,
}; };
@@ -57,7 +55,6 @@ exports.rpcToRpcinfo = (rpc, owner) => {
owner: owner, owner: owner,
argNames: extractArgs(generator(undefined)), argNames: extractArgs(generator(undefined)),
type: rpc.type, type: rpc.type,
visibility: rpc.visibility,
name: rpc.name, name: rpc.name,
unhook: rpc.unhook, unhook: rpc.unhook,
generator: generator, generator: generator,
@@ -126,7 +123,10 @@ class RPCSocketServer {
this.io.on('socket', (socket) => { this.io.on('socket', (socket) => {
socket.on('error', this.conf.errorHandler(socket)); socket.on('error', this.conf.errorHandler(socket));
socket.on('close', this.conf.closeHandler(socket)); socket.on('close', this.conf.closeHandler(socket));
this.initApis(socket); if (this.visibility === "127.0.0.1")
this.initApis(socket);
else
this.initPublicApis(socket);
}); });
this.wsServer.listen(this.port, this.visibility); this.wsServer.listen(this.port, this.visibility);
} }
@@ -140,13 +140,25 @@ class RPCSocketServer {
{ {
name: 'info', name: 'info',
type: 'call', type: 'call',
visibility: 'private',
func: async () => rpcInfos func: async () => rpcInfos
} }
]; ];
const rpcInfos = [ const rpcInfos = [
...exports.rpcHooker(socket, "Admin", adminRPCs, false), ...exports.rpcHooker(socket, "Admin", adminRPCs, false),
...this.rpcExporters.flatMap(exporter => exports.rpcHooker(socket, exporter.name, exporter.exportRPCs())) ...this.rpcExporters.flatMap(exporter => exports.rpcHooker(socket, exporter.name, [...exporter.exportPublicRPCs(), ...exporter.exportRPCs()]))
];
}
initPublicApis(socket) {
const adminRPCs = [
{
name: 'info',
type: 'call',
func: async () => rpcInfos
}
];
const rpcInfos = [
...exports.rpcHooker(socket, "Admin", adminRPCs, false),
...this.rpcExporters.flatMap(exporter => exports.rpcHooker(socket, exporter.name, exporter.exportPublicRPCs()))
]; ];
} }
} }
@@ -1,6 +1,4 @@
declare type RPCReceiver = { import { Socket } from "../backend/RPCSocketServer";
[RPCGroup in string]: any;
};
/** /**
* Dynamic library to communicate with FrontblockService remotely * Dynamic library to communicate with FrontblockService remotely
* *
@@ -8,13 +6,22 @@ declare type RPCReceiver = {
* Will ask it's service for available RPCs and parse them into methods of this object * Will ask it's service for available RPCs and parse them into methods of this object
* for convenient access. * for convenient access.
*/ */
export declare class RPCaller implements RPCReceiver { export declare class RPCSocket implements Socket {
port: number;
private server;
private tls;
private socket; private socket;
constructor(port: number, server: string, tls?: boolean); constructor(port: number, server: string, tls?: boolean);
hook(name: any, args: any): Socket;
unhook(name: any): Socket;
on(type: "error" | "close", f: (e?: any) => void): Socket;
destroy(): void;
close(): void;
call(rpcname: string, ...args: any[]): Promise<any>;
fire(rpcname: string, ...args: any[]): Promise<any>;
connect(): Promise<void>; connect(): Promise<void>;
info(): Promise<any>; info(): Promise<any>;
private callGenerator; private callGenerator;
private hookGenerator; private hookGenerator;
private unhookGenerator; private unhookGenerator;
} }
export {};
@@ -12,11 +12,35 @@ function stripAfterEquals(str) {
* Will ask it's service for available RPCs and parse them into methods of this object * Will ask it's service for available RPCs and parse them into methods of this object
* for convenient access. * for convenient access.
*/ */
class RPCaller { class RPCSocket {
constructor(port, server, tls = false) { constructor(port, server, tls = false) {
this.socket = bsock.connect(port, server, tls); this.port = port;
this.server = server;
this.tls = tls;
}
hook(name, args) {
return this.socket.hook(name, args);
}
unhook(name) {
return this.socket.unhook(name);
}
on(type, f) {
return this.socket.on(type, name);
}
destroy() {
return this.socket.destroy();
}
close() {
return this.socket.close();
}
async call(rpcname, ...args) {
return await this.socket.call.apply(this.socket, [rpcname, ...args]);
}
async fire(rpcname, ...args) {
return await this.socket.fire.apply(this.socket, [rpcname, ...args]);
} }
async connect() { async connect() {
this.socket = await bsock.connect(this.port, this.server, this.tls);
const info = await this.info(); const info = await this.info();
info.forEach(i => { info.forEach(i => {
let f; let f;
@@ -68,4 +92,4 @@ class RPCaller {
} )()`); } )()`);
} }
} }
exports.RPCaller = RPCaller; exports.RPCSocket = RPCSocket;
+5 -5
View File
@@ -2,17 +2,17 @@
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const RPCSocketServer_1 = require("../src/backend/RPCSocketServer"); const RPCSocketServer_1 = require("../src/backend/RPCSocketServer");
//@ts-ignore //@ts-ignore
const RPCaller_1 = require("../src/frontend/RPCaller"); const RPCSocket_1 = require("../src/frontend/RPCSocket");
new RPCSocketServer_1.RPCSocketServer(20000, [{ new RPCSocketServer_1.RPCSocketServer(20000, [{
name: "HelloWorldRPCGroup", name: "HelloWorldRPCGroup",
exportPublicRPCs: () => [],
exportRPCs: () => [{ exportRPCs: () => [{
type: 'call', type: 'call',
name: 'echo', name: 'echo',
func: async (s) => s, func: async (s) => s,
visibility: 'private' }],
}] }], "0.0.0.0");
}]); const caller = new RPCSocket_1.RPCSocket(20000, 'localhost');
const caller = new RPCaller_1.RPCaller(20000, 'localhost');
caller.connect().then(_ => { caller.connect().then(_ => {
caller.info().then(console.log); caller.info().then(console.log);
caller["HelloWorldRPCGroup"].echo("x").then(console.log); caller["HelloWorldRPCGroup"].echo("x").then(console.log);
+23 -8
View File
@@ -50,6 +50,7 @@ export type AsyncFunction = (...args) => Promise<any>
export interface RPCExporter{ export interface RPCExporter{
name: string name: string
exportRPCs() : socketioRPC[] exportRPCs() : socketioRPC[]
exportPublicRPCs() : socketioRPC[]
} }
type baseRPC = { type baseRPC = {
@@ -107,7 +108,6 @@ export const rpcToRpcinfo = (rpc : socketioRPC, owner: string):RpcInfo => {
owner: owner, owner: owner,
argNames: extractArgs(rpc.func), argNames: extractArgs(rpc.func),
type: rpc.type, type: rpc.type,
visibility: rpc.visibility,
name: rpc.name, name: rpc.name,
func: rpc.func, func: rpc.func,
} }
@@ -116,7 +116,6 @@ export const rpcToRpcinfo = (rpc : socketioRPC, owner: string):RpcInfo => {
owner: owner, owner: owner,
argNames: extractArgs(rpc.func), argNames: extractArgs(rpc.func),
type: rpc.type, type: rpc.type,
visibility: rpc.visibility,
name: rpc.name, name: rpc.name,
func: rpc.func, func: rpc.func,
} }
@@ -126,7 +125,6 @@ export const rpcToRpcinfo = (rpc : socketioRPC, owner: string):RpcInfo => {
owner: owner, owner: owner,
argNames: extractArgs(generator(undefined)), argNames: extractArgs(generator(undefined)),
type: rpc.type, type: rpc.type,
visibility: rpc.visibility,
name: rpc.name, name: rpc.name,
unhook: rpc.unhook, unhook: rpc.unhook,
generator: generator, generator: generator,
@@ -184,7 +182,7 @@ const extractArgs = (f:Function):string[] => {
type OnFunction = (type: 'error' | 'close', f: (e?:any)=>void) => Socket type OnFunction = (type: 'error' | 'close', f: (e?:any)=>void) => Socket
export type Socket = { export interface Socket {
port: number port: number
hook: (rpcname: string, ...args: any[]) => Socket hook: (rpcname: string, ...args: any[]) => Socket
unhook: (rpcname:string) => Socket unhook: (rpcname:string) => Socket
@@ -225,7 +223,10 @@ export class RPCSocketServer{
this.io.on('socket', (socket:Socket) => { this.io.on('socket', (socket:Socket) => {
socket.on('error', this.conf.errorHandler(socket)) socket.on('error', this.conf.errorHandler(socket))
socket.on('close', this.conf.closeHandler(socket)) socket.on('close', this.conf.closeHandler(socket))
this.initApis(socket) if(this.visibility === "127.0.0.1")
this.initApis(socket)
else
this.initPublicApis(socket)
}) })
this.wsServer.listen(this.port, this.visibility) this.wsServer.listen(this.port, this.visibility)
}catch(e){ }catch(e){
@@ -234,19 +235,33 @@ export class RPCSocketServer{
} }
} }
protected initApis(socket){ protected initApis(socket:Socket){
const adminRPCs:socketioRPC[] = [ const adminRPCs:socketioRPC[] = [
{ {
name: 'info', name: 'info',
type: 'call', type: 'call',
visibility: 'private',
func: async () => rpcInfos func: async () => rpcInfos
} }
] ]
const rpcInfos:ExtendedRpcInfo[] = [ const rpcInfos:ExtendedRpcInfo[] = [
...rpcHooker(socket, "Admin", adminRPCs, false), ...rpcHooker(socket, "Admin", adminRPCs, false),
...this.rpcExporters.flatMap(exporter => rpcHooker(socket, exporter.name, exporter.exportRPCs())) ...this.rpcExporters.flatMap(exporter => rpcHooker(socket, exporter.name, [...exporter.exportPublicRPCs(), ...exporter.exportRPCs()]))
]
}
protected initPublicApis(socket:Socket){
const adminRPCs:socketioRPC[] = [
{
name: 'info',
type: 'call',
func: async () => rpcInfos
}
]
const rpcInfos:ExtendedRpcInfo[] = [
...rpcHooker(socket, "Admin", adminRPCs, false),
...this.rpcExporters.flatMap(exporter => rpcHooker(socket, exporter.name, exporter.exportPublicRPCs()))
] ]
} }
} }
@@ -1,4 +1,4 @@
import { ExtendedRpcInfo, UnhookFunction, callbackFunction, AsyncFunction } from "../backend/RPCSocketServer"; import { ExtendedRpcInfo, UnhookFunction, callbackFunction, AsyncFunction, Socket } from "../backend/RPCSocketServer";
var bsock = require('bsock') var bsock = require('bsock')
//fix args with defaults like "force = true" -> "force" //fix args with defaults like "force = true" -> "force"
@@ -6,9 +6,6 @@ function stripAfterEquals(str:string){
return str.split("=")[0] return str.split("=")[0]
} }
type RPCReceiver = {
[RPCGroup in string]: any
}
/** /**
* Dynamic library to communicate with FrontblockService remotely * Dynamic library to communicate with FrontblockService remotely
@@ -17,14 +14,42 @@ type RPCReceiver = {
* Will ask it's service for available RPCs and parse them into methods of this object * Will ask it's service for available RPCs and parse them into methods of this object
* for convenient access. * for convenient access.
*/ */
export class RPCaller implements RPCReceiver{ export class RPCSocket implements Socket{
private socket private socket: Socket
constructor(public port:number, private server: string, private tls: boolean = false){
}
constructor(port:number, server: string, tls: boolean = false){ hook(name, args){
this.socket = bsock.connect(port, server, tls) return this.socket.hook(name, args)
}
unhook(name){
return this.socket.unhook(name)
}
on(type: "error" | "close", f: (e?: any) => void){
return this.socket.on(type, name)
}
destroy(){
return this.socket.destroy()
}
close(){
return this.socket.close()
}
async call (rpcname: string, ...args: any[]) : Promise<any>{
return await this.socket.call.apply(this.socket, [rpcname, ...args])
}
async fire(rpcname: string, ...args: any[]) : Promise<any>{
return await this.socket.fire.apply(this.socket, [rpcname, ...args])
} }
async connect(){ async connect(){
this.socket = await bsock.connect(this.port, this.server, this.tls)
const info:ExtendedRpcInfo[] = await this.info() const info:ExtendedRpcInfo[] = await this.info()
info.forEach(i => { info.forEach(i => {
let f: any let f: any
+1 -1
View File
@@ -4,7 +4,7 @@ const TerserPlugin = require('terser-webpack-plugin');
module.exports = { module.exports = {
mode: 'production', mode: 'production',
target: "web", target: "web",
entry: path.resolve(__dirname, 'RPCaller.ts'), entry: path.resolve(__dirname, 'RPCSocket.ts'),
output: { output: {
path: path.resolve(__dirname, '../../lib'), path: path.resolve(__dirname, '../../lib'),
filename: 'RPCaller.min.js', filename: 'RPCaller.min.js',
+5 -5
View File
@@ -1,18 +1,18 @@
import { RPCSocketServer } from '../src/backend/RPCSocketServer' import { RPCSocketServer } from '../src/backend/RPCSocketServer'
//@ts-ignore //@ts-ignore
import {RPCaller} from '../src/frontend/RPCaller' import {RPCSocket} from '../src/frontend/RPCSocket'
new RPCSocketServer(20000, [{ new RPCSocketServer(20000, [{
name: "HelloWorldRPCGroup", name: "HelloWorldRPCGroup",
exportPublicRPCs: () => [],
exportRPCs: () => [{ exportRPCs: () => [{
type: 'call', type: 'call',
name: 'echo', name: 'echo',
func: async (s:string) => s, func: async (s:string) => s,
visibility: 'private' }],
}] }])
}] )
const caller = new RPCaller(20000, 'localhost') const caller = new RPCSocket(20000, 'localhost')
caller.connect().then(_ => { caller.connect().then(_ => {
caller.info().then(console.log) caller.info().then(console.log)
caller["HelloWorldRPCGroup"].echo("x").then(console.log) caller["HelloWorldRPCGroup"].echo("x").then(console.log)