Browse Source

v 1.3.0 improve pseudointerfaces

master
peter 4 years ago
parent
commit
cc78248e44
8 changed files with 57 additions and 81 deletions
  1. 2
    2
      README.md
  2. 1
    1
      package.json
  3. 1
    1
      src/Backend.ts
  4. 1
    1
      src/Frontend.ts
  5. 5
    5
      src/Interfaces.ts
  6. 25
    21
      src/Types.ts
  7. 3
    10
      test/Test.ts
  8. 19
    40
      test/devtest.ts

+ 2
- 2
README.md View File

@@ -107,7 +107,7 @@ It is possible to declare pseudo-interfaces for servers and clients by using ser
107 107
 This feature is currently still in development and considered **unstable and untested**. Use with caution.
108 108
 
109 109
 ```typescript
110
-type MyInterface = RPCInterface<{ 
110
+type MyInterface = { 
111 111
     Group1: { 
112 112
         triggerCallbacks: (...args:any[]) => Promise<void>,
113 113
         subscribe: (param:string, callback:Function) => Promise<SubscriptionResponse<{a: string}>>,
@@ -116,7 +116,7 @@ type MyInterface = RPCInterface<{
116 116
     Group2: {
117 117
         echo: (x:string) => Promise<string>
118 118
     }
119
-}>
119
+}
120 120
 ```
121 121
 Create a client using
