'use strict' var bsock = require('bsock') import * as T from './Types'; import * as I from './Interfaces'; //fix args with defaults like "force = true" -> "force" function stripAfterEquals(str:string){ return str.split("=")[0] } export class RPCSocket implements I.Socket{ private socket: I.Socket constructor(public port:number, private server: string, private tls: boolean = false){ Object.defineProperty(this, 'socket', {value: undefined, writable: true}) } public hook(name: T.Name, args: T.Arg){ return this.socket.hook(name, args) } public unhook(name: T.Name){ return this.socket.unhook(name) } public on(type: "error" | "close", f: (e?: any) => void){ return this.socket.on(type, f) } public destroy(){ return this.socket.destroy() } public close(){ return this.socket.close() } public async call (rpcname: T.Name, ...args: T.Any[]) : Promise{ return await this.socket.call.apply(this.socket, [rpcname, ...args]) } public async fire(rpcname: T.Name, ...args: T.Any[]) : Promise{ return await this.socket.fire.apply(this.socket, [rpcname, ...args]) } public async connect(){ this.socket = await bsock.connect(this.port, this.server, this.tls) const info:T.ExtendedRpcInfo[] = await this.info() info.forEach(i => { let f: any switch (i.type) { case 'Call': f = this.callGenerator(i.uniqueName, i.argNames) break case 'Hook': f = this.hookGenerator(i.uniqueName, i.argNames) break case 'Unhook': f = this.unhookGenerator(i.uniqueName, i.argNames) break } if(this[i.owner] == null) this[i.owner] = {} this[i.owner][i.name] = f this[i.owner][i.name].bind(this) }) } public async info(){ return await this.socket.call('info') } private callGenerator(fnName: T.Name, fnArgs:T.Arg[]): T.AsyncFunction{ const headerArgs = fnArgs.join(",") const argParams = fnArgs.map(stripAfterEquals).join(",") return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", '+argParams+')} )()' ) } private hookGenerator(fnName: T.Name, fnArgs:T.Arg[]): T.CallbackFunction{ const headerArgs = fnArgs.join(",") 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(res.uid, callback) } return res } )()` ) } private unhookGenerator(fnName: T.Name, fnArgs:T.Arg[]): T.UnhookFunction{ const headerArgs = fnArgs.join(",") const argParams = fnArgs.map(stripAfterEquals).join(",") if(fnArgs.length != 1) console.error("UnhookFunction", fnName, "specified more than one argument: ("+headerArgs+")") return eval( `( () => async (`+headerArgs+`) => { const r = await this.socket.call("`+fnName+`", `+argParams+`) this.socket.unhook(`+argParams+`) return res } )()` ) } }