import * as uuid from "uuid/v4" import * as T from "./Types"; import * as I from "./Interfaces"; export const rpcToRpcinfo = (rpc : T.RPC, owner: T.Owner):T.RpcInfo => { switch(rpc.type){ case "Call" : return { owner: owner, argNames: extractArgs(rpc.call), type: rpc.type, name: rpc.name, call: rpc.call, } case "Unhook" : return { owner: owner, argNames: extractArgs(rpc.unhook), type: rpc.type, name: rpc.name, unhook: rpc.unhook, } case "Hook" : const generator = hookGenerator(rpc) return { owner: owner, argNames: extractArgs(generator(undefined)), type: rpc.type, name: rpc.name, unhook: rpc.unhook, generator: generator, } } } export function rpcHooker(socket: I.Socket, exporter:I.Exporter, makeUnique = true):T.ExtendedRpcInfo[]{ const owner = exporter.name const RPCs = [...exporter.publicRPCs(), ...exporter.localRPCs()] const suffix = makeUnique?"-"+uuid().substr(0,4):"" return RPCs.map(rpc => rpcToRpcinfo(rpc, owner)) .map(info => { const ret:any = info ret.uniqueName = info.name+suffix switch(info.type){ case "Hook": socket.hook(ret.uniqueName, info.generator(socket)) break; case "Unhook": socket.hook(ret.uniqueName, info.unhook) break; case "Call": socket.hook(ret.uniqueName, info.call) break; } socket.on('close', () => socket.unhook(info.name)) return ret }) } const hookGenerator = (rpc:T.HookRPC): T.HookInfo['generator'] => { const argsArr = extractArgs(rpc.clbk) argsArr.pop() const args = argsArr.join(',') return eval(`(socket) => async (`+args+`) => { const res = await rpc.clbk(`+args+(args.length!==0?',':'')+` (x) => { socket.call(res.uid, x) }) if(res.result == 'Success'){ socket.on('close', async () => { const unhookRes = await rpc.unhook(res.uid) console.log("Specific close handler for", rpc.name, res.uid, unhookRes) }) } return res }`) } const extractArgs = (f:Function):T.Arg[] => { let fn = String(f) let args = fn.substr(0, fn.indexOf(")")) args = args.substr(fn.indexOf("(")+1) let ret = args.split(",") return ret }