122 122
 ```typescript

+ 1
- 1
package.json View File

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

+ 1
- 1
src/Backend.ts View File

@@ -29,7 +29,7 @@ export class RPCServer<
29 29
      */
30 30
     constructor(
31 31
         private port:number,
32
-        private exporters: I.RPCExporter<T.RPCInterface<InterfaceT>, keyof T.RPCInterface<InterfaceT>, SubResType>[] = [],
32
+        private exporters: I.RPCExporter<T.RPCInterface<InterfaceT>, keyof InterfaceT, SubResType>[] = [],
33 33
         conf: T.SocketConf =  {}
34 34
     ){
35 35
         

+ 1
- 1
src/Frontend.ts View File

@@ -129,7 +129,7 @@ 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.AsyncFunction{
132
+    private callGenerator(fnName: string, fnArgs:string[]): T.AnyFunction{
133 133
         const headerArgs = fnArgs.join(",")
134 134
         const argParams = fnArgs.map(stripAfterEquals).join(",")
135 135
         return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", '+argParams+')} )()' )

+ 5
- 5
src/Interfaces.ts View File

@@ -2,15 +2,15 @@ import * as T from "./Types";
2 2
 import * as I from "./Interfaces"
3 3
 
4 4
 /**
5
- * Interface for all classes that may export RPCs
5
+ * Interface for all classes that export RPCs
6 6
  */
7 7
 export interface RPCExporter<
8
-    Ifc extends T.RPCInterface, 
9
-    K extends keyof Ifc, 
8
+    Ifc extends T.RPCInterface,
9
+    Name extends keyof Ifc,
10 10
     SubresT = {}
11 11
 >{
12
-    name: K
13
-    exportRPCs() : T.RPC<Ifc[K], keyof Ifc[K], SubresT>[]
12
+    name: Name
13
+    exportRPCs() : T.RPCInterfaceArray<Ifc, SubresT>[Name]
14 14
 }
15 15
 
16 16
 /**

+ 25
- 21
src/Types.ts View File

@@ -1,9 +1,7 @@
1 1
 import * as I from "./Interfaces";
2 2
 
3
-export type AnyFunction = (...any:any)=>any
4
-export type AsyncFunction<Fn extends AnyFunction = AnyFunction> = ReturnType<Fn> extends Promise<any> ? Fn : (...any:Parameters<Fn>) => Promise<ReturnType<Fn>>
5
-export type RPCGroup = { [name in string] : AsyncFunction }
6
-export type RPCInterface<Impl extends RPCInterface = {}> = { [groupName in string]: RPCGroup } & Impl
3
+export type AnyFunction = (...args:any) => any
4
+export type HookFunction<F extends AnyFunction = AnyFunction, SubresT = {}> = (...args: Parameters<F>) => Promise<SubscriptionResponse<SubresT> | ErrorResponse>
7 5
 
8 6
 export type Visibility = "127.0.0.1" | "0.0.0.0"
9 7
 export type ConnectionHandler = (socket:I.Socket) => void
@@ -19,7 +17,6 @@ export type SocketConf = {
19 17
 export type ResponseType = "Subscribe" | "Success" | "Error"
20 18
 export type Outcome = "Success" | "Error"
21 19
 
22
-
23 20
 export type Respose<T> = T & { result: Outcome }
24 21
 export type SuccessResponse<T = {}> = Respose<T> & { result: "Success" } 
25 22
 export type ErrorResponse<T = {}> = Respose<T> & { result: "Error", message?:string }
@@ -27,22 +24,31 @@ export type SubscriptionResponse<T = {}> = Respose<T> & { result: "Success"; uui
27 24
 
28 25
 export type RPCType = 'Hook' | 'Unhook' | 'Call'
29 26
 
30
-export type HookT<G extends RPCGroup, K extends keyof G, SubresT> = AsyncFunction<HookFunction<G[K], SubresT>>
31
-export type CallT<G extends RPCGroup, K extends keyof G> = AsyncFunction<G[K]>
27
+export type CallRPC<N, F> = {
28
+    name: N
29
+    call: F
30
+}
32 31
 
33
-export type HookRPC<G extends RPCGroup, K extends keyof G, SubresT = {}> = {
34
-    name: K
35
-    hook: HookT<G, K, SubresT>
36
-    onCallback?: CallbackFunction,
32
+export type HookRPC<N, F extends AnyFunction, SubresT = {}> = {
33
+    name: N
34
+    hook: HookFunction<F, SubresT>
35
+    onCallback?: AnyFunction
37 36
     onClose?: HookCloseFunction<SubresT>
38 37
 }
39 38
 
40
-export type CallRPC<G extends RPCGroup, K extends keyof G> = {
41
-    name: K
42
-    call: CallT<G,K>
43
-} 
39
+export type RPC<N, F extends AnyFunction, SubresT = {}> = HookRPC<N, F, SubresT> | CallRPC<N,F> | F
44 40
 
45
-export type RPC<G extends RPCGroup, Kg extends keyof G, SubresT> = CallRPC<G, Kg> | HookRPC<G, Kg, SubresT>
41
+export type RPCInterface<Impl extends RPCInterface = {}> = {
42
+    [grp in string] : {
43
+        [rpc in string] : AnyFunction
44
+    } 
45
+} & Impl
46
+
47
+export type RPCInterfaceArray<Itfc extends RPCInterface, SubresT = {}> = {
48
+    [grp in keyof Itfc]: Array<
49
+      { [rpc in keyof Itfc[grp]]: RPC<rpc, Itfc[grp][rpc], SubresT> }[keyof Itfc[grp]]
50
+    >
51
+}
46 52
 
47 53
 export type BaseInfo = {
48 54
     name: string,
@@ -50,14 +56,14 @@ export type BaseInfo = {
50 56
     argNames: string[],
51 57
 }
52 58
 
53
-export type HookInfo<T = {}> = BaseInfo & { 
59
+export type HookInfo<SubresT = {}> = BaseInfo & { 
54 60
     type: 'Hook', 
55
-    generator: (socket?:I.Socket) => HookFunction<AnyFunction, T>
61
+    generator: (socket?:I.Socket) => (...args:any) => SubresT
56 62
 }
57 63
 
58 64
 export type CallInfo = BaseInfo & {
59 65
     type: 'Call',
60
-    call: AsyncFunction
66
+    call: AnyFunction
61 67
 }
62 68
 
63 69
 export type RpcInfo = HookInfo |  CallInfo
@@ -65,5 +71,3 @@ export type ExtendedRpcInfo = RpcInfo & { uniqueName: string }
65 71
 
66 72
 export type OnFunction = (type: 'error' | 'close', f: (e?:any)=>void) => I.Socket
67 73
 export type HookCloseFunction<T = {}> = (res:SubscriptionResponse<T>, rpc:HookRPC<any, any, T>) => any
68
-export type HookFunction<F extends AnyFunction = AnyFunction, SubResT = {}> = AsyncFunction<(...args:Parameters<F>) => SubscriptionResponse<SubResT> | ErrorResponse>
69
-export type CallbackFunction = (callback:AnyFunction, ...args:any) => any

+ 3
- 10
test/Test.ts View File

@@ -4,6 +4,7 @@ import { RPCServer } from '../src/Backend'
4 4
 import * as uuidv4 from "uuid/v4"
5 5
 import { RPCSocket } from "../src/Frontend";
6 6
 import { SubscriptionResponse } from "../src/Types";
7
+import { makeSubResponse } from "../src/Utils";
7 8
 
8 9
 const add = (...args:number[]) => {return args.reduce((a,b)=>a+b, 0)}
9 10
 function makeServer(){
@@ -18,21 +19,13 @@ function makeServer(){
18 19
                 name: 'simpleSubscribe',
19 20
                 hook: async(callback) => {
20 21
                     subcallback =  callback
21
-                    return {
22
-                        result: "Success",
23
-                        uuid: uuidv4(),
24
-                        topic: "test"
25
-                    }
22
+                    return makeSubResponse<{topic: string}>({topic: "test"})
26 23
                 }
27 24
             },{
28 25
                 name: 'subscribe',
29 26
                 hook: async (callback) => {
30 27
                     subcallback = callback
31
-                    return {
32
-                        result: "Success",
33
-                        uuid: uuidv4(),
34
-                        topic: "test"
35
-                    }
28
+                    return makeSubResponse<{topic: string}>({topic: "test"})
36 29
                 },
37 30
                 onClose: (res, rpc) => { 
38 31
                     console.log("onClose", rpc.name === 'subscribe' && res?"OK":"")

+ 19
- 40
test/devtest.ts View File

@@ -1,55 +1,40 @@
1 1
 import { RPCServer } from "../src/Backend";
2
-import { SubscriptionResponse, CallRPC, HookRPC, RPCInterface } from "../src/Types";
2
+import { SubscriptionResponse, RPCInterface } from "../src/Types";
3 3
 import { RPCSocket } from "../src/Frontend";
4
+import { makeSubResponse } from "../src/Utils";
4 5
 
5
-type MyInterface = RPCInterface<{ 
6
+type SubresExtension = {a:string}
7
+
8
+type MyInterface = { 
6 9
     Group1: { 
7 10
         triggerCallbacks: (...args:any[]) => Promise<void>,
8
-        subscribe: (param:string, callback:Function) => Promise<SubscriptionResponse<{a: string}>>,
11
+        subscribe: (param:string, callback:Function) => Promise<SubscriptionResponse<SubresExtension>>,
9 12
         unsubscribe: (uuid:string) => Promise<void>
10 13
     },
11 14
     Group2: {
12 15
         echo: (x:string) => Promise<string>
13 16
     }
14
-}>
15
-
16
-const callbacks:Map<string, Function> = new Map()
17
+}
17 18
 
18
-new RPCServer<{a:string}, MyInterface>(20000, 
19
+new RPCServer<SubresExtension, MyInterface>(20000, 
19 20
     [{
20
-        name: "Group1",
21
-        exportRPCs: () => [
22
-        <HookRPC<MyInterface['Group1'], 'subscribe', {a:string}>>{
21
+        name: 'Group1',
22
+        exportRPCs: () => [{
23
+            name: 'triggerCallbacks',
24
+            call: async () => { /*...*/ }
25
+        },{
23 26
             name: 'subscribe',
24
-            hook: async (param, callback) => { const _uuid = ""+Math.random(); console.log(param); callbacks.set(_uuid, callback); return { result: 'Success', a: '3', uuid: _uuid} }
25
-        },
26
-        <CallRPC<MyInterface['Group1'], 'unsubscribe'>>{
27
+            hook: async (param, callback) => { return makeSubResponse<SubresExtension>({a: "test"}) }
28
+        },{
27 29
             name: 'unsubscribe',
28
-            call: async (uuid) => { callbacks.delete(uuid) }
29
-        },
30
-        <CallRPC<MyInterface['Group1'], 'triggerCallbacks'>>{
31
-            name: 'triggerCallbacks',
32
-            call: async (...args) => { callbacks.forEach(cb => cb.apply({}, args)) }
33
-        }]
34
-    },{
35
-        name: 'Group2',
36
-        exportRPCs: () => [
37
-        <CallRPC<MyInterface['Group2'], 'echo'>>{
38
-            name: 'echo',
39
-            call: async (x) => x
40
-        }]
41
-    }]
42
-)
43
-
44
-new RPCServer<{a:string}, MyInterface>(20001, 
45
-    [{
46
-        name: "Group1",
47
-        exportRPCs: () => []
30
+            call: async(uuid) => { }
31
+        }
32
+    ]
48 33
     },{
49 34
         name: 'Group2',
50 35
         exportRPCs: () => [{
51 36
             name: 'echo',
52
-            call: async (x) => x+" lol"
37
+            call: async (x) => "..."
53 38
         }]
54 39
     }]
55 40
 )
@@ -65,10 +50,4 @@ RPCSocket.makeSocket<MyInterface>(20000, 'localhost').then((async (client) => {
65 50
     })
66 51
 
67 52
     await client.Group1.triggerCallbacks("Hello", "World", "Callbacks")
68
-}))
69
-
70
-RPCSocket.makeSocket<MyInterface>(20001, 'localhost').then((async (client) => {
71
-    console.log(client)
72
-    const r = await client.Group2.echo("hee")
73
-    console.log(r)
74 53
 }))

Loading…
Cancel
Save