diff --git a/package.json b/package.json index ab7f732..6fbf3c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rpclibrary", - "version": "1.8.0", + "version": "1.8.1", "description": "rpclibrary is a websocket on steroids!", "main": "./js/Index.js", "repository": { diff --git a/src/Backend.ts b/src/Backend.ts index 2a889c6..e08e77c 100644 --- a/src/Backend.ts +++ b/src/Backend.ts @@ -14,6 +14,7 @@ export class RPCServer< SubResType = {}, InterfaceT extends T.RPCInterface = T.RPCInterface, > implements I.Destroyable{ + private ws = http.createServer() private io = bsock.createServer() private visibility:T.Visibility diff --git a/src/Frontend.ts b/src/Frontend.ts index 06743e7..66cd9de 100644 --- a/src/Frontend.ts +++ b/src/Frontend.ts @@ -18,8 +18,8 @@ export class RPCSocket implements I.Socket{ } private socket: I.Socket - private closeHandlers: T.CloseHandler[] = [] - private errorHandlers: T.ErrorHandler[] = [] + private closeHandlers: T.FrontEndHandlerType['close'][] = [] + private errorHandlers: T.FrontEndHandlerType['error'][] = [] private hooks : {[name in string]: T.AnyFunction} = {} /** @@ -62,11 +62,11 @@ export class RPCSocket implements I.Socket{ * @param type 'error' or 'close' * @param f The listener to attach */ - public on(type: T, f: T.HandlerType[T]){ + public on(type: T, f: T.FrontEndHandlerType[T]){ if(!this.socket){ switch(type){ - case "error": this.errorHandlers.push( f); break; - case "close": this.closeHandlers.push( f); break; + case "error": this.errorHandlers.push( f); break; + case "close": this.closeHandlers.push( f); break; default: throw new Error('socket.on only supports ´error´ and ´close´ as first parameter. Got: ´'+type+'´') } }else{ @@ -74,6 +74,16 @@ export class RPCSocket implements I.Socket{ } } + /** + * Emit a LOCAL event + * @param eventName The event name to emit under + * @param data The data the event carries + */ + public emit(eventName:string, data:any){ + if(!this.socket) return + this.socket.emit(eventName, data) + } + /** * Destroys the socket */ @@ -97,7 +107,11 @@ export class RPCSocket implements I.Socket{ */ public async call (rpcname: string, ...args: any[]) : Promise{ if(!this.socket) throw new Error("The socket is not connected! Use socket.connect() first") - return await this.socket.call.apply(this.socket, [rpcname, ...args]) + try{ + return await this.socket.call.apply(this.socket, [rpcname, ...args]) + }catch(e){ + this.emit('error', e) + } } /** @@ -159,7 +173,9 @@ export class RPCSocket implements I.Socket{ const argParams = fnArgs.map(stripAfterEquals).join(",") sesame = appendComma(sesame) - return eval(`async (${headerArgs}) => { return await this.socket.call("${fnName}", ${sesame} ${argParams})}`) + return eval(`async (${headerArgs}) => { + return await this.socket.call("${fnName}", ${sesame} ${argParams}) + }`) } /** @@ -179,7 +195,6 @@ export class RPCSocket implements I.Socket{ return eval( ` async (${headerArgs} callback) => { - const r = await this.socket.call("${fnName}", ${sesame} ${argParams}) if(r && r.result === 'Success'){ this.socket.hook(r.uuid, callback) diff --git a/src/Interfaces.ts b/src/Interfaces.ts index 4a39bde..3c8428c 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -22,7 +22,8 @@ export interface Socket extends Destroyable { unhook: (rpcname:string) => void call: (rpcname:string, ...args: any[]) => Promise fire: (rpcname:string, ...args: any[]) => Promise - on: T.OnFunction + on: T.OnFunction + emit: (eventName: string, data:any) => void close() : void } diff --git a/src/Types.ts b/src/Types.ts index 138e381..3296e6e 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -12,9 +12,9 @@ export type ExceptionHandling = 'local' | 'remote' export type SesameConf = { sesame?: string | SesameFunction } -export type HandlerType = { - 'error' : ErrorHandler - 'close' : CloseHandler +export type FrontEndHandlerType = { + 'error' : (e: any) => void + 'close' : () => void } export type ServerConf = { @@ -84,5 +84,5 @@ export type CallInfo = BaseInfo & { export type RpcInfo = HookInfo | CallInfo export type ExtendedRpcInfo = RpcInfo & { uniqueName: string } -export type OnFunction = (type: T, f: HandlerType[T]) => void +export type OnFunction = (type: T, f: FrontEndHandlerType[T]) => void export type HookCloseFunction = (res:SubscriptionResponse, rpc:HookRPC) => any diff --git a/test/Test.ts b/test/Test.ts index be4c4e7..6c9e18e 100644 --- a/test/Test.ts +++ b/test/Test.ts @@ -551,14 +551,17 @@ describe("Class binding", ()=>{ } let serv: RPCServer, - sock: RPCSocket, + sock: RPCSocket & myExporterIfc, exporter: MyExporter before((done)=>{ exporter = new MyExporter() serv = new RPCServer(21004, [exporter]) - sock = new RPCSocket(21004, 'localhost') - sock.connect().then(_ => done()) + const s = new RPCSocket(21004, 'localhost') + s.connect().then(conn => { + sock = conn + done() + }) }) after(() => { sock.destroy() @@ -574,13 +577,11 @@ describe("Class binding", ()=>{ describe("attaching handlers before connecting", ()=>{ - - it("fires error if server is unreachable", (done)=>{ const sock = new RPCSocket(21004, 'localhost') let errorHandleCount = 0 - sock.on('error', (socket) => { + sock.on('error', (err) => { //attached listener fires first if(errorHandleCount != 0){ console.log("Error handler didn't fire first"); @@ -601,4 +602,41 @@ describe("attaching handlers before connecting", ()=>{ } }) }) + + it("fires error if call is unknown", (done)=>{ + const serv = new RPCServer(21004) + const sock = new RPCSocket(21004, 'localhost') + + sock.on('error', (err) => { + sock.destroy() + serv.destroy() + done() + }) + + sock.connect().then(_ => { + sock.call("unknownRPC123", "AAAAA").catch(e => { + console.log("unexpected call catch clause"); + done(e) + }) + }).catch(e => { + console.log("unexpected connect catch clause"); + done(e) + }) + }) + + it("demands catch on method invocation if call is unknown", (done)=>{ + const serv = new RPCServer(21004) + const sock = new RPCSocket(21004, 'localhost') + + sock.connect().then(_ => { + sock.call("unknownRPC123", "AAAAA").catch(e => { + sock.destroy() + serv.destroy() + done() + }) + }).catch(e => { + console.log("unexpected connect catch clause"); + done(e) + }) + }) }) \ No newline at end of file