Browse Source

v0.1.4 sesame sockets

master
peter 4 years ago
parent
commit
4087a12a87
8 changed files with 603 additions and 756 deletions
  1. 524
    726
      package-lock.json
  2. 1
    1
      package.json
  3. 2
    2
      src/Backend.ts
  4. 30
    17
      src/Frontend.ts
  5. 2
    2
      src/Interfaces.ts
  6. 8
    1
      src/Types.ts
  7. 15
    6
      src/Utils.ts
  8. 21
    1
      test/devtest.ts

+ 524
- 726
package-lock.json
File diff suppressed because it is too large
View File


+ 1
- 1
package.json View File

@@ -1,6 +1,6 @@
1 1
 {
2 2
   "name": "rpclibrary",
3
-  "version": "1.3.17",
3
+  "version": "1.4.0",
4 4
   "description": "rpclibrary is a websocket on steroids!",
5 5
   "main": "./js/Index.js",
6 6
   "repository": {

+ 2
- 2
src/Backend.ts View File

@@ -30,7 +30,7 @@ export class RPCServer<
30 30
     constructor(
31 31
         private port:number,
32 32
         private exporters: I.RPCExporter<T.RPCInterface<InterfaceT>, keyof InterfaceT, SubResType>[] = [],
33
-        conf: T.SocketConf =  {}
33
+        private conf: T.ServerConf =  {}
34 34
     ){
35 35
         
36 36
         if(!conf.visibility) this.visibility = "127.0.0.1"        
@@ -82,7 +82,7 @@ export class RPCServer<
82 82
     protected initRPCs(socket:I.Socket){
83 83
         socket.hook('info', () => rpcInfos)
84 84
         const rpcInfos:T.ExtendedRpcInfo[] = [
85
-            ...this.exporters.flatMap(exporter => U.rpcHooker(socket, exporter))
85
+            ...this.exporters.flatMap(exporter => U.rpcHooker(socket, exporter, this.conf.sesame))
86 86
         ]
87 87
     }
88 88
 

+ 30
- 17
src/Frontend.ts View File

@@ -17,8 +17,8 @@ function stripAfterEquals(str:string):string{
17 17
  * A websocket-on-steroids with built-in RPC capabilities
18 18
  */
19 19
 export class RPCSocket implements I.Socket{
20
-    static async makeSocket<T extends T.RPCInterface= T.RPCInterface>(port:number, server: string, tls: boolean = false): Promise<RPCSocket & T.RPCInterface<T>> {
21
-        const socket = <RPCSocket & T> new RPCSocket(port, server, tls)
20
+    static async makeSocket<T extends T.RPCInterface= T.RPCInterface>(port:number, server: string, conf?:T.SocketConf): Promise<RPCSocket & T.RPCInterface<T>> {
21
+        const socket = <RPCSocket & T> new RPCSocket(port, server, conf)
22 22
         return await socket.connect<T>()
23 23
     }
24 24
 
@@ -30,7 +30,7 @@ export class RPCSocket implements I.Socket{
30 30
      * @param server Server address
31 31
      * @param tls @default false use TLS
32 32
      */
33
-    constructor(public port:number, private server: string, private tls: boolean = false){
33
+    constructor(public port:number, private server: string, private conf:T.SocketConf = { tls: false }){
34 34
         Object.defineProperty(this, 'socket', {value: undefined, writable: true})
35 35
     }
36 36
 
@@ -95,18 +95,18 @@ export class RPCSocket implements I.Socket{
95 95
     /**
96 96
      * Connects to the server and attaches available RPCs to this object
97 97
      */
98
-    public async connect<T extends T.RPCInterface= T.RPCInterface>() : Promise<RPCSocket & T.RPCInterface<T>>{
99
-        this.socket = await bsock.connect(this.port, this.server, this.tls)
98
+    public async connect<T extends T.RPCInterface= T.RPCInterface>( sesame?: string ) : Promise<RPCSocket & T.RPCInterface<T>>{
99
+        this.socket = await bsock.connect(this.port, this.server, this.conf.tls?this.conf.tls:false)
100 100
 
101 101
         const info:T.ExtendedRpcInfo[] = await this.info()
102 102
         info.forEach(i => {
103 103
             let f: any
104 104
             switch (i.type) {
105 105
                 case 'Call':
106
-                    f = this.callGenerator(i.uniqueName, i.argNames)    
106
+                    f = this.callGenerator(i.uniqueName, i.argNames, sesame)    
107 107
                     break                
108 108
                 case 'Hook':
109
-                    f = this.hookGenerator(i.uniqueName, i.argNames)                    
109
+                    f = this.hookGenerator(i.uniqueName, i.argNames, sesame)                    
110 110
                     break
111 111
             }
112 112
             if(this[i.owner] == null)
@@ -129,10 +129,13 @@ export class RPCSocket implements I.Socket{
129 129
      * @param fnName The function name
130 130
      * @param fnArgs A string-list of parameters
131 131
      */
132
-    private callGenerator(fnName: string, fnArgs:string[]): T.AnyFunction{
132
+    private callGenerator(fnName: string, fnArgs:string[], sesame?:string): T.AnyFunction{
133 133
         const headerArgs = fnArgs.join(",")
134 134
         const argParams = fnArgs.map(stripAfterEquals).join(",")
135
-        return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", '+argParams+')} )()' )
135
+        if(!sesame)
136
+            return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", '+argParams+')} )()' )
137
+        else   
138
+            return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", "'+sesame+'", '+argParams+')} )()' )
136 139
     }
137 140
 
138 141
     /**
@@ -140,15 +143,25 @@ export class RPCSocket implements I.Socket{
140 143
      * @param fnName The function name
141 144
      * @param fnArgs A string-list of parameters
142 145
      */
143
-    private hookGenerator(fnName: string, fnArgs:string[]): T.HookFunction{
146
+    private hookGenerator(fnName: string, fnArgs:string[], sesame?:string): T.HookFunction{
144 147
         const headerArgs = fnArgs.join(",")
145 148
         const argParams = fnArgs.map(stripAfterEquals).join(",")
146
-        return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
147
-                            const r = await this.socket.call("`+fnName+`", `+argParams+`)
148
-                            if(r.result === 'Success'){
149
-                                this.socket.hook(r.uuid, callback)
150
-                            }
151
-                            return r
152
-                        } )()` )
149
+        if(!sesame){
150
+            return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
151
+                const r = await this.socket.call("`+fnName+`", `+argParams+`)
152
+                if(r.result === 'Success'){
153
+                    this.socket.hook(r.uuid, callback)
154
+                }
155
+                return r
156
+            } )()` )
157
+        }else{
158
+            return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
159
+                const r = await this.socket.call("`+fnName+`", "`+sesame+`", `+argParams+`)
160
+                if(r.result === 'Success'){
161
+                    this.socket.hook(r.uuid, callback)
162
+                }
163
+                return r
164
+            } )()` )
165
+        }
153 166
     }
154 167
 }

+ 2
- 2
src/Interfaces.ts View File

@@ -5,8 +5,8 @@ import * as I from "./Interfaces"
5 5
  * Interface for all classes that export RPCs
6 6
  */
7 7
 export interface RPCExporter<
8
-    Ifc extends T.RPCInterface,
9
-    Name extends keyof Ifc,
8
+    Ifc extends T.RPCInterface = T.RPCInterface,
9
+    Name extends keyof Ifc = keyof Ifc,
10 10
     SubresT = {}
11 11
 >{
12 12
     name: Name

+ 8
- 1
src/Types.ts View File

@@ -7,11 +7,18 @@ export type Visibility = "127.0.0.1" | "0.0.0.0"
7 7
 export type ConnectionHandler = (socket:I.Socket) => void
8 8
 export type ErrorHandler = (socket:I.Socket, error:any) => void
9 9
 export type CloseHandler = (socket:I.Socket) =>  void
10
-export type SocketConf = {
10
+export type SesameConf = {
11
+    sesame?: string
12
+}
13
+export type ServerConf = {
11 14
     connectionHandler?: ConnectionHandler
12 15
     errorHandler?: ErrorHandler
13 16
     closeHandler?: CloseHandler
14 17
     visibility?: Visibility
18
+} & SesameConf
19
+
20
+export type SocketConf = {
21
+    tls:boolean
15 22
 }
16 23
 
17 24
 export type ResponseType = "Subscribe" | "Success" | "Error"

+ 15
- 6
src/Utils.ts View File

@@ -10,7 +10,7 @@ import { SubscriptionResponse } from "./Types";
10 10
  * @param owner The owning RPC group's name
11 11
  * @throws Error on RPC without name property
12 12
  */
13
-export const rpcToRpcinfo = <SubResT = {}>(rpc : T.RPC<any, any, SubResT>, owner: string):T.RpcInfo => {
13
+export const rpcToRpcinfo = <SubResT = {}>(rpc : T.RPC<any, any, SubResT>, owner: string, sesame?:string):T.RpcInfo => {
14 14
     switch (typeof rpc){
15 15
         case  "object":
16 16
             if(rpc['call']){
@@ -19,10 +19,10 @@ export const rpcToRpcinfo = <SubResT = {}>(rpc : T.RPC<any, any, SubResT>, owner
19 19
                     argNames: extractArgs(rpc['call']),
20 20
                     type: "Call",
21 21
                     name: rpc.name,
22
-                    call: rpc['call'],
22
+                    call: sesame?async (_sesame, ...args) => {if(sesame === _sesame) return await rpc['call'].apply({}, args)}:rpc['call'],
23 23
                 }
24 24
             }else{
25
-                const generator = hookGenerator(<T.HookRPC<any, any, any>>rpc)
25
+                const generator = hookGenerator(<T.HookRPC<any, any, any>>rpc, sesame)
26 26
                 return {
27 27
                     owner: owner,
28 28
                     argNames: extractArgs(generator(undefined)),
@@ -56,15 +56,18 @@ RPC did not provide a name.
56 56
  * @param exporter The exporter
57 57
  * @param makeUnique @default true Attach a suffix to RPC names
58 58
  */
59
-export function rpcHooker<SubResT = {}>(socket: I.Socket, exporter:I.RPCExporter<any, any, SubResT>, makeUnique = true):T.ExtendedRpcInfo[]{
59
+export function rpcHooker<SubResT = {}>(socket: I.Socket, exporter:I.RPCExporter<any, any, SubResT>, sesame?:string, makeUnique = true):T.ExtendedRpcInfo[]{
60 60
     const owner = exporter.name
61 61
     const RPCs = [...exporter.exportRPCs()]
62
+
63
+
62 64
     const suffix = makeUnique?"-"+uuidv4().substr(0,4):""
63
-    return RPCs.map(rpc => rpcToRpcinfo(rpc, owner))
65
+    return RPCs.map(rpc => rpcToRpcinfo(rpc, owner, sesame))
64 66
     .map(info => {
65 67
         const ret:any = info
66 68
         ret.uniqueName = info.name+suffix
67 69
 
70
+
68 71
         switch(info.type){
69 72
             case "Hook":
70 73
                 socket.hook(ret.uniqueName, info.generator(socket))
@@ -82,8 +85,14 @@ export function rpcHooker<SubResT = {}>(socket: I.Socket, exporter:I.RPCExporter
82 85
  * @param rpc The RPC to transform
83 86
  * @returns A {@link HookFunction}
84 87
  */
85
-const hookGenerator = (rpc:T.HookRPC<any, any, any>): T.HookInfo['generator'] => { 
88
+const hookGenerator = (rpc:T.HookRPC<any, any, any>, sesame?:string): T.HookInfo['generator'] => { 
86 89
     const argsArr = extractArgs(rpc.hook)
90
+    if(sesame){
91
+        const _sesame = argsArr.shift()
92
+        if(sesame !== _sesame){
93
+            throw new Error('Bad sesame')
94
+        }
95
+    }
87 96
     argsArr.pop()
88 97
     const args = argsArr.join(',')
89 98
 

+ 21
- 1
test/devtest.ts View File

@@ -50,4 +50,24 @@ RPCSocket.makeSocket<MyInterface>(20000, 'localhost').then((async (client) => {
50 50
     })
51 51
 
52 52
     await client.Group1.triggerCallbacks("Hello", "World", "Callbacks")
53
-}))
53
+}))
54
+
55
+const srv = new RPCServer(30000, [{
56
+    name: 'Group2',
57
+    exportRPCs: () => [{
58
+        name: 'echo',
59
+        call: async (x) => x
60
+    }]
61
+}], {
62
+    sesame: 'open'
63
+})
64
+
65
+const s = new RPCSocket(30000, 'localhost')
66
+s.connect("open").then(async() => {
67
+    s['Group2']['echo']('open', 'dfgfg').then(console.log)
68
+    s['Group2']['echo']('dfgfg').then(console.log)
69
+
70
+    s['Group2']['echo']('dfgfg').then(console.log)
71
+
72
+})
73
+

Loading…
Cancel
Save