v0.1.4 sesame sockets
This commit is contained in:
Generated
+539
-741
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rpclibrary",
|
"name": "rpclibrary",
|
||||||
"version": "1.3.17",
|
"version": "1.4.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": {
|
||||||
|
|||||||
+2
-2
@@ -30,7 +30,7 @@ export class RPCServer<
|
|||||||
constructor(
|
constructor(
|
||||||
private port:number,
|
private port:number,
|
||||||
private exporters: I.RPCExporter<T.RPCInterface<InterfaceT>, keyof InterfaceT, SubResType>[] = [],
|
private exporters: I.RPCExporter<T.RPCInterface<InterfaceT>, keyof InterfaceT, SubResType>[] = [],
|
||||||
conf: T.SocketConf = {}
|
private conf: T.ServerConf = {}
|
||||||
){
|
){
|
||||||
|
|
||||||
if(!conf.visibility) this.visibility = "127.0.0.1"
|
if(!conf.visibility) this.visibility = "127.0.0.1"
|
||||||
@@ -82,7 +82,7 @@ export class RPCServer<
|
|||||||
protected initRPCs(socket:I.Socket){
|
protected initRPCs(socket:I.Socket){
|
||||||
socket.hook('info', () => rpcInfos)
|
socket.hook('info', () => rpcInfos)
|
||||||
const rpcInfos:T.ExtendedRpcInfo[] = [
|
const rpcInfos:T.ExtendedRpcInfo[] = [
|
||||||
...this.exporters.flatMap(exporter => U.rpcHooker(socket, exporter))
|
...this.exporters.flatMap(exporter => U.rpcHooker(socket, exporter, this.conf.sesame))
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+30
-17
@@ -17,8 +17,8 @@ function stripAfterEquals(str:string):string{
|
|||||||
* A websocket-on-steroids with built-in RPC capabilities
|
* A websocket-on-steroids with built-in RPC capabilities
|
||||||
*/
|
*/
|
||||||
export class RPCSocket implements I.Socket{
|
export class RPCSocket implements I.Socket{
|
||||||
static async makeSocket<T extends T.RPCInterface= T.RPCInterface>(port:number, server: string, tls: boolean = false): Promise<RPCSocket & T.RPCInterface<T>> {
|
static async makeSocket<T extends T.RPCInterface= T.RPCInterface>(port:number, server: string, conf?:T.SocketConf): Promise<RPCSocket & T.RPCInterface<T>> {
|
||||||
const socket = <RPCSocket & T> new RPCSocket(port, server, tls)
|
const socket = <RPCSocket & T> new RPCSocket(port, server, conf)
|
||||||
return await socket.connect<T>()
|
return await socket.connect<T>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ export class RPCSocket implements I.Socket{
|
|||||||
* @param server Server address
|
* @param server Server address
|
||||||
* @param tls @default false use TLS
|
* @param tls @default false use TLS
|
||||||
*/
|
*/
|
||||||
constructor(public port:number, private server: string, private tls: boolean = false){
|
constructor(public port:number, private server: string, private conf:T.SocketConf = { tls: false }){
|
||||||
Object.defineProperty(this, 'socket', {value: undefined, writable: true})
|
Object.defineProperty(this, 'socket', {value: undefined, writable: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,18 +95,18 @@ export class RPCSocket implements I.Socket{
|
|||||||
/**
|
/**
|
||||||
* Connects to the server and attaches available RPCs to this object
|
* Connects to the server and attaches available RPCs to this object
|
||||||
*/
|
*/
|
||||||
public async connect<T extends T.RPCInterface= T.RPCInterface>() : Promise<RPCSocket & T.RPCInterface<T>>{
|
public async connect<T extends T.RPCInterface= T.RPCInterface>( sesame?: string ) : Promise<RPCSocket & T.RPCInterface<T>>{
|
||||||
this.socket = await bsock.connect(this.port, this.server, this.tls)
|
this.socket = await bsock.connect(this.port, this.server, this.conf.tls?this.conf.tls:false)
|
||||||
|
|
||||||
const info:T.ExtendedRpcInfo[] = await this.info()
|
const info:T.ExtendedRpcInfo[] = await this.info()
|
||||||
info.forEach(i => {
|
info.forEach(i => {
|
||||||
let f: any
|
let f: any
|
||||||
switch (i.type) {
|
switch (i.type) {
|
||||||
case 'Call':
|
case 'Call':
|
||||||
f = this.callGenerator(i.uniqueName, i.argNames)
|
f = this.callGenerator(i.uniqueName, i.argNames, sesame)
|
||||||
break
|
break
|
||||||
case 'Hook':
|
case 'Hook':
|
||||||
f = this.hookGenerator(i.uniqueName, i.argNames)
|
f = this.hookGenerator(i.uniqueName, i.argNames, sesame)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if(this[i.owner] == null)
|
if(this[i.owner] == null)
|
||||||
@@ -129,10 +129,13 @@ 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.AnyFunction{
|
private callGenerator(fnName: string, fnArgs:string[], sesame?: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+')} )()' )
|
if(!sesame)
|
||||||
|
return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", '+argParams+')} )()' )
|
||||||
|
else
|
||||||
|
return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", "'+sesame+'", '+argParams+')} )()' )
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,15 +143,25 @@ 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 hookGenerator(fnName: string, fnArgs:string[]): T.HookFunction{
|
private hookGenerator(fnName: string, fnArgs:string[], sesame?:string): T.HookFunction{
|
||||||
const headerArgs = fnArgs.join(",")
|
const headerArgs = fnArgs.join(",")
|
||||||
const argParams = fnArgs.map(stripAfterEquals).join(",")
|
const argParams = fnArgs.map(stripAfterEquals).join(",")
|
||||||
return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
|
if(!sesame){
|
||||||
const r = await this.socket.call("`+fnName+`", `+argParams+`)
|
return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
|
||||||
if(r.result === 'Success'){
|
const r = await this.socket.call("`+fnName+`", `+argParams+`)
|
||||||
this.socket.hook(r.uuid, callback)
|
if(r.result === 'Success'){
|
||||||
}
|
this.socket.hook(r.uuid, callback)
|
||||||
return r
|
}
|
||||||
} )()` )
|
return r
|
||||||
|
} )()` )
|
||||||
|
}else{
|
||||||
|
return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
|
||||||
|
const r = await this.socket.call("`+fnName+`", "`+sesame+`", `+argParams+`)
|
||||||
|
if(r.result === 'Success'){
|
||||||
|
this.socket.hook(r.uuid, callback)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
} )()` )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -5,8 +5,8 @@ import * as I from "./Interfaces"
|
|||||||
* Interface for all classes that export RPCs
|
* Interface for all classes that export RPCs
|
||||||
*/
|
*/
|
||||||
export interface RPCExporter<
|
export interface RPCExporter<
|
||||||
Ifc extends T.RPCInterface,
|
Ifc extends T.RPCInterface = T.RPCInterface,
|
||||||
Name extends keyof Ifc,
|
Name extends keyof Ifc = keyof Ifc,
|
||||||
SubresT = {}
|
SubresT = {}
|
||||||
>{
|
>{
|
||||||
name: Name
|
name: Name
|
||||||
|
|||||||
+8
-1
@@ -7,11 +7,18 @@ 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
|
||||||
export type ErrorHandler = (socket:I.Socket, error:any) => void
|
export type ErrorHandler = (socket:I.Socket, error:any) => void
|
||||||
export type CloseHandler = (socket:I.Socket) => void
|
export type CloseHandler = (socket:I.Socket) => void
|
||||||
export type SocketConf = {
|
export type SesameConf = {
|
||||||
|
sesame?: string
|
||||||
|
}
|
||||||
|
export type ServerConf = {
|
||||||
connectionHandler?: ConnectionHandler
|
connectionHandler?: ConnectionHandler
|
||||||
errorHandler?: ErrorHandler
|
errorHandler?: ErrorHandler
|
||||||
closeHandler?: CloseHandler
|
closeHandler?: CloseHandler
|
||||||
visibility?: Visibility
|
visibility?: Visibility
|
||||||
|
} & SesameConf
|
||||||
|
|
||||||
|
export type SocketConf = {
|
||||||
|
tls:boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ResponseType = "Subscribe" | "Success" | "Error"
|
export type ResponseType = "Subscribe" | "Success" | "Error"
|
||||||
|
|||||||
+15
-6
@@ -10,7 +10,7 @@ import { SubscriptionResponse } from "./Types";
|
|||||||
* @param owner The owning RPC group's name
|
* @param owner The owning RPC group's name
|
||||||
* @throws Error on RPC without name property
|
* @throws Error on RPC without name property
|
||||||
*/
|
*/
|
||||||
export const rpcToRpcinfo = <SubResT = {}>(rpc : T.RPC<any, any, SubResT>, owner: string):T.RpcInfo => {
|
export const rpcToRpcinfo = <SubResT = {}>(rpc : T.RPC<any, any, SubResT>, owner: string, sesame?:string):T.RpcInfo => {
|
||||||
switch (typeof rpc){
|
switch (typeof rpc){
|
||||||
case "object":
|
case "object":
|
||||||
if(rpc['call']){
|
if(rpc['call']){
|
||||||
@@ -19,10 +19,10 @@ export const rpcToRpcinfo = <SubResT = {}>(rpc : T.RPC<any, any, SubResT>, owner
|
|||||||
argNames: extractArgs(rpc['call']),
|
argNames: extractArgs(rpc['call']),
|
||||||
type: "Call",
|
type: "Call",
|
||||||
name: rpc.name,
|
name: rpc.name,
|
||||||
call: rpc['call'],
|
call: sesame?async (_sesame, ...args) => {if(sesame === _sesame) return await rpc['call'].apply({}, args)}:rpc['call'],
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
const generator = hookGenerator(<T.HookRPC<any, any, any>>rpc)
|
const generator = hookGenerator(<T.HookRPC<any, any, any>>rpc, sesame)
|
||||||
return {
|
return {
|
||||||
owner: owner,
|
owner: owner,
|
||||||
argNames: extractArgs(generator(undefined)),
|
argNames: extractArgs(generator(undefined)),
|
||||||
@@ -56,15 +56,18 @@ RPC did not provide a name.
|
|||||||
* @param exporter The exporter
|
* @param exporter The exporter
|
||||||
* @param makeUnique @default true Attach a suffix to RPC names
|
* @param makeUnique @default true Attach a suffix to RPC names
|
||||||
*/
|
*/
|
||||||
export function rpcHooker<SubResT = {}>(socket: I.Socket, exporter:I.RPCExporter<any, any, SubResT>, makeUnique = true):T.ExtendedRpcInfo[]{
|
export function rpcHooker<SubResT = {}>(socket: I.Socket, exporter:I.RPCExporter<any, any, SubResT>, sesame?:string, makeUnique = true):T.ExtendedRpcInfo[]{
|
||||||
const owner = exporter.name
|
const owner = exporter.name
|
||||||
const RPCs = [...exporter.exportRPCs()]
|
const RPCs = [...exporter.exportRPCs()]
|
||||||
|
|
||||||
|
|
||||||
const suffix = makeUnique?"-"+uuidv4().substr(0,4):""
|
const suffix = makeUnique?"-"+uuidv4().substr(0,4):""
|
||||||
return RPCs.map(rpc => rpcToRpcinfo(rpc, owner))
|
return RPCs.map(rpc => rpcToRpcinfo(rpc, owner, sesame))
|
||||||
.map(info => {
|
.map(info => {
|
||||||
const ret:any = info
|
const ret:any = info
|
||||||
ret.uniqueName = info.name+suffix
|
ret.uniqueName = info.name+suffix
|
||||||
|
|
||||||
|
|
||||||
switch(info.type){
|
switch(info.type){
|
||||||
case "Hook":
|
case "Hook":
|
||||||
socket.hook(ret.uniqueName, info.generator(socket))
|
socket.hook(ret.uniqueName, info.generator(socket))
|
||||||
@@ -82,8 +85,14 @@ export function rpcHooker<SubResT = {}>(socket: I.Socket, exporter:I.RPCExporter
|
|||||||
* @param rpc The RPC to transform
|
* @param rpc The RPC to transform
|
||||||
* @returns A {@link HookFunction}
|
* @returns A {@link HookFunction}
|
||||||
*/
|
*/
|
||||||
const hookGenerator = (rpc:T.HookRPC<any, any, any>): T.HookInfo['generator'] => {
|
const hookGenerator = (rpc:T.HookRPC<any, any, any>, sesame?:string): T.HookInfo['generator'] => {
|
||||||
const argsArr = extractArgs(rpc.hook)
|
const argsArr = extractArgs(rpc.hook)
|
||||||
|
if(sesame){
|
||||||
|
const _sesame = argsArr.shift()
|
||||||
|
if(sesame !== _sesame){
|
||||||
|
throw new Error('Bad sesame')
|
||||||
|
}
|
||||||
|
}
|
||||||
argsArr.pop()
|
argsArr.pop()
|
||||||
const args = argsArr.join(',')
|
const args = argsArr.join(',')
|
||||||
|
|
||||||
|
|||||||
+21
-1
@@ -50,4 +50,24 @@ RPCSocket.makeSocket<MyInterface>(20000, 'localhost').then((async (client) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
await client.Group1.triggerCallbacks("Hello", "World", "Callbacks")
|
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