This commit is contained in:
2019-09-21 02:56:03 +02:00
parent 968885767a
commit 2b765eb2a2
11 changed files with 165 additions and 77 deletions
+40 -21
View File
@@ -18,17 +18,46 @@ export {
export class Server{
private ws = http.createServer()
private io = bsock.createServer()
private visibility:T.Visibility
private closeHandler:T.CloseHandler
private errorHandler: T.ErrorHandler
private connectionHandler: T.ConnectionHandler
constructor(
private port:number,
private exporters: I.Exporter[] = [],
private conf: T.SocketConf = {
errorHandler: (socket:I.Socket) => (error:any) => { socket.destroy(); console.error(error) },
closeHandler: (socket:I.Socket) => () => { console.log("Socket closing") },
connectionHandler: (socket:I.Socket) => { console.log("New websocket connection in port "+socket.port)},
visibility: "127.0.0.1"
}
conf: T.SocketConf = {}
){
if(!conf.visibility) this.visibility = "127.0.0.1"
if(!conf.errorHandler) this.errorHandler =
(socket:I.Socket) => (error:any) => {
socket.destroy();
console.error(error)
}
if(!conf.closeHandler) this.closeHandler =
(socket:I.Socket) => () => {
console.log("Socket on port "+socket.port+"closing")
}
if(!conf.connectionHandler) this.connectionHandler =
(socket:I.Socket) => {
console.log("New websocket connection in port "+socket.port)
}
let badRPC
if(badRPC = exporters.flatMap(ex => ex.exportRPCs()).find(rpc => !rpc.name))
throw new Error(`
RPC did not provide a name.
\nUse funtion name(..){ .. } syntax instead.
\n
\n<------------OFFENDING RPC:
\n`+badRPC.toString()+`
\n>------------OFFENDING RPC`)
this.startWebsocket()
}
@@ -36,14 +65,12 @@ export class Server{
try{
this.io.attach(this.ws)
this.io.on('socket', (socket:I.Socket) => {
socket.on('error', this.conf.errorHandler(socket))
socket.on('close', this.conf.closeHandler(socket))
if(this.conf.visibility === "127.0.0.1")
this.initRPCs(socket)
else
this.initPublicRPCs(socket)
socket.on('error', this.errorHandler(socket))
socket.on('close', this.closeHandler(socket))
this.connectionHandler(socket)
this.initRPCs(socket)
})
this.ws.listen(this.port, this.conf.visibility)
this.ws.listen(this.port, this.visibility)
}catch(e){
//@ts-ignore
this.errorHandler(undefined)("Unable to connect to socket")
@@ -57,12 +84,4 @@ export class Server{
...this.exporters.flatMap(exporter => U.rpcHooker(socket, exporter))
]
}
protected initPublicRPCs(socket:I.Socket){
socket.hook('info', () => rpcInfos)
const rpcInfos:T.ExtendedRpcInfo[] = [
...this.exporters.flatMap(exporter => U.rpcHooker(socket, exporter))
]
}
}
+4 -6
View File
@@ -1,6 +1,6 @@
'use strict'
var bsock = require('bsock')
import bsock = require('bsock');
import * as T from './Types';
import * as U from './Utils';
@@ -26,8 +26,6 @@ export class Client implements I.Socket{
constructor(public port:number, private server: string, private tls: boolean = false){
}
public hook(name: T.Name, args: T.Arg){
return this.socket.hook(name, args)
}
@@ -96,9 +94,9 @@ export class Client implements I.Socket{
return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
const r = await this.socket.call("`+fnName+`", `+argParams+`)
if(r.uid != null){
this.socket.hook(res.uid, callback)
this.socket.hook(r.uid, callback)
}
return res
return r
} )()` )
}
@@ -111,7 +109,7 @@ export class Client implements I.Socket{
return eval( `( () => async (`+headerArgs+`) => {
const r = await this.socket.call("`+fnName+`", `+argParams+`)
this.socket.unhook(`+argParams+`)
return res
return r
} )()` )
}
+1 -2
View File
@@ -3,8 +3,7 @@ import * as I from "./Interfaces"
export interface Exporter{
name: T.Name
localRPCs() : T.RPC[]
publicRPCs() : T.RPC[]
exportRPCs() : T.RPC[]
}
export interface Socket {
+10 -8
View File
@@ -6,12 +6,14 @@ export type Any = any
export type Arg = string
export type Name = Arg
export type Owner = Name
export type ConnectionHandler = (socket:I.Socket) => void
export type ErrorHandler = (socket:I.Socket) => (error:any) => void
export type CloseHandler = (socket:I.Socket) => () => void
export type SocketConf = {
connectionHandler: (socket:I.Socket) => void
errorHandler: (socket:I.Socket) => (error:any) => void
closeHandler: (socket:I.Socket) => () => void
visibility: Visibility
connectionHandler?: ConnectionHandler
errorHandler?: ErrorHandler
closeHandler?: CloseHandler
visibility?: Visibility
}
export type RPCType = 'Hook' | 'Unhook' | 'Call'
@@ -23,7 +25,7 @@ export type BaseRPC = {
export type HookRPC = BaseRPC & {
type: 'Hook'
clbk: CallbackFunction
hook: CallbackFunction
unhook: UnhookFunction
}
@@ -32,10 +34,10 @@ export type UnhookRPC = BaseRPC & {
unhook: UnhookFunction
}
export type CallRPC = BaseRPC & {
export type CallRPC = (BaseRPC & {
type: 'Call'
call: AsyncFunction
}
} ) | Function
export type RPC = CallRPC | UnhookRPC | HookRPC
+49 -29
View File
@@ -4,38 +4,59 @@ import * as T from "./Types";
import * as I from "./Interfaces";
export const rpcToRpcinfo = (rpc : T.RPC, owner: T.Owner):T.RpcInfo => {
switch(rpc.type){
case "Call" :
switch (typeof rpc){
case "object":
switch(rpc.type){
case "Call" :
return {
owner: owner,
argNames: extractArgs(rpc.call),
type: rpc.type,
name: rpc.name,
call: rpc.call,
}
case "Unhook" :
return {
owner: owner,
argNames: extractArgs(rpc.unhook),
type: rpc.type,
name: rpc.name,
unhook: rpc.unhook,
}
case "Hook" :
const generator = hookGenerator(rpc)
return {
owner: owner,
argNames: extractArgs(generator(undefined)),
type: rpc.type,
name: rpc.name,
unhook: rpc.unhook,
generator: generator,
}
}
break;
case "function":
if(!rpc.name) throw new Error(`
RPC did not provide a name.
\nUse funtion name(..){ .. } syntax instead.
\n
\n<------------OFFENDING RPC:
\n`+rpc.toString()+`
\n>------------OFFENDING RPC`)
return {
owner: owner,
argNames: extractArgs(rpc.call),
type: rpc.type,
name: rpc.name,
call: rpc.call,
}
case "Unhook" :
return {
owner: owner,
argNames: extractArgs(rpc.unhook),
type: rpc.type,
name: rpc.name,
unhook: rpc.unhook,
}
case "Hook" :
const generator = hookGenerator(rpc)
return {
owner: owner,
argNames: extractArgs(generator(undefined)),
type: rpc.type,
name: rpc.name,
unhook: rpc.unhook,
generator: generator,
type: "Call",
owner : owner,
argNames: extractArgs(rpc),
call: async(...args) => rpc.apply({}, args),
name: rpc.name
}
}
throw new Error("Bad socketIORPC type "+ typeof rpc)
}
export function rpcHooker(socket: I.Socket, exporter:I.Exporter, makeUnique = true):T.ExtendedRpcInfo[]{
const owner = exporter.name
const RPCs = [...exporter.publicRPCs(), ...exporter.localRPCs()]
const RPCs = [...exporter.exportRPCs()]
const suffix = makeUnique?"-"+uuid().substr(0,4):""
return RPCs.map(rpc => rpcToRpcinfo(rpc, owner))
.map(info => {
@@ -59,12 +80,12 @@ export function rpcHooker(socket: I.Socket, exporter:I.Exporter, makeUnique = tr
}
const hookGenerator = (rpc:T.HookRPC): T.HookInfo['generator'] => {
const argsArr = extractArgs(rpc.clbk)
const argsArr = extractArgs(rpc.hook)
argsArr.pop()
const args = argsArr.join(',')
return eval(`(socket) => async (`+args+`) => {
const res = await rpc.clbk(`+args+(args.length!==0?',':'')+` (x) => {
const res = await rpc.hook(`+args+(args.length!==0?',':'')+` (x) => {
socket.call(res.uid, x)
})
if(res.result == 'Success'){
@@ -72,7 +93,6 @@ const hookGenerator = (rpc:T.HookRPC): T.HookInfo['generator'] => {
const unhookRes = await rpc.unhook(res.uid)
console.log("Specific close handler for", rpc.name, res.uid, unhookRes)
})
}
return res
}`)
+1 -1
View File
@@ -5,7 +5,7 @@ const frontendConf = {
target: "web",
entry: path.resolve(__dirname, '..', 'js', 'src', 'Frontend.js'),
output: {
path: path.resolve(__dirname, '..', 'js', 'src'),
path: path.resolve(__dirname, '..', 'js', 'rpclibrary.browser.js'),
filename: "Frontend.js",
libraryTarget: 'commonjs',
},