diff --git a/package.json b/package.json index 600b40c..a06f18d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rpclibrary", - "version": "1.6.0", + "version": "1.6.1", "description": "rpclibrary is a websocket on steroids!", "main": "./js/Index.js", "repository": { diff --git a/src/Backend.ts b/src/Backend.ts index e3ad92a..0273e18 100644 --- a/src/Backend.ts +++ b/src/Backend.ts @@ -40,8 +40,8 @@ export class RPCServer< this.sesame = U.makeSesameFunction(conf.sesame) } - this.errorHandler = (socket:I.Socket) => (error:any) => { - if(conf.errorHandler) conf.errorHandler(socket, error) + this.errorHandler = (socket:I.Socket) => (error:any, rpcName:string, args: any[]) => { + if(conf.errorHandler) conf.errorHandler(socket, error, rpcName, args) else throw error } @@ -69,14 +69,14 @@ export class RPCServer< try{ this.io.attach(this.ws) this.io.on('socket', (socket:I.Socket) => { - socket.on('error', (err) => this.errorHandler(socket, err)) + socket.on('error', (err) => this.errorHandler(socket, err, "bind", [])) socket.on('close', () => this.closeHandler(socket)) this.connectionHandler(socket) this.initRPCs(socket) }) this.ws.listen(this.port, this.visibility) }catch(e){ - this.errorHandler(this.io, e) + this.errorHandler(this.io, e, 'start', []) } } diff --git a/src/Types.ts b/src/Types.ts index dc66722..52413e9 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -5,7 +5,7 @@ export type HookFunction = (. export type Visibility = "127.0.0.1" | "0.0.0.0" export type ConnectionHandler = (socket:I.Socket) => void -export type ErrorHandler = (socket:I.Socket, error:any) => void +export type ErrorHandler = (socket:I.Socket, error:any, rpcName: string, args: any[]) => void export type CloseHandler = (socket:I.Socket) => void export type SesameFunction = (sesame : string) => boolean export type ExceptionHandling = 'local' | 'remote' diff --git a/src/Utils.ts b/src/Utils.ts index 97e8352..83b82c5 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -74,7 +74,7 @@ export function rpcHooker(socket: I.Socket, exporter:I.RPCExporter else rpcFunction = info.call - socket.hook(ret.uniqueName, callGenerator(socket, rpcFunction, errorHandler)) + socket.hook(ret.uniqueName, callGenerator(info.name, socket, rpcFunction, errorHandler)) return ret }) } @@ -83,7 +83,7 @@ export function rpcHooker(socket: I.Socket, exporter:I.RPCExporter * Decorate an RPC with the error handler * @param rpcFunction the function to decorate */ -const callGenerator = (socket: I.Socket, rpcFunction : T.AnyFunction, errorHandler: T.ErrorHandler) : T.AnyFunction => { +const callGenerator = (rpcName : string, socket: I.Socket, rpcFunction : T.AnyFunction, errorHandler: T.ErrorHandler) : T.AnyFunction => { const argsArr = extractArgs(rpcFunction) const args = argsArr.join(',') const argsStr = argsArr.map(stripAfterEquals).join(',') @@ -92,7 +92,7 @@ const callGenerator = (socket: I.Socket, rpcFunction : T.AnyFunction, errorHandl try{ return await rpcFunction(`+argsStr+`) }catch(e){ - errorHandler(socket)(e) + errorHandler(socket)(e, rpcName, [`+args+`]) } }`) } @@ -126,7 +126,7 @@ const hookGenerator = (rpc:T.HookRPC, errorHandler: T.ErrorHandle }) return res }catch(e){ - errorHandler(socket, e) + errorHandler(socket)(e, rpc.name, [`+args+`]) } }`) } @@ -139,7 +139,7 @@ const hookGenerator = (rpc:T.HookRPC, errorHandler: T.ErrorHandle }) return res }catch(e){ - errorHandler(socket, e) + errorHandler(socket)(e, rpc.name, [`+args+`]) } }`) } diff --git a/test/Test.ts b/test/Test.ts index 172c577..62a5276 100644 --- a/test/Test.ts +++ b/test/Test.ts @@ -38,9 +38,9 @@ function makeServer(){ function triggerCallback(...messages:any[]):number {return subcallback.apply({}, messages)}, ] }],{ - connectionHandler: (socket) => { console.log("connectionHandler OK") }, - closeHandler: (socket) => { console.log("closeHandler OK") }, - errorHandler: (socket, err) => { console.error("errorHandler OK SO YOU SHOULDN'T SEE THIS"); throw err } + connectionHandler: (socket) => { }, + closeHandler: (socket) => { }, + errorHandler: (socket, err) => { throw err } }) } @@ -193,12 +193,12 @@ describe('It should do unhook', () => { } }, function checkCandy():string { cb(candy); return candy }, - function stealCandy():string { candy = "_OK"; cb(candy); cb = (...any) => console.log.apply(console,["Server:", ...any]); return candy } + function stealCandy():string { candy = "_OK"; cb(candy); cb = () => {}; return candy } ] }],{ - connectionHandler: (socket) => { console.log("connectionHandler OK") }, - closeHandler: (socket) => { console.log("closeHandler OK") }, - errorHandler: (socket, err) => { console.error("errorHandler OK SO YOU SHOULDN'T SEE THIS"); throw err } + connectionHandler: (socket) => { }, + closeHandler: (socket) => { }, + errorHandler: (socket, err) => { throw err } }) client = new RPCSocket(21000, "localhost") return await client.connect() @@ -210,14 +210,12 @@ describe('It should do unhook', () => { }) it('Unhook+unsubscribe should stop callbacks', (done) => { - client['test'].subscribe(c => console.log("Client: "+c)).then( async (res: SubscriptionResponse) => { + client['test'].subscribe(c => {}).then( async (res: SubscriptionResponse) => { const r1 = await client['test'].checkCandy() const r3 = await client['test'].stealCandy() client.unhook(res.uuid) - console.log("---- No client output below this line") const r2 = await client['test'].checkCandy() const r4 = await client['test'].checkCandy() - console.log("---- More output below") if(r1 === "OK" && r3 === "_OK" && r2 === "_OK" && r4 === "_OK") done() @@ -382,15 +380,14 @@ describe('Error handling', ()=>{ }) }) - it("RPC throws server with handler", (done)=>{ + it("RPC throws on server with handler", (done)=>{ let server = new RPCServer(21004, [ { name: 'createUser' as 'createUser', exportRPCs: () => [{ name: 'createUser' as 'createUser', call: createUser }]}], { - errorHandler: (socket, e) => { - //console.log("EXPECTED SERVER EXCEPTION", String(e)); + errorHandler: (socket, e, rpcName, args) => { done() } }) @@ -416,3 +413,80 @@ describe('Error handling', ()=>{ }) }) }) + +describe("Errorhandler functionality", ()=>{ + let createUser = async( user: {a:any,b:any}) => { + throw new Error("BAD BAD BAD") + } + + it("correct values are passed to the handler", (done)=>{ + let server = new RPCServer(21004, [ { + name: 'createUser' as 'createUser', + exportRPCs: () => [{ + name: 'createUser' as 'createUser', + call: createUser + }]}], { + errorHandler: (socket, e, rpcName, args) => { + if(e.message === "BAD BAD BAD" && rpcName === "createUser" && args[0]['a'] === 'a' && args[0]['b'] === 'b') + done() + } + }) + + let sock = new RPCSocket(21004, 'localhost') + sock.connect().then((cli) => { + cli["createUser"]["createUser"]({ + a:'a', + b:'b' + }) + .then(r => { + if(r != null) + done("UNEXPECTED RESULT " + r) + }) + .catch((e) => { + done("UNEXPECTED CLIENT ERROR " + e) + done(e) + }) + .finally(() => { + sock.destroy() + server.destroy() + }) + }) + }) + + it("handler sees sesame", (done)=>{ + let sesame = "AAAAAAAAAAAAAAA" + let server = new RPCServer(21004, [ { + name: 'createUser' as 'createUser', + exportRPCs: () => [{ + name: 'createUser' as 'createUser', + call: createUser + }]}], { + sesame: sesame, + errorHandler: (socket, e, rpcName, args) => { + if(e.message === "BAD BAD BAD" && rpcName === "createUser" && args[0] === sesame && args[1]['a'] === 'a' && args[1]['b'] === 'b') + done() + } + + }) + + let sock = new RPCSocket(21004, 'localhost') + sock.connect(sesame).then((cli) => { + cli["createUser"]["createUser"]({ + a:'a', + b:'b' + }) + .then(r => { + if(r != null) + done("UNEXPECTED RESULT " + r) + }) + .catch((e) => { + done("UNEXPECTED CLIENT ERROR " + e) + done(e) + }) + .finally(() => { + sock.destroy() + server.destroy() + }) + }) + }) +}) \ No newline at end of file