clean up RPC structure

This commit is contained in:
2019-09-21 14:17:23 +02:00
parent 160be94e3b
commit 67278ff2fe
8 changed files with 93 additions and 75 deletions
-2
View File
@@ -3,7 +3,6 @@ import * as Front from './src/Frontend';
import * as Types from './src/Types';
import * as Utils from './src/Utils';
import * as Interfaces from './src/Interfaces';
import * as Responses from './src/Responses';
export {
Back as Backend,
@@ -11,5 +10,4 @@ export {
Types,
Utils,
Interfaces,
Responses
}
+4 -2
View File
@@ -7,7 +7,9 @@ import * as T from './Types';
import * as U from './Utils';
import * as I from './Interfaces';
export class RPCServer{
export class RPCServer<
SubResType = {}
>{
private ws = http.createServer()
private io = bsock.createServer()
private visibility:T.Visibility
@@ -18,7 +20,7 @@ export class RPCServer{
constructor(
private port:number,
private exporters: I.Exporter[] = [],
private exporters: I.Exporter<SubResType>[] = [],
conf: T.SocketConf = {}
){
+2 -2
View File
@@ -81,8 +81,8 @@ export class RPCSocket implements I.Socket{
const argParams = fnArgs.map(stripAfterEquals).join(",")
return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
const r = await this.socket.call("`+fnName+`", `+argParams+`)
if(r.uid != null){
this.socket.hook(r.uid, callback)
if(r.result === 'Success'){
this.socket.hook(r.uuid, callback)
}
return r
} )()` )
+2 -2
View File
@@ -1,9 +1,9 @@
import * as T from "./Types";
import * as I from "./Interfaces"
export interface Exporter{
export interface Exporter<T = {}>{
name: T.Name
exportRPCs() : T.RPC[]
exportRPCs() : T.RPC<T>[]
}
export interface Socket {
-37
View File
@@ -1,37 +0,0 @@
export type Outcome = "Success" | "Error"
export class Response{
constructor(
public message?:string
){}
}
export class SuccessResponse extends Response{
result:Outcome = "Success"
constructor(
message?:string
){
super(message)
}
}
export class ErrorResponse extends Response{
result:Outcome = "Error"
constructor(
message: string = "Unknown error"
){
super(message)
}
}
export class SubscriptionResponse extends SuccessResponse{
constructor(
public uid: string,
message?:string
){
super(message)
}
}
+18 -10
View File
@@ -1,4 +1,3 @@
import * as R from "./Responses";
import * as I from "./Interfaces";
export type Visibility = "127.0.0.1" | "0.0.0.0"
@@ -16,13 +15,22 @@ export type SocketConf = {
visibility?: Visibility
}
export type ResponseType = "Subscribe" | "Success" | "Error"
export type Outcome = "Success" | "Error"
export type Respose<T> = T & { result: Outcome }
export type SuccessResponse<T = {}> = Respose<T> & { result: "Success" }
export type ErrorResponse<T = {}> = Respose<T> & { result: "Error" }
export type SubscriptionResponse<T = {}> = Respose<T> & { result: "Success"; uuid: string }
export type RPCType = 'Hook' | 'Unhook' | 'Call'
export type HookRPC = {
export type HookRPC<T = {}> = {
name: Name
hook: HookFunction
hook: HookFunction<T>
onCallback?: CallbackFunction,
onClose?: HookCloseFunction
onClose?: HookCloseFunction<T>
}
export type CallRPC = {
@@ -30,7 +38,7 @@ export type CallRPC = {
call: AsyncFunction
} | Function
export type RPC = CallRPC | HookRPC
export type RPC<T = {}> = CallRPC | HookRPC<T>
export type BaseInfo = {
name: Name,
@@ -38,9 +46,9 @@ export type BaseInfo = {
argNames: Name[],
}
export type HookInfo = BaseInfo & {
export type HookInfo<T = {}> = BaseInfo & {
type: 'Hook',
generator: (socket) => HookFunction
generator: (socket) => HookFunction<T>
}
export type CallInfo = BaseInfo & {
@@ -52,7 +60,7 @@ export type RpcInfo = HookInfo | CallInfo
export type ExtendedRpcInfo = RpcInfo & { uniqueName: string }
export type OnFunction = (type: 'error' | 'close', f: (e?:any)=>void) => I.Socket
export type HookCloseFunction = (res:R.SubscriptionResponse, rpc:HookRPC) => any
export type HookFunction = (...args:any[]) => Promise<R.SubscriptionResponse | R.ErrorResponse>
export type HookCloseFunction<T = {}> = (res:SubscriptionResponse<T>, rpc:HookRPC<T>) => any
export type HookFunction<T = {}> = (...args:[any, ...any[]]) => Promise<SubscriptionResponse<T> | ErrorResponse>
export type AsyncFunction = (...args:any[]) => Promise<any>
export type CallbackFunction = (arg: any) => void
export type CallbackFunction = (...args:any[]) => void
+18 -10
View File
@@ -1,9 +1,10 @@
import * as uuid from "uuid/v4"
import * as uuidv4 from "uuid/v4"
import * as T from "./Types";
import * as I from "./Interfaces";
import { SubscriptionResponse } from "./Types";
export const rpcToRpcinfo = (rpc : T.RPC, owner: T.Owner):T.RpcInfo => {
export const rpcToRpcinfo = <SubResT = {}>(rpc : T.RPC<SubResT>, owner: T.Owner):T.RpcInfo => {
switch (typeof rpc){
case "object":
if(rpc['call']){
@@ -15,7 +16,7 @@ export const rpcToRpcinfo = (rpc : T.RPC, owner: T.Owner):T.RpcInfo => {
call: rpc['call'],
}
}else{
const generator = hookGenerator(<T.HookRPC>rpc)
const generator = hookGenerator(<T.HookRPC<any>>rpc)
return {
owner: owner,
argNames: extractArgs(generator(undefined)),
@@ -33,20 +34,20 @@ export const rpcToRpcinfo = (rpc : T.RPC, owner: T.Owner):T.RpcInfo => {
\n`+rpc.toString()+`
\n>------------OFFENDING RPC`)
return {
type: "Call",
owner : owner,
argNames: extractArgs(rpc),
type: "Call",
name: rpc.name,
call: async(...args) => rpc.apply({}, args),
name: rpc.name
}
}
throw new Error("Bad socketIORPC type "+ typeof rpc)
}
export function rpcHooker(socket: I.Socket, exporter:I.Exporter, makeUnique = true):T.ExtendedRpcInfo[]{
export function rpcHooker<SubResT = {}>(socket: I.Socket, exporter:I.Exporter<SubResT>, makeUnique = true):T.ExtendedRpcInfo[]{
const owner = exporter.name
const RPCs = [...exporter.exportRPCs()]
const suffix = makeUnique?"-"+uuid().substr(0,4):""
const suffix = makeUnique?"-"+uuidv4().substr(0,4):""
return RPCs.map(rpc => rpcToRpcinfo(rpc, owner))
.map(info => {
const ret:any = info
@@ -65,7 +66,7 @@ export function rpcHooker(socket: I.Socket, exporter:I.Exporter, makeUnique = tr
})
}
const hookGenerator = (rpc:T.HookRPC): T.HookInfo['generator'] => {
const hookGenerator = (rpc:T.HookRPC<any>): T.HookInfo['generator'] => {
const argsArr = extractArgs(rpc.hook)
argsArr.pop()
const args = argsArr.join(',')
@@ -73,9 +74,9 @@ const hookGenerator = (rpc:T.HookRPC): T.HookInfo['generator'] => {
return eval(`(socket) => async (`+args+`) => {
const res = await rpc.hook(`+args+(args.length!==0?',':'')+` (...cbargs) => {
if(rpc.onCallback) rpc.onCallback.apply({}, cbargs)
socket.call.apply(socket, [res.uid, ...cbargs])
socket.call.apply(socket, [res.uuid, ...cbargs])
})
if(res.result == 'Success'){
if(res.result === 'Success'){
if(rpc.onClose){
socket.on('close', async () => {
rpc.onClose(res, rpc)
@@ -90,3 +91,10 @@ const extractArgs = (f:Function):T.Arg[] => {
let fn
return (fn = String(f)).substr(0, fn.indexOf(")")).substr(fn.indexOf("(")+1).split(",")
}
export function makeSubResponse(uuid?:string):SubscriptionResponse{
return {
result: "Success",
uuid: uuid?uuid:uuidv4(),
}
}
+43 -4
View File
@@ -1,6 +1,8 @@
import { RPCServer } from '../src/Backend'
import { SubscriptionResponse, ErrorResponse, SuccessResponse } from '../src/Responses'
import { SubscriptionResponse, ErrorResponse, SuccessResponse } from '../src/Types'
import { HookRPC } from '../src/Types'
import * as uuidv4 from "uuid/v4"
import { makeSubResponse } from '../src/Utils'
let subcallback
@@ -14,19 +16,56 @@ new RPCServer(20000, [{
name: 'simpleSubscribe',
hook: async(callback) => {
subcallback = callback
return new SubscriptionResponse(""+Math.random())
return makeSubResponse()
}
},{
name: 'subscribe',
hook: async (callback):Promise<any> => {
subcallback = callback
return new SubscriptionResponse(""+Math.random())
return makeSubResponse()
},
onClose: (res:SubscriptionResponse, rpc:HookRPC) => {
console.log("Specific close handler for", rpc.name, res)
subcallback = null
},
onCallback: (...args) => { console.log.apply(console, args) }
onCallback: (...args:any) => { console.log.apply(console, args) }
},
function add(...args:number[]):number {return args.reduce((a,b)=>a+b, 0)},
function triggerCallback(...messages:any[]):number {return subcallback.apply({}, messages)},
]
}])
new RPCServer<{ topic: string}>(20001, [{
name: "HelloWorldRPCGroup",
exportRPCs: () => [
{
name: 'echo',
call: async (s:string) => s,
},{
name: 'simpleSubscribe',
hook: async(callback) => {
subcallback = callback
return {
result: "Success",
uuid: uuidv4(),
topic: ""
}
}
},{
name: 'subscribe',
hook: async (callback) => {
subcallback = callback
return {
result: "Success",
uuid: uuidv4(),
topic: ""
}
},
onClose: (res, rpc) => {
console.log("Specific close handler for", rpc.name, res)
subcallback = null
},
onCallback: (...args:any) => { console.log.apply(console, args) }
},
function add(...args:number[]):number {return args.reduce((a,b)=>a+b, 0)},
function triggerCallback(...messages:any[]):number {return subcallback.apply({}, messages)},