clean up type system, remove subres
This commit is contained in:
Generated
+55
-35
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "rpclibrary",
|
||||
"version": "1.6.1",
|
||||
"version": "1.9.2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -467,9 +467,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"acorn": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
|
||||
"integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
|
||||
"integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
|
||||
"dev": true
|
||||
},
|
||||
"aggregate-error": {
|
||||
@@ -753,9 +753,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"bluebird": {
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz",
|
||||
"integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==",
|
||||
"version": "3.7.2",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
||||
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
|
||||
"dev": true
|
||||
},
|
||||
"bn.js": {
|
||||
@@ -952,9 +952,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"glob": {
|
||||
"version": "7.1.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz",
|
||||
"integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==",
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
@@ -1062,9 +1062,9 @@
|
||||
}
|
||||
},
|
||||
"chownr": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz",
|
||||
"integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==",
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||
"dev": true
|
||||
},
|
||||
"chrome-trace-event": {
|
||||
@@ -1331,6 +1331,11 @@
|
||||
"randomfill": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"crypto-js": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz",
|
||||
"integrity": "sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg=="
|
||||
},
|
||||
"cyclist": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
|
||||
@@ -2661,9 +2666,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"handlebars": {
|
||||
"version": "4.5.1",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.1.tgz",
|
||||
"integrity": "sha512-C29UoFzHe9yM61lOsIlCE5/mQVGrnIOrOq7maQl76L7tYPCgC1og0Ajt6uWnX4ZTxBPnjw+CUvawphwCfJgUnA==",
|
||||
"version": "4.7.3",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.3.tgz",
|
||||
"integrity": "sha512-SRGwSYuNfx8DwHD/6InAPzD6RgeruWLT+B8e8a7gGs8FWgHzlExpTFMEq2IA6QpAfOClpKHy6+8IqTjeBCu6Kg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"neo-async": "^2.6.0",
|
||||
@@ -3388,9 +3393,9 @@
|
||||
}
|
||||
},
|
||||
"kind-of": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
||||
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
|
||||
"dev": true
|
||||
},
|
||||
"lcid": {
|
||||
@@ -4707,9 +4712,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"serialize-javascript": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz",
|
||||
"integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==",
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
|
||||
"integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
|
||||
"dev": true
|
||||
},
|
||||
"set-blocking": {
|
||||
@@ -5039,6 +5044,12 @@
|
||||
"figgy-pudding": "^3.5.1"
|
||||
}
|
||||
},
|
||||
"stackback": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
|
||||
"integrity": "sha1-Gsig2Ug4SNFpXkGLbQMaPDzmjjs=",
|
||||
"dev": true
|
||||
},
|
||||
"static-extend": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
|
||||
@@ -5094,9 +5105,9 @@
|
||||
}
|
||||
},
|
||||
"stream-shift": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
|
||||
"integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
|
||||
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
@@ -5182,9 +5193,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"terser": {
|
||||
"version": "4.3.9",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.3.9.tgz",
|
||||
"integrity": "sha512-NFGMpHjlzmyOtPL+fDw3G7+6Ueh/sz4mkaUYa4lJCxOPTNzd0Uj0aZJOmsDYoSQyfuVoWDMSWTPU3huyOm2zdA==",
|
||||
"version": "4.6.6",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.6.6.tgz",
|
||||
"integrity": "sha512-4lYPyeNmstjIIESr/ysHg2vUPRGf2tzF9z2yYwnowXVuVzLEamPN1Gfrz7f8I9uEPuHcbFlW4PLIAsJoxXyJ1g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "^2.20.0",
|
||||
@@ -5201,16 +5212,16 @@
|
||||
}
|
||||
},
|
||||
"terser-webpack-plugin": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz",
|
||||
"integrity": "sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==",
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz",
|
||||
"integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cacache": "^12.0.2",
|
||||
"find-cache-dir": "^2.1.0",
|
||||
"is-wsl": "^1.1.0",
|
||||
"schema-utils": "^1.0.0",
|
||||
"serialize-javascript": "^1.7.0",
|
||||
"serialize-javascript": "^2.1.2",
|
||||
"source-map": "^0.6.1",
|
||||
"terser": "^4.1.2",
|
||||
"webpack-sources": "^1.4.0",
|
||||
@@ -5488,9 +5499,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.6.7",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.7.tgz",
|
||||
"integrity": "sha512-4sXQDzmdnoXiO+xvmTzQsfIiwrjUCSA95rSP4SEd8tDb51W2TiDOlL76Hl+Kw0Ie42PSItCW8/t6pBNCF2R48A==",
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.8.0.tgz",
|
||||
"integrity": "sha512-ugNSTT8ierCsDHso2jkBHXYrU8Y5/fY2ZUprfrJUiD7YpuFvV4jODLFmb3h4btQjqr5Nh4TX4XtgDfCU1WdioQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5857,6 +5868,15 @@
|
||||
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
|
||||
"dev": true
|
||||
},
|
||||
"why-is-node-running": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.1.2.tgz",
|
||||
"integrity": "sha512-TwUeoRNMAWy8jAD8oFLtgmYKecZkH3yCtbQ17CYVCxd1WaPJAEB6oqkNgm0o+wIzxJi1oHUkOxMk0M/t5jCGeA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"stackback": "0.0.2"
|
||||
}
|
||||
},
|
||||
"wide-align": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
|
||||
|
||||
+4
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "rpclibrary",
|
||||
"version": "1.9.2",
|
||||
"version": "1.10.0",
|
||||
"description": "rpclibrary is a websocket on steroids!",
|
||||
"main": "./js/Index.js",
|
||||
"repository": {
|
||||
@@ -46,10 +46,12 @@
|
||||
"typedoc-plugin-markdown": "^2.2.6",
|
||||
"typescript": "^3.5.3",
|
||||
"webpack": "^4.40.2",
|
||||
"webpack-cli": "^3.3.9"
|
||||
"webpack-cli": "^3.3.9",
|
||||
"why-is-node-running": "^2.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"bsock": "^0.1.9",
|
||||
"crypto-js": "^4.0.0",
|
||||
"http": "0.0.0",
|
||||
"uuid": "^3.3.3"
|
||||
},
|
||||
|
||||
+7
-11
@@ -2,19 +2,15 @@
|
||||
|
||||
import http = require('http');
|
||||
import bsock = require('bsock');
|
||||
|
||||
import * as T from './Types';
|
||||
import * as U from './Utils';
|
||||
import * as I from './Interfaces';
|
||||
import { Socket } from 'dgram';
|
||||
|
||||
type Exporters<InterfaceT extends T.RPCInterface = T.RPCInterface, SubResType = {}> = I.RPCExporter<T.RPCInterface<InterfaceT>, keyof InterfaceT, SubResType>[]
|
||||
|
||||
/**
|
||||
* A Websocket-server-on-steroids with built-in RPC capabilities
|
||||
*/
|
||||
export class RPCServer<
|
||||
SubResType = {},
|
||||
InterfaceT extends T.RPCInterface = T.RPCInterface,
|
||||
> implements I.Destroyable {
|
||||
|
||||
@@ -25,7 +21,7 @@ export class RPCServer<
|
||||
private errorHandler: T.ErrorHandler
|
||||
private connectionHandler: T.ConnectionHandler
|
||||
private sesame?: T.SesameFunction
|
||||
private accessFilter: T.AccessFilter<InterfaceT, SubResType>
|
||||
private accessFilter: T.AccessFilter<InterfaceT>
|
||||
|
||||
/**
|
||||
* @throws On RPC with no name
|
||||
@@ -35,12 +31,11 @@ export class RPCServer<
|
||||
*/
|
||||
constructor(
|
||||
private port: number,
|
||||
private exporters: Exporters<InterfaceT, SubResType> = [],
|
||||
conf: T.ServerConf<InterfaceT, SubResType> = {}
|
||||
private exporters: T.ExporterArray<InterfaceT> = [],
|
||||
conf: T.ServerConf<InterfaceT> = {}
|
||||
) {
|
||||
if (!conf.visibility) this.visibility = "0.0.0.0"
|
||||
|
||||
|
||||
if (conf.sesame) {
|
||||
this.sesame = U.makeSesameFunction(conf.sesame)
|
||||
}
|
||||
@@ -88,7 +83,7 @@ export class RPCServer<
|
||||
this.connectionHandler(socket)
|
||||
this.initRPCs(socket)
|
||||
})
|
||||
this.ws.listen(this.port, this.visibility)
|
||||
this.ws = this.ws.listen(this.port, this.visibility)
|
||||
} catch (e) {
|
||||
this.errorHandler(this.io, e, 'system', [])
|
||||
}
|
||||
@@ -108,8 +103,7 @@ export class RPCServer<
|
||||
/**
|
||||
* Publishes a new list of Exporters. This destroys and restarts the socket
|
||||
* @param exporters the exporters to publish
|
||||
*/
|
||||
public setExporters(exporters: Exporters<InterfaceT, SubResType>):any{
|
||||
public setExporters(exporters: T.ExporterArray<InterfaceT>): any {
|
||||
exporters.forEach(U.fixNames)
|
||||
this.destroy()
|
||||
this.ws = http.createServer()
|
||||
@@ -117,6 +111,8 @@ export class RPCServer<
|
||||
this.exporters = exporters
|
||||
this.startWebsocket()
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
destroy(): void {
|
||||
this.io.close()
|
||||
|
||||
+15
-6
@@ -7,12 +7,12 @@ import * as I from './Interfaces';
|
||||
import { stripAfterEquals, appendComma } from './Utils';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A websocket-on-steroids with built-in RPC capabilities
|
||||
*/
|
||||
export class RPCSocket implements I.Socket{
|
||||
static async makeSocket<T extends T.RPCInterface = T.RPCInterface>(port:number, server: string, sesame?:string, conf?:T.SocketConf): Promise<RPCSocket & T> {
|
||||
export class RPCSocket<Ifc extends T.RPCInterface = T.RPCInterface> implements I.Socket{
|
||||
|
||||
static async makeSocket<T extends T.RPCInterface = T.RPCInterface>(port:number, server: string, sesame?:string, conf?:T.SocketConf): Promise<T.ConnectedSocket<T>> {
|
||||
const socket = new RPCSocket(port, server, conf)
|
||||
return await socket.connect<T>(sesame)
|
||||
}
|
||||
@@ -128,7 +128,7 @@ export class RPCSocket implements I.Socket{
|
||||
/**
|
||||
* Connects to the server and attaches available RPCs to this object
|
||||
*/
|
||||
public async connect<T extends T.RPCInterface= T.RPCInterface>( sesame?: string ) : Promise<RPCSocket & T>{
|
||||
public async connect<T extends T.RPCInterface= Ifc>( sesame?: string ) : Promise<T.ConnectedSocket<T>> {
|
||||
this.socket = await bsock.connect(this.port, this.server, this.conf.tls?this.conf.tls:false)
|
||||
this.errorHandlers.forEach(h => this.socket.on('error', h))
|
||||
this.closeHandlers.forEach(h => this.socket.on('close', h))
|
||||
@@ -197,10 +197,19 @@ export class RPCSocket implements I.Socket{
|
||||
return eval( `
|
||||
async (${headerArgs} callback) => {
|
||||
const r = await this.call("${fnName}", ${sesame} ${argParams})
|
||||
if(r && r.result === 'Success'){
|
||||
try{
|
||||
if(r){
|
||||
if(r.uuid){
|
||||
callback['destroy'] = () => { this.socket.unhook(r.uuid) }
|
||||
this.socket.hook(r.uuid, callback)
|
||||
}
|
||||
return r
|
||||
return r.return
|
||||
}else{
|
||||
throw new Error("Empty response")
|
||||
}
|
||||
}catch(e){
|
||||
throw e
|
||||
}
|
||||
}`)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-5
@@ -4,13 +4,12 @@ import * as I from "./Interfaces"
|
||||
/**
|
||||
* Interface for all classes that export RPCs
|
||||
*/
|
||||
export interface RPCExporter<
|
||||
export type RPCExporter<
|
||||
Ifc extends T.RPCInterface = T.RPCInterface,
|
||||
Name extends keyof Ifc = keyof Ifc,
|
||||
SubresT = {}
|
||||
>{
|
||||
Name extends keyof Ifc = string,
|
||||
> = {
|
||||
name: Name
|
||||
exportRPCs() : T.RPCInterfaceArray<Ifc, SubresT>[Name]
|
||||
exportRPCs() : T.RPCDefinitions<Ifc>[Name]
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+26
-18
@@ -1,8 +1,9 @@
|
||||
import * as I from "./Interfaces";
|
||||
import { RPCSocket } from "./Frontend";
|
||||
|
||||
export type AnyFunction = (...args:any) => any
|
||||
export type HookFunction<F extends AnyFunction = AnyFunction, SubresT = {}> = (...args: Parameters<F>) => Promise<SubscriptionResponse<SubresT> | ErrorResponse>
|
||||
export type AccessFilter<InterfaceT extends RPCInterface, SubresT> = (sesame:string|undefined, exporter: I.RPCExporter<RPCInterface<InterfaceT>, keyof InterfaceT, SubresT>) => Promise<boolean>
|
||||
export type HookFunction = AnyFunction
|
||||
export type AccessFilter<InterfaceT extends RPCInterface = RPCInterface> = (sesame:string|undefined, exporter: I.RPCExporter<InterfaceT, keyof InterfaceT>) => Promise<boolean>
|
||||
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, rpcName: string, args: any[]) => void
|
||||
@@ -17,8 +18,12 @@ export type FrontEndHandlerType = {
|
||||
'close' : () => void
|
||||
}
|
||||
|
||||
export type ServerConf<InterfaceT extends RPCInterface, SubresT> = {
|
||||
accessFilter?: AccessFilter<InterfaceT, SubresT>
|
||||
export type ExporterArray<InterfaceT extends RPCInterface = RPCInterface> = I.RPCExporter<RPCInterface<InterfaceT>, keyof InterfaceT>[]
|
||||
|
||||
export type ConnectedSocket<T extends RPCInterface = RPCInterface> = RPCSocket & T
|
||||
|
||||
export type ServerConf<InterfaceT extends RPCInterface> = {
|
||||
accessFilter?: AccessFilter<InterfaceT>
|
||||
connectionHandler?: ConnectionHandler
|
||||
errorHandler?: ErrorHandler
|
||||
closeHandler?: CloseHandler
|
||||
@@ -36,23 +41,23 @@ export type Outcome = "Success" | "Error"
|
||||
export type Respose<T> = T & { result: Outcome }
|
||||
export type SuccessResponse<T = {}> = Respose<T> & { result: "Success" }
|
||||
export type ErrorResponse<T = {}> = Respose<T> & { result: "Error", message?:string }
|
||||
export type SubscriptionResponse<T = {}> = Respose<T> & { result: "Success"; uuid: string }
|
||||
|
||||
export type RPCType = 'Hook' | 'Unhook' | 'Call'
|
||||
|
||||
export type CallRPC<N, F> = {
|
||||
name: N
|
||||
call: F
|
||||
export type CallRPC<Name, Func extends AnyFunction> = {
|
||||
name: Name
|
||||
call: Func
|
||||
}
|
||||
|
||||
export type HookRPC<N, F extends AnyFunction, SubresT = {}> = {
|
||||
name: N
|
||||
hook: HookFunction<F, SubresT>
|
||||
|
||||
export type HookRPC<Name, Func extends AnyFunction> = {
|
||||
name: Name
|
||||
hook: Func
|
||||
onCallback?: AnyFunction
|
||||
onClose?: HookCloseFunction<SubresT>
|
||||
onClose?: HookCloseFunction<ReturnType<Func> extends Promise<infer T> ? T : ReturnType<Func>>
|
||||
}
|
||||
|
||||
export type RPC<N, F extends AnyFunction, SubresT = {}> = HookRPC<N, F, SubresT> | CallRPC<N,F> | F
|
||||
export type RPC<Name, Func extends AnyFunction> = HookRPC<Name, Func> | CallRPC<Name,Func> | Func
|
||||
|
||||
export type RPCInterface<Impl extends RPCInterface = {}> = {
|
||||
[grp in string] : {
|
||||
@@ -60,10 +65,13 @@ export type RPCInterface<Impl extends RPCInterface = {}> = {
|
||||
}
|
||||
} & Impl
|
||||
|
||||
export type RPCInterfaceArray<Itfc extends RPCInterface, SubresT = {}> = {
|
||||
[grp in keyof Itfc]: Array<
|
||||
{ [rpc in keyof Itfc[grp]]: RPC<rpc, Itfc[grp][rpc], SubresT> }[keyof Itfc[grp]]
|
||||
>
|
||||
export type exportT = {
|
||||
[group in string]: {}
|
||||
}
|
||||
|
||||
//This probably has lots of issues
|
||||
export type RPCDefinitions<Ifc extends RPCInterface> = {
|
||||
[grp in keyof Ifc]:( { [rpc in keyof Ifc[grp]]: RPC<rpc, Ifc[grp][rpc]> }[keyof Ifc[grp]] )[]
|
||||
}
|
||||
|
||||
export type BaseInfo = {
|
||||
@@ -86,4 +94,4 @@ export type RpcInfo = HookInfo | CallInfo
|
||||
export type ExtendedRpcInfo = RpcInfo & { uniqueName: string }
|
||||
|
||||
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: T, rpc:HookRPC<any, any>) => any
|
||||
|
||||
+17
-24
@@ -2,7 +2,6 @@ import * as uuidv4 from "uuid/v4"
|
||||
|
||||
import * as T from "./Types";
|
||||
import * as I from "./Interfaces";
|
||||
import { SubscriptionResponse } from "./Types";
|
||||
|
||||
/**
|
||||
* Translate an RPC to RPCInfo for serialization.
|
||||
@@ -12,7 +11,7 @@ import { SubscriptionResponse } from "./Types";
|
||||
* @param sesame optional sesame phrase to prepend before all RPC arguments
|
||||
* @throws Error on RPC without name property
|
||||
*/
|
||||
export const rpcToRpcinfo = <SubResT = {}>(socket: I.Socket, rpc : T.RPC<any, any, SubResT>, owner: string, errorHandler: T.ErrorHandler, sesame?:T.SesameFunction):T.RpcInfo => {
|
||||
export const rpcToRpcinfo = (socket: I.Socket, rpc : T.RPC<any, any>, owner: string, errorHandler: T.ErrorHandler, sesame?:T.SesameFunction):T.RpcInfo => {
|
||||
switch (typeof rpc){
|
||||
case "object":
|
||||
if(rpc['call']){
|
||||
@@ -24,7 +23,7 @@ export const rpcToRpcinfo = <SubResT = {}>(socket: I.Socket, rpc : T.RPC<any, an
|
||||
call: sesame?async (_sesame, ...args) => {if(sesame(_sesame)) return await rpc['call'].apply({}, args); socket.destroy()}:rpc['call'], // check & remove sesame
|
||||
}
|
||||
}else{
|
||||
const generator = hookGenerator(<T.HookRPC<any, any, any>>rpc, errorHandler, sesame)
|
||||
const generator = hookGenerator(<T.HookRPC<any, any>>rpc, errorHandler, sesame)
|
||||
return {
|
||||
owner: owner,
|
||||
argNames: extractArgs(generator(undefined)),
|
||||
@@ -58,10 +57,9 @@ RPC did not provide a name.
|
||||
* @param exporter The exporter
|
||||
* @param makeUnique @default true Attach a suffix to RPC names
|
||||
*/
|
||||
export function rpcHooker<SubResT = {}>(socket: I.Socket, exporter:I.RPCExporter<any, any, SubResT>, errorHandler: T.ErrorHandler, sesame?:T.SesameFunction, makeUnique = true):T.ExtendedRpcInfo[]{
|
||||
export function rpcHooker(socket: I.Socket, exporter:I.RPCExporter<any, any>, errorHandler: T.ErrorHandler, sesame?:T.SesameFunction, makeUnique = true):T.ExtendedRpcInfo[]{
|
||||
const owner = exporter.name
|
||||
const RPCs = [...exporter.exportRPCs()]
|
||||
|
||||
const RPCs = exporter.exportRPCs()
|
||||
|
||||
return RPCs.map(rpc => rpcToRpcinfo(socket, rpc, owner, errorHandler, sesame))
|
||||
.map(info => {
|
||||
@@ -107,7 +105,7 @@ export function stripAfterEquals(str:string):string{
|
||||
* @param rpc The RPC to transform
|
||||
* @returns A {@link HookFunction}
|
||||
*/
|
||||
const hookGenerator = (rpc:T.HookRPC<any, any, any>, errorHandler: T.ErrorHandler, sesameFn?: T.SesameFunction): T.HookInfo['generator'] => {
|
||||
const hookGenerator = (rpc:T.HookRPC<any, any>, /*not unused!*/ errorHandler: T.ErrorHandler, sesameFn?: T.SesameFunction): T.HookInfo['generator'] => {
|
||||
let argsArr = extractArgs(rpc.hook)
|
||||
argsArr.pop() //remove 'callback' from the end
|
||||
let callArgs = argsArr.join(',')
|
||||
@@ -119,16 +117,23 @@ const hookGenerator = (rpc:T.HookRPC<any, any, any>, errorHandler: T.ErrorHandle
|
||||
|
||||
//note rpc.hook is the associated RPC, not a socket.hook
|
||||
return eval(`
|
||||
(socket) => async (${args}) => {
|
||||
(clientSocket) => async (${args}) => {
|
||||
try{
|
||||
if(sesameFn && !sesameFn(sesame)) return
|
||||
const uuid = uuidv4()
|
||||
const res = await rpc.hook(${callArgs} (...cbargs) => {
|
||||
if(rpc.onCallback) rpc.onCallback.apply({}, cbargs)
|
||||
socket.call.apply(socket, [res.uuid, ...cbargs])
|
||||
if(rpc.onCallback){
|
||||
rpc.onCallback.apply({}, cbargs)
|
||||
}
|
||||
clientSocket.call.apply(clientSocket, [uuid, ...cbargs])
|
||||
})
|
||||
return res
|
||||
if(rpc.onClose){
|
||||
clientSocket.on('close', () => rpc.onClose(res, rpc))
|
||||
}
|
||||
return {'uuid': uuid, 'return': res}
|
||||
}catch(e){
|
||||
errorHandler(socket)(e, ${rpc.name}, [${args}])
|
||||
//can throw to pass exception to client or swallow to keep it local
|
||||
errorHandler(clientSocket)(e, ${rpc.name}, [${args}])
|
||||
}
|
||||
}`)
|
||||
}
|
||||
@@ -147,18 +152,6 @@ const extractArgs = (f:Function):string[] => {
|
||||
return fn!==""?fn.split(',') : []
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple utility function to create basic {@link SubscriptionResponse}
|
||||
* @param uuid optional uuid to use, otherwise defaults to uuid/v4
|
||||
*/
|
||||
export function makeSubResponse<T extends {} = {}>(extension:T):SubscriptionResponse & T{
|
||||
return {
|
||||
result: "Success",
|
||||
uuid: uuidv4(),
|
||||
...extension
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function makeSesameFunction (sesame : T.SesameFunction | string) : T.SesameFunction {
|
||||
if(typeof sesame === 'function'){
|
||||
|
||||
+142
-99
@@ -1,16 +1,14 @@
|
||||
import { describe, it, Func } from "mocha";
|
||||
|
||||
import { RPCServer, RPCSocket, SubscriptionResponse, makeSubResponse } from '../Index'
|
||||
import * as uuidv4 from "uuid/v4"
|
||||
import { doesNotReject } from "assert";
|
||||
import { Socket } from "dgram";
|
||||
import { describe, it } from "mocha";
|
||||
import { RPCServer, RPCSocket } from '../Index'
|
||||
import { RPCExporter } from "../src/Interfaces";
|
||||
import { ConnectedSocket } from "../src/Types";
|
||||
import * as log from 'why-is-node-running';
|
||||
|
||||
const add = (...args: number[]) => { return args.reduce((a, b) => a + b, 0) }
|
||||
function makeServer() {
|
||||
let subcallback
|
||||
return new RPCServer<{ topic: string }>(21010, [{
|
||||
name: "test",
|
||||
return new RPCServer(21010, [{
|
||||
name: 'test',
|
||||
exportRPCs: () => [
|
||||
{
|
||||
name: 'echo',
|
||||
@@ -19,13 +17,14 @@ function makeServer(){
|
||||
name: 'simpleSubscribe',
|
||||
hook: async (callback) => {
|
||||
subcallback = callback
|
||||
return makeSubResponse<{topic: string}>({topic: "test"})
|
||||
}
|
||||
return { topic: "test" }
|
||||
},
|
||||
onClose: (res) => { }
|
||||
}, {
|
||||
name: 'subscribe',
|
||||
hook: async (callback) => {
|
||||
subcallback = callback
|
||||
return makeSubResponse<{topic: string}>({topic: "test"})
|
||||
return { topic: "test" }
|
||||
},
|
||||
onClose: (res, rpc) => {
|
||||
console.log("onClose", rpc.name === 'subscribe' && res ? "OK" : "")
|
||||
@@ -47,21 +46,11 @@ function makeServer(){
|
||||
|
||||
|
||||
describe('RPCServer', () => {
|
||||
let server: RPCServer<{ topic: string }, any>
|
||||
|
||||
before(() => {
|
||||
server = makeServer()
|
||||
})
|
||||
|
||||
after(() => {
|
||||
server.destroy()
|
||||
})
|
||||
|
||||
it('should be able to use all kinds of RPC definitions', (done) => {
|
||||
|
||||
let client, server
|
||||
const echo = (x) => x
|
||||
|
||||
const server = new RPCServer(21003, [{
|
||||
before(done => {
|
||||
server = new RPCServer(21003, [{
|
||||
name: 'HelloWorldRPCGroup',
|
||||
exportRPCs: () => [
|
||||
echo, //named function variable
|
||||
@@ -73,17 +62,28 @@ describe('RPCServer', () => {
|
||||
]
|
||||
}])
|
||||
|
||||
const client = new RPCSocket(21003, 'localhost')
|
||||
client = new RPCSocket(21003, 'localhost')
|
||||
done()
|
||||
})
|
||||
|
||||
after(done => {
|
||||
client.destroy()
|
||||
server.destroy()
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
it('should be able to use all kinds of RPC definitions', (done) => {
|
||||
client.connect().then(async () => {
|
||||
const r0 = await client['HelloWorldRPCGroup'].echo('Hello')
|
||||
const r1 = await client['HelloWorldRPCGroup'].echof('World')
|
||||
const r2 = await client['HelloWorldRPCGroup'].echoExplicit('R', 'P', 'C!')
|
||||
|
||||
|
||||
if (r0 === 'Hello' && r1 === 'World' && r2.join('') === 'RPC!') {
|
||||
client.destroy()
|
||||
server.destroy()
|
||||
done()
|
||||
}else{
|
||||
done(new Error("Bad response"))
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -91,7 +91,7 @@ describe('RPCServer', () => {
|
||||
it('new RPCServer() should fail on bad RPC', (done) => {
|
||||
try {
|
||||
new RPCServer(20001, [{
|
||||
name: "bad",
|
||||
name: 'bad',
|
||||
exportRPCs: () => [
|
||||
(aaa, bbb, ccc) => { return aaa + bbb + ccc }
|
||||
]
|
||||
@@ -106,7 +106,7 @@ describe('RPCServer', () => {
|
||||
|
||||
describe('RPCSocket', () => {
|
||||
let client: RPCSocket
|
||||
let server: RPCServer<{topic: string}>
|
||||
let server: RPCServer
|
||||
|
||||
before(async () => {
|
||||
server = makeServer()
|
||||
@@ -140,7 +140,7 @@ describe('RPCSocket', () => {
|
||||
|
||||
it('should subscribe with success', (done) => {
|
||||
client['test'].simpleSubscribe(console.log).then(res => {
|
||||
if(res.result === 'Success'){
|
||||
if (res.topic === 'test') {
|
||||
done()
|
||||
} else {
|
||||
console.error(res)
|
||||
@@ -173,48 +173,42 @@ describe('RPCSocket', () => {
|
||||
})
|
||||
|
||||
describe('It should do unhook', () => {
|
||||
let candy = "OK"
|
||||
const yesCandy = "OK"
|
||||
const noCandy = "stolen"
|
||||
let candy = yesCandy
|
||||
let cb: Function
|
||||
let cb2: Function
|
||||
let client: RPCSocket
|
||||
let server: RPCServer<{topic: string}>
|
||||
let server: RPCServer
|
||||
|
||||
before(async () => {
|
||||
server = new RPCServer<{ topic: string }>(21010, [{
|
||||
server = new RPCServer(21010, [{
|
||||
name: "test",
|
||||
exportRPCs: () => [{
|
||||
name: 'subscribe',
|
||||
hook: async(callback):Promise<SubscriptionResponse<{topic:string}>> => {
|
||||
hook: async (callback): Promise<void> => {
|
||||
cb = <Function>callback
|
||||
return {
|
||||
result: "Success",
|
||||
uuid: uuidv4(),
|
||||
topic: "test"
|
||||
}
|
||||
return
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'subscribeWithParam',
|
||||
hook: async(param, callback):Promise<SubscriptionResponse<{topic:string}>> => {
|
||||
hook: async (param, callback): Promise<{ uuid: string }> => {
|
||||
|
||||
if (param != "OK") {
|
||||
console.log("param was" + param);
|
||||
return {
|
||||
result: "Success",
|
||||
uuid: "no",
|
||||
topic: "test"
|
||||
}
|
||||
}
|
||||
cb2 = <Function>callback
|
||||
return {
|
||||
result: "Success",
|
||||
uuid: "OK",
|
||||
topic: "test"
|
||||
}
|
||||
}
|
||||
},
|
||||
function checkCandy():string { cb(candy); return candy },
|
||||
function stealCandy():string { candy = "_OK"; cb(candy); cb = () => {}; return candy }
|
||||
function publish(): string { cb(candy); return candy },
|
||||
function unsubscribe(): string { candy = noCandy; cb(candy); cb = () => { }; return candy }
|
||||
]
|
||||
}], {
|
||||
connectionHandler: (socket) => { },
|
||||
@@ -231,23 +225,33 @@ describe('It should do unhook', () => {
|
||||
})
|
||||
|
||||
it('Subscribe with param', (done) => {
|
||||
client['test'].subscribeWithParam("OK", c => {}).then( async (res: SubscriptionResponse) => {
|
||||
if(res.uuid === "OK"){
|
||||
client['test'].subscribeWithParam("OK", c => { }).then(async (res) => {
|
||||
if (res.uuid === candy) {
|
||||
done()
|
||||
} else
|
||||
done(new Error("Results did not match " + res.uuid))
|
||||
})
|
||||
})
|
||||
|
||||
it('Unhook+unsubscribe should stop callbacks', (done) => {
|
||||
client['test'].subscribe(c => {}).then( async (res: SubscriptionResponse) => {
|
||||
const r1 = await client['test'].checkCandy()
|
||||
const r3 = await client['test'].stealCandy()
|
||||
client.unhook(res.uuid)
|
||||
const r2 = await client['test'].checkCandy()
|
||||
const r4 = await client['test'].checkCandy()
|
||||
let run = 0
|
||||
const expected = [yesCandy, noCandy, noCandy, noCandy]
|
||||
|
||||
if(r1 === "OK" && r3 === "_OK" && r2 === "_OK" && r4 === "_OK")
|
||||
it('Unhook+unsubscribe should stop callbacks', (done) => {
|
||||
|
||||
client['test'].subscribe(function myCallback(c){
|
||||
if(run == 1)
|
||||
(myCallback as any).destroy()
|
||||
|
||||
if (c !== expected[run++]) {
|
||||
done(new Error(`Wrong candy '${c}' in iteration '${run - 1}'`))
|
||||
}
|
||||
}).then(async function(res){
|
||||
const r1 = await client['test'].publish()
|
||||
const r3 = await client['test'].unsubscribe()
|
||||
const r2 = await client['test'].publish()
|
||||
const r4 = await client['test'].publish()
|
||||
|
||||
if (r1 === yesCandy && r3 === noCandy && r2 === noCandy && r4 === noCandy)
|
||||
done()
|
||||
else
|
||||
done(new Error("Results did not match: " + [r1, r2, r3, r4]))
|
||||
@@ -255,43 +259,54 @@ describe('It should do unhook', () => {
|
||||
})
|
||||
})
|
||||
|
||||
type topicDTO = { topic: string; }
|
||||
|
||||
type SesameTestIfc = {
|
||||
test: {
|
||||
checkCandy: () => Promise<string>
|
||||
subscribe: (callback) => Promise<SubscriptionResponse<{ topic: string; }>>
|
||||
subscribe: (callback: Function) => Promise<topicDTO>
|
||||
manyParams: <A=string,B=number,C=boolean,D=Object>(a:A, b:B, c:C, d:D) => Promise<[A, B, C, D]>
|
||||
}
|
||||
|
||||
other: {
|
||||
echo: (x:any) => Promise<any>
|
||||
}
|
||||
}
|
||||
|
||||
describe('Sesame should unlock the socket', () => {
|
||||
let candy = "OK"
|
||||
let client: RPCSocket & SesameTestIfc
|
||||
let server: RPCServer
|
||||
let cb = (...args) => {}
|
||||
let client: ConnectedSocket<SesameTestIfc>
|
||||
let server: RPCServer<SesameTestIfc>
|
||||
let cb: Function = (...args) => { }
|
||||
|
||||
before((done) => {
|
||||
server = new RPCServer(21004, [{
|
||||
server = new RPCServer<SesameTestIfc>(21004, [{
|
||||
name: "test",
|
||||
exportRPCs: () => [
|
||||
{
|
||||
name: 'subscribe',
|
||||
hook: async (callback) => {
|
||||
cb = callback
|
||||
return <SubscriptionResponse>{
|
||||
result: "Success",
|
||||
uuid: uuidv4(),
|
||||
return {
|
||||
topic: 'test'
|
||||
}
|
||||
}
|
||||
},
|
||||
async function checkCandy():Promise<string> { cb(candy); cb=()=>{}; return candy },
|
||||
onClose: (a) => { }
|
||||
},
|
||||
async function checkCandy() { cb(candy); cb = () => { }; return candy },
|
||||
async function manyParams(a, b, c, d) { return [a, b, c, d] }
|
||||
]}
|
||||
],{
|
||||
],
|
||||
},{
|
||||
name: 'other',
|
||||
exportRPCs: () => [
|
||||
async function echo(x){return x}
|
||||
]
|
||||
|
||||
}], {
|
||||
sesame: (_sesame) => _sesame === 'sesame!'
|
||||
})
|
||||
const sock = new RPCSocket(21004, "localhost")
|
||||
sock.connect<SesameTestIfc>('sesame!').then(cli => {
|
||||
const sock = new RPCSocket<SesameTestIfc>(21004, "localhost")
|
||||
sock.connect('sesame!').then(cli => {
|
||||
client = cli
|
||||
done()
|
||||
})
|
||||
@@ -345,8 +360,8 @@ describe('Sesame should unlock the socket', () => {
|
||||
done()
|
||||
}
|
||||
}).then(d => {
|
||||
if(d.result !== 'Success')
|
||||
done('unexpected valid response')
|
||||
if (d.topic !== 'test')
|
||||
done('unexpected invalid response')
|
||||
|
||||
client.test.checkCandy()
|
||||
})
|
||||
@@ -355,18 +370,20 @@ describe('Sesame should unlock the socket', () => {
|
||||
|
||||
|
||||
describe('Error handling', () => {
|
||||
const errtxt = "BAD BAD BAD"
|
||||
|
||||
let createUser = async (user: { a: any, b: any }) => {
|
||||
throw new Error("BAD BAD BAD")
|
||||
throw new Error(errtxt)
|
||||
}
|
||||
|
||||
it("RPC throws on client without handler", (done) => {
|
||||
let server = new RPCServer(21004, [{
|
||||
name: 'createUser' as 'createUser',
|
||||
name: "createUser",
|
||||
exportRPCs: () => [{
|
||||
name: 'createUser' as 'createUser',
|
||||
call: createUser
|
||||
}]}], {
|
||||
}]
|
||||
}], {
|
||||
|
||||
})
|
||||
|
||||
@@ -378,11 +395,13 @@ describe('Error handling', ()=>{
|
||||
})
|
||||
.then(r => {
|
||||
if (r != null)
|
||||
done("UNEXPECTED RESULT " + r)
|
||||
done(new Error("UNEXPECTED RESULT " + r))
|
||||
})
|
||||
.catch((e) => {
|
||||
//console.log("EXPECTED CLIENT EXCEPTION", String(e));
|
||||
if (e.message === errtxt)
|
||||
done()
|
||||
else
|
||||
done(e)
|
||||
})
|
||||
.finally(() => {
|
||||
cli.destroy()
|
||||
@@ -394,11 +413,12 @@ describe('Error handling', ()=>{
|
||||
|
||||
it("RPC throws on server with handler", (done) => {
|
||||
let server = new RPCServer(21004, [{
|
||||
name: 'createUser' as 'createUser',
|
||||
name: "createUser",
|
||||
exportRPCs: () => [{
|
||||
name: 'createUser' as 'createUser',
|
||||
call: createUser
|
||||
}]}], {
|
||||
}]
|
||||
}], {
|
||||
errorHandler: (socket, e, rpcName, args) => {
|
||||
done()
|
||||
}
|
||||
@@ -429,19 +449,22 @@ describe('Error handling', ()=>{
|
||||
|
||||
|
||||
describe("Errorhandler functionality", () => {
|
||||
const errtxt = "BAD BAD BAD"
|
||||
|
||||
let createUser = async (user: { a: any, b: any }) => {
|
||||
throw new Error("BAD BAD BAD")
|
||||
throw new Error(errtxt)
|
||||
}
|
||||
|
||||
it("correct values are passed to the handler", (done) => {
|
||||
let server = new RPCServer(21004, [{
|
||||
name: 'createUser' as 'createUser',
|
||||
name: "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')
|
||||
if (e.message === errtxt && rpcName === "createUser" && args[0]['a'] === 'a' && args[0]['b'] === 'b')
|
||||
done()
|
||||
}
|
||||
})
|
||||
@@ -457,8 +480,7 @@ describe("Errorhandler functionality", ()=>{
|
||||
done("UNEXPECTED RESULT " + r)
|
||||
})
|
||||
.catch((e) => {
|
||||
done("UNEXPECTED CLIENT ERROR " + e)
|
||||
done(e)
|
||||
done(new Error("UNEXPECTED CLIENT ERROR " + e.message))
|
||||
})
|
||||
.finally(() => {
|
||||
cli.destroy()
|
||||
@@ -471,14 +493,15 @@ describe("Errorhandler functionality", ()=>{
|
||||
it("handler sees sesame", (done) => {
|
||||
let sesame = "AAAAAAAAAAAAAAA"
|
||||
let server = new RPCServer(21004, [{
|
||||
name: 'createUser' as 'createUser',
|
||||
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')
|
||||
if (e.message === errtxt && rpcName === "createUser" && args[0] === sesame && args[1]['a'] === 'a' && args[1]['b'] === 'b')
|
||||
done()
|
||||
}
|
||||
|
||||
@@ -517,24 +540,24 @@ type myExporterIfc = {
|
||||
describe("Class binding", () => {
|
||||
|
||||
let exporter1: MyExporter
|
||||
let serv : RPCServer<{}, myExporterIfc>
|
||||
let serv: RPCServer<myExporterIfc>
|
||||
let sock: RPCSocket & myExporterIfc
|
||||
let allowed = true
|
||||
|
||||
class MyExporter implements RPCExporter<myExporterIfc>{
|
||||
name = "MyExporter" as "MyExporter";
|
||||
name = "MyExporter" as "MyExporter"
|
||||
exportRPCs = () => [
|
||||
this.myRPC
|
||||
]
|
||||
|
||||
myRPC = async () => {
|
||||
serv.setExporters([new MyOtherExporter])
|
||||
//serv.setExporters([new MyOtherExporter])
|
||||
return "Hello World"
|
||||
}
|
||||
}
|
||||
|
||||
class MyOtherExporter implements RPCExporter<myExporterIfc>{
|
||||
name = "MyExporter" as "MyExporter";
|
||||
name = "MyExporter" as "MyExporter"
|
||||
exportRPCs = () => [
|
||||
this.myRPC
|
||||
]
|
||||
@@ -547,14 +570,13 @@ describe("Class binding", ()=>{
|
||||
|
||||
before(done => {
|
||||
exporter1 = new MyExporter()
|
||||
serv = new RPCServer<{}, myExporterIfc>(21004, [exporter1], {
|
||||
serv = new RPCServer<myExporterIfc>(21004, [exporter1], {
|
||||
accessFilter: async (sesame, exporter) => {
|
||||
switch(exporter.name){
|
||||
case "MyExporter":
|
||||
if(exporter.name === 'MyExporter'){
|
||||
if (!allowed) return false
|
||||
allowed = false
|
||||
return sesame === 'xxx';
|
||||
default:
|
||||
}else{
|
||||
return false
|
||||
}
|
||||
},
|
||||
@@ -564,7 +586,6 @@ describe("Class binding", ()=>{
|
||||
})
|
||||
|
||||
beforeEach((done) => {
|
||||
|
||||
const s = new RPCSocket(21004, 'localhost')
|
||||
s.connect<myExporterIfc>("xxx").then(conn => {
|
||||
sock = conn
|
||||
@@ -572,7 +593,7 @@ describe("Class binding", ()=>{
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(done => {
|
||||
afterEach((done) => {
|
||||
sock.destroy()
|
||||
done()
|
||||
})
|
||||
@@ -581,7 +602,11 @@ describe("Class binding", ()=>{
|
||||
serv.destroy()
|
||||
})
|
||||
|
||||
it("binds correctly", (done)=>{
|
||||
/* The server-side socket will enter a 30s timeout if destroyed by a RPC.
|
||||
to mitigate the impact on testing time these are not run.
|
||||
|
||||
it("binds correctly", function(done){
|
||||
this.timeout(1000)
|
||||
sock['MyExporter'].myRPC().then((res) => {
|
||||
done(new Error(res))
|
||||
}).catch(e => {
|
||||
@@ -592,6 +617,7 @@ describe("Class binding", ()=>{
|
||||
})
|
||||
|
||||
it("changes exporters", (done) => {
|
||||
|
||||
sock['MyExporter'].myRPC().then((res) => {
|
||||
if (res === "Hello Borld")
|
||||
done()
|
||||
@@ -599,6 +625,16 @@ describe("Class binding", ()=>{
|
||||
done(new Error(res))
|
||||
})
|
||||
})
|
||||
*/
|
||||
|
||||
|
||||
it("use sesameFilter for available", (done) => {
|
||||
if (sock['MyExporter']){
|
||||
allowed = false
|
||||
done()
|
||||
}
|
||||
else done(new Error("RPC supposed to be here"))
|
||||
})
|
||||
|
||||
it("use sesameFilter", (done) => {
|
||||
if (!sock['MyExporter']) done()
|
||||
@@ -667,4 +703,11 @@ describe("attaching handlers before connecting", ()=>{
|
||||
done(e)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('finally', () => {
|
||||
it('print open handles (Ignore `DNSCHANNEL` and `Immediate`)', () => {
|
||||
log()
|
||||
})
|
||||
})
|
||||
@@ -1,73 +0,0 @@
|
||||
import { RPCServer } from "../src/Backend";
|
||||
import { SubscriptionResponse, RPCInterface } from "../src/Types";
|
||||
import { RPCSocket } from "../src/Frontend";
|
||||
import { makeSubResponse } from "../src/Utils";
|
||||
|
||||
type SubresExtension = {a:string}
|
||||
|
||||
type MyInterface = {
|
||||
Group1: {
|
||||
triggerCallbacks: (...args:any[]) => Promise<void>,
|
||||
subscribe: (param:string, callback:Function) => Promise<SubscriptionResponse<SubresExtension>>,
|
||||
unsubscribe: (uuid:string) => Promise<void>
|
||||
},
|
||||
Group2: {
|
||||
echo: (x:string) => Promise<string>
|
||||
}
|
||||
}
|
||||
|
||||
new RPCServer<SubresExtension, MyInterface>(20000,
|
||||
[{
|
||||
name: 'Group1',
|
||||
exportRPCs: () => [{
|
||||
name: 'triggerCallbacks',
|
||||
call: async () => { /*...*/ }
|
||||
},{
|
||||
name: 'subscribe',
|
||||
hook: async (param, callback) => { return makeSubResponse<SubresExtension>({a: "test"}) }
|
||||
},{
|
||||
name: 'unsubscribe',
|
||||
call: async(uuid) => { }
|
||||
}
|
||||
]
|
||||
},{
|
||||
name: 'Group2',
|
||||
exportRPCs: () => [{
|
||||
name: 'echo',
|
||||
call: async (x) => "..."
|
||||
}]
|
||||
}]
|
||||
)
|
||||
|
||||
RPCSocket.makeSocket<MyInterface>(20000, 'localhost').then((async (client) => {
|
||||
console.log(client)
|
||||
const res = await client.Group1.subscribe('test', async (...args:any) => {
|
||||
console.log.apply(console, args)
|
||||
|
||||
/* close the callbacks once you're done */
|
||||
await client.Group1.unsubscribe(res.uuid)
|
||||
client.unhook(res.uuid)
|
||||
})
|
||||
|
||||
await client.Group1.triggerCallbacks("Hello", "World", "Callbacks")
|
||||
}))
|
||||
|
||||
const srv = new RPCServer(30000, [{
|
||||
name: 'Group2',
|
||||
exportRPCs: () => [{
|
||||
name: 'echo',
|
||||
call: async (x) => x
|
||||
}]
|
||||
}], {
|
||||
sesame: 'open'
|
||||
})
|
||||
|
||||
const s = new RPCSocket(30000, 'localhost')
|
||||
s.connect("open").then(async() => {
|
||||
s['Group2']['echo']('open', 'dfgfg').then(console.log)
|
||||
s['Group2']['echo']('dfgfg').then(console.log)
|
||||
|
||||
s['Group2']['echo']('dfgfg').then(console.log)
|
||||
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user