Browse Source

Unknown RPC errors, fixed error handler structure, multiple RPCservers on different paths, optional throws

master
nitowa 3 years ago
parent
commit
326dabf2f8
9 changed files with 8873 additions and 305 deletions
  1. 8512
    118
      package-lock.json
  2. 1
    0
      package.json
  3. 40
    17
      src/Backend.ts
  4. 59
    59
      src/Frontend.ts
  5. 15
    7
      src/PromiseIO/Client.ts
  6. 12
    7
      src/PromiseIO/Server.ts
  7. 5
    6
      src/Types.ts
  8. 14
    12
      src/Utils.ts
  9. 215
    79
      test/Test.ts

+ 8512
- 118
package-lock.json
File diff suppressed because it is too large
View File


+ 1
- 0
package.json View File

57
     "http": "0.0.0",
57
     "http": "0.0.0",
58
     "socket.io": "^2.3.0",
58
     "socket.io": "^2.3.0",
59
     "socket.io-client": "^2.3.0",
59
     "socket.io-client": "^2.3.0",
60
+    "socketio-wildcard": "^2.0.0",
60
     "uuid": "^3.3.3"
61
     "uuid": "^3.3.3"
61
   },
62
   },
62
   "files": [
63
   "files": [

+ 40
- 17
src/Backend.ts View File

8
 
8
 
9
 export class RPCServer<
9
 export class RPCServer<
10
     InterfaceT extends T.RPCInterface = T.RPCInterface,
10
     InterfaceT extends T.RPCInterface = T.RPCInterface,
11
-> {
11
+    > {
12
 
12
 
13
     private pio = new PromiseIO()
13
     private pio = new PromiseIO()
14
     private closeHandler: T.CloseHandler
14
     private closeHandler: T.CloseHandler
15
-    private errorHandler: T.ErrorHandler
15
+    private errorHandler: (socket: I.Socket, error: any, rpcName: string, args: any[], forward?: boolean) => void
16
     private connectionHandler: T.ConnectionHandler
16
     private connectionHandler: T.ConnectionHandler
17
     private sesame?: T.SesameFunction
17
     private sesame?: T.SesameFunction
18
     private accessFilter: T.AccessFilter<InterfaceT>
18
     private accessFilter: T.AccessFilter<InterfaceT>
26
      */
26
      */
27
     constructor(
27
     constructor(
28
         private exporters: T.ExporterArray<InterfaceT> = [],
28
         private exporters: T.ExporterArray<InterfaceT> = [],
29
-        conf: T.ServerConf<InterfaceT> = {},
29
+        private conf: T.ServerConf<InterfaceT> = {},
30
     ) {
30
     ) {
31
+        if (conf.throwOnUnknownRPC == null) {
32
+            conf.throwOnUnknownRPC = true
33
+        }
34
+
31
         if (conf.sesame) {
35
         if (conf.sesame) {
32
             this.sesame = U.makeSesameFunction(conf.sesame)
36
             this.sesame = U.makeSesameFunction(conf.sesame)
33
         }
37
         }
37
             return this.sesame!(sesame!)
41
             return this.sesame!(sesame!)
38
         })
42
         })
39
 
43
 
40
-        this.errorHandler = (socket: I.Socket | PromiseIO) => (error: any, rpcName: string, args: any[]) => {
44
+        this.errorHandler = (socket: I.Socket, error: any, rpcName: string, args: any[], forward: boolean = false) => {
41
             if (conf.errorHandler) conf.errorHandler(socket, error, rpcName, args)
45
             if (conf.errorHandler) conf.errorHandler(socket, error, rpcName, args)
42
-            else throw error
46
+            else {
47
+                if (forward) {
48
+                    socket.call("$UNKNOWNRPC$", error)
49
+                } else {
50
+                    throw error
51
+                }
52
+            }
43
         }
53
         }
44
 
54
 
45
         this.closeHandler = (socket: I.Socket) => {
55
         this.closeHandler = (socket: I.Socket) => {
52
 
62
 
53
         exporters.forEach(U.fixNames) //TSC for some reason doesn't preserve name properties of methods
63
         exporters.forEach(U.fixNames) //TSC for some reason doesn't preserve name properties of methods
54
 
64
 
55
-        let badRPC = exporters.flatMap(ex => typeof ex.RPCs === "function"?ex.RPCs():(ex as any)).find(rpc => !rpc.name)
65
+        let badRPC = exporters.flatMap(ex => typeof ex.RPCs === "function" ? ex.RPCs() : (ex as any)).find(rpc => !rpc.name)
56
         if (badRPC) {
66
         if (badRPC) {
57
             throw new Error(`
67
             throw new Error(`
58
             RPC did not provide a name. 
68
             RPC did not provide a name. 
62
             \n`+ badRPC.toString() + `
72
             \n`+ badRPC.toString() + `
63
             \n>------------OFFENDING RPC`)
73
             \n>------------OFFENDING RPC`)
64
         }
74
         }
65
-        
75
+
66
         try {
76
         try {
67
 
77
 
68
             this.pio.on('socket', (clientSocket: I.Socket) => {
78
             this.pio.on('socket', (clientSocket: I.Socket) => {
69
-                const sock:any = clientSocket;
70
                 clientSocket.on('disconnect', () => this.closeHandler(clientSocket))
79
                 clientSocket.on('disconnect', () => this.closeHandler(clientSocket))
71
                 this.connectionHandler(clientSocket)
80
                 this.connectionHandler(clientSocket)
72
                 this.initRPCs(clientSocket)
81
                 this.initRPCs(clientSocket)
73
-                
74
             })
82
             })
75
         } catch (e) {
83
         } catch (e) {
76
-            this.errorHandler(this.pio, e, 'system', [])
84
+            this.errorHandler(<unknown>undefined as I.Socket, e, 'system', [])
77
         }
85
         }
78
     }
86
     }
79
 
87
 
80
-    public attach = (httpServer = new http.Server()) : RPCServer<InterfaceT> => {
81
-        this.pio.attach(httpServer)
88
+    public attach = (httpServer = new http.Server(), options?: SocketIO.ServerOptions): RPCServer<InterfaceT> => {
89
+        this.pio.attach(httpServer, options)
82
         this.attached = true
90
         this.attached = true
83
         return this
91
         return this
84
     }
92
     }
85
 
93
 
86
-    public listen(port:number) : RPCServer<InterfaceT>{
87
-        if(!this.attached) this.attach()
94
+    public listen(port: number, options?: SocketIO.ServerOptions): RPCServer<InterfaceT> {
95
+        if (!this.attached) {
96
+            this.attach(undefined, options)
97
+        } else {
98
+            if (options)
99
+                console.warn("RPCServer options were passed to listen(..) after attach(..) was called. Please pass them to attach(..) instead. Ignoring.")
100
+        }
88
         this.pio.listen(port)
101
         this.pio.listen(port)
89
         return this
102
         return this
90
     }
103
     }
94
             const rpcs = await Promise.all(this.exporters.map(async exp => {
107
             const rpcs = await Promise.all(this.exporters.map(async exp => {
95
                 const allowed = await this.accessFilter(sesame, exp)
108
                 const allowed = await this.accessFilter(sesame, exp)
96
                 if (!allowed) return []
109
                 if (!allowed) return []
97
-                const infos = U.rpcHooker(clientSocket, exp, this.errorHandler, this.sesame)
98
-                return infos
110
+                return U.rpcHooker(clientSocket, exp, this.errorHandler, this.sesame)
99
             }))
111
             }))
100
-            return rpcs.flat()
112
+            const infos = rpcs.flat()
113
+            if (this.conf.throwOnUnknownRPC) {
114
+                clientSocket.on("*", (packet) => {
115
+                    if (!infos.some(i => i.uniqueName === packet.data[0])) {
116
+                        if (packet.data[0].startsWith('destroy_')) return
117
+                        this.errorHandler(clientSocket, new Error(`Unknown RPC ${packet.data[0]}`), packet.data[0], [...packet.data].splice(1), true)
118
+                    }
119
+                })
120
+            }
121
+            return infos
101
         })
