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 Types from './src/Types';
|
||||||
import * as Utils from './src/Utils';
|
import * as Utils from './src/Utils';
|
||||||
import * as Interfaces from './src/Interfaces';
|
import * as Interfaces from './src/Interfaces';
|
||||||
import * as Responses from './src/Responses';
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Back as Backend,
|
Back as Backend,
|
||||||
@@ -11,5 +10,4 @@ export {
|
|||||||
Types,
|
Types,
|
||||||
Utils,
|
Utils,
|
||||||
Interfaces,
|
Interfaces,
|
||||||
Responses
|
|
||||||
}
|
}
|
||||||
+4
-2
@@ -7,7 +7,9 @@ import * as T from './Types';
|
|||||||
import * as U from './Utils';
|
import * as U from './Utils';
|
||||||
import * as I from './Interfaces';
|
import * as I from './Interfaces';
|
||||||
|
|
||||||
export class RPCServer{
|
export class RPCServer<
|
||||||
|
SubResType = {}
|
||||||
|
>{
|
||||||
private ws = http.createServer()
|
private ws = http.createServer()
|
||||||
private io = bsock.createServer()
|
private io = bsock.createServer()
|
||||||
private visibility:T.Visibility
|
private visibility:T.Visibility
|
||||||
@@ -18,7 +20,7 @@ export class RPCServer{
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private port:number,
|
private port:number,
|
||||||
private exporters: I.Exporter[] = [],
|
private exporters: I.Exporter<SubResType>[] = [],
|
||||||
conf: T.SocketConf = {}
|
conf: T.SocketConf = {}
|
||||||
){
|
){
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -81,8 +81,8 @@ export class RPCSocket implements I.Socket{
|
|||||||
const argParams = fnArgs.map(stripAfterEquals).join(",")
|
const argParams = fnArgs.map(stripAfterEquals).join(",")
|
||||||
return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
|
return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
|
||||||
const r = await this.socket.call("`+fnName+`", `+argParams+`)
|
const r = await this.socket.call("`+fnName+`", `+argParams+`)
|
||||||
if(r.uid != null){
|
if(r.result === 'Success'){
|
||||||
this.socket.hook(r.uid, callback)
|
this.socket.hook(r.uuid, callback)
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
} )()` )
|
} )()` )
|
||||||
|
|||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
import * as T from "./Types";
|
import * as T from "./Types";
|
||||||
import * as I from "./Interfaces"
|
import * as I from "./Interfaces"
|
||||||
|
|
||||||
export interface Exporter{
|
export interface Exporter<T = {}>{
|
||||||
name: T.Name
|
name: T.Name
|
||||||
exportRPCs() : T.RPC[]
|
exportRPCs() : T.RPC<T>[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Socket {
|
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";
|
import * as I from "./Interfaces";
|
||||||
|
|
||||||
export type Visibility = "127.0.0.1" | "0.0.0.0"
|
export type Visibility = "127.0.0.1" | "0.0.0.0"
|
||||||
@@ -16,13 +15,22 @@ export type SocketConf = {
|
|||||||
visibility?: Visibility
|
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 RPCType = 'Hook' | 'Unhook' | 'Call'
|
||||||
|
|
||||||
export type HookRPC = {
|
export type HookRPC<T = {}> = {
|
||||||
name: Name
|
name: Name
|
||||||
hook: HookFunction
|
hook: HookFunction<T>
|
||||||
onCallback?: CallbackFunction,
|
onCallback?: CallbackFunction,
|
||||||
onClose?: HookCloseFunction
|
onClose?: HookCloseFunction<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CallRPC = {
|
export type CallRPC = {
|
||||||
@@ -30,7 +38,7 @@ export type CallRPC = {
|
|||||||
call: AsyncFunction
|
call: AsyncFunction
|
||||||
} | Function
|
} | Function
|
||||||
|
|
||||||
export type RPC = CallRPC | HookRPC
|
export type RPC<T = {}> = CallRPC | HookRPC<T>
|
||||||
|
|
||||||
export type BaseInfo = {
|
export type BaseInfo = {
|
||||||
name: Name,
|
name: Name,
|
||||||
@@ -38,9 +46,9 @@ export type BaseInfo = {
|
|||||||
argNames: Name[],
|
argNames: Name[],
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HookInfo = BaseInfo & {
|
export type HookInfo<T = {}> = BaseInfo & {
|
||||||
type: 'Hook',
|
type: 'Hook',
|
||||||
generator: (socket) => HookFunction
|
generator: (socket) => HookFunction<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CallInfo = BaseInfo & {
|
export type CallInfo = BaseInfo & {
|
||||||
@@ -52,7 +60,7 @@ export type RpcInfo = HookInfo | CallInfo
|
|||||||
export type ExtendedRpcInfo = RpcInfo & { uniqueName: string }
|
export type ExtendedRpcInfo = RpcInfo & { uniqueName: string }
|
||||||
|
|
||||||
export type OnFunction = (type: 'error' | 'close', f: (e?:any)=>void) => I.Socket
|
export type OnFunction = (type: 'error' | 'close', f: (e?:any)=>void) => I.Socket
|
||||||
export type HookCloseFunction = (res:R.SubscriptionResponse, rpc:HookRPC) => any
|
export type HookCloseFunction<T = {}> = (res:SubscriptionResponse<T>, rpc:HookRPC<T>) => any
|
||||||
export type HookFunction = (...args:any[]) => Promise<R.SubscriptionResponse | R.ErrorResponse>
|
export type HookFunction<T = {}> = (...args:[any, ...any[]]) => Promise<SubscriptionResponse<T> | ErrorResponse>
|
||||||
export type AsyncFunction = (...args:any[]) => Promise<any>
|
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 T from "./Types";
|
||||||
import * as I from "./Interfaces";
|
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){
|
switch (typeof rpc){
|
||||||
case "object":
|
case "object":
|
||||||
if(rpc['call']){
|
if(rpc['call']){
|
||||||
@@ -15,7 +16,7 @@ export const rpcToRpcinfo = (rpc : T.RPC, owner: T.Owner):T.RpcInfo => {
|
|||||||
call: rpc['call'],
|
call: rpc['call'],
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
const generator = hookGenerator(<T.HookRPC>rpc)
|
const generator = hookGenerator(<T.HookRPC<any>>rpc)
|
||||||
return {
|
return {
|
||||||
owner: owner,
|
owner: owner,
|
||||||
argNames: extractArgs(generator(undefined)),
|
argNames: extractArgs(generator(undefined)),
|
||||||
@@ -26,27 +27,27 @@ export const rpcToRpcinfo = (rpc : T.RPC, owner: T.Owner):T.RpcInfo => {
|
|||||||
}
|
}
|
||||||
case "function":
|
case "function":
|
||||||
if(!rpc.name) throw new Error(`
|
if(!rpc.name) throw new Error(`
|
||||||
RPC did not provide a name.
|
RPC did not provide a name.
|
||||||
\nUse funtion name(..){ .. } syntax instead.
|
\nUse funtion name(..){ .. } syntax instead.
|
||||||
\n
|
\n
|
||||||
\n<------------OFFENDING RPC:
|
\n<------------OFFENDING RPC:
|
||||||
\n`+rpc.toString()+`
|
\n`+rpc.toString()+`
|
||||||
\n>------------OFFENDING RPC`)
|
\n>------------OFFENDING RPC`)
|
||||||
return {
|
return {
|
||||||
type: "Call",
|
|
||||||
owner : owner,
|
owner : owner,
|
||||||
argNames: extractArgs(rpc),
|
argNames: extractArgs(rpc),
|
||||||
|
type: "Call",
|
||||||
|
name: rpc.name,
|
||||||
call: async(...args) => rpc.apply({}, args),
|
call: async(...args) => rpc.apply({}, args),
|
||||||
name: rpc.name
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Error("Bad socketIORPC type "+ typeof rpc)
|
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 owner = exporter.name
|
||||||
const RPCs = [...exporter.exportRPCs()]
|
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))
|
return RPCs.map(rpc => rpcToRpcinfo(rpc, owner))
|
||||||
.map(info => {
|
.map(info => {
|
||||||
const ret:any = 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)
|
const argsArr = extractArgs(rpc.hook)
|
||||||
argsArr.pop()
|
argsArr.pop()
|
||||||
const args = argsArr.join(',')
|
const args = argsArr.join(',')
|
||||||
@@ -73,9 +74,9 @@ const hookGenerator = (rpc:T.HookRPC): T.HookInfo['generator'] => {
|
|||||||
return eval(`(socket) => async (`+args+`) => {
|
return eval(`(socket) => async (`+args+`) => {
|
||||||
const res = await rpc.hook(`+args+(args.length!==0?',':'')+` (...cbargs) => {
|
const res = await rpc.hook(`+args+(args.length!==0?',':'')+` (...cbargs) => {
|
||||||
if(rpc.onCallback) rpc.onCallback.apply({}, 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){
|
if(rpc.onClose){
|
||||||
socket.on('close', async () => {
|
socket.on('close', async () => {
|
||||||
rpc.onClose(res, rpc)
|
rpc.onClose(res, rpc)
|
||||||
@@ -90,3 +91,10 @@ const extractArgs = (f:Function):T.Arg[] => {
|
|||||||
let fn
|
let fn
|
||||||
return (fn = String(f)).substr(0, fn.indexOf(")")).substr(fn.indexOf("(")+1).split(",")
|
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 { RPCServer } from '../src/Backend'
|
||||||
import { SubscriptionResponse, ErrorResponse, SuccessResponse } from '../src/Responses'
|
import { SubscriptionResponse, ErrorResponse, SuccessResponse } from '../src/Types'
|
||||||
import { HookRPC } from '../src/Types'
|
import { HookRPC } from '../src/Types'
|
||||||
|
import * as uuidv4 from "uuid/v4"
|
||||||
|
import { makeSubResponse } from '../src/Utils'
|
||||||
|
|
||||||
let subcallback
|
let subcallback
|
||||||
|
|
||||||
@@ -14,19 +16,56 @@ new RPCServer(20000, [{
|
|||||||
name: 'simpleSubscribe',
|
name: 'simpleSubscribe',
|
||||||
hook: async(callback) => {
|
hook: async(callback) => {
|
||||||
subcallback = callback
|
subcallback = callback
|
||||||
return new SubscriptionResponse(""+Math.random())
|
return makeSubResponse()
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
name: 'subscribe',
|
name: 'subscribe',
|
||||||
hook: async (callback):Promise<any> => {
|
hook: async (callback):Promise<any> => {
|
||||||
subcallback = callback
|
subcallback = callback
|
||||||
return new SubscriptionResponse(""+Math.random())
|
return makeSubResponse()
|
||||||
},
|
},
|
||||||
onClose: (res:SubscriptionResponse, rpc:HookRPC) => {
|
onClose: (res:SubscriptionResponse, rpc:HookRPC) => {
|
||||||
console.log("Specific close handler for", rpc.name, res)
|
console.log("Specific close handler for", rpc.name, res)
|
||||||
subcallback = null
|
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 add(...args:number[]):number {return args.reduce((a,b)=>a+b, 0)},
|
||||||
function triggerCallback(...messages:any[]):number {return subcallback.apply({}, messages)},
|
function triggerCallback(...messages:any[]):number {return subcallback.apply({}, messages)},
|
||||||
|
|||||||
Reference in New Issue
Block a user