123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- 'use strict'
-
- import bsock = require('bsock');
-
- import * as T from './Types';
- import * as I from './Interfaces';
-
- /**
- * Utility function to strip parameters like "a = 3" of their defaults
- * @param str The parameter to modify
- */
- function stripAfterEquals(str:string):string{
- return str.split("=")[0]
- }
-
- /**
- * A websocket-on-steroids with built-in RPC capabilities
- */
- export class RPCSocket implements I.Socket{
- private socket: I.Socket
-
- /**
- *
- * @param port Port to connect to
- * @param server Server address
- * @param tls @default false use TLS
- */
- constructor(public port:number, private server: string, private tls: boolean = false){
- Object.defineProperty(this, 'socket', {value: undefined, writable: true})
- }
-
- /**
- * Hooks a handler to a function name. Use {@link call} to trigger it.
- * @param name The function name to listen on
- * @param handler The handler to attach
- */
- public hook(name: T.Name, handler: (...args:any[]) => any | Promise<any>){
- return this.socket.hook(name, handler)
- }
-
- /**
- * Removes a {@link hook} listener by name.
- * @param name The function name
- */
- public unhook(name: T.Name){
- return this.socket.unhook(name)
- }
-
- /**
- * Attach a listener to error or close events
- * @param type 'error' or 'close'
- * @param f The listener to attach
- */
- public on(type: "error" | "close", f: (e?: any) => void){
- return this.socket.on(type, f)
- }
-
- /**
- * Destroys the socket
- */
- public destroy(){
- return this.socket.destroy()
- }
-
- /**
- * Closes the socket. It may attempt to reconnect.
- */
- public close(){
- return this.socket.close()
- }
-
- /**
- * Trigger a hooked handler on the server
- * @param rpcname The function to call
- * @param args other arguments
- */
- public async call (rpcname: T.Name, ...args: T.Any[]) : Promise<T.Any>{
- return await this.socket.call.apply(this.socket, [rpcname, ...args])
- }
-
- /**
- * An alternative to call that does not wait for confirmation and doesn't return a value.
- * @param rpcname The function to call
- * @param args other arguments
- */
- public async fire(rpcname: T.Name, ...args: T.Any[]) : Promise<void>{
- await this.socket.fire.apply(this.socket, [rpcname, ...args])
- }
-
- /**
- * Connects to the server and attaches available RPCs to this object
- */
- 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
- }
- if(this[i.owner] == null)
- this[i.owner] = {}
- this[i.owner][i.name] = f
- this[i.owner][i.name].bind(this)
- })
- }
-
- /**
- * Get a list of available RPCs from the server
- */
- public async info(){
- return await this.socket.call('info')
- }
-
- /**
- * Utility {@link AsyncFunction} generator
- * @param fnName The function name
- * @param fnArgs A string-list of parameters
- */
- 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+')} )()' )
- }
-
- /**
- * Utility {@link HookFunction} generator
- * @param fnName The function name
- * @param fnArgs A string-list of parameters
- */
- private hookGenerator(fnName: T.Name, fnArgs:T.Arg[]): T.HookFunction{
- 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.result === 'Success'){
- this.socket.hook(r.uuid, callback)
- }
- return r
- } )()` )
- }
- }
|