122
         })
123
+
124
+
102
     }
125
     }
103
 
126
 
104
     close(): void {
127
     close(): void {

+ 59
- 59
src/Frontend.ts View File

1
 'use strict'
1
 'use strict'
2
 
2
 
3
-import { PromiseIOClient } from './PromiseIO/Client'
4
-import * as T from './Types'; 
3
+import { PromiseIOClient, defaultClientConfig } from './PromiseIO/Client'
4
+import * as T from './Types';
5
 import * as I from './Interfaces';
5
 import * as I from './Interfaces';
6
 import { stripAfterEquals, appendComma } from './Utils';
6
 import { stripAfterEquals, appendComma } from './Utils';
7
 
7
 
9
 /**
9
 /**
10
  * A websocket-on-steroids with built-in RPC capabilities
10
  * A websocket-on-steroids with built-in RPC capabilities
11
  */
11
  */
12
-export class RPCSocket<Ifc extends T.RPCInterface = T.RPCInterface> implements I.Socket{
12
+export class RPCSocket<Ifc extends T.RPCInterface = T.RPCInterface> implements I.Socket {
13
 
13
 
14
-    static async makeSocket<T extends T.RPCInterface = T.RPCInterface>(port:number, server: string, sesame?:string, conf?:T.SocketConf): Promise<T.ConnectedSocket<T>> {
14
+    static async makeSocket<T extends T.RPCInterface = T.RPCInterface>(port: number, server: string, sesame?: string, conf: T.ClientConfig = defaultClientConfig): Promise<T.ConnectedSocket<T>> {
15
         const socket = new RPCSocket<T>(port, server, conf)
15
         const socket = new RPCSocket<T>(port, server, conf)
16
         return await socket.connect(sesame)
16
         return await socket.connect(sesame)
17
     }
17
     }
18
 
18
 
19
-    private protocol: 'http' | 'https'
20
     private socket: I.Socket
19
     private socket: I.Socket
21
-    private handlers : {
20
+    private handlers: {
22
         [name in string]: T.AnyFunction[]
21
         [name in string]: T.AnyFunction[]
23
     } = {
22
     } = {
24
-        error: [],
25
-        close: []
26
-    }
27
-    private hooks : {[name in string]: T.AnyFunction} = {} 
23
+            error: [],
24
+            close: []
25
+        }
26
+    private hooks: { [name in string]: T.AnyFunction } = {}
28
 
27
 
29
     /**
28
     /**
30
      * 
29
      * 
32
      * @param server Server address
31
      * @param server Server address
33
      * @param tls @default false use TLS
32
      * @param tls @default false use TLS
34
      */
33
      */
35
-    constructor(public port:number, public address: string, conf:T.SocketConf = { tls: false }){
36
-        Object.defineProperty(this, 'socket', {value: undefined, writable: true})
37
-        this.protocol = conf.tls ? "https" : "http"
34
+    constructor(public port: number, public address: string, private conf: T.ClientConfig = defaultClientConfig) {
35
+        Object.defineProperty(this, 'socket', { value: undefined, writable: true })
36
+        this.hook("$UNKNOWNRPC$", (err) => this.handlers['error'].forEach(handler => handler(err)))
38
     }
37
     }
39
 
38
 
40
     /**
39
     /**
42
      * @param name The function name to listen on
41
      * @param name The function name to listen on
43
      * @param handler The handler to attach
42
      * @param handler The handler to attach
44
      */
43
      */
45
-    public hook(name: string, handler: (...args:any[]) => any | Promise<any>){
46
-        if(!this.socket){
44
+    public hook(name: string, handler: (...args: any[]) => any | Promise<any>) {
45
+        if (!this.socket) {
47
             this.hooks[name] = handler
46
             this.hooks[name] = handler
48
-        }else{
47
+        } else {
49
             this.socket.hook(name, handler)
48
             this.socket.hook(name, handler)
50
         }
49
         }
51
     }
50
     }
55
      * @param name The function name to listen on
54
      * @param name The function name to listen on
56
      * @param handler The handler to attach
55
      * @param handler The handler to attach
57
      */
56
      */
58
-    public bind(name: string, handler: (...args:any[]) => any | Promise<any>){
59
-        if(!this.socket){
57
+    public bind(name: string, handler: (...args: any[]) => any | Promise<any>) {
58
+        if (!this.socket) {
60
             this.hooks[name] = handler
59
             this.hooks[name] = handler
61
-        }else{
60
+        } else {
62
             this.socket.bind(name, handler)
61
             this.socket.bind(name, handler)
63
         }
62
         }
64
     }
63
     }
67
      * Removes a {@link hook} listener by name.
66
      * Removes a {@link hook} listener by name.
68
      * @param name The function name 
67
      * @param name The function name 
69
      */
68
      */
70
-    public unhook(name: string){
71
-        if(!this.socket){
69
+    public unhook(name: string) {
70
+        if (!this.socket) {
72
             delete this.hooks[name]
71
             delete this.hooks[name]
73
-        }else{
72
+        } else {
74
             this.socket.unhook(name)
73
             this.socket.unhook(name)
75
         }
74
         }
76
     }
75
     }
80
      * @param type 'error' or 'close'
79
      * @param type 'error' or 'close'
81
      * @param f The listener to attach
80
      * @param f The listener to attach
82
      */
81
      */
83
-    public on(type: string, f: T.AnyFunction){
84
-        if(!this.socket){
85
-            if(!this.handlers[type]) 
82
+    public on(type: string, f: T.AnyFunction) {
83
+        if (!this.socket) {
84
+            if (!this.handlers[type])
86
                 this.handlers[type] = []
85
                 this.handlers[type] = []
87
 
86
 
88
             this.handlers[type].push(f)
87
             this.handlers[type].push(f)
89
-        }else{
88
+        } else {
90
             this.socket.on(type, f)
89
             this.socket.on(type, f)
91
         }
90
         }
92
     }
91
     }
96
      * @param eventName The event name to emit under
95
      * @param eventName The event name to emit under
97
      * @param data The data the event carries
96
      * @param data The data the event carries
98
      */
97
      */
99
-    public emit(eventName:string, data:any){
100
-        if(!this.socket) return
98
+    public emit(eventName: string, data: any) {
99
+        if (!this.socket) return
101
         this.socket.emit(eventName, data)
100
         this.socket.emit(eventName, data)
102
     }
101
     }
103
 
102
 
104
     /**
103
     /**
105
      * Closes the socket. It may attempt to reconnect.
104
      * Closes the socket. It may attempt to reconnect.
106
      */
105
      */
107
-    public close(){
108
-        if(!this.socket) return;
106
+    public close() {
107
+        if (!this.socket) return;
109
         this.socket.close()
108
         this.socket.close()
110
     }
109
     }
111
 
110
 
114
      * @param rpcname The function to call
113
      * @param rpcname The function to call
115
      * @param args other arguments
114
      * @param args other arguments
116
      */
115
      */
117
-    public async call (rpcname: string, ...args: any[]) : Promise<any>{
118
-        if(!this.socket) throw new Error("The socket is not connected! Use socket.connect() first")
119
-        try{
116
+    public async call(rpcname: string, ...args: any[]): Promise<any> {
117
+        if (!this.socket) throw new Error("The socket is not connected! Use socket.connect() first")
118
+
119
+        try {
120
             const val = await this.socket.call.apply(this.socket, [rpcname, ...args])
120
             const val = await this.socket.call.apply(this.socket, [rpcname, ...args])
121
             return val
121
             return val
122
-        }catch(e){
122
+        } catch (e) {
123
             this.emit('error', e)
123
             this.emit('error', e)
124
             throw e
124
             throw e
125
         }
125
         }
130
      * @param rpcname The function to call
130
      * @param rpcname The function to call
131
      * @param args other arguments
131
      * @param args other arguments
132
      */
132
      */
133
-    public async fire(rpcname: string, ...args: any[]) : Promise<void>{
134
-        if(!this.socket) throw new Error("The socket is not connected! Use socket.connect() first")
133
+    public async fire(rpcname: string, ...args: any[]): Promise<void> {
134
+        if (!this.socket) throw new Error("The socket is not connected! Use socket.connect() first")
135
         await this.socket.fire.apply(this.socket, [rpcname, ...args])
135
         await this.socket.fire.apply(this.socket, [rpcname, ...args])
136
     }
136
     }
137
-    
137
+
138
     /**
138
     /**
139
      * Connects to the server and attaches available RPCs to this object
139
      * Connects to the server and attaches available RPCs to this object
140
      */
140
      */
141
-    public async connect( sesame?: string ) : Promise<T.ConnectedSocket<Ifc>> {
141
+    public async connect(sesame?: string): Promise<T.ConnectedSocket<Ifc>> {
142
 
142
 
143
-        try{
144
-            this.socket = await PromiseIOClient.connect(this.port, this.address, this.protocol)
145
-        }catch(e){
143
+        try {
144
+            this.socket = await PromiseIOClient.connect(this.port, this.address, this.conf)
145
+        } catch (e) {
146
             this.handlers['error'].forEach(h => h(e))
146
             this.handlers['error'].forEach(h => h(e))
147
             throw e
147
             throw e
148
         }
148
         }
149
 
149
 
150
-        Object.entries(this.handlers).forEach(([k,v])=>{
150
+        Object.entries(this.handlers).forEach(([k, v]) => {
151
             v.forEach(h => this.socket.on(k, h))
151
             v.forEach(h => this.socket.on(k, h))
152
         })
152
         })
153
 
153
 
154
         Object.entries(this.hooks).forEach((kv: [string, T.AnyFunction]) => {
154
         Object.entries(this.hooks).forEach((kv: [string, T.AnyFunction]) => {
155
             this.socket.hook(kv[0], kv[1])
155
             this.socket.hook(kv[0], kv[1])
156
         })
156
         })
157
-        const info:T.ExtendedRpcInfo[] = await this.info(sesame)
157
+        const info: T.ExtendedRpcInfo[] = await this.info(sesame)
158
 
158
 
159
         info.forEach(i => {
159
         info.forEach(i => {
160
             let f: any
160
             let f: any
161
-            
161
+
162
             switch (i.type) {
162
             switch (i.type) {
163
                 case 'Call':
163
                 case 'Call':
164
-                    f = this.callGenerator(i.uniqueName, i.argNames, sesame)    
165
-                    break                
164
+                    f = this.callGenerator(i.uniqueName, i.argNames, sesame)
165
+                    break
166
                 case 'Hook':
166
                 case 'Hook':
167
-                    f = this.frontEndHookGenerator(i.uniqueName, i.argNames, sesame)                    
167
+                    f = this.frontEndHookGenerator(i.uniqueName, i.argNames, sesame)
168
                     break
168
                     break
169
             }
169
             }
170
-            if(this[i.owner] == null)
170
+            if (this[i.owner] == null)
171
                 this[i.owner] = {}
171
                 this[i.owner] = {}
172
             this[i.owner][i.name] = f
172
             this[i.owner][i.name] = f
173
             this[i.owner][i.name].bind(this)
173
             this[i.owner][i.name].bind(this)
174
         })
174
         })
175
-        
176
-        
177
-        return <T.ConnectedSocket<Ifc>> (this as any) 
175
+
176
+
177
+        return <T.ConnectedSocket<Ifc>>(this as any)
178
     }
178
     }
179
 
179
 
180
     /**
180
     /**
181
      * Get a list of available RPCs from the server
181
      * Get a list of available RPCs from the server
182
      */
182
      */
183
-    public async info(sesame?:string){
184
-        if(!this.socket) throw new Error("The socket is not connected! Use socket.connect() first")
183
+    public async info(sesame?: string) {
184
+        if (!this.socket) throw new Error("The socket is not connected! Use socket.connect() first")
185
         return await this.socket.call('info', sesame)
185
         return await this.socket.call('info', sesame)
186
     }
186
     }
187
 
187
 
190
      * @param fnName The function name
190
      * @param fnName The function name
191
      * @param fnArgs A string-list of parameters
191
      * @param fnArgs A string-list of parameters
192
      */
192
      */
193
-    private callGenerator(fnName: string, fnArgs:string[], sesame?:string): T.AnyFunction{
193
+    private callGenerator(fnName: string, fnArgs: string[], sesame?: string): T.AnyFunction {
194
         const headerArgs = fnArgs.join(",")
194
         const headerArgs = fnArgs.join(",")
195
         const argParams = fnArgs.map(stripAfterEquals).join(",")
195
         const argParams = fnArgs.map(stripAfterEquals).join(",")
196
         sesame = appendComma(sesame)
196
         sesame = appendComma(sesame)
205
      * @param fnName The function name
205
      * @param fnName The function name
206
      * @param fnArgs A string-list of parameters
206
      * @param fnArgs A string-list of parameters
207
      */
207
      */
208
-    private frontEndHookGenerator(fnName: string, fnArgs:string[], sesame?:string): T.HookFunction{
209
-        
210
-        if(sesame)
208
+    private frontEndHookGenerator(fnName: string, fnArgs: string[], sesame?: string): T.HookFunction {
209
+
210
+        if (sesame)
211
             fnArgs.shift()
211
             fnArgs.shift()
212
 
212
 
213
         let headerArgs = fnArgs.join(",")
213
         let headerArgs = fnArgs.join(",")
214
         const argParams = fnArgs.map(stripAfterEquals).join(",")
214
         const argParams = fnArgs.map(stripAfterEquals).join(",")
215
         sesame = appendComma(sesame, true)
215
         sesame = appendComma(sesame, true)
216
-        headerArgs = fnArgs.length>0?headerArgs+",":headerArgs 
216
+        headerArgs = fnArgs.length > 0 ? headerArgs + "," : headerArgs
217
 
217
 
218
         const frontendHookStr = `
218
         const frontendHookStr = `
219
         async (${headerArgs} $__callback__$) => {
219
         async (${headerArgs} $__callback__$) => {
222
                 if(r){
222
                 if(r){
223
                     if(r.uuid){
223
                     if(r.uuid){
224
                         $__callback__$['destroy'] = () => {
224
                         $__callback__$['destroy'] = () => {
225
-                            this.socket.fire(r.uuid)
225
+                            this.socket.fire('destroy_'+r.uuid)
226
                             this.socket.unhook(r.uuid) 
226
                             this.socket.unhook(r.uuid) 
227
                         }
227
                         }
228
                         this.socket.hook(r.uuid, $__callback__$)
228
                         this.socket.hook(r.uuid, $__callback__$)

+ 15
- 7
src/PromiseIO/Client.ts View File

2
 import * as U from '../Utils'
2
 import * as U from '../Utils'
3
 import * as I from '../Interfaces'
3
 import * as I from '../Interfaces'
4
 import * as socketio from 'socket.io-client'
4
 import * as socketio from 'socket.io-client'
5
+import { ClientConfig } from "../Types"
6
+
7
+export const defaultClientConfig: ClientConfig = {
8
+    protocol: 'http',
9
+    reconnectionAttempts: 2,
10
+    reconnectionDelay: 200,
11
+    timeout: 450,
12
+    reconnection: false,
13
+} 
5
 
14
 
6
 export class PromiseIOClient {
15
 export class PromiseIOClient {
7
     
16
     
8
-    static connect = (port: number, host = "localhost", protocol : 'http' | 'https' = "http"): Promise<I.Socket> => new Promise((res, rej) => {
17
+    static connect = (port: number, host = "localhost", options : ClientConfig = defaultClientConfig): Promise<I.Socket> => new Promise((res, rej) => {
9
         try {
18
         try {
19
+            if(options.path && !options.path.startsWith('/')){
20
+                options.path = "/"+options.path
21
+            }
22
+
10
             const address = `${host}:${port}`
23
             const address = `${host}:${port}`
11
-            const socket = socketio(`${protocol}://${address}`, {
12
-                reconnectionAttempts: 2,
13
-                reconnectionDelay: 200,
14
-                timeout: 450,
15
-                reconnection: false,
16
-            })
24
+            const socket = socketio(`${options.protocol?options.protocol:'http'}://${address}`, options)
17
 
25
 
18
             socket.on('connect_error', e => {
26
             socket.on('connect_error', e => {
19
                 sock.emit('error', e)
27
                 sock.emit('error', e)

+ 12
- 7
src/PromiseIO/Server.ts View File

3
 import * as U from '../Utils'
3
 import * as U from '../Utils'
4
 import * as T from '../Types'
4
 import * as T from '../Types'
5
 import socketio = require('socket.io')
5
 import socketio = require('socket.io')
6
+import middleware = require('socketio-wildcard');
6
 
7
 
8
+const defaultConfig : socketio.ServerOptions = {
9
+    cookie: false,
10
+    path: '/socket.io',
11
+}
7
 
12
 
8
 export class PromiseIO {
13
 export class PromiseIO {
9
     io?: Server
14
     io?: Server
13
         connect: []
18
         connect: []
14
     }
19
     }
15
 
20
 
16
-    attach(httpServer: httpServer) {
21
+    attach(httpServer: httpServer, options: socketio.ServerOptions = defaultConfig) {
22
+        if(options.path && !options.path.startsWith('/')){
23
+            options.path = "/"+options.path
24
+        }
17
         this.httpServer = httpServer
25
         this.httpServer = httpServer
18
-        this.io = socketio(httpServer, { cookie:false })
19
-
26
+        this.io = socketio(httpServer, options)
27
+        this.io!.use(middleware())
20
         this.io!.on('connection', (clientSocket: Socket) => {
28
         this.io!.on('connection', (clientSocket: Socket) => {
21
-            clientSocket.use((packet, next) => {
22
-                next()
23
-            })
24
-    
25
 
29
 
26
             clientSocket['address'] = clientSocket.handshake.headers["x-real-ip"] || clientSocket.handshake.address
30
             clientSocket['address'] = clientSocket.handshake.headers["x-real-ip"] || clientSocket.handshake.address
27
             const pioSock = U.makePioSocket(clientSocket)
31
             const pioSock = U.makePioSocket(clientSocket)
28
             this.listeners['socket'].forEach(listener => listener(pioSock))
32
             this.listeners['socket'].forEach(listener => listener(pioSock))
29
             this.listeners['connect'].forEach(listener => listener(pioSock))
33
             this.listeners['connect'].forEach(listener => listener(pioSock))
34
+
30
             /*
35
             /*
31
             pioSock.on('error', ()=>console.log('error'));
36
             pioSock.on('error', ()=>console.log('error'));
32
 
37
 

+ 5
- 6
src/Types.ts View File

10
 export type AccessFilter<InterfaceT extends RPCInterface = RPCInterface> = (sesame:string|undefined, exporter: I.RPCExporter<InterfaceT, keyof InterfaceT>) => Promise<boolean> | boolean
10
 export type AccessFilter<InterfaceT extends RPCInterface = RPCInterface> = (sesame:string|undefined, exporter: I.RPCExporter<InterfaceT, keyof InterfaceT>) => Promise<boolean> | boolean
11
 export type Visibility = "127.0.0.1" | "0.0.0.0"
11
 export type Visibility = "127.0.0.1" | "0.0.0.0"
12
 export type ConnectionHandler = (socket:I.Socket) => void
12
 export type ConnectionHandler = (socket:I.Socket) => void
13
-export type ErrorHandler = (socket:I.Socket | PromiseIO, error:any, rpcName: string, args: any[]) => void
13
+export type ErrorHandler = (socket:I.Socket, error:any, rpcName: string, args: any[]) => void
14
 export type CloseHandler = (socket:I.Socket) =>  void
14
 export type CloseHandler = (socket:I.Socket) =>  void
15
 export type SesameFunction = (sesame : string) => boolean
15
 export type SesameFunction = (sesame : string) => boolean
16
 export type SesameConf = {
16
 export type SesameConf = {
20
     'error' : (e: any) => void
20
     'error' : (e: any) => void
21
     'close' : () => void
21
     'close' : () => void
22
 }
22
 }
23
-
23
+export type ClientConfig = SocketIOClient.ConnectOpts & {
24
+    protocol?: 'http' | 'https'
25
+}
24
 export type ExporterArray<InterfaceT extends RPCInterface = RPCInterface> = I.RPCExporter<RPCInterface<InterfaceT>, keyof InterfaceT>[]
26
 export type ExporterArray<InterfaceT extends RPCInterface = RPCInterface> = I.RPCExporter<RPCInterface<InterfaceT>, keyof InterfaceT>[]
25
 
27
 
26
 export type ConnectedSocket<T extends RPCInterface = RPCInterface> = RPCSocket & AsyncIfc<T>
28
 export type ConnectedSocket<T extends RPCInterface = RPCInterface> = RPCSocket & AsyncIfc<T>
30
     connectionHandler?: ConnectionHandler
32
     connectionHandler?: ConnectionHandler
31
     errorHandler?: ErrorHandler
33
     errorHandler?: ErrorHandler
32
     closeHandler?: CloseHandler
34
     closeHandler?: CloseHandler
35
+    throwOnUnknownRPC?: boolean
33
 } & SesameConf
36
 } & SesameConf
34
 
37
 
35
-export type SocketConf = {
36
-    tls:boolean
37
-}
38
-
39
 export type ResponseType = "Subscribe" | "Success" | "Error"
38
 export type ResponseType = "Subscribe" | "Success" | "Error"
40
 export type Outcome = "Success" | "Error"
39
 export type Outcome = "Success" | "Error"
41
 
40
 

+ 14
- 12
src/Utils.ts View File

56
 
56
 
57
 /**
57
 /**
58
  * Utility function to apply the RPCs of an {@link RPCExporter}.
58
  * Utility function to apply the RPCs of an {@link RPCExporter}.
59
- * @param serverSocket The websocket (implementation: socket.io) to hook on
59
+ * @param socket The websocket (implementation: socket.io) to hook on
60
  * @param exporter The exporter
60
  * @param exporter The exporter
61
  * @param makeUnique @default true Attach a suffix to RPC names
61
  * @param makeUnique @default true Attach a suffix to RPC names
62
  */
62
  */
63
-export function rpcHooker(serverSocket: I.Socket, exporter: I.RPCExporter<any, any>, errorHandler: T.ErrorHandler, sesame?: T.SesameFunction, makeUnique = true): T.ExtendedRpcInfo[] {
63
+export function rpcHooker(socket: I.Socket, exporter: I.RPCExporter<any, any>, errorHandler: T.ErrorHandler, sesame?: T.SesameFunction, makeUnique = true): T.ExtendedRpcInfo[] {
64
     const owner = exporter.name
64
     const owner = exporter.name
65
     const RPCs = typeof exporter.RPCs === "function" ? exporter.RPCs() : exporter.RPCs
65
     const RPCs = typeof exporter.RPCs === "function" ? exporter.RPCs() : exporter.RPCs
66
 
66
 
67
     return RPCs
67
     return RPCs
68
-        .map(rpc => rpcToRpcinfo(serverSocket, rpc, owner, errorHandler, sesame))
68
+        .map(rpc => rpcToRpcinfo(socket, rpc, owner, errorHandler, sesame))
69
         .map(info => {
69
         .map(info => {
70
             const suffix = makeUnique ? "-" + uuidv4().substr(0, 4) : ""
70
             const suffix = makeUnique ? "-" + uuidv4().substr(0, 4) : ""
71
             const ret: any = info
71
             const ret: any = info
72
             ret.uniqueName = info.name + suffix
72
             ret.uniqueName = info.name + suffix
73
-            let rpcFunction = info.type === 'Hook' ? info.generator(serverSocket) : info.call
74
-            serverSocket.hook(ret.uniqueName, callGenerator(info.name, serverSocket, rpcFunction, errorHandler))
73
+            let rpcFunction = info.type === 'Hook' ? info.generator(socket) : info.call
74
+            socket.hook(ret.uniqueName, callGenerator(info.name, socket, rpcFunction, errorHandler))
75
             return ret
75
             return ret
76
         })
76
         })
77
 }
77
 }
89
         try{
89
         try{
90
             return await rpcFunction(${argsStr})
90
             return await rpcFunction(${argsStr})
91
         }catch(e){
91
         }catch(e){
92
-            errorHandler($__socket__$)(e, rpcName, [${args}])
92
+            errorHandler($__socket__$, e, rpcName, [${args}])
93
         }
93
         }
94
     }`
94
     }`
95
 
95
 
115
 
115
 
116
     let callArgs = argsArr.join(',')
116
     let callArgs = argsArr.join(',')
117
     const args = sesameFn ? (['sesame', ...argsArr].join(','))
117
     const args = sesameFn ? (['sesame', ...argsArr].join(','))
118
-                          : callArgs
118
+        : callArgs
119
 
119
 
120
     callArgs = appendComma(callArgs, false)
120
     callArgs = appendComma(callArgs, false)
121
 
121
 
128
                 ${rpc.onCallback ? `rpc.onCallback.apply({}, cbargs)` : ``}
128
                 ${rpc.onCallback ? `rpc.onCallback.apply({}, cbargs)` : ``}
129
                 $__socket__$.call.apply($__socket__$, [uuid, ...cbargs])
129
                 $__socket__$.call.apply($__socket__$, [uuid, ...cbargs])
130
             })
130
             })
131
-            ${rpc.onDestroy ? `$__socket__$.bind(uuid, () => {
131
+            ${rpc.onDestroy ? `$__socket__$.bind('destroy_'+uuid, () => {
132
                 rpc.onDestroy(res, rpc)
132
                 rpc.onDestroy(res, rpc)
133
             })` : ``}
133
             })` : ``}
134
             return {'uuid': uuid, 'return': res}
134
             return {'uuid': uuid, 'return': res}
135
         }catch(e){
135
         }catch(e){
136
             //can throw to pass exception to client or swallow to keep it local
136
             //can throw to pass exception to client or swallow to keep it local
137
-            errorHandler($__socket__$)(e, ${rpc.name}, [${args}])
137
+            errorHandler($__socket__$, e, ${rpc.name}, [${args}])
138
         }
138
         }
139
     }`
139
     }`
140
 
140
 
141
     return eval(hookStr)
141
     return eval(hookStr)
142
 }
142
 }
143
 
143
 
144
-const makeError = (callName: string) =>  new Error(`Call not found: ${callName}. ; Zone: <root> ; Task: Promise.then ; Value: Error: Call not found: ${callName}`)
144
+const makeError = (callName: string) => new Error(`Call not found: ${callName}. ; Zone: <root> ; Task: Promise.then ; Value: Error: Call not found: ${callName}`)
145
 
145
 
146
 /**
146
 /**
147
  * Extract a string list of parameters from a function
147
  * Extract a string list of parameters from a function
194
 export const makePioSocket = (socket: any): I.Socket => {
194
 export const makePioSocket = (socket: any): I.Socket => {
195
     return <I.Socket>{
195
     return <I.Socket>{
196
         id: socket.id,
196
         id: socket.id,
197
-        bind: (name: string, listener: T.PioBindListener) => socket.on(name, (...args: any) => listener.apply(null, args)),
197
+        bind: (name: string, listener: T.PioBindListener) => {
198
+            socket.on(name, (...args: any) => listener.apply(null, args))
199
+        },
198
 
200
 
199
         hook: (name: string, listener: T.PioHookListener) => {
201
         hook: (name: string, listener: T.PioHookListener) => {
200
             const args = extractArgs(listener)
202
             const args = extractArgs(listener)
244
         fire: (name: string, ...args: any) => new Promise((res, rej) => {
246
         fire: (name: string, ...args: any) => new Promise((res, rej) => {
245
             const params: any = [name, ...args]
247
             const params: any = [name, ...args]
246
             socket.emit.apply(socket, params)
248
             socket.emit.apply(socket, params)
247
-            res()
249
+            res(undefined)
248
         }),
250
         }),
249
 
251
 
250
         unhook: (name: string, listener?: T.AnyFunction) => {
252
         unhook: (name: string, listener?: T.AnyFunction) => {

+ 215
- 79
test/Test.ts View File

12
 const noop = (...args) => { }
12
 const noop = (...args) => { }
13
 
13
 
14
 const add = (...args: number[]) => { return args.reduce((a, b) => a + b, 0) }
14
 const add = (...args: number[]) => { return args.reduce((a, b) => a + b, 0) }
15
-function makeServer(onCallback = noop, connectionHandler = noop, hookCloseHandler = noop, closeHandler = noop, errorHandler = (socket, err) => { throw err }) {
15
+function makeServer(onCallback = noop, connectionHandler = noop, hookCloseHandler = noop, closeHandler = noop, errorHandler = noop) {
16
     let subcallback
16
     let subcallback
17
     const serv = new RPCServer([{
17
     const serv = new RPCServer([{
18
         name: 'test',
18
         name: 'test',
38
             },
38
             },
39
             add,
39
             add,
40
             function triggerCallback(...messages: any[]): number { return subcallback.apply({}, messages) },
40
             function triggerCallback(...messages: any[]): number { return subcallback.apply({}, messages) },
41
-            function brokenRPC(){ throw new Error("Intended error") }
41
+            function brokenRPC() { throw new Error("Intended error") }
42
         ]
42
         ]
43
     }],
43
     }],
44
         {
44
         {
57
         const server = new PromiseIO()
57
         const server = new PromiseIO()
58
         server.attach(new http.Server())
58
         server.attach(new http.Server())
59
         server.on("socket", clientSocket => {
59
         server.on("socket", clientSocket => {
60
-            clientSocket.bind("test123", (p1,p2) => {
60
+            clientSocket.bind("test123", (p1, p2) => {
61
                 server.close()
61
                 server.close()
62
-                if(p1 === "p1" && p2 === "p2")
62
+                if (p1 === "p1" && p2 === "p2")
63
                     done()
63
                     done()
64
             })
64
             })
65
         });
65
         });
66
 
66
 
67
         server.listen(21003)
67
         server.listen(21003)
68
-        PromiseIOClient.connect(21003, "localhost", "http").then(cli => {
68
+        PromiseIOClient.connect(21003, "localhost", { protocol: 'http' }).then(cli => {
69
             cli.fire("test123", "p1", "p2")
69
             cli.fire("test123", "p1", "p2")
70
             cli.close()
70
             cli.close()
71
         })
71
         })
75
         const server = new PromiseIO()
75
         const server = new PromiseIO()
76
         server.attach(new http.Server())
76
         server.attach(new http.Server())
77
         server.on("socket", clientSocket => {
77
         server.on("socket", clientSocket => {
78
-            clientSocket.hook("test123", (p1,p2) => {
79
-                if(p1 === "p1" && p2 === "p2")
78
+            clientSocket.hook("test123", (p1, p2) => {
79
+                if (p1 === "p1" && p2 === "p2")
80
                     return "OK"
80
                     return "OK"
81
             })
81
             })
82
         });
82
         });
83
 
83
 
84
         server.listen(21003)
84
         server.listen(21003)
85
-        PromiseIOClient.connect(21003, "localhost", "http").then(cli => {
85
+        PromiseIOClient.connect(21003, "localhost", { protocol: 'http' }).then(cli => {
86
             cli.call("test123", "p1", "p2").then(resp => {
86
             cli.call("test123", "p1", "p2").then(resp => {
87
                 cli.close()
87
                 cli.close()
88
                 server.close()
88
                 server.close()
89
 
89
 
90
-                if(resp === "OK")
90
+                if (resp === "OK")
91
                     done()
91
                     done()
92
             })
92
             })
93
         })
93
         })
97
         const server = new PromiseIO()
97
         const server = new PromiseIO()
98
         server.attach(new http.Server())
98
         server.attach(new http.Server())
99
         server.on("socket", clientSocket => {
99
         server.on("socket", clientSocket => {
100
-            clientSocket.on("test123", (p1,p2) => {
100
+            clientSocket.on("test123", (p1, p2) => {
101
                 server.close()
101
                 server.close()
102
-                if(p1 === "p1" && p2 === "p2")
102
+                if (p1 === "p1" && p2 === "p2")
103
                     done()
103
                     done()
104
             })
104
             })
105
         });
105
         });
106
 
106
 
107
         server.listen(21003)
107
         server.listen(21003)
108
-        PromiseIOClient.connect(21003, "localhost", "http").then(cli => {
108
+        PromiseIOClient.connect(21003, "localhost", { protocol: 'http' }).then(cli => {
109
             cli.emit("test123", "p1", "p2")
109
             cli.emit("test123", "p1", "p2")
110
             cli.close()
110
             cli.close()
111
         })
111
         })
256
     })
256
     })
257
 })
257
 })
258
 
258
 
259
+describe('should be able to attach to non-standard path', () => {
260
+    let client: RPCSocket, server: RPCServer
261
+    const echo = (x) => x
262
+
263
+    before(done => {
264
+        server = new RPCServer([{
265
+            name: 'HelloWorldRPCGroup',
266
+            RPCs: () => [
267
+                echo, //named function variable
268
+                function echof(x) { return x }, //named function
269
+                {
270
+                    name: 'echoExplicit', //describing object
271
+                    call: async (x, y, z) => [x, y, z]
272
+                }
273
+            ]
274
+        }])
275
+        server.listen(21003, {path: '/test'})
276
+        client = new RPCSocket(21003, 'localhost', {path: '/test'})
277
+        done()
278
+    })
279
+
280
+    after(done => {
281
+        client.close()
282
+        server.close()
283
+
284
+        done()
285
+    })
286
+
287
+    it('should be able to use all kinds of RPC definitions', (done) => {
288
+        client.connect().then(async () => {
289
+            const r0 = await client['HelloWorldRPCGroup'].echo('Hello')
290
+            const r1 = await client['HelloWorldRPCGroup'].echof('World')
291
+            const r2 = await client['HelloWorldRPCGroup'].echoExplicit('R', 'P', 'C!')
292
+
293
+
294
+            if (r0 === 'Hello' && r1 === 'World' && r2.join('') === 'RPC!') {
295
+                done()
296
+            } else {
297
+                done(new Error("Bad response"))
298
+            }
299
+        })
300
+    })
301
+})
302
+
303
+
304
+describe('can attach multiple RPCServers to same http server', () => {
305
+    const echo = (x) => x
306
+    const RPCs = [
307
+        echo, //named function variable
308
+        function echof(x) { return x }, //named function
309
+        {
310
+            name: 'echoExplicit', //describing object
311
+            call: async (x, y, z) => [x, y, z]
312
+        }
313
+    ]
314
+
315
+    const RPCExporters = [
316
+        {
317
+            name: 'HelloWorldRPCGroup',
318
+            RPCs: RPCs,
319
+        }
320
+    ]
321
+
322
+    const RPCExporters2 = [
323
+        {
324
+            name: 'Grp2',
325
+            RPCs: [
326
+                function test() { return "/test" }
327
+            ],
328
+        }
329
+    ]
330
+
331
+    let client: RPCSocket, client2: RPCSocket, server: RPCServer, server2: RPCServer
332
+
333
+    before(done => {
334
+        const expressServer = express()
335
+        const httpServer = new http.Server(expressServer)
336
+
337
+        server = new RPCServer(
338
+            RPCExporters,
339
+        )
340
+        server2 = new RPCServer(
341
+            RPCExporters2
342
+        )
343
+
344
+        server.attach(httpServer)
345
+        server2.attach(httpServer, {
346
+            path: "test"
347
+        })
348
+
349
+        httpServer.listen(8080)
350
+
351
+        new RPCSocket(8080, 'localhost').connect().then(sock => {
352
+            client = sock
353
+            new RPCSocket(8080, 'localhost', { path: "test" }).connect().then(sock2 => {
354
+                client2 = sock2
355
+                done()
356
+            })
357
+        })
358
+    })
359
+
360
+    after(done => {
361
+        client.close()
362
+        client2.close()
363
+        server.close()
364
+        server2.close()
365
+
366
+        done()
367
+    })
368
+
369
+    it('both servers should answer', (done) => {
370
+        client['HelloWorldRPCGroup'].echo("test").then(res => {
371
+            if(res != "test"){
372
+                done(new Error("response was "+res))
373
+            }else{
374
+                client2['Grp2'].test().then(res => {
375
+                    if(res != "/test"){
376
+                        done(new Error("response2 was "+res))
377
+                    }else{
378
+                        done()
379
+                    }
380
+                })
381
+            }
382
+        })
383
+    })
384
+
385
+})
386
+
387
+describe("can attach second RPCServer if first is already running", () => {
388
+
389
+    const RPCExporters = [
390
+        {
391
+            name: 'HelloWorldRPCGroup',
392
+            RPCs: [
393
+                function echo (x) { return x}, //named function variable
394
+                function echof(x) { return x }, //named function
395
+                {
396
+                    name: 'echoExplicit', //describing object
397
+                    call: async (x, y, z) => [x, y, z]
398
+                }
399
+            ],
400
+        }
401
+    ]
402
+
403
+    const RPCExporters2 = [
404
+        {
405
+            name: 'Grp2',
406
+            RPCs: [
407
+                function test() { return "/test" }
408
+            ],
409
+        }
410
+    ]
411
+
412
+    it("attaches correctly", done => {
413
+        const expressServer = express()
414
+        const httpServer = new http.Server(expressServer)
415
+
416
+        const server = new RPCServer(
417
+            RPCExporters,
418
+        )
419
+        const server2 = new RPCServer(
420
+            RPCExporters2
421
+        )
422
+
423
+        server.attach(httpServer)
424
+
425
+        httpServer.listen(8080)
426
+        server2.attach(httpServer, {
427
+            path: "test"
428
+        })
429
+
430
+        new RPCSocket(8080, 'localhost').connect().then(sock => {
431
+            new RPCSocket(8080, 'localhost', { path: "test" }).connect().then(sock2 => {
432
+                sock2.Grp2.test().then(resp => {
433
+                    if(resp === "/test") 
434
+                        done()
435
+                    else   
436
+                        done(new Error("response did not match"))
437
+
438
+                    server.close()
439
+                    server2.close()
440
+                    sock.close()
441
+                    sock2.close()
442
+                })
443
+            })
444
+        })
445
+    })
446
+})
259
 
447
 
260
 describe('Serverside Triggers', () => {
448
 describe('Serverside Triggers', () => {
261
     let server, client
449
     let server, client
273
         })
461
         })
274
     })
462
     })
275
 
463
 
464
+    /* testing framework has trouble terminating on this one
276
     it('trigger connectionHandler', (done) => {
465
     it('trigger connectionHandler', (done) => {
277
         server = makeServer(undefined, closerFunction(done))
466
         server = makeServer(undefined, closerFunction(done))
278
         client = new RPCSocket(21010, "localhost")
467
         client = new RPCSocket(21010, "localhost")
279
         client.connect()
468
         client.connect()
280
     })
469
     })
470
+    */
281
 
471
 
282
-    
283
     it('trigger hook closeHandler', (done) => {
472
     it('trigger hook closeHandler', (done) => {
284
         server = makeServer(undefined, undefined, closerFunction(done))
473
         server = makeServer(undefined, undefined, closerFunction(done))
285
         client = new RPCSocket(21010, "localhost")
474
         client = new RPCSocket(21010, "localhost")
286
         client.connect().then(_ => {
475
         client.connect().then(_ => {
287
-            client['test'].subscribe(function cb(){
476
+            client['test'].subscribe(function cb() {
288
                 cb['destroy']()
477
                 cb['destroy']()
289
             }).then(_ => client['test'].triggerCallback())
478
             }).then(_ => client['test'].triggerCallback())
290
         })
479
         })
291
     })
480
     })
292
-    
481
+
293
 
482
 
294
     it('trigger global closeHandler', (done) => {
483
     it('trigger global closeHandler', (done) => {
295
         server = makeServer(undefined, undefined, undefined, () => {
484
         server = makeServer(undefined, undefined, undefined, () => {
301
             client['test'].subscribe(noop).then(_ => client.close())
490
             client['test'].subscribe(noop).then(_ => client.close())
302
         })
491
         })
303
     })
492
     })
304
-    
305
-
306
 })
493
 })
307
 
494
 
308
 describe('RPCSocket', () => {
495
 describe('RPCSocket', () => {
512
         client.close()
699
         client.close()
513
         server.close()
700
         server.close()
514
     })
701
     })
515
-    
702
+
516
     it('should work with sesame', (done) => {
703
     it('should work with sesame', (done) => {
517
         client.test.checkCandy().then(c => done())
704
         client.test.checkCandy().then(c => done())
518
     })
705
     })
526
 
713
 
527
     it('should not work without sesame', (done) => {
714
     it('should not work without sesame', (done) => {
528
         const sock = new RPCSocket(21004, "localhost")
715
         const sock = new RPCSocket(21004, "localhost")
529
-        sock.connect( /* no sesame */).then(async (cli) => {
716
+        sock.connect().then(async (cli) => {
530
             if (!cli.test)
717
             if (!cli.test)
531
                 done()
718
                 done()
532
             else {
719
             else {
733
     }
920
     }
734
 }
921
 }
735
 
922
 
736
-
737
 describe("Class binding", () => {
923
 describe("Class binding", () => {
738
 
924
 
739
     let exporter1: MyExporter
925
     let exporter1: MyExporter
802
         serv.close()
988
         serv.close()
803
     })
989
     })
804
 
990
 
805
-    /* The server-side socket will enter a 30s timeout if destroyed by a RPC.
806
-       to mitigate the impact on testing time these are not run.
807
-
808
-    it("binds correctly", function(done){
809
-        this.timeout(1000)
810
-        sock['MyExporter'].myRPC().then((res) => {
811
-            done(new Error(res))
812
-        }).catch(e => {
813
-            //job will time out because of setExporters
814
-            allowed = true
815
-            done()
816
-        })
817
-    })
818
-
819
-    it("changes exporters", (done) => {
820
-        
821
-        sock['MyExporter'].myRPC().then((res) => {
822
-            if (res === "Hello Borld")
823
-                done()
824
-            else
825
-                done(new Error(res))
826
-        })
827
-    })
828
-    */
829
-
830
-
831
     it("use sesameFilter for available", (done) => {
991
     it("use sesameFilter for available", (done) => {
832
         if (sock['MyExporter']) {
992
         if (sock['MyExporter']) {
833
             allowed = false
993
             allowed = false
842
     })
1002
     })
843
 })
1003
 })
844
 
1004
 
1005
+/*
1006
+describe('finally', () => {
1007
+    it('print open handles (Ignore `DNSCHANNEL` and `Immediate`)', () => {
1008
+        //log(console)
1009
+    })
1010
+})
1011
+*/
1012
+
845
 
1013
 
846
 describe("attaching handlers before connecting", () => {
1014
 describe("attaching handlers before connecting", () => {
847
     it("fires error if server is unreachable", (done) => {
1015
     it("fires error if server is unreachable", (done) => {
870
         })
1038
         })
871
     })
1039
     })
872
 
1040
 
873
-    /*
874
-     * ## 1.11.0 breaking ##
875
-     * 
876
-     * API change: Move from bsock to socketio changes underlying API for when errors are thrown.
877
-     * socketio does not throw on unknown listener. This behaviour is considered more consistent with the design 
878
-     * goals of RPClibrary and was thus adopted 
879
-     *
880
-          
881
-     
882
     it("fires error if call is unknown", (done) => {
1041
     it("fires error if call is unknown", (done) => {
883
-        const serv = new RPCServer(21004)
1042
+        const serv = new RPCServer().listen(21004)
884
         const sock = new RPCSocket(21004, 'localhost')
1043
         const sock = new RPCSocket(21004, 'localhost')
885
 
1044
 
886
         sock.on('error', (err) => {
1045
         sock.on('error', (err) => {
900
         })
1059
         })
901
     })
1060
     })
902
 
1061
 
903
-    it("demands catch on method invocation if call is unknown", (done) => {
904
-        const serv = new RPCServer(21004)
905
-        const sock = new RPCSocket(21004, 'localhost')
906
-
907
-        sock.connect().then(_ => {
908
-            sock.call("unknownRPC123", "AAAAA").catch(e => {
909
-                sock.close()
910
-                serv.close()
911
-                done()
912
-            })
913
-        }).catch(e => {
914
-            console.log("unexpected connect catch clause");
915
-            done(e)
916
-        })
917
-    })
918
-    */
919
-
920
 })
1062
 })
921
-
922
-describe('finally', () => {
923
-    it('print open handles (Ignore `DNSCHANNEL` and `Immediate`)', () => {
924
-        //log(console)
925
-    })
926
-})

Loading…
Cancel
Save