attach errorhandler to failed calls and failed connects

This commit is contained in:
2020-02-25 17:38:48 +01:00
parent b97d88b9e1
commit bc7593bda5
6 changed files with 75 additions and 20 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "rpclibrary", "name": "rpclibrary",
"version": "1.8.0", "version": "1.8.1",
"description": "rpclibrary is a websocket on steroids!", "description": "rpclibrary is a websocket on steroids!",
"main": "./js/Index.js", "main": "./js/Index.js",
"repository": { "repository": {
+1
View File
@@ -14,6 +14,7 @@ export class RPCServer<
SubResType = {}, SubResType = {},
InterfaceT extends T.RPCInterface = T.RPCInterface, InterfaceT extends T.RPCInterface = T.RPCInterface,
> implements I.Destroyable{ > implements I.Destroyable{
private ws = http.createServer() private ws = http.createServer()
private io = bsock.createServer() private io = bsock.createServer()
private visibility:T.Visibility private visibility:T.Visibility
+23 -8
View File
@@ -18,8 +18,8 @@ export class RPCSocket implements I.Socket{
} }
private socket: I.Socket private socket: I.Socket
private closeHandlers: T.CloseHandler[] = [] private closeHandlers: T.FrontEndHandlerType['close'][] = []
private errorHandlers: T.ErrorHandler[] = [] private errorHandlers: T.FrontEndHandlerType['error'][] = []
private hooks : {[name in string]: T.AnyFunction} = {} private hooks : {[name in string]: T.AnyFunction} = {}
/** /**
@@ -62,11 +62,11 @@ export class RPCSocket implements I.Socket{
* @param type 'error' or 'close' * @param type 'error' or 'close'
* @param f The listener to attach * @param f The listener to attach
*/ */
public on<T extends "error" | "close">(type: T, f: T.HandlerType[T]){ public on<T extends "error" | "close">(type: T, f: T.FrontEndHandlerType[T]){
if(!this.socket){ if(!this.socket){
switch(type){ switch(type){
case "error": this.errorHandlers.push(<T.HandlerType['error']> f); break; case "error": this.errorHandlers.push(<T.FrontEndHandlerType['error']> f); break;
case "close": this.closeHandlers.push(<T.HandlerType['close']> f); break; case "close": this.closeHandlers.push(<T.FrontEndHandlerType['close']> f); break;
default: throw new Error('socket.on only supports ´error´ and ´close´ as first parameter. Got: ´'+type+'´') default: throw new Error('socket.on only supports ´error´ and ´close´ as first parameter. Got: ´'+type+'´')
} }
}else{ }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 * Destroys the socket
*/ */
@@ -97,7 +107,11 @@ export class RPCSocket implements I.Socket{
*/ */
public async call (rpcname: string, ...args: any[]) : Promise<any>{ public async call (rpcname: string, ...args: any[]) : Promise<any>{
if(!this.socket) throw new Error("The socket is not connected! Use socket.connect() first") 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(",") const argParams = fnArgs.map(stripAfterEquals).join(",")
sesame = appendComma(sesame) 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( ` return eval( `
async (${headerArgs} callback) => { async (${headerArgs} callback) => {
const r = await this.socket.call("${fnName}", ${sesame} ${argParams}) const r = await this.socket.call("${fnName}", ${sesame} ${argParams})
if(r && r.result === 'Success'){ if(r && r.result === 'Success'){
this.socket.hook(r.uuid, callback) this.socket.hook(r.uuid, callback)
+2 -1
View File
@@ -22,7 +22,8 @@ export interface Socket extends Destroyable {
unhook: (rpcname:string) => void unhook: (rpcname:string) => void
call: (rpcname:string, ...args: any[]) => Promise<any> call: (rpcname:string, ...args: any[]) => Promise<any>
fire: (rpcname:string, ...args: any[]) => Promise<any> fire: (rpcname:string, ...args: any[]) => Promise<any>
on: T.OnFunction on: T.OnFunction
emit: (eventName: string, data:any) => void
close() : void close() : void
} }
+4 -4
View File
@@ -12,9 +12,9 @@ export type ExceptionHandling = 'local' | 'remote'
export type SesameConf = { export type SesameConf = {
sesame?: string | SesameFunction sesame?: string | SesameFunction
} }
export type HandlerType = { export type FrontEndHandlerType = {
'error' : ErrorHandler 'error' : (e: any) => void
'close' : CloseHandler 'close' : () => void
} }
export type ServerConf = { export type ServerConf = {
@@ -84,5 +84,5 @@ export type CallInfo = BaseInfo & {
export type RpcInfo = HookInfo | CallInfo export type RpcInfo = HookInfo | CallInfo
export type ExtendedRpcInfo = RpcInfo & { uniqueName: string } export type ExtendedRpcInfo = RpcInfo & { uniqueName: string }
export type OnFunction = <T extends "error" | "close">(type: T, f: HandlerType[T]) => void export type OnFunction = <T extends "error" | "close">(type: T, f: FrontEndHandlerType[T]) => void
export type HookCloseFunction<T = {}> = (res:SubscriptionResponse<T>, rpc:HookRPC<any, any, T>) => any export type HookCloseFunction<T = {}> = (res:SubscriptionResponse<T>, rpc:HookRPC<any, any, T>) => any
+44 -6
View File
@@ -551,14 +551,17 @@ describe("Class binding", ()=>{
} }
let serv: RPCServer, let serv: RPCServer,
sock: RPCSocket, sock: RPCSocket & myExporterIfc,
exporter: MyExporter exporter: MyExporter
before((done)=>{ before((done)=>{
exporter = new MyExporter() exporter = new MyExporter()
serv = new RPCServer(21004, [exporter]) serv = new RPCServer(21004, [exporter])
sock = new RPCSocket(21004, 'localhost') const s = new RPCSocket(21004, 'localhost')
sock.connect<myExporterIfc>().then(_ => done()) s.connect<myExporterIfc>().then(conn => {
sock = conn
done()
})
}) })
after(() => { after(() => {
sock.destroy() sock.destroy()
@@ -574,13 +577,11 @@ describe("Class binding", ()=>{
describe("attaching handlers before connecting", ()=>{ describe("attaching handlers before connecting", ()=>{
it("fires error if server is unreachable", (done)=>{ it("fires error if server is unreachable", (done)=>{
const sock = new RPCSocket(21004, 'localhost') const sock = new RPCSocket(21004, 'localhost')
let errorHandleCount = 0 let errorHandleCount = 0
sock.on('error', (socket) => { sock.on('error', (err) => {
//attached listener fires first //attached listener fires first
if(errorHandleCount != 0){ if(errorHandleCount != 0){
console.log("Error handler didn't fire first"); 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)
})
})
}) })