clean up RPC structure
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
|
||||
+24
-16
@@ -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)),
|
||||
@@ -26,27 +27,27 @@ export const rpcToRpcinfo = (rpc : T.RPC, owner: T.Owner):T.RpcInfo => {
|
||||
}
|
||||
case "function":
|
||||
if(!rpc.name) throw new Error(`
|
||||
RPC did not provide a name.
|
||||
\nUse funtion name(..){ .. } syntax instead.
|
||||
\n
|
||||
\n<------------OFFENDING RPC:
|
||||
\n`+rpc.toString()+`
|
||||
\n>------------OFFENDING RPC`)
|
||||
RPC did not provide a name.
|
||||
\nUse funtion name(..){ .. } syntax instead.
|
||||
\n
|
||||
\n<------------OFFENDING RPC:
|
||||
\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)
|
||||
@@ -89,4 +90,11 @@ const hookGenerator = (rpc:T.HookRPC): T.HookInfo['generator'] => {
|
||||
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
@@ -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)},
|
||||
|
||||
Reference in New Issue
Block a user