v 1.3.0 improve pseudointerfaces
This commit is contained in:
@@ -107,7 +107,7 @@ It is possible to declare pseudo-interfaces for servers and clients by using ser
|
|||||||
This feature is currently still in development and considered **unstable and untested**. Use with caution.
|
This feature is currently still in development and considered **unstable and untested**. Use with caution.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
type MyInterface = RPCInterface<{
|
type MyInterface = {
|
||||||
Group1: {
|
Group1: {
|
||||||
triggerCallbacks: (...args:any[]) => Promise<void>,
|
triggerCallbacks: (...args:any[]) => Promise<void>,
|
||||||
subscribe: (param:string, callback:Function) => Promise<SubscriptionResponse<{a: string}>>,
|
subscribe: (param:string, callback:Function) => Promise<SubscriptionResponse<{a: string}>>,
|
||||||
@@ -116,7 +116,7 @@ type MyInterface = RPCInterface<{
|
|||||||
Group2: {
|
Group2: {
|
||||||
echo: (x:string) => Promise<string>
|
echo: (x:string) => Promise<string>
|
||||||
}
|
}
|
||||||
}>
|
}
|
||||||
```
|
```
|
||||||
Create a client using
|
Create a client using
|
||||||
```typescript
|
```typescript
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rpclibrary",
|
"name": "rpclibrary",
|
||||||
"version": "1.2.6",
|
"version": "1.3.0",
|
||||||
"description": "rpclibrary is a websocket on steroids!",
|
"description": "rpclibrary is a websocket on steroids!",
|
||||||
"main": "./js/Index.js",
|
"main": "./js/Index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ export class RPCServer<
|
|||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
private port:number,
|
private port:number,
|
||||||
private exporters: I.RPCExporter<T.RPCInterface<InterfaceT>, keyof T.RPCInterface<InterfaceT>, SubResType>[] = [],
|
private exporters: I.RPCExporter<T.RPCInterface<InterfaceT>, keyof InterfaceT, SubResType>[] = [],
|
||||||
conf: T.SocketConf = {}
|
conf: T.SocketConf = {}
|
||||||
){
|
){
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -129,7 +129,7 @@ export class RPCSocket implements I.Socket{
|
|||||||
* @param fnName The function name
|
* @param fnName The function name
|
||||||
* @param fnArgs A string-list of parameters
|
* @param fnArgs A string-list of parameters
|
||||||
*/
|
*/
|
||||||
private callGenerator(fnName: string, fnArgs:string[]): T.AsyncFunction{
|
private callGenerator(fnName: string, fnArgs:string[]): T.AnyFunction{
|
||||||
const headerArgs = fnArgs.join(",")
|
const headerArgs = fnArgs.join(",")
|
||||||
const argParams = fnArgs.map(stripAfterEquals).join(",")
|
const argParams = fnArgs.map(stripAfterEquals).join(",")
|
||||||
return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", '+argParams+')} )()' )
|
return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", '+argParams+')} )()' )
|
||||||
|
|||||||
+4
-4
@@ -2,15 +2,15 @@ import * as T from "./Types";
|
|||||||
import * as I from "./Interfaces"
|
import * as I from "./Interfaces"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for all classes that may export RPCs
|
* Interface for all classes that export RPCs
|
||||||
*/
|
*/
|
||||||
export interface RPCExporter<
|
export interface RPCExporter<
|
||||||
Ifc extends T.RPCInterface,
|
Ifc extends T.RPCInterface,
|
||||||
K extends keyof Ifc,
|
Name extends keyof Ifc,
|
||||||
SubresT = {}
|
SubresT = {}
|
||||||
>{
|
>{
|
||||||
name: K
|
name: Name
|
||||||
exportRPCs() : T.RPC<Ifc[K], keyof Ifc[K], SubresT>[]
|
exportRPCs() : T.RPCInterfaceArray<Ifc, SubresT>[Name]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+25
-21
@@ -1,9 +1,7 @@
|
|||||||
import * as I from "./Interfaces";
|
import * as I from "./Interfaces";
|
||||||
|
|
||||||
export type AnyFunction = (...any:any)=>any
|
export type AnyFunction = (...args:any) => any
|
||||||
export type AsyncFunction<Fn extends AnyFunction = AnyFunction> = ReturnType<Fn> extends Promise<any> ? Fn : (...any:Parameters<Fn>) => Promise<ReturnType<Fn>>
|
export type HookFunction<F extends AnyFunction = AnyFunction, SubresT = {}> = (...args: Parameters<F>) => Promise<SubscriptionResponse<SubresT> | ErrorResponse>
|
||||||
export type RPCGroup = { [name in string] : AsyncFunction }
|
|
||||||
export type RPCInterface<Impl extends RPCInterface = {}> = { [groupName in string]: RPCGroup } & Impl
|
|
||||||
|
|
||||||
export type Visibility = "127.0.0.1" | "0.0.0.0"
|
export type Visibility = "127.0.0.1" | "0.0.0.0"
|
||||||
export type ConnectionHandler = (socket:I.Socket) => void
|
export type ConnectionHandler = (socket:I.Socket) => void
|
||||||
@@ -19,7 +17,6 @@ export type SocketConf = {
|
|||||||
export type ResponseType = "Subscribe" | "Success" | "Error"
|
export type ResponseType = "Subscribe" | "Success" | "Error"
|
||||||
export type Outcome = "Success" | "Error"
|
export type Outcome = "Success" | "Error"
|
||||||
|
|
||||||
|
|
||||||
export type Respose<T> = T & { result: Outcome }
|
export type Respose<T> = T & { result: Outcome }
|
||||||
export type SuccessResponse<T = {}> = Respose<T> & { result: "Success" }
|
export type SuccessResponse<T = {}> = Respose<T> & { result: "Success" }
|
||||||
export type ErrorResponse<T = {}> = Respose<T> & { result: "Error", message?:string }
|
export type ErrorResponse<T = {}> = Respose<T> & { result: "Error", message?:string }
|
||||||
@@ -27,22 +24,31 @@ export type SubscriptionResponse<T = {}> = Respose<T> & { result: "Success"; uui
|
|||||||
|
|
||||||
export type RPCType = 'Hook' | 'Unhook' | 'Call'
|
export type RPCType = 'Hook' | 'Unhook' | 'Call'
|
||||||
|
|
||||||
export type HookT<G extends RPCGroup, K extends keyof G, SubresT> = AsyncFunction<HookFunction<G[K], SubresT>>
|
export type CallRPC<N, F> = {
|
||||||
export type CallT<G extends RPCGroup, K extends keyof G> = AsyncFunction<G[K]>
|
name: N
|
||||||
|
call: F
|
||||||
|
}
|
||||||
|
|
||||||
export type HookRPC<G extends RPCGroup, K extends keyof G, SubresT = {}> = {
|
export type HookRPC<N, F extends AnyFunction, SubresT = {}> = {
|
||||||
name: K
|
name: N
|
||||||
hook: HookT<G, K, SubresT>
|
hook: HookFunction<F, SubresT>
|
||||||
onCallback?: CallbackFunction,
|
onCallback?: AnyFunction
|
||||||
onClose?: HookCloseFunction<SubresT>
|
onClose?: HookCloseFunction<SubresT>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CallRPC<G extends RPCGroup, K extends keyof G> = {
|
export type RPC<N, F extends AnyFunction, SubresT = {}> = HookRPC<N, F, SubresT> | CallRPC<N,F> | F
|
||||||
name: K
|
|
||||||
call: CallT<G,K>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type RPC<G extends RPCGroup, Kg extends keyof G, SubresT> = CallRPC<G, Kg> | HookRPC<G, Kg, SubresT>
|
export type RPCInterface<Impl extends RPCInterface = {}> = {
|
||||||
|
[grp in string] : {
|
||||||
|
[rpc in string] : AnyFunction
|
||||||
|
}
|
||||||
|
} & 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 BaseInfo = {
|
export type BaseInfo = {
|
||||||
name: string,
|
name: string,
|
||||||
@@ -50,14 +56,14 @@ export type BaseInfo = {
|
|||||||
argNames: string[],
|
argNames: string[],
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HookInfo<T = {}> = BaseInfo & {
|
export type HookInfo<SubresT = {}> = BaseInfo & {
|
||||||
type: 'Hook',
|
type: 'Hook',
|
||||||
generator: (socket?:I.Socket) => HookFunction<AnyFunction, T>
|
generator: (socket?:I.Socket) => (...args:any) => SubresT
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CallInfo = BaseInfo & {
|
export type CallInfo = BaseInfo & {
|
||||||
type: 'Call',
|
type: 'Call',
|
||||||
call: AsyncFunction
|
call: AnyFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RpcInfo = HookInfo | CallInfo
|
export type RpcInfo = HookInfo | CallInfo
|
||||||
@@ -65,5 +71,3 @@ export type ExtendedRpcInfo = RpcInfo & { uniqueName: string }
|
|||||||
|
|
||||||
export type OnFunction = (type: 'error' | 'close', f: (e?:any)=>void) => I.Socket
|
export type OnFunction = (type: 'error' | 'close', f: (e?:any)=>void) => I.Socket
|
||||||
export type HookCloseFunction<T = {}> = (res:SubscriptionResponse<T>, rpc:HookRPC<any, any, T>) => any
|
export type HookCloseFunction<T = {}> = (res:SubscriptionResponse<T>, rpc:HookRPC<any, any, T>) => any
|
||||||
export type HookFunction<F extends AnyFunction = AnyFunction, SubResT = {}> = AsyncFunction<(...args:Parameters<F>) => SubscriptionResponse<SubResT> | ErrorResponse>
|
|
||||||
export type CallbackFunction = (callback:AnyFunction, ...args:any) => any
|
|
||||||
+3
-10
@@ -4,6 +4,7 @@ import { RPCServer } from '../src/Backend'
|
|||||||
import * as uuidv4 from "uuid/v4"
|
import * as uuidv4 from "uuid/v4"
|
||||||
import { RPCSocket } from "../src/Frontend";
|
import { RPCSocket } from "../src/Frontend";
|
||||||
import { SubscriptionResponse } from "../src/Types";
|
import { SubscriptionResponse } from "../src/Types";
|
||||||
|
import { makeSubResponse } from "../src/Utils";
|
||||||
|
|
||||||
const add = (...args:number[]) => {return args.reduce((a,b)=>a+b, 0)}
|
const add = (...args:number[]) => {return args.reduce((a,b)=>a+b, 0)}
|
||||||
function makeServer(){
|
function makeServer(){
|
||||||
@@ -18,21 +19,13 @@ function makeServer(){
|
|||||||
name: 'simpleSubscribe',
|
name: 'simpleSubscribe',
|
||||||
hook: async(callback) => {
|
hook: async(callback) => {
|
||||||
subcallback = callback
|
subcallback = callback
|
||||||
return {
|
return makeSubResponse<{topic: string}>({topic: "test"})
|
||||||
result: "Success",
|
|
||||||
uuid: uuidv4(),
|
|
||||||
topic: "test"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
name: 'subscribe',
|
name: 'subscribe',
|
||||||
hook: async (callback) => {
|
hook: async (callback) => {
|
||||||
subcallback = callback
|
subcallback = callback
|
||||||
return {
|
return makeSubResponse<{topic: string}>({topic: "test"})
|
||||||
result: "Success",
|
|
||||||
uuid: uuidv4(),
|
|
||||||
topic: "test"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onClose: (res, rpc) => {
|
onClose: (res, rpc) => {
|
||||||
console.log("onClose", rpc.name === 'subscribe' && res?"OK":"")
|
console.log("onClose", rpc.name === 'subscribe' && res?"OK":"")
|
||||||
|
|||||||
+19
-40
@@ -1,55 +1,40 @@
|
|||||||
import { RPCServer } from "../src/Backend";
|
import { RPCServer } from "../src/Backend";
|
||||||
import { SubscriptionResponse, CallRPC, HookRPC, RPCInterface } from "../src/Types";
|
import { SubscriptionResponse, RPCInterface } from "../src/Types";
|
||||||
import { RPCSocket } from "../src/Frontend";
|
import { RPCSocket } from "../src/Frontend";
|
||||||
|
import { makeSubResponse } from "../src/Utils";
|
||||||
|
|
||||||
type MyInterface = RPCInterface<{
|
type SubresExtension = {a:string}
|
||||||
|
|
||||||
|
type MyInterface = {
|
||||||
Group1: {
|
Group1: {
|
||||||
triggerCallbacks: (...args:any[]) => Promise<void>,
|
triggerCallbacks: (...args:any[]) => Promise<void>,
|
||||||
subscribe: (param:string, callback:Function) => Promise<SubscriptionResponse<{a: string}>>,
|
subscribe: (param:string, callback:Function) => Promise<SubscriptionResponse<SubresExtension>>,
|
||||||
unsubscribe: (uuid:string) => Promise<void>
|
unsubscribe: (uuid:string) => Promise<void>
|
||||||
},
|
},
|
||||||
Group2: {
|
Group2: {
|
||||||
echo: (x:string) => Promise<string>
|
echo: (x:string) => Promise<string>
|
||||||
}
|
}
|
||||||
}>
|
}
|
||||||
|
|
||||||
const callbacks:Map<string, Function> = new Map()
|
new RPCServer<SubresExtension, MyInterface>(20000,
|
||||||
|
|
||||||
new RPCServer<{a:string}, MyInterface>(20000,
|
|
||||||
[{
|
[{
|
||||||
name: "Group1",
|
name: 'Group1',
|
||||||
exportRPCs: () => [
|
exportRPCs: () => [{
|
||||||
<HookRPC<MyInterface['Group1'], 'subscribe', {a:string}>>{
|
|
||||||
name: 'subscribe',
|
|
||||||
hook: async (param, callback) => { const _uuid = ""+Math.random(); console.log(param); callbacks.set(_uuid, callback); return { result: 'Success', a: '3', uuid: _uuid} }
|
|
||||||
},
|
|
||||||
<CallRPC<MyInterface['Group1'], 'unsubscribe'>>{
|
|
||||||
name: 'unsubscribe',
|
|
||||||
call: async (uuid) => { callbacks.delete(uuid) }
|
|
||||||
},
|
|
||||||
<CallRPC<MyInterface['Group1'], 'triggerCallbacks'>>{
|
|
||||||
name: 'triggerCallbacks',
|
name: 'triggerCallbacks',
|
||||||
call: async (...args) => { callbacks.forEach(cb => cb.apply({}, args)) }
|
call: async () => { /*...*/ }
|
||||||
}]
|
|
||||||
},{
|
},{
|
||||||
name: 'Group2',
|
name: 'subscribe',
|
||||||
exportRPCs: () => [
|
hook: async (param, callback) => { return makeSubResponse<SubresExtension>({a: "test"}) }
|
||||||
<CallRPC<MyInterface['Group2'], 'echo'>>{
|
},{
|
||||||
name: 'echo',
|
name: 'unsubscribe',
|
||||||
call: async (x) => x
|
call: async(uuid) => { }
|
||||||
}]
|
}
|
||||||
}]
|
]
|
||||||
)
|
|
||||||
|
|
||||||
new RPCServer<{a:string}, MyInterface>(20001,
|
|
||||||
[{
|
|
||||||
name: "Group1",
|
|
||||||
exportRPCs: () => []
|
|
||||||
},{
|
},{
|
||||||
name: 'Group2',
|
name: 'Group2',
|
||||||
exportRPCs: () => [{
|
exportRPCs: () => [{
|
||||||
name: 'echo',
|
name: 'echo',
|
||||||
call: async (x) => x+" lol"
|
call: async (x) => "..."
|
||||||
}]
|
}]
|
||||||
}]
|
}]
|
||||||
)
|
)
|
||||||
@@ -66,9 +51,3 @@ RPCSocket.makeSocket<MyInterface>(20000, 'localhost').then((async (client) => {
|
|||||||
|
|
||||||
await client.Group1.triggerCallbacks("Hello", "World", "Callbacks")
|
await client.Group1.triggerCallbacks("Hello", "World", "Callbacks")
|
||||||
}))
|
}))
|
||||||
|
|
||||||
RPCSocket.makeSocket<MyInterface>(20001, 'localhost').then((async (client) => {
|
|
||||||
console.log(client)
|
|
||||||
const r = await client.Group2.echo("hee")
|
|
||||||
console.log(r)
|
|
||||||
}))
|
|
||||||
Reference in New Issue
Block a user